From bc5b7bc975d2f75858b9872ef718e373183c3e4c Mon Sep 17 00:00:00 2001 From: Genoil Date: Tue, 24 Mar 2015 07:29:58 +0100 Subject: [PATCH 01/65] Win32 requires ios::binary when writing dag file. --- libdevcore/CommonIO.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libdevcore/CommonIO.cpp b/libdevcore/CommonIO.cpp index 4fa132073..0ebc91b15 100644 --- a/libdevcore/CommonIO.cpp +++ b/libdevcore/CommonIO.cpp @@ -112,6 +112,6 @@ string dev::contentsString(std::string const& _file) void dev::writeFile(std::string const& _file, bytesConstRef _data) { - ofstream(_file, ios::trunc).write((char const*)_data.data(), _data.size()); + ofstream(_file, ios::trunc | ios::binary).write((char const*)_data.data(), _data.size()); } From f8e789be8a673d567aed9076df33b378b5021caa Mon Sep 17 00:00:00 2001 From: Genoil Date: Fri, 3 Apr 2015 07:45:11 +0200 Subject: [PATCH 02/65] added function to read from disk into (OpenCL) buffer --- libdevcore/CommonIO.cpp | 17 +++++++++++++++++ libdevcore/CommonIO.h | 4 ++++ 2 files changed, 21 insertions(+) diff --git a/libdevcore/CommonIO.cpp b/libdevcore/CommonIO.cpp index 46d6e3a6b..12a35c6cb 100644 --- a/libdevcore/CommonIO.cpp +++ b/libdevcore/CommonIO.cpp @@ -75,6 +75,23 @@ bytesRef dev::contentsNew(std::string const& _file) return ret; } +// Don't forget to delete[] later. +uint64_t dev::contentsToBuffer(std::string const& _file, void * buf) +{ + std::ifstream is(_file, std::ifstream::binary); + if (!is) + return 0; + // get length of file: + is.seekg(0, is.end); + streamoff length = is.tellg(); + if (length == 0) // return early, MSVC does not like reading 0 bytes + return 0; + is.seekg(0, is.beg); + is.read((char*)buf, length); + is.close(); + return (uint64_t)length; +} + bytes dev::contents(std::string const& _file) { std::ifstream is(_file, std::ifstream::binary); diff --git a/libdevcore/CommonIO.h b/libdevcore/CommonIO.h index f42f449bb..d3f92d3d2 100644 --- a/libdevcore/CommonIO.h +++ b/libdevcore/CommonIO.h @@ -48,6 +48,10 @@ std::string contentsString(std::string const& _file); /// Retrieve and returns the allocated contents of the given file. If the file doesn't exist or isn't readable, returns nullptr. Don't forget to delete [] when finished. bytesRef contentsNew(std::string const& _file); +/// Retrieve and returns the allocated contents of the given file and load into buffer. Used to fill mapped OpenCL buffer. +uint64_t contentsToBuffer(std::string const& _file, void * buf); + + /// Write the given binary data into the given file, replacing the file if it pre-exists. void writeFile(std::string const& _file, bytesConstRef _data); /// Write the given binary data into the given file, replacing the file if it pre-exists. From 67ec7d9043d210d926e47d26180ef6a8b5c9863f Mon Sep 17 00:00:00 2001 From: Jan Willem Penterman Date: Thu, 16 Apr 2015 17:23:24 +0200 Subject: [PATCH 03/65] enable eth GPU mining --- eth/main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/eth/main.cpp b/eth/main.cpp index 5de9290ae..cdc74b7e6 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -926,6 +926,7 @@ int main(int argc, char** argv) { c->setGasPricer(gasPricer); c->setForceMining(forceMining); + c->setTurboMining(minerType == MinerType::GPU); c->setAddress(coinbase); } From ca77f96cc49fa4fd4aae880063651d71ca7d85d3 Mon Sep 17 00:00:00 2001 From: Genoil Date: Thu, 16 Apr 2015 23:21:30 +0200 Subject: [PATCH 04/65] allow selection of other OpenCL platform than 0, using --opencl-platform n parameters --- eth/main.cpp | 12 ++++++++++++ libethash-cl/ethash_cl_miner.cpp | 24 ++++++++++++++---------- libethash-cl/ethash_cl_miner.h | 4 ++-- libethcore/Ethash.cpp | 5 +++-- libethcore/Ethash.h | 2 ++ 5 files changed, 33 insertions(+), 14 deletions(-) diff --git a/eth/main.cpp b/eth/main.cpp index cdc74b7e6..fa37effc9 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -134,6 +134,7 @@ void help() << " -f,--force-mining Mine even when there are no transactions to mine (default: off)" << endl << " -C,--cpu When mining, use the CPU." << endl << " -G,--opencl When mining use the GPU via OpenCL." << endl + << " --opencl-platform When mining using -G/--opencl use OpenCL platform n (default: 0)." << endl << " --opencl-device When mining using -G/--opencl use OpenCL device n (default: 0)." << endl << "Client networking:" << endl << " --client-name Add a name to your client's version string (default: blank)." << endl @@ -394,6 +395,7 @@ int main(int argc, char** argv) /// Mining options MinerType minerType = MinerType::CPU; + unsigned openclPlatform = 0; unsigned openclDevice = 0; /// File name for import/export. @@ -511,6 +513,15 @@ int main(int argc, char** argv) cerr << "Bad " << arg << " option: " << argv[i] << endl; return -1; } + else if (arg == "--opencl-platform" && i + 1 < argc) + try { + openclPlatform= stol(argv[++i]); + } + catch (...) + { + cerr << "Bad " << arg << " option: " << argv[i] << endl; + return -1; + } else if (arg == "--opencl-device" && i + 1 < argc) try { openclDevice = stol(argv[++i]); @@ -809,6 +820,7 @@ int main(int argc, char** argv) if (sessionSecret) sigKey = KeyPair(sessionSecret); + ProofOfWork::GPUMiner::setDefaultPlatform(openclPlatform); ProofOfWork::GPUMiner::setDefaultDevice(openclDevice); // Two codepaths is necessary since named block require database, but numbered diff --git a/libethash-cl/ethash_cl_miner.cpp b/libethash-cl/ethash_cl_miner.cpp index 172123439..53eabe349 100644 --- a/libethash-cl/ethash_cl_miner.cpp +++ b/libethash-cl/ethash_cl_miner.cpp @@ -57,7 +57,7 @@ ethash_cl_miner::ethash_cl_miner() { } -std::string ethash_cl_miner::platform_info() +std::string ethash_cl_miner::platform_info(unsigned _platformId, unsigned _deviceId) { std::vector platforms; cl::Platform::get(&platforms); @@ -67,21 +67,22 @@ std::string ethash_cl_miner::platform_info() return std::string(); } - // get GPU device of the default platform + // get GPU device of the selected platform std::vector devices; - platforms[0].getDevices(CL_DEVICE_TYPE_ALL, &devices); + unsigned platform_num = std::min(_platformId, platforms.size() - 1); + platforms[platform_num].getDevices(CL_DEVICE_TYPE_ALL, &devices); if (devices.empty()) { debugf("No OpenCL devices found.\n"); return std::string(); } - // use default device - unsigned device_num = 0; + // use selected default device + unsigned device_num = std::min(_deviceId, devices.size() - 1); cl::Device& device = devices[device_num]; std::string device_version = device.getInfo(); - return "{ \"platform\": \"" + platforms[0].getInfo() + "\", \"device\": \"" + device.getInfo() + "\", \"version\": \"" + device_version + "\" }"; + return "{ \"platform\": \"" + platforms[platform_num].getInfo() + "\", \"device\": \"" + device.getInfo() + "\", \"version\": \"" + device_version + "\" }"; } void ethash_cl_miner::finish() @@ -92,7 +93,7 @@ void ethash_cl_miner::finish() } } -bool ethash_cl_miner::init(ethash_params const& params, std::function _fillDAG, unsigned workgroup_size, unsigned _deviceId) +bool ethash_cl_miner::init(ethash_params const& params, std::function _fillDAG, unsigned workgroup_size, unsigned _platformId, unsigned _deviceId) { // store params m_params = params; @@ -106,12 +107,15 @@ bool ethash_cl_miner::init(ethash_params const& params, std::function().c_str()); + // use selected platform + + _platformId = std::min(_platformId, platforms.size() - 1); + + fprintf(stderr, "Using platform: %s\n", platforms[_platformId].getInfo().c_str()); // get GPU device of the default platform std::vector devices; - platforms[0].getDevices(CL_DEVICE_TYPE_ALL, &devices); + platforms[_platformId].getDevices(CL_DEVICE_TYPE_ALL, &devices); if (devices.empty()) { debugf("No OpenCL devices found.\n"); diff --git a/libethash-cl/ethash_cl_miner.h b/libethash-cl/ethash_cl_miner.h index 90793ae97..3046f037b 100644 --- a/libethash-cl/ethash_cl_miner.h +++ b/libethash-cl/ethash_cl_miner.h @@ -31,8 +31,8 @@ public: public: ethash_cl_miner(); - bool init(ethash_params const& params, std::function _fillDAG, unsigned workgroup_size = 64, unsigned _deviceId = 0); - static std::string platform_info(); + bool init(ethash_params const& params, std::function _fillDAG, unsigned workgroup_size = 64, unsigned _platformId = 0, unsigned _deviceId = 0); + static std::string platform_info(unsigned _platformId = 0, unsigned _deviceId = 0); void finish(); void hash(uint8_t* ret, uint8_t const* header, uint64_t nonce, unsigned count); diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index 977149e7a..1bd970317 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -262,6 +262,7 @@ private: Ethash::GPUMiner* m_owner = nullptr; }; +unsigned Ethash::GPUMiner::s_platformId = 0; unsigned Ethash::GPUMiner::s_deviceId = 0; Ethash::GPUMiner::GPUMiner(ConstructionInfo const& _ci): @@ -305,7 +306,7 @@ void Ethash::GPUMiner::workLoop() auto p = EthashAux::params(m_minerSeed); auto cb = [&](void* d) { EthashAux::full(m_minerSeed, bytesRef((byte*)d, p.full_size)); }; - m_miner->init(p, cb, 32, s_deviceId); + m_miner->init(p, cb, 32, s_platformId, s_deviceId); } uint64_t upper64OfBoundary = (uint64_t)(u64)((u256)w.boundary >> 192); @@ -320,7 +321,7 @@ void Ethash::GPUMiner::pause() std::string Ethash::GPUMiner::platformInfo() { - return ethash_cl_miner::platform_info(); + return ethash_cl_miner::platform_info(s_platformId, s_deviceId); } #endif diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 077da4460..7888d4bef 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -113,6 +113,7 @@ public: static unsigned instances() { return 1; } static std::string platformInfo(); + static void setDefaultPlatform(unsigned _id) { s_platformId = _id; } static void setDefaultDevice(unsigned _id) { s_deviceId = _id; } protected: @@ -129,6 +130,7 @@ public: ethash_cl_miner* m_miner = nullptr; h256 m_minerSeed; ///< Last seed in m_miner + static unsigned s_platformId; static unsigned s_deviceId; }; #else From 9bd34c39f9625bc5f5f2ea10b235df1f7cbee5f0 Mon Sep 17 00:00:00 2001 From: Genoil Date: Thu, 16 Apr 2015 23:21:30 +0200 Subject: [PATCH 05/65] allow selection of other OpenCL platform than 0, using --opencl-platform n parameters --- eth/main.cpp | 12 ++++++++++++ libethash-cl/ethash_cl_miner.cpp | 24 ++++++++++++++---------- libethash-cl/ethash_cl_miner.h | 4 ++-- libethcore/Ethash.cpp | 5 +++-- libethcore/Ethash.h | 3 +++ 5 files changed, 34 insertions(+), 14 deletions(-) diff --git a/eth/main.cpp b/eth/main.cpp index cdc74b7e6..fa37effc9 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -134,6 +134,7 @@ void help() << " -f,--force-mining Mine even when there are no transactions to mine (default: off)" << endl << " -C,--cpu When mining, use the CPU." << endl << " -G,--opencl When mining use the GPU via OpenCL." << endl + << " --opencl-platform When mining using -G/--opencl use OpenCL platform n (default: 0)." << endl << " --opencl-device When mining using -G/--opencl use OpenCL device n (default: 0)." << endl << "Client networking:" << endl << " --client-name Add a name to your client's version string (default: blank)." << endl @@ -394,6 +395,7 @@ int main(int argc, char** argv) /// Mining options MinerType minerType = MinerType::CPU; + unsigned openclPlatform = 0; unsigned openclDevice = 0; /// File name for import/export. @@ -511,6 +513,15 @@ int main(int argc, char** argv) cerr << "Bad " << arg << " option: " << argv[i] << endl; return -1; } + else if (arg == "--opencl-platform" && i + 1 < argc) + try { + openclPlatform= stol(argv[++i]); + } + catch (...) + { + cerr << "Bad " << arg << " option: " << argv[i] << endl; + return -1; + } else if (arg == "--opencl-device" && i + 1 < argc) try { openclDevice = stol(argv[++i]); @@ -809,6 +820,7 @@ int main(int argc, char** argv) if (sessionSecret) sigKey = KeyPair(sessionSecret); + ProofOfWork::GPUMiner::setDefaultPlatform(openclPlatform); ProofOfWork::GPUMiner::setDefaultDevice(openclDevice); // Two codepaths is necessary since named block require database, but numbered diff --git a/libethash-cl/ethash_cl_miner.cpp b/libethash-cl/ethash_cl_miner.cpp index 172123439..53eabe349 100644 --- a/libethash-cl/ethash_cl_miner.cpp +++ b/libethash-cl/ethash_cl_miner.cpp @@ -57,7 +57,7 @@ ethash_cl_miner::ethash_cl_miner() { } -std::string ethash_cl_miner::platform_info() +std::string ethash_cl_miner::platform_info(unsigned _platformId, unsigned _deviceId) { std::vector platforms; cl::Platform::get(&platforms); @@ -67,21 +67,22 @@ std::string ethash_cl_miner::platform_info() return std::string(); } - // get GPU device of the default platform + // get GPU device of the selected platform std::vector devices; - platforms[0].getDevices(CL_DEVICE_TYPE_ALL, &devices); + unsigned platform_num = std::min(_platformId, platforms.size() - 1); + platforms[platform_num].getDevices(CL_DEVICE_TYPE_ALL, &devices); if (devices.empty()) { debugf("No OpenCL devices found.\n"); return std::string(); } - // use default device - unsigned device_num = 0; + // use selected default device + unsigned device_num = std::min(_deviceId, devices.size() - 1); cl::Device& device = devices[device_num]; std::string device_version = device.getInfo(); - return "{ \"platform\": \"" + platforms[0].getInfo() + "\", \"device\": \"" + device.getInfo() + "\", \"version\": \"" + device_version + "\" }"; + return "{ \"platform\": \"" + platforms[platform_num].getInfo() + "\", \"device\": \"" + device.getInfo() + "\", \"version\": \"" + device_version + "\" }"; } void ethash_cl_miner::finish() @@ -92,7 +93,7 @@ void ethash_cl_miner::finish() } } -bool ethash_cl_miner::init(ethash_params const& params, std::function _fillDAG, unsigned workgroup_size, unsigned _deviceId) +bool ethash_cl_miner::init(ethash_params const& params, std::function _fillDAG, unsigned workgroup_size, unsigned _platformId, unsigned _deviceId) { // store params m_params = params; @@ -106,12 +107,15 @@ bool ethash_cl_miner::init(ethash_params const& params, std::function().c_str()); + // use selected platform + + _platformId = std::min(_platformId, platforms.size() - 1); + + fprintf(stderr, "Using platform: %s\n", platforms[_platformId].getInfo().c_str()); // get GPU device of the default platform std::vector devices; - platforms[0].getDevices(CL_DEVICE_TYPE_ALL, &devices); + platforms[_platformId].getDevices(CL_DEVICE_TYPE_ALL, &devices); if (devices.empty()) { debugf("No OpenCL devices found.\n"); diff --git a/libethash-cl/ethash_cl_miner.h b/libethash-cl/ethash_cl_miner.h index 90793ae97..3046f037b 100644 --- a/libethash-cl/ethash_cl_miner.h +++ b/libethash-cl/ethash_cl_miner.h @@ -31,8 +31,8 @@ public: public: ethash_cl_miner(); - bool init(ethash_params const& params, std::function _fillDAG, unsigned workgroup_size = 64, unsigned _deviceId = 0); - static std::string platform_info(); + bool init(ethash_params const& params, std::function _fillDAG, unsigned workgroup_size = 64, unsigned _platformId = 0, unsigned _deviceId = 0); + static std::string platform_info(unsigned _platformId = 0, unsigned _deviceId = 0); void finish(); void hash(uint8_t* ret, uint8_t const* header, uint64_t nonce, unsigned count); diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index 977149e7a..1bd970317 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -262,6 +262,7 @@ private: Ethash::GPUMiner* m_owner = nullptr; }; +unsigned Ethash::GPUMiner::s_platformId = 0; unsigned Ethash::GPUMiner::s_deviceId = 0; Ethash::GPUMiner::GPUMiner(ConstructionInfo const& _ci): @@ -305,7 +306,7 @@ void Ethash::GPUMiner::workLoop() auto p = EthashAux::params(m_minerSeed); auto cb = [&](void* d) { EthashAux::full(m_minerSeed, bytesRef((byte*)d, p.full_size)); }; - m_miner->init(p, cb, 32, s_deviceId); + m_miner->init(p, cb, 32, s_platformId, s_deviceId); } uint64_t upper64OfBoundary = (uint64_t)(u64)((u256)w.boundary >> 192); @@ -320,7 +321,7 @@ void Ethash::GPUMiner::pause() std::string Ethash::GPUMiner::platformInfo() { - return ethash_cl_miner::platform_info(); + return ethash_cl_miner::platform_info(s_platformId, s_deviceId); } #endif diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 077da4460..2bbe7d649 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -86,6 +86,7 @@ public: static unsigned instances() { return std::thread::hardware_concurrency(); } static std::string platformInfo(); + static void setDefaultPlatform(unsigned) {} static void setDefaultDevice(unsigned) {} protected: @@ -113,6 +114,7 @@ public: static unsigned instances() { return 1; } static std::string platformInfo(); + static void setDefaultPlatform(unsigned _id) { s_platformId = _id; } static void setDefaultDevice(unsigned _id) { s_deviceId = _id; } protected: @@ -129,6 +131,7 @@ public: ethash_cl_miner* m_miner = nullptr; h256 m_minerSeed; ///< Last seed in m_miner + static unsigned s_platformId; static unsigned s_deviceId; }; #else From f3b17793874341459c512b9c81f9dc04d6abe39c Mon Sep 17 00:00:00 2001 From: caktux Date: Mon, 13 Apr 2015 23:02:45 -0400 Subject: [PATCH 06/65] catch cerr in neth --- neth/main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/neth/main.cpp b/neth/main.cpp index 4c38da0a4..31df2ffcb 100644 --- a/neth/main.cpp +++ b/neth/main.cpp @@ -626,6 +626,7 @@ int main(int argc, char** argv) logwin = newwin(height * 2 / 5 - 2, width * 2 / 3, qheight, 0); nc::nc_window_streambuf outbuf(logwin, std::cout); + nc::nc_window_streambuf eoutbuf(logwin, std::cerr); consolewin = newwin(qheight, width / 4, 0, 0); nc::nc_window_streambuf coutbuf(consolewin, ccout); From cdf7a0cd53737417b0345941ff45c0edc3b04cc8 Mon Sep 17 00:00:00 2001 From: Jan Willem Penterman Date: Fri, 17 Apr 2015 12:43:02 +0200 Subject: [PATCH 07/65] fix skipping import of future blocks --- libethereum/BlockQueue.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index b76e4bed6..b3e68fd3f 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -132,11 +132,12 @@ bool BlockQueue::doneDrain(h256s const& _bad) void BlockQueue::tick(BlockChain const& _bc) { unsigned t = time(0); - for (auto i = m_future.begin(); i != m_future.end() && i->first < t; ++i) + for (auto i = m_future.begin(); i != m_future.end() && i->first <= t; ++i) import(&(i->second), _bc); WriteGuard l(m_lock); m_future.erase(m_future.begin(), m_future.upper_bound(t)); + } template T advanced(T _t, unsigned _n) From 8d6b69068151c333dd5c65613ffd79c504fbdadf Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 17 Apr 2015 14:23:54 +0200 Subject: [PATCH 08/65] Fixed packed negative signed integers storage display --- mix/ClientModel.cpp | 2 ++ mix/test/qml/js/TestDebugger.js | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index 3478a88fa..dad1ced62 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -498,6 +498,8 @@ QVariant ClientModel::formatStorageValue(SolidityType const& _type, map Date: Fri, 17 Apr 2015 14:45:44 +0200 Subject: [PATCH 09/65] add some balance for gas estimation --- mix/MixClient.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index 965a4c5ac..35d7dc413 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -117,6 +117,7 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c lastHashes[i] = lastHashes[i - 1] ? bc().details(lastHashes[i - 1]).parent : h256(); State execState = _state; + execState.addBalance(t.sender(), t.gas() * t.gasPrice()); //give it enough balance for gas estimation Executive execution(execState, lastHashes, 0); execution.initialize(&rlp); execution.execute(); From f10469774789d707aa133793fc6efc20e24d9682 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 17 Apr 2015 14:53:22 +0200 Subject: [PATCH 10/65] Redo thread safety in Client. Rework some Worker threading stuff. --- libdevcore/Common.cpp | 2 +- libdevcore/Worker.cpp | 20 +++--- libdevcore/Worker.h | 5 +- libdevcrypto/OverlayDB.cpp | 7 --- libdevcrypto/OverlayDB.h | 1 - libethcore/Ethash.cpp | 27 ++++---- libethereum/Client.cpp | 123 +++++++++++++++---------------------- libethereum/Client.h | 11 ++-- libethereum/State.cpp | 2 + 9 files changed, 88 insertions(+), 110 deletions(-) diff --git a/libdevcore/Common.cpp b/libdevcore/Common.cpp index 7cdc433f3..649e79310 100644 --- a/libdevcore/Common.cpp +++ b/libdevcore/Common.cpp @@ -27,7 +27,7 @@ using namespace dev; namespace dev { -char const* Version = "0.9.9"; +char const* Version = "0.9.10"; } diff --git a/libdevcore/Worker.cpp b/libdevcore/Worker.cpp index 8c1fbb9c7..0f30a0aff 100644 --- a/libdevcore/Worker.cpp +++ b/libdevcore/Worker.cpp @@ -43,30 +43,32 @@ void Worker::startWorking(IfRunning _ir) } catch (...) {} cnote << "Spawning" << m_name; m_stop = false; + m_stopped = false; m_work.reset(new thread([&]() { setThreadName(m_name.c_str()); startedWorking(); workLoop(); - m_work->detach(); cnote << "Finishing up worker thread"; doneWorking(); + ETH_GUARDED(x_work) + m_work->detach(); + m_stopped = true; })); } void Worker::stopWorking() { // cnote << "stopWorking for thread" << m_name; - Guard l(x_work); - if (!m_work || !m_work->joinable()) - return; + ETH_GUARDED(x_work) + if (!m_work || !m_work->joinable()) + return; cnote << "Stopping" << m_name; m_stop = true; - try { - m_work->join(); - } - catch (...) {} - m_work.reset(); + while (!m_stopped) + this_thread::sleep_for(chrono::microseconds(50)); + ETH_GUARDED(x_work) + m_work.reset(); cnote << "Stopped" << m_name; } diff --git a/libdevcore/Worker.h b/libdevcore/Worker.h index 287ff6d6f..aad1dfc0e 100644 --- a/libdevcore/Worker.h +++ b/libdevcore/Worker.h @@ -59,7 +59,7 @@ protected: void stopWorking(); /// Returns if worker thread is present. - bool isWorking() const { Guard l(x_work); return !!m_work; } + bool isWorking() const { Guard l(x_work); return !!m_work && m_work->joinable(); } /// Called after thread is started from startWorking(). virtual void startedWorking() {} @@ -83,7 +83,8 @@ private: mutable Mutex x_work; ///< Lock for the network existance. std::unique_ptr m_work; ///< The network thread. - bool m_stop = false; + std::atomic m_stop = {false}; + std::atomic m_stopped = {false}; }; } diff --git a/libdevcrypto/OverlayDB.cpp b/libdevcrypto/OverlayDB.cpp index 4bd698f57..5f8aea667 100644 --- a/libdevcrypto/OverlayDB.cpp +++ b/libdevcrypto/OverlayDB.cpp @@ -34,13 +34,6 @@ OverlayDB::~OverlayDB() cnote << "Closing state DB"; } -void OverlayDB::setDB(ldb::DB* _db, bool _clearOverlay) -{ - m_db = std::shared_ptr(_db); - if (_clearOverlay) - m_over.clear(); -} - void OverlayDB::commit() { if (m_db) diff --git a/libdevcrypto/OverlayDB.h b/libdevcrypto/OverlayDB.h index d027afbd4..7f7736ac1 100644 --- a/libdevcrypto/OverlayDB.h +++ b/libdevcrypto/OverlayDB.h @@ -42,7 +42,6 @@ public: ~OverlayDB(); ldb::DB* db() const { return m_db.get(); } - void setDB(ldb::DB* _db, bool _clearOverlay = true); void commit(); void rollback(); diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index 977149e7a..16d17b1e8 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -295,21 +295,24 @@ void Ethash::GPUMiner::kickOff() void Ethash::GPUMiner::workLoop() { // take local copy of work since it may end up being overwritten by kickOff/pause. - WorkPackage w = work(); - if (!m_miner || m_minerSeed != w.seedHash) - { - m_minerSeed = w.seedHash; + try { + WorkPackage w = work(); + if (!m_miner || m_minerSeed != w.seedHash) + { + m_minerSeed = w.seedHash; - delete m_miner; - m_miner = new ethash_cl_miner; + delete m_miner; + m_miner = new ethash_cl_miner; - auto p = EthashAux::params(m_minerSeed); - auto cb = [&](void* d) { EthashAux::full(m_minerSeed, bytesRef((byte*)d, p.full_size)); }; - m_miner->init(p, cb, 32, s_deviceId); - } + auto p = EthashAux::params(m_minerSeed); + auto cb = [&](void* d) { EthashAux::full(m_minerSeed, bytesRef((byte*)d, p.full_size)); }; + m_miner->init(p, cb, 32, s_deviceId); + } - uint64_t upper64OfBoundary = (uint64_t)(u64)((u256)w.boundary >> 192); - m_miner->search(w.headerHash.data(), upper64OfBoundary, *m_hook); + uint64_t upper64OfBoundary = (uint64_t)(u64)((u256)w.boundary >> 192); + m_miner->search(w.headerHash.data(), upper64OfBoundary, *m_hook); + } + catch (...) {} } void Ethash::GPUMiner::pause() diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index b9df1cf90..1684ef54d 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -197,16 +197,17 @@ void Client::startedWorking() // Synchronise the state according to the head of the block chain. // TODO: currently it contains keys for *all* blocks. Make it remove old ones. cdebug << "startedWorking()"; - WriteGuard l(x_stateDB); cdebug << m_bc.number() << m_bc.currentHash(); - cdebug << "Pre:" << m_preMine.info(); cdebug << "Post:" << m_postMine.info(); cdebug << "Pre:" << m_preMine.info().headerHash(WithoutNonce) << "; Post:" << m_postMine.info().headerHash(WithoutNonce); - m_preMine.sync(m_bc); - m_postMine = m_preMine; + ETH_WRITE_GUARDED(x_preMine) + m_preMine.sync(m_bc); + ETH_WRITE_GUARDED(x_postMine) + ETH_READ_GUARDED(x_preMine) + m_postMine = m_preMine; cdebug << "Pre:" << m_preMine.info(); cdebug << "Post:" << m_postMine.info(); @@ -217,13 +218,18 @@ void Client::doneWorking() { // Synchronise the state according to the head of the block chain. // TODO: currently it contains keys for *all* blocks. Make it remove old ones. - WriteGuard l(x_stateDB); - m_preMine.sync(m_bc); - m_postMine = m_preMine; + ETH_WRITE_GUARDED(x_preMine) + m_preMine.sync(m_bc); + ETH_WRITE_GUARDED(x_postMine) + ETH_READ_GUARDED(x_preMine) + m_postMine = m_preMine; } void Client::killChain() { + WriteGuard l(x_postMine); + WriteGuard l2(x_preMine); + bool wasMining = isMining(); if (wasMining) stopMining(); @@ -235,8 +241,8 @@ void Client::killChain() m_preMine = State(); m_postMine = State(); +// ETH_WRITE_GUARDED(x_stateDB) // no point doing this yet since we can't control where else it's open yet. { - WriteGuard l(x_stateDB); m_stateDB = OverlayDB(); m_stateDB = State::openDB(Defaults::dbPath(), WithExisting::Kill); } @@ -258,15 +264,16 @@ void Client::killChain() void Client::clearPending() { h256Set changeds; + ETH_WRITE_GUARDED(x_postMine) { - WriteGuard l(x_stateDB); if (!m_postMine.pending().size()) return; // for (unsigned i = 0; i < m_postMine.pending().size(); ++i) // appendFromNewPending(m_postMine.logBloom(i), changeds); changeds.insert(PendingChangedFilter); m_tq.clear(); - m_postMine = m_preMine; + ETH_READ_GUARDED(x_preMine) + m_postMine = m_preMine; } startMining(); @@ -364,29 +371,6 @@ std::list Client::miningHistory() return ret; } -/*void Client::setupState(State& _s) -{ - { - ReadGuard l(x_stateDB); - cwork << "SETUP MINE"; - _s = m_postMine; - } - if (m_paranoia) - { - if (_s.amIJustParanoid(m_bc)) - { - cnote << "I'm just paranoid. Block is fine."; - _s.commitToMine(m_bc); - } - else - { - cwarn << "I'm not just paranoid. Cannot mine. Please file a bug report."; - } - } - else - _s.commitToMine(m_bc); -}*/ - ExecutionResult Client::call(Address _dest, bytes const& _data, u256 _gas, u256 _value, u256 _gasPrice, Address const& _from) { ExecutionResult ret; @@ -394,11 +378,9 @@ ExecutionResult Client::call(Address _dest, bytes const& _data, u256 _gas, u256 { State temp; // cdebug << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret)); - { - ReadGuard l(x_stateDB); + ETH_READ_GUARDED(x_postMine) temp = m_postMine; - temp.addBalance(_from, _value + _gasPrice * _gas); - } + temp.addBalance(_from, _value + _gasPrice * _gas); Executive e(temp, LastHashes(), 0); if (!e.call(_dest, _dest, _from, _value, _gasPrice, &_data, _gas, _from)) e.go(); @@ -420,10 +402,11 @@ bool Client::submitWork(ProofOfWork::Solution const& _solution) { bytes newBlock; { - WriteGuard l(x_stateDB); + WriteGuard l(x_postMine); if (!m_postMine.completeMine(_solution)) return false; newBlock = m_postMine.blockData(); + // OPTIMISE: very inefficient to not utilise the existing OverlayDB in m_postMine that contains all trie changes. } m_bq.import(&newBlock, m_bc, true); /* @@ -439,13 +422,9 @@ void Client::syncBlockQueue() cwork << "BQ ==> CHAIN ==> STATE"; { - WriteGuard l(x_stateDB); - OverlayDB db = m_stateDB; - ETH_WRITE_UNGUARDED(x_stateDB) - tie(ir.first, ir.second, m_syncBlockQueue) = m_bc.sync(m_bq, db, 100); + tie(ir.first, ir.second, m_syncBlockQueue) = m_bc.sync(m_bq, m_stateDB, 100); if (ir.first.empty()) return; - m_stateDB = db; } onChainChanged(ir); } @@ -458,25 +437,26 @@ void Client::syncTransactionQueue() h256Set changeds; TransactionReceipts newPendingReceipts; - ETH_WRITE_GUARDED(x_stateDB) + ETH_WRITE_GUARDED(x_postMine) newPendingReceipts = m_postMine.sync(m_bc, m_tq, *m_gp); - if (newPendingReceipts.size()) - { + if (newPendingReceipts.empty()) + return; + + ETH_READ_GUARDED(x_postMine) for (size_t i = 0; i < newPendingReceipts.size(); i++) appendFromNewPending(newPendingReceipts[i], changeds, m_postMine.pending()[i].sha3()); - changeds.insert(PendingChangedFilter); + changeds.insert(PendingChangedFilter); - // TODO: Tell farm about new transaction (i.e. restartProofOfWork mining). - onPostStateChanged(); + // TODO: Tell farm about new transaction (i.e. restartProofOfWork mining). + onPostStateChanged(); - // Tell watches about the new transactions. - noteChanged(changeds); + // Tell watches about the new transactions. + noteChanged(changeds); - // Tell network about the new transactions. - if (auto h = m_host.lock()) - h->noteNewTransactions(); - } + // Tell network about the new transactions. + if (auto h = m_host.lock()) + h->noteNewTransactions(); } void Client::onChainChanged(ImportRoute const& _ir) @@ -514,18 +494,21 @@ void Client::onChainChanged(ImportRoute const& _ir) // RESTART MINING // LOCKS REALLY NEEDED? - ETH_WRITE_GUARDED(x_stateDB) - if (m_preMine.sync(m_bc) || m_postMine.address() != m_preMine.address()) - { - if (isMining()) - cnote << "New block on chain."; + bool preChanged = false; + ETH_WRITE_GUARDED(x_preMine) + preChanged = m_preMine.sync(m_bc); + if (preChanged || m_postMine.address() != m_preMine.address()) + { + if (isMining()) + cnote << "New block on chain."; - m_postMine = m_preMine; - changeds.insert(PendingChangedFilter); + ETH_WRITE_GUARDED(x_postMine) + ETH_READ_GUARDED(x_preMine) + m_postMine = m_preMine; + changeds.insert(PendingChangedFilter); - ETH_WRITE_UNGUARDED(x_stateDB) - onPostStateChanged(); - } + onPostStateChanged(); + } noteChanged(changeds); } @@ -536,7 +519,7 @@ void Client::onPostStateChanged() if (isMining()) { { - WriteGuard l(x_stateDB); + WriteGuard l(x_postMine); m_postMine.commitToMine(m_bc); m_miningInfo = m_postMine.info(); } @@ -606,15 +589,13 @@ void Client::checkWatchGarbage() { // watches garbage collection vector toUninstall; - { - Guard l(x_filtersWatches); + ETH_GUARDED(x_filtersWatches) for (auto key: keysOf(m_watches)) if (m_watches[key].lastPoll != chrono::system_clock::time_point::max() && chrono::system_clock::now() - m_watches[key].lastPoll > chrono::seconds(20)) { toUninstall.push_back(key); cnote << "GC: Uninstall" << key << "(" << chrono::duration_cast(chrono::system_clock::now() - m_watches[key].lastPoll).count() << "s old)"; } - } for (auto i: toUninstall) uninstallWatch(i); @@ -627,7 +608,6 @@ void Client::checkWatchGarbage() State Client::asOf(h256 const& _block) const { - ReadGuard l(x_stateDB); return State(m_stateDB, bc(), _block); } @@ -638,19 +618,16 @@ void Client::prepareForTransaction() State Client::state(unsigned _txi, h256 _block) const { - ReadGuard l(x_stateDB); return State(m_stateDB, m_bc, _block).fromPending(_txi); } eth::State Client::state(h256 _block) const { - ReadGuard l(x_stateDB); return State(m_stateDB, m_bc, _block); } eth::State Client::state(unsigned _txi) const { - ReadGuard l(x_stateDB); return m_postMine.fromPending(_txi); } diff --git a/libethereum/Client.h b/libethereum/Client.h index 1dfa45d7e..aa2dd61b8 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -144,7 +144,7 @@ public: dev::eth::State state(unsigned _txi) const; /// Get the object representing the current state of Ethereum. - dev::eth::State postState() const { ReadGuard l(x_stateDB); return m_postMine; } + dev::eth::State postState() const { ReadGuard l(x_postMine); return m_postMine; } /// Get the object representing the current canonical blockchain. CanonBlockChain const& blockChain() const { return m_bc; } /// Get some information on the block queue. @@ -152,7 +152,7 @@ public: // Mining stuff: - void setAddress(Address _us) { WriteGuard l(x_stateDB); m_preMine.setAddress(_us); } + void setAddress(Address _us) { WriteGuard l(x_preMine); m_preMine.setAddress(_us); } /// Check block validity prior to mining. bool miningParanoia() const { return m_paranoia; } @@ -214,8 +214,8 @@ protected: /// Works properly with LatestBlock and PendingBlock. using ClientBase::asOf; virtual State asOf(h256 const& _block) const override; - virtual State preMine() const override { ReadGuard l(x_stateDB); return m_preMine; } - virtual State postMine() const override { ReadGuard l(x_stateDB); return m_postMine; } + virtual State preMine() const override { ReadGuard l(x_preMine); return m_preMine; } + virtual State postMine() const override { ReadGuard l(x_postMine); return m_postMine; } virtual void prepareForTransaction() override; /// Collate the changed filters for the bloom filter of the given pending transaction. @@ -271,9 +271,10 @@ private: BlockQueue m_bq; ///< Maintains a list of incoming blocks not yet on the blockchain (to be imported). std::shared_ptr m_gp; ///< The gas pricer. - mutable SharedMutex x_stateDB; ///< Lock on the state DB, effectively a lock on m_postMine. OverlayDB m_stateDB; ///< Acts as the central point for the state database, so multiple States can share it. + mutable SharedMutex x_preMine; ///< Lock on the OverlayDB and other attributes of m_preMine. State m_preMine; ///< The present state of the client. + mutable SharedMutex x_postMine; ///< Lock on the OverlayDB and other attributes of m_postMine. State m_postMine; ///< The state of the client which we're mining (i.e. it'll have all the rewards added). BlockInfo m_miningInfo; ///< The header we're attempting to mine on (derived from m_postMine). diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 65f267b0f..ec5023ff8 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -690,7 +690,9 @@ void State::cleanup(bool _fullCommit) paranoia("immediately before database commit", true); // Commit the new trie to disk. + cnote << "Commiting to disk..."; m_db.commit(); + cnote << "Committed."; paranoia("immediately after database commit", true); m_previousBlock = m_currentBlock; From 45117f53b064d4c04ce0e4eda490daee4891d62c Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 2 Apr 2015 15:10:35 +0200 Subject: [PATCH 11/65] Allowing abstract contracts constructor to have no args - If a constructor is part of an abstract contract we can omit its arguments - IF a contract is abstract make sure to not create and/or request Assembly code about it since it's not compiled --- libsolidity/AST.cpp | 14 +++++++------- libsolidity/AST.h | 2 +- libsolidity/Compiler.cpp | 1 + libsolidity/CompilerStack.cpp | 16 +++++++++++----- libsolidity/CompilerStack.h | 4 ++-- mix/CodeModel.cpp | 2 +- test/SolidityNameAndTypeResolution.cpp | 18 ++++++++++++++++-- 7 files changed, 39 insertions(+), 18 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 0abdf7819..370166462 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -281,7 +281,7 @@ void InheritanceSpecifier::checkTypeRequirements() ContractDefinition const* base = dynamic_cast(m_baseName->getReferencedDeclaration()); solAssert(base, "Base contract not available."); TypePointers parameterTypes = ContractType(*base).getConstructorType()->getParameterTypes(); - if (parameterTypes.size() != m_arguments.size()) + if (m_arguments.size() != 0 && parameterTypes.size() != m_arguments.size()) BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for constructor call.")); for (size_t i = 0; i < m_arguments.size(); ++i) if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[i])) @@ -348,8 +348,8 @@ void FunctionDefinition::checkTypeRequirements() } for (ASTPointer const& modifier: m_functionModifiers) modifier->checkTypeRequirements(isConstructor() ? - dynamic_cast(*getScope()).getBaseContracts() : - vector>()); + dynamic_cast(*getScope()).getLinearizedBaseContracts() : + vector()); if (m_body) m_body->checkTypeRequirements(); } @@ -426,7 +426,7 @@ void ModifierDefinition::checkTypeRequirements() m_body->checkTypeRequirements(); } -void ModifierInvocation::checkTypeRequirements(vector> const& _bases) +void ModifierInvocation::checkTypeRequirements(vector const& _bases) { m_modifierName->checkTypeRequirements(); for (ASTPointer const& argument: m_arguments) @@ -439,10 +439,10 @@ void ModifierInvocation::checkTypeRequirements(vectorgetParameters(); else // check parameters for Base constructors - for (auto const& base: _bases) - if (declaration == base->getName()->getReferencedDeclaration()) + for (auto const* base: _bases) + if (declaration == base) { - if (auto referencedConstructor = dynamic_cast(*declaration).getConstructor()) + if (auto referencedConstructor = base->getConstructor()) parameters = &referencedConstructor->getParameters(); else parameters = &emptyParameterList; diff --git a/libsolidity/AST.h b/libsolidity/AST.h index 9f5f9fcb1..8c36caeaf 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -566,7 +566,7 @@ public: std::vector> const& getArguments() const { return m_arguments; } /// @param _bases is the list of base contracts for base constructor calls. For modifiers an empty vector should be passed. - void checkTypeRequirements(std::vector> const& _bases); + void checkTypeRequirements(std::vector const& _bases); private: ASTPointer m_modifierName; diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index 886565cb4..f0197e23b 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -136,6 +136,7 @@ void Compiler::appendBaseConstructor(FunctionDefinition const& _constructor) FunctionType constructorType(_constructor); if (!constructorType.getParameterTypes().empty()) { + solAssert(m_baseArguments.count(&_constructor), ""); std::vector> const* arguments = m_baseArguments[&_constructor]; solAssert(arguments, ""); for (unsigned i = 0; i < arguments->size(); ++i) diff --git a/libsolidity/CompilerStack.cpp b/libsolidity/CompilerStack.cpp index 1301bfa5d..c35d9324c 100644 --- a/libsolidity/CompilerStack.cpp +++ b/libsolidity/CompilerStack.cpp @@ -157,14 +157,16 @@ bytes const& CompilerStack::compile(string const& _sourceCode, bool _optimize) return getBytecode(); } -eth::AssemblyItems const& CompilerStack::getAssemblyItems(string const& _contractName) const +eth::AssemblyItems const* CompilerStack::getAssemblyItems(string const& _contractName) const { - return getContract(_contractName).compiler->getAssemblyItems(); + Contract const& contract = getContract(_contractName); + return contract.compiler ? &getContract(_contractName).compiler->getAssemblyItems() : nullptr; } -eth::AssemblyItems const& CompilerStack::getRuntimeAssemblyItems(string const& _contractName) const +eth::AssemblyItems const* CompilerStack::getRuntimeAssemblyItems(string const& _contractName) const { - return getContract(_contractName).compiler->getRuntimeAssemblyItems(); + Contract const& contract = getContract(_contractName); + return contract.compiler ? &getContract(_contractName).compiler->getRuntimeAssemblyItems() : nullptr; } bytes const& CompilerStack::getBytecode(string const& _contractName) const @@ -184,7 +186,11 @@ dev::h256 CompilerStack::getContractCodeHash(string const& _contractName) const void CompilerStack::streamAssembly(ostream& _outStream, string const& _contractName, StringMap _sourceCodes) const { - getContract(_contractName).compiler->streamAssembly(_outStream, _sourceCodes); + Contract const& contract = getContract(_contractName); + if (contract.compiler) + getContract(_contractName).compiler->streamAssembly(_outStream, _sourceCodes); + else + _outStream << "Contract not fully implemented" << endl; } string const& CompilerStack::getInterface(string const& _contractName) const diff --git a/libsolidity/CompilerStack.h b/libsolidity/CompilerStack.h index 1cf576ab4..19c1ba4e1 100644 --- a/libsolidity/CompilerStack.h +++ b/libsolidity/CompilerStack.h @@ -94,9 +94,9 @@ public: /// @returns the runtime bytecode for the contract, i.e. the code that is returned by the constructor. bytes const& getRuntimeBytecode(std::string const& _contractName = "") const; /// @returns normal contract assembly items - eth::AssemblyItems const& getAssemblyItems(std::string const& _contractName = "") const; + eth::AssemblyItems const* getAssemblyItems(std::string const& _contractName = "") const; /// @returns runtime contract assembly items - eth::AssemblyItems const& getRuntimeAssemblyItems(std::string const& _contractName = "") const; + eth::AssemblyItems const* getRuntimeAssemblyItems(std::string const& _contractName = "") const; /// @returns hash of the runtime bytecode for the contract, i.e. the code that is returned by the constructor. dev::h256 getContractCodeHash(std::string const& _contractName = "") const; diff --git a/mix/CodeModel.cpp b/mix/CodeModel.cpp index 87aa5a2f8..63e8cc1c3 100644 --- a/mix/CodeModel.cpp +++ b/mix/CodeModel.cpp @@ -135,7 +135,7 @@ CompiledContract::CompiledContract(const dev::solidity::CompilerStack& _compiler CollectDeclarationsVisitor visitor(&m_functions, &m_locals); m_storage = collectStorage(contractDefinition); contractDefinition.accept(visitor); - m_assemblyItems = _compiler.getRuntimeAssemblyItems(name); + m_assemblyItems = *_compiler.getRuntimeAssemblyItems(name); m_constructorAssemblyItems = _compiler.getAssemblyItems(name); } diff --git a/test/SolidityNameAndTypeResolution.cpp b/test/SolidityNameAndTypeResolution.cpp index ffa78ed9e..caca8b04e 100644 --- a/test/SolidityNameAndTypeResolution.cpp +++ b/test/SolidityNameAndTypeResolution.cpp @@ -407,6 +407,20 @@ BOOST_AUTO_TEST_CASE(create_abstract_contract) BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); } +BOOST_AUTO_TEST_CASE(abstract_contract_constructor_args_optional) +{ + ASTPointer sourceUnit; + char const* text = R"( + contract BaseBase { function BaseBase(uint j); } + contract base is BaseBase { function foo(); } + contract derived is base { + function derived(uint i) BaseBase(i){} + function foo() {} + } + )"; + ETH_TEST_REQUIRE_NO_THROW(parseTextAndResolveNames(text), "Parsing and name resolving failed"); +} + BOOST_AUTO_TEST_CASE(redeclare_implemented_abstract_function_as_abstract) { ASTPointer sourceUnit; @@ -665,7 +679,7 @@ BOOST_AUTO_TEST_CASE(missing_base_constructor_arguments) contract A { function A(uint a) { } } contract B is A { } )"; - BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); + ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed"); } BOOST_AUTO_TEST_CASE(base_constructor_arguments_override) @@ -674,7 +688,7 @@ BOOST_AUTO_TEST_CASE(base_constructor_arguments_override) contract A { function A(uint a) { } } contract B is A { } )"; - BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); + ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed"); } BOOST_AUTO_TEST_CASE(implicit_derived_to_base_conversion) From 2279e402748b087ebf4e896980bcb8c19391a926 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 2 Apr 2015 16:56:12 +0200 Subject: [PATCH 12/65] Check all constructors in inheritance chain get args - Also add a missing override in a function of EnumValue --- libsolidity/AST.cpp | 42 ++++++++++++++++++++++++++ libsolidity/AST.h | 3 +- test/SolidityNameAndTypeResolution.cpp | 19 ++++++++++++ 3 files changed, 63 insertions(+), 1 deletion(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 370166462..4d183889c 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -54,6 +54,7 @@ void ContractDefinition::checkTypeRequirements() checkIllegalOverrides(); checkAbstractFunctions(); + checkAbstractConstructors(); FunctionDefinition const* constructor = getConstructor(); if (constructor && !constructor->getReturnParameters().empty()) @@ -152,6 +153,47 @@ void ContractDefinition::checkAbstractFunctions() } } +void ContractDefinition::checkAbstractConstructors() +{ + set argumentsNeeded; + set argumentsProvided; + // check that we get arguments for all base constructors that need it. + // If not mark the contract as abstract (not fully implemented) + vector const& bases = getLinearizedBaseContracts(); + for (ContractDefinition const* contract: bases) + { + FunctionDefinition const* constructor = contract->getConstructor(); + if (constructor) + { + if (!constructor->getParameters().empty()) + argumentsProvided.insert(constructor); + for (auto const& modifier: constructor->getModifiers()) + { + auto baseContract = dynamic_cast( + modifier->getName()->getReferencedDeclaration()); + if (baseContract) + { + FunctionDefinition const* baseConstructor = baseContract->getConstructor(); + if (argumentsProvided.count(baseConstructor) == 1) + argumentsNeeded.insert(baseConstructor); + } + } + } + + for (ASTPointer const& base: contract->getBaseContracts()) + { + ContractDefinition const* baseContract = dynamic_cast( + base->getName()->getReferencedDeclaration()); + solAssert(baseContract, ""); + FunctionDefinition const* baseConstructor = baseContract->getConstructor(); + if (argumentsProvided.count(baseConstructor) == 1) + argumentsNeeded.insert(baseConstructor); + } + } + if (argumentsProvided != argumentsNeeded) + setFullyImplemented(false); +} + void ContractDefinition::checkIllegalOverrides() const { // TODO unify this at a later point. for this we need to put the constness and the access specifier diff --git a/libsolidity/AST.h b/libsolidity/AST.h index 8c36caeaf..99abf2295 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -284,6 +284,7 @@ public: private: void checkIllegalOverrides() const; void checkAbstractFunctions(); + void checkAbstractConstructors(); std::vector, FunctionTypePointer>> const& getInterfaceFunctionList() const; @@ -376,7 +377,7 @@ class EnumValue: public Declaration virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTConstVisitor& _visitor) const override; - TypePointer getType(ContractDefinition const* = nullptr) const; + TypePointer getType(ContractDefinition const* = nullptr) const override; }; /** diff --git a/test/SolidityNameAndTypeResolution.cpp b/test/SolidityNameAndTypeResolution.cpp index caca8b04e..c1a274b0c 100644 --- a/test/SolidityNameAndTypeResolution.cpp +++ b/test/SolidityNameAndTypeResolution.cpp @@ -421,6 +421,25 @@ BOOST_AUTO_TEST_CASE(abstract_contract_constructor_args_optional) ETH_TEST_REQUIRE_NO_THROW(parseTextAndResolveNames(text), "Parsing and name resolving failed"); } +BOOST_AUTO_TEST_CASE(abstract_contract_constructor_args_not_provided) +{ + ASTPointer sourceUnit; + char const* text = R"( + contract BaseBase { function BaseBase(uint j); } + contract base is BaseBase { function foo(); } + contract derived is base { + function derived(uint i) {} + function foo() {} + } + )"; + ETH_TEST_REQUIRE_NO_THROW(sourceUnit = parseTextAndResolveNames(text), "Parsing and name resolving failed"); + std::vector> nodes = sourceUnit->getNodes(); + BOOST_CHECK_EQUAL(nodes.size(), 3); + ContractDefinition* derived = dynamic_cast(nodes[2].get()); + BOOST_CHECK(derived); + BOOST_CHECK(!derived->isFullyImplemented()); +} + BOOST_AUTO_TEST_CASE(redeclare_implemented_abstract_function_as_abstract) { ASTPointer sourceUnit; From c2279518566a50ab796d4fe6921523a8abce4d47 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 2 Apr 2015 17:05:27 +0200 Subject: [PATCH 13/65] size()!=0 -> !empty() --- libsolidity/AST.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 4d183889c..a66aa9897 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -323,7 +323,7 @@ void InheritanceSpecifier::checkTypeRequirements() ContractDefinition const* base = dynamic_cast(m_baseName->getReferencedDeclaration()); solAssert(base, "Base contract not available."); TypePointers parameterTypes = ContractType(*base).getConstructorType()->getParameterTypes(); - if (m_arguments.size() != 0 && parameterTypes.size() != m_arguments.size()) + if (!m_arguments.empty() && parameterTypes.size() != m_arguments.size()) BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for constructor call.")); for (size_t i = 0; i < m_arguments.size(); ++i) if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[i])) From 3a2d903252dfea5127d955617af17c203f3f9aed Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 2 Apr 2015 17:12:15 +0200 Subject: [PATCH 14/65] Fixing new abstract contract error location reporting --- libsolidity/AST.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index a66aa9897..7f4b8710e 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -728,7 +728,7 @@ void NewExpression::checkTypeRequirements() if (!m_contract) BOOST_THROW_EXCEPTION(createTypeError("Identifier is not a contract.")); if (!m_contract->isFullyImplemented()) - BOOST_THROW_EXCEPTION(m_contract->createTypeError("Trying to create an instance of an abstract contract.")); + BOOST_THROW_EXCEPTION(createTypeError("Trying to create an instance of an abstract contract.")); shared_ptr contractType = make_shared(*m_contract); TypePointers const& parameterTypes = contractType->getConstructorType()->getParameterTypes(); m_type = make_shared(parameterTypes, TypePointers{contractType}, From 86caafd9e935caf30ea1fd96b8b9469e27b5b645 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 2 Apr 2015 17:42:43 +0200 Subject: [PATCH 15/65] Add "this" contract's ctor to provided ctors set - Also properly naming the 2 sets in checkAbstractConstructors() function --- libsolidity/AST.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 7f4b8710e..1c12ef5a1 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -166,7 +166,7 @@ void ContractDefinition::checkAbstractConstructors() if (constructor) { if (!constructor->getParameters().empty()) - argumentsProvided.insert(constructor); + argumentsNeeded.insert(constructor); for (auto const& modifier: constructor->getModifiers()) { auto baseContract = dynamic_cast( @@ -174,8 +174,8 @@ void ContractDefinition::checkAbstractConstructors() if (baseContract) { FunctionDefinition const* baseConstructor = baseContract->getConstructor(); - if (argumentsProvided.count(baseConstructor) == 1) - argumentsNeeded.insert(baseConstructor); + if (argumentsNeeded.count(baseConstructor) == 1) + argumentsProvided.insert(baseConstructor); } } } @@ -186,10 +186,13 @@ void ContractDefinition::checkAbstractConstructors() base->getName()->getReferencedDeclaration()); solAssert(baseContract, ""); FunctionDefinition const* baseConstructor = baseContract->getConstructor(); - if (argumentsProvided.count(baseConstructor) == 1) - argumentsNeeded.insert(baseConstructor); + if (argumentsNeeded.count(baseConstructor) == 1) + argumentsProvided.insert(baseConstructor); } } + // add this contract's constructor to the provided too + if (getConstructor() && !getConstructor()->getParameters().empty()) + argumentsProvided.insert(getConstructor()); if (argumentsProvided != argumentsNeeded) setFullyImplemented(false); } From 5be5fc55a0beb86fa77dea32d475457ad962c000 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 2 Apr 2015 17:50:43 +0200 Subject: [PATCH 16/65] Adding forgotten virtual specifier to EnumValue getType() --- libsolidity/AST.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsolidity/AST.h b/libsolidity/AST.h index 99abf2295..0c133ff1a 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -377,7 +377,7 @@ class EnumValue: public Declaration virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTConstVisitor& _visitor) const override; - TypePointer getType(ContractDefinition const* = nullptr) const override; + virtual TypePointer getType(ContractDefinition const* = nullptr) const override; }; /** From 9079da740a293b99f14bc321346b18f6aa429929 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Tue, 7 Apr 2015 16:57:52 +0200 Subject: [PATCH 17/65] minor tweak after rebase --- mix/CodeModel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix/CodeModel.cpp b/mix/CodeModel.cpp index 63e8cc1c3..d84bbd8f4 100644 --- a/mix/CodeModel.cpp +++ b/mix/CodeModel.cpp @@ -136,7 +136,7 @@ CompiledContract::CompiledContract(const dev::solidity::CompilerStack& _compiler m_storage = collectStorage(contractDefinition); contractDefinition.accept(visitor); m_assemblyItems = *_compiler.getRuntimeAssemblyItems(name); - m_constructorAssemblyItems = _compiler.getAssemblyItems(name); + m_constructorAssemblyItems = *_compiler.getAssemblyItems(name); } QString CompiledContract::codeHex() const From 8148e7b1df562ab9bd947d0e42bf56264d1dbcdd Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 17 Apr 2015 15:55:09 +0200 Subject: [PATCH 18/65] tests --- mix/test/qml/TestMain.qml | 10 ++++++++++ mix/test/qml/js/TestMiner.js | 10 ++++++++++ mix/test/qml/js/TestProject.js | 4 ++-- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/mix/test/qml/TestMain.qml b/mix/test/qml/TestMain.qml index 73cff824e..778e4dc20 100644 --- a/mix/test/qml/TestMain.qml +++ b/mix/test/qml/TestMain.qml @@ -58,11 +58,20 @@ TestCase ts.keyPressChar(mainApplication, "S", Qt.ControlModifier, 200); //Ctrl+S } + function waitForMining() + { + while (mainApplication.clientModel.mining) + ts.waitForSignal(mainApplication.clientModel, "miningComplete()", 5000); + wait(1); //allow events to propagate 2 times for transaction log to be updated + wait(1); + } function waitForExecution() { while (mainApplication.clientModel.running) ts.waitForSignal(mainApplication.clientModel, "runComplete()", 5000); + wait(1); //allow events to propagate 2 times for transaction log to be updated + wait(1); } function editHtml(c) @@ -89,6 +98,7 @@ TestCase function test_dbg_vm() { TestDebugger.test_vmDebugging(); } function test_miner_getDefaultiner() { TestMiner.test_getDefaultMiner(); } function test_miner_selectMiner() { TestMiner.test_selectMiner(); } + function test_miner_mine() { TestMiner.test_mine(); } function test_project_contractRename() { TestProject.test_contractRename(); } } diff --git a/mix/test/qml/js/TestMiner.js b/mix/test/qml/js/TestMiner.js index a24b0ce19..9d98c9f24 100644 --- a/mix/test/qml/js/TestMiner.js +++ b/mix/test/qml/js/TestMiner.js @@ -18,3 +18,13 @@ function test_selectMiner() compare(state.miner.secret, account.secret); } +function test_mine() +{ + newProject(); + mainApplication.mainContent.startQuickDebugging(); + waitForExecution(); + mainApplication.clientModel.mine(); + waitForMining(); + tryCompare(mainApplication.mainContent.rightPane.transactionLog.transactionModel.get(3), "contract", " - Block - "); +} + diff --git a/mix/test/qml/js/TestProject.js b/mix/test/qml/js/TestProject.js index 444760ea3..0d20ec9a8 100644 --- a/mix/test/qml/js/TestProject.js +++ b/mix/test/qml/js/TestProject.js @@ -1,11 +1,12 @@ function test_contractRename() { newProject(); + waitForExecution(); tryCompare(mainApplication.mainContent.projectNavigator.sections.itemAt(0).model.get(0), "name", "Contract"); editContract("contract Renamed {}"); mainApplication.mainContent.startQuickDebugging(); waitForExecution(); - wait(1000); + tryCompare(mainApplication.mainContent.rightPane.transactionLog.transactionModel.get(2), "contract", "Renamed"); tryCompare(mainApplication.mainContent.projectNavigator.sections.itemAt(0).model.get(0), "name", "Renamed"); mainApplication.projectModel.stateListModel.editState(0); mainApplication.projectModel.stateDialog.model.editTransaction(2); @@ -14,5 +15,4 @@ function test_contractRename() tryCompare(transactionDialog, "functionId", "Renamed"); transactionDialog.close(); mainApplication.projectModel.stateDialog.close(); - tryCompare(mainApplication.mainContent.rightPane.transactionLog.transactionModel.get(2), "contract", "Renamed"); } From cad916a00d6af31b359b087a6b3363e0344aa3ef Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 17 Apr 2015 16:17:21 +0200 Subject: [PATCH 19/65] Fixing detection of abstract contract --- libsolidity/AST.cpp | 41 ++++++++++++++++++----------------------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 1c12ef5a1..5f681205d 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -155,45 +155,40 @@ void ContractDefinition::checkAbstractFunctions() void ContractDefinition::checkAbstractConstructors() { - set argumentsNeeded; - set argumentsProvided; + set argumentsNeeded; // check that we get arguments for all base constructors that need it. // If not mark the contract as abstract (not fully implemented) + vector const& bases = getLinearizedBaseContracts(); + for (ContractDefinition const* contract: bases) + if (FunctionDefinition const* constructor = contract->getConstructor()) + if (contract != this && !constructor->getParameters().empty()) + argumentsNeeded.insert(contract); + for (ContractDefinition const* contract: bases) { - FunctionDefinition const* constructor = contract->getConstructor(); - if (constructor) - { - if (!constructor->getParameters().empty()) - argumentsNeeded.insert(constructor); + if (FunctionDefinition const* constructor = contract->getConstructor()) for (auto const& modifier: constructor->getModifiers()) { auto baseContract = dynamic_cast( - modifier->getName()->getReferencedDeclaration()); + modifier->getName()->getReferencedDeclaration() + ); if (baseContract) - { - FunctionDefinition const* baseConstructor = baseContract->getConstructor(); - if (argumentsNeeded.count(baseConstructor) == 1) - argumentsProvided.insert(baseConstructor); - } + argumentsNeeded.erase(baseContract); } - } + for (ASTPointer const& base: contract->getBaseContracts()) { - ContractDefinition const* baseContract = dynamic_cast( - base->getName()->getReferencedDeclaration()); + auto baseContract = dynamic_cast( + base->getName()->getReferencedDeclaration() + ); solAssert(baseContract, ""); - FunctionDefinition const* baseConstructor = baseContract->getConstructor(); - if (argumentsNeeded.count(baseConstructor) == 1) - argumentsProvided.insert(baseConstructor); + if (!base->getArguments().empty()) + argumentsNeeded.erase(baseContract); } } - // add this contract's constructor to the provided too - if (getConstructor() && !getConstructor()->getParameters().empty()) - argumentsProvided.insert(getConstructor()); - if (argumentsProvided != argumentsNeeded) + if (!argumentsNeeded.empty()) setFullyImplemented(false); } From acc9b124ae89cde7b0954969e91c72557a5300e3 Mon Sep 17 00:00:00 2001 From: yann300 Date: Fri, 17 Apr 2015 17:32:28 +0200 Subject: [PATCH 20/65] bug fix: copy paste from transaction logs --- mix/qml/TransactionLog.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix/qml/TransactionLog.qml b/mix/qml/TransactionLog.qml index 86f8b2a74..16ed3e9bf 100644 --- a/mix/qml/TransactionLog.qml +++ b/mix/qml/TransactionLog.qml @@ -151,7 +151,7 @@ Item { Keys.onPressed: { if ((event.modifiers & Qt.ControlModifier) && event.key === Qt.Key_C && currentRow >=0 && currentRow < logTable.model.count) { var item = logTable.model.get(currentRow); - appContext.toClipboard(item.returned); + clipboard.text = item.returned; } } } From 2a5a5a99f91ff69abd4b510450c04806cca0bab2 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Fri, 17 Apr 2015 17:41:41 +0200 Subject: [PATCH 21/65] added asm-json flag to cl compiler Conflicts: libsolidity/CompilerStack.cpp --- libevmcore/Assembly.cpp | 3 ++- libevmcore/Assembly.h | 2 +- libsolidity/Compiler.h | 5 +++-- libsolidity/CompilerContext.h | 3 ++- libsolidity/CompilerStack.cpp | 4 ++-- libsolidity/CompilerStack.h | 3 ++- solc/CommandLineInterface.cpp | 38 +++++++++++++++++++++-------------- 7 files changed, 35 insertions(+), 23 deletions(-) diff --git a/libevmcore/Assembly.cpp b/libevmcore/Assembly.cpp index bf4ea2145..589912857 100644 --- a/libevmcore/Assembly.cpp +++ b/libevmcore/Assembly.cpp @@ -101,8 +101,9 @@ string Assembly::getLocationFromSources(StringMap const& _sourceCodes, SourceLoc return move(cut); } -ostream& Assembly::stream(ostream& _out, string const& _prefix, StringMap const& _sourceCodes) const +ostream& Assembly::stream(ostream& _out, string const& _prefix, StringMap const& _sourceCodes, bool _inJsonFormat) const { + (void)_inJsonFormat; _out << _prefix << ".code:" << endl; for (AssemblyItem const& i: m_items) { diff --git a/libevmcore/Assembly.h b/libevmcore/Assembly.h index 2744af900..06cac8801 100644 --- a/libevmcore/Assembly.h +++ b/libevmcore/Assembly.h @@ -86,7 +86,7 @@ public: bytes assemble() const; Assembly& optimise(bool _enable); - std::ostream& stream(std::ostream& _out, std::string const& _prefix = "", const StringMap &_sourceCodes = StringMap()) const; + std::ostream& stream(std::ostream& _out, std::string const& _prefix = "", const StringMap &_sourceCodes = StringMap(), bool _inJsonFormat = false) const; protected: std::string getLocationFromSources(StringMap const& _sourceCodes, SourceLocation const& _location) const; diff --git a/libsolidity/Compiler.h b/libsolidity/Compiler.h index 4b1e1b4d6..260aebd33 100644 --- a/libsolidity/Compiler.h +++ b/libsolidity/Compiler.h @@ -42,9 +42,10 @@ public: bytes getAssembledBytecode() { return m_context.getAssembledBytecode(m_optimize); } bytes getRuntimeBytecode() { return m_runtimeContext.getAssembledBytecode(m_optimize);} /// @arg _sourceCodes is the map of input files to source code strings - void streamAssembly(std::ostream& _stream, StringMap const& _sourceCodes = StringMap()) const + /// @arg _inJsonFromat shows weather the out should be in Json format + void streamAssembly(std::ostream& _stream, StringMap const& _sourceCodes = StringMap(), bool _inJsonFormat = false) const { - m_context.streamAssembly(_stream, _sourceCodes); + m_context.streamAssembly(_stream, _sourceCodes, _inJsonFormat); } /// @returns Assembly items of the normal compiler context eth::AssemblyItems const& getAssemblyItems() const { return m_context.getAssembly().getItems(); } diff --git a/libsolidity/CompilerContext.h b/libsolidity/CompilerContext.h index e752d59b8..3fcf0706d 100644 --- a/libsolidity/CompilerContext.h +++ b/libsolidity/CompilerContext.h @@ -122,7 +122,8 @@ public: eth::Assembly const& getAssembly() const { return m_asm; } /// @arg _sourceCodes is the map of input files to source code strings - void streamAssembly(std::ostream& _stream, StringMap const& _sourceCodes = StringMap()) const { m_asm.stream(_stream, "", _sourceCodes); } + /// @arg _inJsonFromat shows weather the out should be in Json format + void streamAssembly(std::ostream& _stream, StringMap const& _sourceCodes = StringMap(), bool _inJsonFormat = false) const { m_asm.stream(_stream, "", _sourceCodes, _inJsonFormat); } bytes getAssembledBytecode(bool _optimize = false) { return m_asm.optimise(_optimize).assemble(); } diff --git a/libsolidity/CompilerStack.cpp b/libsolidity/CompilerStack.cpp index c35d9324c..592f61276 100644 --- a/libsolidity/CompilerStack.cpp +++ b/libsolidity/CompilerStack.cpp @@ -184,11 +184,11 @@ dev::h256 CompilerStack::getContractCodeHash(string const& _contractName) const return dev::sha3(getRuntimeBytecode(_contractName)); } -void CompilerStack::streamAssembly(ostream& _outStream, string const& _contractName, StringMap _sourceCodes) const +void CompilerStack::streamAssembly(ostream& _outStream, string const& _contractName, StringMap _sourceCodes, bool _inJsonFormat) const { Contract const& contract = getContract(_contractName); if (contract.compiler) - getContract(_contractName).compiler->streamAssembly(_outStream, _sourceCodes); + contract(_contractName).compiler->streamAssembly(_outStream, _sourceCodes, _inJsonFormat); else _outStream << "Contract not fully implemented" << endl; } diff --git a/libsolidity/CompilerStack.h b/libsolidity/CompilerStack.h index 19c1ba4e1..ef3d09663 100644 --- a/libsolidity/CompilerStack.h +++ b/libsolidity/CompilerStack.h @@ -102,8 +102,9 @@ public: /// Streams a verbose version of the assembly to @a _outStream. /// @arg _sourceCodes is the map of input files to source code strings + /// @arg _inJsonFromat shows weather the out should be in Json format /// Prerequisite: Successful compilation. - void streamAssembly(std::ostream& _outStream, std::string const& _contractName = "", StringMap _sourceCodes = StringMap()) const; + void streamAssembly(std::ostream& _outStream, std::string const& _contractName = "", StringMap _sourceCodes = StringMap(), bool _inJsonFormat = false) const; /// Returns a string representing the contract interface in JSON. /// Prerequisite: Successful call to parse or compile. diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index 6ed90cdea..d21839f14 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -55,6 +55,7 @@ namespace solidity static string const g_argAbiStr = "json-abi"; static string const g_argSolAbiStr = "sol-abi"; static string const g_argAsmStr = "asm"; +static string const g_argAsmJsonStr = "asm-json"; static string const g_argAstStr = "ast"; static string const g_argAstJson = "ast-json"; static string const g_argBinaryStr = "binary"; @@ -80,10 +81,15 @@ static bool needStdout(po::variables_map const& _args) { return - argToStdout(_args, g_argAbiStr) || argToStdout(_args, g_argSolAbiStr) || - argToStdout(_args, g_argNatspecUserStr) || argToStdout(_args, g_argAstJson) || - argToStdout(_args, g_argNatspecDevStr) || argToStdout(_args, g_argAsmStr) || - argToStdout(_args, g_argOpcodesStr) || argToStdout(_args, g_argBinaryStr); + argToStdout(_args, g_argAbiStr) || + argToStdout(_args, g_argSolAbiStr) || + argToStdout(_args, g_argNatspecUserStr) || + argToStdout(_args, g_argAstJson) || + argToStdout(_args, g_argNatspecDevStr) || + argToStdout(_args, g_argAsmStr) || + argToStdout(_args, g_argAsmJsonStr) || + argToStdout(_args, g_argOpcodesStr) || + argToStdout(_args, g_argBinaryStr); } static inline bool outputToFile(OutputType type) @@ -215,23 +221,25 @@ bool CommandLineInterface::parseArguments(int argc, char** argv) ("add-std", po::value()->default_value(false), "Add standard contracts") ("input-file", po::value>(), "input file") (g_argAstStr.c_str(), po::value()->value_name("stdout|file|both"), - "Request to output the AST of the contract.") + "Request to output the AST of the contract.") (g_argAstJson.c_str(), po::value()->value_name("stdout|file|both"), - "Request to output the AST of the contract in JSON format.") + "Request to output the AST of the contract in JSON format.") (g_argAsmStr.c_str(), po::value()->value_name("stdout|file|both"), - "Request to output the EVM assembly of the contract.") + "Request to output the EVM assembly of the contract.") + (g_argAsmJsonStr.c_str(), po::value()->value_name("stdout|file|both"), + "Request to output the EVM assembly of the contract in JSON format.") (g_argOpcodesStr.c_str(), po::value()->value_name("stdout|file|both"), - "Request to output the Opcodes of the contract.") + "Request to output the Opcodes of the contract.") (g_argBinaryStr.c_str(), po::value()->value_name("stdout|file|both"), - "Request to output the contract in binary (hexadecimal).") + "Request to output the contract in binary (hexadecimal).") (g_argAbiStr.c_str(), po::value()->value_name("stdout|file|both"), - "Request to output the contract's JSON ABI interface.") + "Request to output the contract's JSON ABI interface.") (g_argSolAbiStr.c_str(), po::value()->value_name("stdout|file|both"), - "Request to output the contract's Solidity ABI interface.") + "Request to output the contract's Solidity ABI interface.") (g_argNatspecUserStr.c_str(), po::value()->value_name("stdout|file|both"), - "Request to output the contract's Natspec user documentation.") + "Request to output the contract's Natspec user documentation.") (g_argNatspecDevStr.c_str(), po::value()->value_name("stdout|file|both"), - "Request to output the contract's Natspec developer documentation."); + "Request to output the contract's Natspec developer documentation."); // All positional options should be interpreted as input files po::positional_options_description p; @@ -417,13 +425,13 @@ void CommandLineInterface::actOnInput() if (outputToStdout(choice)) { cout << "EVM assembly:" << endl; - m_compiler->streamAssembly(cout, contract, m_sourceCodes); + m_compiler->streamAssembly(cout, contract, m_sourceCodes, m_args.count(g_argAsmJsonStr)); } if (outputToFile(choice)) { ofstream outFile(contract + ".evm"); - m_compiler->streamAssembly(outFile, contract, m_sourceCodes); + m_compiler->streamAssembly(outFile, contract, m_sourceCodes, m_args.count(g_argAsmJsonStr)); outFile.close(); } } From 1305502fc95c361833a7e02c26d0ee5a94ce42da Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Fri, 17 Apr 2015 16:13:34 +0200 Subject: [PATCH 22/65] initial output for asm-json flag. Conflicts: libevmcore/Assembly.cpp --- libevmcore/Assembly.cpp | 162 +++++++++++++++++++++++++++++++++- libevmcore/Assembly.h | 6 ++ libevmcore/CMakeLists.txt | 1 + solc/CommandLineInterface.cpp | 4 +- 4 files changed, 169 insertions(+), 4 deletions(-) diff --git a/libevmcore/Assembly.cpp b/libevmcore/Assembly.cpp index 589912857..0d24618ee 100644 --- a/libevmcore/Assembly.cpp +++ b/libevmcore/Assembly.cpp @@ -24,6 +24,7 @@ #include #include #include +#include using namespace std; using namespace dev; @@ -101,9 +102,8 @@ string Assembly::getLocationFromSources(StringMap const& _sourceCodes, SourceLoc return move(cut); } -ostream& Assembly::stream(ostream& _out, string const& _prefix, StringMap const& _sourceCodes, bool _inJsonFormat) const +ostream& Assembly::streamAsm(ostream& _out, string const& _prefix, StringMap const& _sourceCodes) const { - (void)_inJsonFormat; _out << _prefix << ".code:" << endl; for (AssemblyItem const& i: m_items) { @@ -158,6 +158,164 @@ ostream& Assembly::stream(ostream& _out, string const& _prefix, StringMap const& return _out; } +ostream& Assembly::streamAsmJson(ostream& _out, string const& _prefix, StringMap const& _sourceCodes, bool _inJsonFormat) const +{ + Json::Value root; + + string currentArrayName = ".code"; + std::vector currentCollection; + for (AssemblyItem const& i: m_items) + { + //todo check and remove where location.isEmpty() + switch (i.type()) + { + case Operation: + { + Json::Value op; + op["name"] = instructionInfo(i.instruction()).name; + op["jumpType"] = i.getJumpTypeAsString(); + op["locationX"] = i.getLocation().start; + op["locationY"] = i.getLocation().end; + currentCollection.push_back(op); + //_out << " " << instructionInfo(i.instruction()).name << "\t" << i.getJumpTypeAsString(); + } + break; + case Push: + { + Json::Value pushitem; + pushitem["name"] = "PUSH"; + pushitem["value"] = string(i.data()); + pushitem["locationX"] = boost::lexical_cast(i.getLocation().start); + pushitem["locationY"] = boost::lexical_cast(i.getLocation().end); + currentCollection.push_back(pushitem); + //_out << " PUSH " << i.data(); + } + break; + case PushString: + { + Json::Value pushString; + pushString["name"] = "PUSH tag"; + pushString["value"] = m_strings.at((h256)i.data()); + pushString["locationX"] = i.getLocation().start; + pushString["locationY"] = i.getLocation().end; + currentCollection.push_back(pushString); + //_out << " PUSH \"" << m_strings.at((h256)i.data()) << "\""; + } + break; + case PushTag: + { + Json::Value pushTag; + pushTag["name"] = "PUSH [tag]"; + pushTag["value"] = string(i.data()); + pushTag["locationX"] = boost::lexical_cast(i.getLocation().start); + pushTag["locationY"] = boost::lexical_cast(i.getLocation().end); + currentCollection.push_back(pushTag); + } + //_out << " PUSH [tag" << i.data() << "]"; + break; + case PushSub: + { + Json::Value pushSub; + pushSub["name"] = "PUSH [$]"; + pushSub["value"] = h256(i.data()).abridged() ; + pushSub["locationX"] = boost::lexical_cast(i.getLocation().start); + pushSub["locationY"] = boost::lexical_cast(i.getLocation().end); + currentCollection.push_back(pushSub); + } + //_out << " PUSH [$" << h256(i.data()).abridged() << "]"; + break; + case PushSubSize: + { + Json::Value pushSubSize; + pushSubSize["name"] = "PUSH #[$]"; + pushSubSize["value"] = h256(i.data()).abridged(); + pushSubSize["locationX"] = boost::lexical_cast(i.getLocation().start); + pushSubSize["locationY"] = boost::lexical_cast(i.getLocation().end); + currentCollection.push_back(pushSubSize); + } + //_out << " PUSH #[$" << h256(i.data()).abridged() << "]"; + break; + case PushProgramSize: + { + Json::Value pushSize; + pushSize["name"] = "PUSHSIZE"; + pushSize["locationX"] = boost::lexical_cast(i.getLocation().start); + pushSize["locationY"] = boost::lexical_cast(i.getLocation().end); + currentCollection.push_back(pushSize); + } + //_out << " PUSHSIZE"; + break; + case Tag: + { + Json::Value collection(Json::arrayValue); + for(auto it: currentCollection) + collection.append(it); + currentCollection.clear(); + root[currentArrayName] = collection; + currentArrayName = "tag" + string(i.data()); + } + //_out << "tag" << i.data() << ": " << endl << _prefix << " JUMPDEST"; + break; + case PushData: + { + Json::Value pushData; + pushData["name"] = "PUSH hex"; + std::stringstream hexStr; + hexStr << hex << (unsigned)i.data(); + pushData["value"] = hexStr.str(); + pushData["locationX"] = boost::lexical_cast(i.getLocation().start); + pushData["locationY"] = boost::lexical_cast(i.getLocation().end); + currentCollection.push_back(pushData); + } + //_out << " PUSH [" << hex << (unsigned)i.data() << "]"; + break; + default: + BOOST_THROW_EXCEPTION(InvalidOpcode()); + } + } + + //todo check if the last was tag + Json::Value collection(Json::arrayValue); + for(auto it: currentCollection) + collection.append(it); + root[currentArrayName] = collection; + + if (!m_data.empty() || !m_subs.empty()) + { + Json::Value dataCollection(Json::arrayValue); + for (auto const& i: m_data) + if (u256(i.first) >= m_subs.size()) + { + std::stringstream hexStr; + hexStr << _prefix << hex << (unsigned)(u256)i.first << ": " << toHex(i.second); + Json::Value data; + data["value"] = hexStr.str(); + dataCollection.append(data); + } + root[_prefix + ".data"] = collection; + + for (size_t i = 0; i < m_subs.size(); ++i) + { + std::stringstream hexStr; + hexStr << _prefix << hex << i << ": "; + //_out << _prefix << " " << hex << i << ": " << endl; + //todo check recursion + m_subs[i].stream(_out, _prefix + " ", _sourceCodes, _inJsonFormat); + } + } + + _out << root; + return _out; +} + +ostream& Assembly::stream(ostream& _out, string const& _prefix, StringMap const& _sourceCodes, bool _inJsonFormat) const +{ + if (!_inJsonFormat) + return streamAsm(_out, _prefix, _sourceCodes); + else + return streamAsmJson(_out, _prefix, _sourceCodes, _inJsonFormat); +} + AssemblyItem const& Assembly::append(AssemblyItem const& _i) { m_deposit += _i.deposit(); diff --git a/libevmcore/Assembly.h b/libevmcore/Assembly.h index 06cac8801..d2927abac 100644 --- a/libevmcore/Assembly.h +++ b/libevmcore/Assembly.h @@ -93,6 +93,10 @@ protected: void donePath() { if (m_totalDeposit != INT_MAX && m_totalDeposit != m_deposit) BOOST_THROW_EXCEPTION(InvalidDeposit()); } unsigned bytesRequired() const; +private: + std::ostream& streamAsmJson(std::ostream& _out, const std::string &_prefix, const StringMap &_sourceCodes, bool _inJsonFormat) const; + std::ostream& streamAsm(std::ostream& _out, std::string const& _prefix, StringMap const& _sourceCodes) const; +protected: unsigned m_usedTags = 0; AssemblyItems m_items; mutable std::map m_data; @@ -104,8 +108,10 @@ protected: int m_totalDeposit = 0; SourceLocation m_currentSourceLocation; + }; + inline std::ostream& operator<<(std::ostream& _out, Assembly const& _a) { _a.stream(_out); diff --git a/libevmcore/CMakeLists.txt b/libevmcore/CMakeLists.txt index 6a834936b..83a4e115c 100644 --- a/libevmcore/CMakeLists.txt +++ b/libevmcore/CMakeLists.txt @@ -11,6 +11,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB") aux_source_directory(. SRC_LIST) +include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS}) include_directories(BEFORE ..) include_directories(${Boost_INCLUDE_DIRS}) diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index d21839f14..cb924d9b5 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -419,9 +419,9 @@ void CommandLineInterface::actOnInput() cout << endl << "======= " << contract << " =======" << endl; // do we need EVM assembly? - if (m_args.count(g_argAsmStr)) + if (m_args.count(g_argAsmStr) || m_args.count(g_argAsmJsonStr)) { - auto choice = m_args[g_argAsmStr].as(); + auto choice = m_args.count(g_argAsmStr) ? m_args[g_argAsmStr].as() : m_args[g_argAsmJsonStr].as(); if (outputToStdout(choice)) { cout << "EVM assembly:" << endl; From 2189306c9d355b38d7981b2811475a138e98bec6 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Mon, 13 Apr 2015 18:09:35 +0200 Subject: [PATCH 23/65] reordered output. modified push tags --- libevmcore/Assembly.cpp | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/libevmcore/Assembly.cpp b/libevmcore/Assembly.cpp index 0d24618ee..bd9b5e832 100644 --- a/libevmcore/Assembly.cpp +++ b/libevmcore/Assembly.cpp @@ -216,8 +216,8 @@ ostream& Assembly::streamAsmJson(ostream& _out, string const& _prefix, StringMap case PushSub: { Json::Value pushSub; - pushSub["name"] = "PUSH [$]"; - pushSub["value"] = h256(i.data()).abridged() ; + pushSub["name"] = "PUSH"; + pushSub["value"] = "[$]" + string(h256(i.data()).abridged()); pushSub["locationX"] = boost::lexical_cast(i.getLocation().start); pushSub["locationY"] = boost::lexical_cast(i.getLocation().end); currentCollection.push_back(pushSub); @@ -227,8 +227,8 @@ ostream& Assembly::streamAsmJson(ostream& _out, string const& _prefix, StringMap case PushSubSize: { Json::Value pushSubSize; - pushSubSize["name"] = "PUSH #[$]"; - pushSubSize["value"] = h256(i.data()).abridged(); + pushSubSize["name"] = "PUSH"; + pushSubSize["value"] = "#[$]" + string(h256(i.data()).abridged()); pushSubSize["locationX"] = boost::lexical_cast(i.getLocation().start); pushSubSize["locationY"] = boost::lexical_cast(i.getLocation().end); currentCollection.push_back(pushSubSize); @@ -253,6 +253,9 @@ ostream& Assembly::streamAsmJson(ostream& _out, string const& _prefix, StringMap currentCollection.clear(); root[currentArrayName] = collection; currentArrayName = "tag" + string(i.data()); + Json::Value jumpdest; + jumpdest["name"] = "JUMDEST"; + currentCollection.push_back(jumpdest); } //_out << "tag" << i.data() << ": " << endl << _prefix << " JUMPDEST"; break; @@ -292,19 +295,21 @@ ostream& Assembly::streamAsmJson(ostream& _out, string const& _prefix, StringMap data["value"] = hexStr.str(); dataCollection.append(data); } - root[_prefix + ".data"] = collection; for (size_t i = 0; i < m_subs.size(); ++i) { std::stringstream hexStr; hexStr << _prefix << hex << i << ": "; //_out << _prefix << " " << hex << i << ": " << endl; - //todo check recursion + //todo check recursion check order. m_subs[i].stream(_out, _prefix + " ", _sourceCodes, _inJsonFormat); } - } + root[_prefix + ".data"] = collection; + _out << root; + + } else + _out << root; - _out << root; return _out; } From 4ef9b70dd3cd71773953d2225295fc6e68ccaf8e Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Tue, 14 Apr 2015 11:38:36 +0200 Subject: [PATCH 24/65] style fixes --- libevmcore/Assembly.cpp | 9 ++++----- libevmcore/Assembly.h | 12 ++++++++++-- libsolidity/Compiler.h | 2 +- libsolidity/CompilerContext.h | 7 +++++-- libsolidity/CompilerStack.h | 2 +- 5 files changed, 21 insertions(+), 11 deletions(-) diff --git a/libevmcore/Assembly.cpp b/libevmcore/Assembly.cpp index bd9b5e832..99ff168df 100644 --- a/libevmcore/Assembly.cpp +++ b/libevmcore/Assembly.cpp @@ -248,7 +248,7 @@ ostream& Assembly::streamAsmJson(ostream& _out, string const& _prefix, StringMap case Tag: { Json::Value collection(Json::arrayValue); - for(auto it: currentCollection) + for (auto it: currentCollection) collection.append(it); currentCollection.clear(); root[currentArrayName] = collection; @@ -279,7 +279,7 @@ ostream& Assembly::streamAsmJson(ostream& _out, string const& _prefix, StringMap //todo check if the last was tag Json::Value collection(Json::arrayValue); - for(auto it: currentCollection) + for (auto it: currentCollection) collection.append(it); root[currentArrayName] = collection; @@ -295,6 +295,8 @@ ostream& Assembly::streamAsmJson(ostream& _out, string const& _prefix, StringMap data["value"] = hexStr.str(); dataCollection.append(data); } + root[_prefix + ".data"] = collection; + _out << root; for (size_t i = 0; i < m_subs.size(); ++i) { @@ -304,9 +306,6 @@ ostream& Assembly::streamAsmJson(ostream& _out, string const& _prefix, StringMap //todo check recursion check order. m_subs[i].stream(_out, _prefix + " ", _sourceCodes, _inJsonFormat); } - root[_prefix + ".data"] = collection; - _out << root; - } else _out << root; diff --git a/libevmcore/Assembly.h b/libevmcore/Assembly.h index d2927abac..6eef34194 100644 --- a/libevmcore/Assembly.h +++ b/libevmcore/Assembly.h @@ -86,7 +86,11 @@ public: bytes assemble() const; Assembly& optimise(bool _enable); - std::ostream& stream(std::ostream& _out, std::string const& _prefix = "", const StringMap &_sourceCodes = StringMap(), bool _inJsonFormat = false) const; + std::ostream& stream( + std::ostream& _out, + std::string const& _prefix = "", + const StringMap &_sourceCodes = StringMap(), + bool _inJsonFormat = false) const; protected: std::string getLocationFromSources(StringMap const& _sourceCodes, SourceLocation const& _location) const; @@ -94,7 +98,11 @@ protected: unsigned bytesRequired() const; private: - std::ostream& streamAsmJson(std::ostream& _out, const std::string &_prefix, const StringMap &_sourceCodes, bool _inJsonFormat) const; + std::ostream& streamAsmJson( + std::ostream& _out, + const std::string &_prefix, + const StringMap &_sourceCodes, + bool _inJsonFormat) const; std::ostream& streamAsm(std::ostream& _out, std::string const& _prefix, StringMap const& _sourceCodes) const; protected: unsigned m_usedTags = 0; diff --git a/libsolidity/Compiler.h b/libsolidity/Compiler.h index 260aebd33..d476ec684 100644 --- a/libsolidity/Compiler.h +++ b/libsolidity/Compiler.h @@ -42,7 +42,7 @@ public: bytes getAssembledBytecode() { return m_context.getAssembledBytecode(m_optimize); } bytes getRuntimeBytecode() { return m_runtimeContext.getAssembledBytecode(m_optimize);} /// @arg _sourceCodes is the map of input files to source code strings - /// @arg _inJsonFromat shows weather the out should be in Json format + /// @arg _inJsonFromat shows whether the out should be in Json format void streamAssembly(std::ostream& _stream, StringMap const& _sourceCodes = StringMap(), bool _inJsonFormat = false) const { m_context.streamAssembly(_stream, _sourceCodes, _inJsonFormat); diff --git a/libsolidity/CompilerContext.h b/libsolidity/CompilerContext.h index 3fcf0706d..9c2156bfa 100644 --- a/libsolidity/CompilerContext.h +++ b/libsolidity/CompilerContext.h @@ -122,8 +122,11 @@ public: eth::Assembly const& getAssembly() const { return m_asm; } /// @arg _sourceCodes is the map of input files to source code strings - /// @arg _inJsonFromat shows weather the out should be in Json format - void streamAssembly(std::ostream& _stream, StringMap const& _sourceCodes = StringMap(), bool _inJsonFormat = false) const { m_asm.stream(_stream, "", _sourceCodes, _inJsonFormat); } + /// @arg _inJsonFormat shows whether the out should be in Json format + void streamAssembly(std::ostream& _stream, StringMap const& _sourceCodes = StringMap(), bool _inJsonFormat = false) const + { + m_asm.stream(_stream, "", _sourceCodes, _inJsonFormat); + } bytes getAssembledBytecode(bool _optimize = false) { return m_asm.optimise(_optimize).assemble(); } diff --git a/libsolidity/CompilerStack.h b/libsolidity/CompilerStack.h index ef3d09663..2e7c217d5 100644 --- a/libsolidity/CompilerStack.h +++ b/libsolidity/CompilerStack.h @@ -102,7 +102,7 @@ public: /// Streams a verbose version of the assembly to @a _outStream. /// @arg _sourceCodes is the map of input files to source code strings - /// @arg _inJsonFromat shows weather the out should be in Json format + /// @arg _inJsonFromat shows whether the out should be in Json format /// Prerequisite: Successful compilation. void streamAssembly(std::ostream& _outStream, std::string const& _contractName = "", StringMap _sourceCodes = StringMap(), bool _inJsonFormat = false) const; From 9fa9190f1d4a7e49bee9a8ff523a51bdbe9f2080 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Tue, 14 Apr 2015 15:42:27 +0200 Subject: [PATCH 25/65] code refactoring --- libevmcore/Assembly.cpp | 136 +++++++++++++--------------------------- libevmcore/Assembly.h | 6 ++ 2 files changed, 51 insertions(+), 91 deletions(-) diff --git a/libevmcore/Assembly.cpp b/libevmcore/Assembly.cpp index 99ff168df..3bdf3e0a0 100644 --- a/libevmcore/Assembly.cpp +++ b/libevmcore/Assembly.cpp @@ -158,6 +158,20 @@ ostream& Assembly::streamAsm(ostream& _out, string const& _prefix, StringMap con return _out; } +Json::Value Assembly::createJsonValue(string _name, int _locationX, int _locationY, string _value, string _jumpType) const +{ + Json::Value value; + assert(!_name.empty()); + value["name"] = _name; + value["locationX"] = _locationX; + value["locationY"] = _locationY; + if (!_value.empty()) + value["value"] = _value; + if (!_jumpType.empty()) + value["jumpType"] = _jumpType; + return move(value); +} + ostream& Assembly::streamAsmJson(ostream& _out, string const& _prefix, StringMap const& _sourceCodes, bool _inJsonFormat) const { Json::Value root; @@ -166,111 +180,50 @@ ostream& Assembly::streamAsmJson(ostream& _out, string const& _prefix, StringMap std::vector currentCollection; for (AssemblyItem const& i: m_items) { - //todo check and remove where location.isEmpty() switch (i.type()) { case Operation: - { - Json::Value op; - op["name"] = instructionInfo(i.instruction()).name; - op["jumpType"] = i.getJumpTypeAsString(); - op["locationX"] = i.getLocation().start; - op["locationY"] = i.getLocation().end; - currentCollection.push_back(op); - //_out << " " << instructionInfo(i.instruction()).name << "\t" << i.getJumpTypeAsString(); - } + currentCollection.push_back(createJsonValue(instructionInfo(i.instruction()).name, i.getLocation().start, i.getLocation().end, i.getJumpTypeAsString())); break; case Push: - { - Json::Value pushitem; - pushitem["name"] = "PUSH"; - pushitem["value"] = string(i.data()); - pushitem["locationX"] = boost::lexical_cast(i.getLocation().start); - pushitem["locationY"] = boost::lexical_cast(i.getLocation().end); - currentCollection.push_back(pushitem); - //_out << " PUSH " << i.data(); - } + currentCollection.push_back(createJsonValue(string("PUSH"), i.getLocation().start, i.getLocation().end, string(i.data()), i.getJumpTypeAsString())); break; case PushString: - { - Json::Value pushString; - pushString["name"] = "PUSH tag"; - pushString["value"] = m_strings.at((h256)i.data()); - pushString["locationX"] = i.getLocation().start; - pushString["locationY"] = i.getLocation().end; - currentCollection.push_back(pushString); - //_out << " PUSH \"" << m_strings.at((h256)i.data()) << "\""; - } + currentCollection.push_back(createJsonValue(string("PUSH tag"), i.getLocation().start, i.getLocation().end, m_strings.at((h256)i.data()))); break; case PushTag: - { - Json::Value pushTag; - pushTag["name"] = "PUSH [tag]"; - pushTag["value"] = string(i.data()); - pushTag["locationX"] = boost::lexical_cast(i.getLocation().start); - pushTag["locationY"] = boost::lexical_cast(i.getLocation().end); - currentCollection.push_back(pushTag); - } - //_out << " PUSH [tag" << i.data() << "]"; + currentCollection.push_back(createJsonValue(string("PUSH [tag]"), i.getLocation().start, i.getLocation().end, string(i.data()))); break; case PushSub: - { - Json::Value pushSub; - pushSub["name"] = "PUSH"; - pushSub["value"] = "[$]" + string(h256(i.data()).abridged()); - pushSub["locationX"] = boost::lexical_cast(i.getLocation().start); - pushSub["locationY"] = boost::lexical_cast(i.getLocation().end); - currentCollection.push_back(pushSub); - } - //_out << " PUSH [$" << h256(i.data()).abridged() << "]"; + currentCollection.push_back(createJsonValue(string("PUSH"), i.getLocation().start, i.getLocation().end, string("[$]" + string(h256(i.data()).abridged())))); break; case PushSubSize: - { - Json::Value pushSubSize; - pushSubSize["name"] = "PUSH"; - pushSubSize["value"] = "#[$]" + string(h256(i.data()).abridged()); - pushSubSize["locationX"] = boost::lexical_cast(i.getLocation().start); - pushSubSize["locationY"] = boost::lexical_cast(i.getLocation().end); - currentCollection.push_back(pushSubSize); - } - //_out << " PUSH #[$" << h256(i.data()).abridged() << "]"; + currentCollection.push_back(createJsonValue(string("PUSH"), i.getLocation().start, i.getLocation().end, string("#[$]" + string(h256(i.data()).abridged())))); break; case PushProgramSize: - { - Json::Value pushSize; - pushSize["name"] = "PUSHSIZE"; - pushSize["locationX"] = boost::lexical_cast(i.getLocation().start); - pushSize["locationY"] = boost::lexical_cast(i.getLocation().end); - currentCollection.push_back(pushSize); - } - //_out << " PUSHSIZE"; + currentCollection.push_back(createJsonValue(string("PUSHSIZE"), i.getLocation().start, i.getLocation().end)); break; case Tag: - { - Json::Value collection(Json::arrayValue); - for (auto it: currentCollection) - collection.append(it); - currentCollection.clear(); - root[currentArrayName] = collection; - currentArrayName = "tag" + string(i.data()); - Json::Value jumpdest; - jumpdest["name"] = "JUMDEST"; - currentCollection.push_back(jumpdest); - } - //_out << "tag" << i.data() << ": " << endl << _prefix << " JUMPDEST"; + { + Json::Value collection(Json::arrayValue); + for (auto it: currentCollection) + collection.append(it); + currentCollection.clear(); + root[currentArrayName] = collection; + currentArrayName = "tag" + string(i.data()); + Json::Value jumpdest; + jumpdest["name"] = "JUMDEST"; + currentCollection.push_back(jumpdest); + } break; case PushData: - { - Json::Value pushData; - pushData["name"] = "PUSH hex"; - std::stringstream hexStr; - hexStr << hex << (unsigned)i.data(); - pushData["value"] = hexStr.str(); - pushData["locationX"] = boost::lexical_cast(i.getLocation().start); - pushData["locationY"] = boost::lexical_cast(i.getLocation().end); - currentCollection.push_back(pushData); - } - //_out << " PUSH [" << hex << (unsigned)i.data() << "]"; + { + Json::Value pushData; + pushData["name"] = "PUSH hex"; + std::stringstream hexStr; + hexStr << hex << (unsigned)i.data(); + currentCollection.push_back(createJsonValue(string("PUSH hex"), i.getLocation().start, i.getLocation().end, hexStr.str())); + } break; default: BOOST_THROW_EXCEPTION(InvalidOpcode()); @@ -283,6 +236,7 @@ ostream& Assembly::streamAsmJson(ostream& _out, string const& _prefix, StringMap collection.append(it); root[currentArrayName] = collection; + Json::Value rootData; if (!m_data.empty() || !m_subs.empty()) { Json::Value dataCollection(Json::arrayValue); @@ -295,8 +249,8 @@ ostream& Assembly::streamAsmJson(ostream& _out, string const& _prefix, StringMap data["value"] = hexStr.str(); dataCollection.append(data); } - root[_prefix + ".data"] = collection; - _out << root; + rootData[_prefix + ".data"] = collection; + _out << root << rootData; for (size_t i = 0; i < m_subs.size(); ++i) { @@ -314,10 +268,10 @@ ostream& Assembly::streamAsmJson(ostream& _out, string const& _prefix, StringMap ostream& Assembly::stream(ostream& _out, string const& _prefix, StringMap const& _sourceCodes, bool _inJsonFormat) const { - if (!_inJsonFormat) - return streamAsm(_out, _prefix, _sourceCodes); - else + if (_inJsonFormat) return streamAsmJson(_out, _prefix, _sourceCodes, _inJsonFormat); + else + return streamAsm(_out, _prefix, _sourceCodes); } AssemblyItem const& Assembly::append(AssemblyItem const& _i) diff --git a/libevmcore/Assembly.h b/libevmcore/Assembly.h index 6eef34194..49c45d37b 100644 --- a/libevmcore/Assembly.h +++ b/libevmcore/Assembly.h @@ -30,6 +30,10 @@ #include #include "Exceptions.h" +namespace Json +{ +class Value; +} namespace dev { namespace eth @@ -104,6 +108,8 @@ private: const StringMap &_sourceCodes, bool _inJsonFormat) const; std::ostream& streamAsm(std::ostream& _out, std::string const& _prefix, StringMap const& _sourceCodes) const; + Json::Value createJsonValue(std::string _name, int _locationX, int _locationY, std::string _value = std::string(), std::string _jumpType = std::string()) const; + protected: unsigned m_usedTags = 0; AssemblyItems m_items; From c6652616ae67583e16a7e0e237b386c541eb9466 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Fri, 17 Apr 2015 16:15:25 +0200 Subject: [PATCH 26/65] reordered output Conflicts: libevmcore/Assembly.cpp --- libevmcore/Assembly.cpp | 57 ++++++++++++++++++++++++++--------------- libevmcore/Assembly.h | 8 +++--- liblll/CMakeLists.txt | 1 + 3 files changed, 43 insertions(+), 23 deletions(-) diff --git a/libevmcore/Assembly.cpp b/libevmcore/Assembly.cpp index 3bdf3e0a0..f794ffa3b 100644 --- a/libevmcore/Assembly.cpp +++ b/libevmcore/Assembly.cpp @@ -30,6 +30,8 @@ using namespace std; using namespace dev; using namespace dev::eth; + + void Assembly::append(Assembly const& _a) { auto newDeposit = m_deposit + _a.deposit(); @@ -66,6 +68,13 @@ void Assembly::append(Assembly const& _a, int _deposit) } } +string Assembly::out() const +{ + stringstream ret; + stream(ret); + return ret.str(); +} + unsigned Assembly::bytesRequired() const { for (unsigned br = 1;; ++br) @@ -172,7 +181,7 @@ Json::Value Assembly::createJsonValue(string _name, int _locationX, int _locatio return move(value); } -ostream& Assembly::streamAsmJson(ostream& _out, string const& _prefix, StringMap const& _sourceCodes, bool _inJsonFormat) const +Json::Value Assembly::streamAsmJson(ostream& _out, string const& _prefix, StringMap const& _sourceCodes, bool _inJsonFormat) const { Json::Value root; @@ -183,25 +192,32 @@ ostream& Assembly::streamAsmJson(ostream& _out, string const& _prefix, StringMap switch (i.type()) { case Operation: - currentCollection.push_back(createJsonValue(instructionInfo(i.instruction()).name, i.getLocation().start, i.getLocation().end, i.getJumpTypeAsString())); + currentCollection.push_back( + createJsonValue(instructionInfo(i.instruction()).name, i.getLocation().start, i.getLocation().end, i.getJumpTypeAsString())); break; case Push: - currentCollection.push_back(createJsonValue(string("PUSH"), i.getLocation().start, i.getLocation().end, string(i.data()), i.getJumpTypeAsString())); + currentCollection.push_back( + createJsonValue(string("PUSH"), i.getLocation().start, i.getLocation().end, string(i.data()), i.getJumpTypeAsString())); break; case PushString: - currentCollection.push_back(createJsonValue(string("PUSH tag"), i.getLocation().start, i.getLocation().end, m_strings.at((h256)i.data()))); + currentCollection.push_back( + createJsonValue(string("PUSH tag"), i.getLocation().start, i.getLocation().end, m_strings.at((h256)i.data()))); break; case PushTag: - currentCollection.push_back(createJsonValue(string("PUSH [tag]"), i.getLocation().start, i.getLocation().end, string(i.data()))); + currentCollection.push_back( + createJsonValue(string("PUSH [tag]"), i.getLocation().start, i.getLocation().end, string(i.data()))); break; case PushSub: - currentCollection.push_back(createJsonValue(string("PUSH"), i.getLocation().start, i.getLocation().end, string("[$]" + string(h256(i.data()).abridged())))); + currentCollection.push_back( + createJsonValue(string("PUSH"), i.getLocation().start, i.getLocation().end, string("[$]" + string(h256(i.data()).abridged())))); break; case PushSubSize: - currentCollection.push_back(createJsonValue(string("PUSH"), i.getLocation().start, i.getLocation().end, string("#[$]" + string(h256(i.data()).abridged())))); + currentCollection.push_back( + createJsonValue(string("PUSH"), i.getLocation().start, i.getLocation().end, string("#[$]" + string(h256(i.data()).abridged())))); break; case PushProgramSize: - currentCollection.push_back(createJsonValue(string("PUSHSIZE"), i.getLocation().start, i.getLocation().end)); + currentCollection.push_back( + createJsonValue(string("PUSHSIZE"), i.getLocation().start, i.getLocation().end)); break; case Tag: { @@ -230,13 +246,11 @@ ostream& Assembly::streamAsmJson(ostream& _out, string const& _prefix, StringMap } } - //todo check if the last was tag Json::Value collection(Json::arrayValue); for (auto it: currentCollection) collection.append(it); root[currentArrayName] = collection; - Json::Value rootData; if (!m_data.empty() || !m_subs.empty()) { Json::Value dataCollection(Json::arrayValue); @@ -249,29 +263,32 @@ ostream& Assembly::streamAsmJson(ostream& _out, string const& _prefix, StringMap data["value"] = hexStr.str(); dataCollection.append(data); } - rootData[_prefix + ".data"] = collection; - _out << root << rootData; for (size_t i = 0; i < m_subs.size(); ++i) { std::stringstream hexStr; - hexStr << _prefix << hex << i << ": "; - //_out << _prefix << " " << hex << i << ": " << endl; - //todo check recursion check order. - m_subs[i].stream(_out, _prefix + " ", _sourceCodes, _inJsonFormat); + hexStr << _prefix << hex << i; + Json::Value num; + num["sub assembly"] = hexStr.str(); + dataCollection.append(num); + dataCollection.append(m_subs[i].stream(_out, _prefix + " ", _sourceCodes, _inJsonFormat)); } - } else + root[_prefix + ".data"] = dataCollection; _out << root; + } - return _out; + return move(root); } -ostream& Assembly::stream(ostream& _out, string const& _prefix, StringMap const& _sourceCodes, bool _inJsonFormat) const +Json::Value Assembly::stream(ostream& _out, string const& _prefix, StringMap const& _sourceCodes, bool _inJsonFormat) const { if (_inJsonFormat) return streamAsmJson(_out, _prefix, _sourceCodes, _inJsonFormat); else - return streamAsm(_out, _prefix, _sourceCodes); + { + streamAsm(_out, _prefix, _sourceCodes); + return Json::Value(); + } } AssemblyItem const& Assembly::append(AssemblyItem const& _i) diff --git a/libevmcore/Assembly.h b/libevmcore/Assembly.h index 49c45d37b..2de399b0a 100644 --- a/libevmcore/Assembly.h +++ b/libevmcore/Assembly.h @@ -29,6 +29,7 @@ #include #include #include "Exceptions.h" +#include namespace Json { @@ -80,7 +81,7 @@ public: void popTo(int _deposit) { while (m_deposit > _deposit) append(Instruction::POP); } void injectStart(AssemblyItem const& _i); - std::string out() const { std::stringstream ret; stream(ret); return ret.str(); } + std::string out() const; int deposit() const { return m_deposit; } void adjustDeposit(int _adjustment) { m_deposit += _adjustment; if (asserts(m_deposit >= 0)) BOOST_THROW_EXCEPTION(InvalidDeposit()); } void setDeposit(int _deposit) { m_deposit = _deposit; if (asserts(m_deposit >= 0)) BOOST_THROW_EXCEPTION(InvalidDeposit()); } @@ -90,7 +91,7 @@ public: bytes assemble() const; Assembly& optimise(bool _enable); - std::ostream& stream( + Json::Value stream( std::ostream& _out, std::string const& _prefix = "", const StringMap &_sourceCodes = StringMap(), @@ -102,7 +103,7 @@ protected: unsigned bytesRequired() const; private: - std::ostream& streamAsmJson( + Json::Value streamAsmJson( std::ostream& _out, const std::string &_prefix, const StringMap &_sourceCodes, @@ -132,5 +133,6 @@ inline std::ostream& operator<<(std::ostream& _out, Assembly const& _a) return _out; } + } } diff --git a/liblll/CMakeLists.txt b/liblll/CMakeLists.txt index e60522a7c..b865d4afe 100644 --- a/liblll/CMakeLists.txt +++ b/liblll/CMakeLists.txt @@ -11,6 +11,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB") aux_source_directory(. SRC_LIST) +include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS}) include_directories(BEFORE ..) include_directories(${Boost_INCLUDE_DIRS}) From 3482c4dfc2cf67ce0d9c7a5595b17c526f0ffb7f Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Wed, 15 Apr 2015 13:28:49 +0200 Subject: [PATCH 27/65] fixed extension of file json format changed value for PUSH to hex --- libevmcore/Assembly.cpp | 46 +++++++++++++++++------------------ libevmcore/Assembly.h | 3 --- solc/CommandLineInterface.cpp | 2 +- 3 files changed, 24 insertions(+), 27 deletions(-) diff --git a/libevmcore/Assembly.cpp b/libevmcore/Assembly.cpp index f794ffa3b..cb4af28c9 100644 --- a/libevmcore/Assembly.cpp +++ b/libevmcore/Assembly.cpp @@ -25,13 +25,10 @@ #include #include #include - using namespace std; using namespace dev; using namespace dev::eth; - - void Assembly::append(Assembly const& _a) { auto newDeposit = m_deposit + _a.deposit(); @@ -170,7 +167,6 @@ ostream& Assembly::streamAsm(ostream& _out, string const& _prefix, StringMap con Json::Value Assembly::createJsonValue(string _name, int _locationX, int _locationY, string _value, string _jumpType) const { Json::Value value; - assert(!_name.empty()); value["name"] = _name; value["locationX"] = _locationX; value["locationY"] = _locationY; @@ -196,8 +192,12 @@ Json::Value Assembly::streamAsmJson(ostream& _out, string const& _prefix, String createJsonValue(instructionInfo(i.instruction()).name, i.getLocation().start, i.getLocation().end, i.getJumpTypeAsString())); break; case Push: + { + std::stringstream hexStr; + hexStr << hex << (unsigned)i.data(); currentCollection.push_back( - createJsonValue(string("PUSH"), i.getLocation().start, i.getLocation().end, string(i.data()), i.getJumpTypeAsString())); + createJsonValue(string("PUSH"), i.getLocation().start, i.getLocation().end, hexStr.str(), i.getJumpTypeAsString())); + } break; case PushString: currentCollection.push_back( @@ -220,26 +220,26 @@ Json::Value Assembly::streamAsmJson(ostream& _out, string const& _prefix, String createJsonValue(string("PUSHSIZE"), i.getLocation().start, i.getLocation().end)); break; case Tag: - { - Json::Value collection(Json::arrayValue); - for (auto it: currentCollection) - collection.append(it); - currentCollection.clear(); - root[currentArrayName] = collection; - currentArrayName = "tag" + string(i.data()); - Json::Value jumpdest; - jumpdest["name"] = "JUMDEST"; - currentCollection.push_back(jumpdest); - } + { + Json::Value collection(Json::arrayValue); + for (auto it: currentCollection) + collection.append(it); + currentCollection.clear(); + root[currentArrayName] = collection; + currentArrayName = "tag" + string(i.data()); + Json::Value jumpdest; + jumpdest["name"] = "JUMDEST"; + currentCollection.push_back(jumpdest); + } break; case PushData: - { - Json::Value pushData; - pushData["name"] = "PUSH hex"; - std::stringstream hexStr; - hexStr << hex << (unsigned)i.data(); - currentCollection.push_back(createJsonValue(string("PUSH hex"), i.getLocation().start, i.getLocation().end, hexStr.str())); - } + { + Json::Value pushData; + pushData["name"] = "PUSH hex"; + std::stringstream hexStr; + hexStr << hex << (unsigned)i.data(); + currentCollection.push_back(createJsonValue(string("PUSH hex"), i.getLocation().start, i.getLocation().end, hexStr.str())); + } break; default: BOOST_THROW_EXCEPTION(InvalidOpcode()); diff --git a/libevmcore/Assembly.h b/libevmcore/Assembly.h index 2de399b0a..86169a93d 100644 --- a/libevmcore/Assembly.h +++ b/libevmcore/Assembly.h @@ -123,16 +123,13 @@ protected: int m_totalDeposit = 0; SourceLocation m_currentSourceLocation; - }; - inline std::ostream& operator<<(std::ostream& _out, Assembly const& _a) { _a.stream(_out); return _out; } - } } diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index cb924d9b5..182015709 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -430,7 +430,7 @@ void CommandLineInterface::actOnInput() if (outputToFile(choice)) { - ofstream outFile(contract + ".evm"); + ofstream outFile(contract + (m_args.count(g_argAsmJsonStr) ? "_evm.json" : ".evm")); m_compiler->streamAssembly(outFile, contract, m_sourceCodes, m_args.count(g_argAsmJsonStr)); outFile.close(); } From 95e161bfc99c2f83a8b9f522679c101de7fa8b98 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Wed, 15 Apr 2015 14:09:39 +0200 Subject: [PATCH 28/65] style fixes --- libevmcore/Assembly.cpp | 16 ++++++++-------- libevmcore/Assembly.h | 18 ++++++++++-------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/libevmcore/Assembly.cpp b/libevmcore/Assembly.cpp index cb4af28c9..a5ea0211e 100644 --- a/libevmcore/Assembly.cpp +++ b/libevmcore/Assembly.cpp @@ -189,35 +189,35 @@ Json::Value Assembly::streamAsmJson(ostream& _out, string const& _prefix, String { case Operation: currentCollection.push_back( - createJsonValue(instructionInfo(i.instruction()).name, i.getLocation().start, i.getLocation().end, i.getJumpTypeAsString())); + createJsonValue(instructionInfo(i.instruction()).name, i.getLocation().start, i.getLocation().end, i.getJumpTypeAsString())); break; case Push: { std::stringstream hexStr; - hexStr << hex << (unsigned)i.data(); + hexStr << hex << i.data(); currentCollection.push_back( - createJsonValue(string("PUSH"), i.getLocation().start, i.getLocation().end, hexStr.str(), i.getJumpTypeAsString())); + createJsonValue(string("PUSH"), i.getLocation().start, i.getLocation().end, hexStr.str(), i.getJumpTypeAsString())); } break; case PushString: currentCollection.push_back( - createJsonValue(string("PUSH tag"), i.getLocation().start, i.getLocation().end, m_strings.at((h256)i.data()))); + createJsonValue(string("PUSH tag"), i.getLocation().start, i.getLocation().end, m_strings.at((h256)i.data()))); break; case PushTag: currentCollection.push_back( - createJsonValue(string("PUSH [tag]"), i.getLocation().start, i.getLocation().end, string(i.data()))); + createJsonValue(string("PUSH [tag]"), i.getLocation().start, i.getLocation().end, string(i.data()))); break; case PushSub: currentCollection.push_back( - createJsonValue(string("PUSH"), i.getLocation().start, i.getLocation().end, string("[$]" + string(h256(i.data()).abridged())))); + createJsonValue(string("PUSH"), i.getLocation().start, i.getLocation().end, string("[$]" + dev::toString(h256(i.data()))))); break; case PushSubSize: currentCollection.push_back( - createJsonValue(string("PUSH"), i.getLocation().start, i.getLocation().end, string("#[$]" + string(h256(i.data()).abridged())))); + createJsonValue(string("PUSH"), i.getLocation().start, i.getLocation().end, string("#[$]" + dev::toString(h256(i.data()))))); break; case PushProgramSize: currentCollection.push_back( - createJsonValue(string("PUSHSIZE"), i.getLocation().start, i.getLocation().end)); + createJsonValue(string("PUSHSIZE"), i.getLocation().start, i.getLocation().end)); break; case Tag: { diff --git a/libevmcore/Assembly.h b/libevmcore/Assembly.h index 86169a93d..86fd222b3 100644 --- a/libevmcore/Assembly.h +++ b/libevmcore/Assembly.h @@ -92,10 +92,11 @@ public: bytes assemble() const; Assembly& optimise(bool _enable); Json::Value stream( - std::ostream& _out, - std::string const& _prefix = "", - const StringMap &_sourceCodes = StringMap(), - bool _inJsonFormat = false) const; + std::ostream& _out, + std::string const& _prefix = "", + const StringMap &_sourceCodes = StringMap(), + bool _inJsonFormat = false + ) const; protected: std::string getLocationFromSources(StringMap const& _sourceCodes, SourceLocation const& _location) const; @@ -104,10 +105,11 @@ protected: private: Json::Value streamAsmJson( - std::ostream& _out, - const std::string &_prefix, - const StringMap &_sourceCodes, - bool _inJsonFormat) const; + std::ostream& _out, + const std::string &_prefix, + const StringMap &_sourceCodes, + bool _inJsonFormat + ) const; std::ostream& streamAsm(std::ostream& _out, std::string const& _prefix, StringMap const& _sourceCodes) const; Json::Value createJsonValue(std::string _name, int _locationX, int _locationY, std::string _value = std::string(), std::string _jumpType = std::string()) const; From 20132bd44547ac5447dad42f149bede1ff0b4a9d Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Wed, 15 Apr 2015 14:29:18 +0200 Subject: [PATCH 29/65] renamed locationx/y to begin/end --- libevmcore/Assembly.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libevmcore/Assembly.cpp b/libevmcore/Assembly.cpp index a5ea0211e..fbb1b94f4 100644 --- a/libevmcore/Assembly.cpp +++ b/libevmcore/Assembly.cpp @@ -168,8 +168,8 @@ Json::Value Assembly::createJsonValue(string _name, int _locationX, int _locatio { Json::Value value; value["name"] = _name; - value["locationX"] = _locationX; - value["locationY"] = _locationY; + value["begin"] = _locationX; + value["end"] = _locationY; if (!_value.empty()) value["value"] = _value; if (!_jumpType.empty()) From 6d56c979ab2e8e5d7c4b449feb0fd6bc9cb50979 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Wed, 15 Apr 2015 15:00:20 +0200 Subject: [PATCH 30/65] removed explicit move --- libevmcore/Assembly.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libevmcore/Assembly.cpp b/libevmcore/Assembly.cpp index fbb1b94f4..7a82bcee5 100644 --- a/libevmcore/Assembly.cpp +++ b/libevmcore/Assembly.cpp @@ -174,7 +174,7 @@ Json::Value Assembly::createJsonValue(string _name, int _locationX, int _locatio value["value"] = _value; if (!_jumpType.empty()) value["jumpType"] = _jumpType; - return move(value); + return value; } Json::Value Assembly::streamAsmJson(ostream& _out, string const& _prefix, StringMap const& _sourceCodes, bool _inJsonFormat) const @@ -277,7 +277,7 @@ Json::Value Assembly::streamAsmJson(ostream& _out, string const& _prefix, String _out << root; } - return move(root); + return root; } Json::Value Assembly::stream(ostream& _out, string const& _prefix, StringMap const& _sourceCodes, bool _inJsonFormat) const From a89b7ee9119e252baf1e9e129b5d22870f9af80b Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Wed, 15 Apr 2015 15:54:11 +0200 Subject: [PATCH 31/65] fixed push #[$] and push [$] --- libevmcore/Assembly.cpp | 20 ++++++++++++-------- libevmcore/Assembly.h | 2 +- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/libevmcore/Assembly.cpp b/libevmcore/Assembly.cpp index 7a82bcee5..b4081776d 100644 --- a/libevmcore/Assembly.cpp +++ b/libevmcore/Assembly.cpp @@ -164,12 +164,12 @@ ostream& Assembly::streamAsm(ostream& _out, string const& _prefix, StringMap con return _out; } -Json::Value Assembly::createJsonValue(string _name, int _locationX, int _locationY, string _value, string _jumpType) const +Json::Value Assembly::createJsonValue(string _name, int _begin, int _end, string _value, string _jumpType) const { Json::Value value; value["name"] = _name; - value["begin"] = _locationX; - value["end"] = _locationY; + value["begin"] = _begin; + value["end"] = _end; if (!_value.empty()) value["value"] = _value; if (!_jumpType.empty()) @@ -204,16 +204,20 @@ Json::Value Assembly::streamAsmJson(ostream& _out, string const& _prefix, String createJsonValue(string("PUSH tag"), i.getLocation().start, i.getLocation().end, m_strings.at((h256)i.data()))); break; case PushTag: + { + std::stringstream hexStr; + hexStr << hex << i.data(); currentCollection.push_back( - createJsonValue(string("PUSH [tag]"), i.getLocation().start, i.getLocation().end, string(i.data()))); + createJsonValue(string("PUSH [tag]"), i.getLocation().start, i.getLocation().end, hexStr.str())); + } break; case PushSub: currentCollection.push_back( - createJsonValue(string("PUSH"), i.getLocation().start, i.getLocation().end, string("[$]" + dev::toString(h256(i.data()))))); + createJsonValue(string("PUSH [$]"), i.getLocation().start, i.getLocation().end, dev::toString(h256(i.data())))); break; case PushSubSize: currentCollection.push_back( - createJsonValue(string("PUSH"), i.getLocation().start, i.getLocation().end, string("#[$]" + dev::toString(h256(i.data()))))); + createJsonValue(string("PUSH #[$]"), i.getLocation().start, i.getLocation().end, dev::toString(h256(i.data())))); break; case PushProgramSize: currentCollection.push_back( @@ -237,7 +241,7 @@ Json::Value Assembly::streamAsmJson(ostream& _out, string const& _prefix, String Json::Value pushData; pushData["name"] = "PUSH hex"; std::stringstream hexStr; - hexStr << hex << (unsigned)i.data(); + hexStr << hex << i.data(); currentCollection.push_back(createJsonValue(string("PUSH hex"), i.getLocation().start, i.getLocation().end, hexStr.str())); } break; @@ -258,7 +262,7 @@ Json::Value Assembly::streamAsmJson(ostream& _out, string const& _prefix, String if (u256(i.first) >= m_subs.size()) { std::stringstream hexStr; - hexStr << _prefix << hex << (unsigned)(u256)i.first << ": " << toHex(i.second); + hexStr << _prefix << hex << (u256)i.first << ": " << toHex(i.second); Json::Value data; data["value"] = hexStr.str(); dataCollection.append(data); diff --git a/libevmcore/Assembly.h b/libevmcore/Assembly.h index 86fd222b3..d0eb43a20 100644 --- a/libevmcore/Assembly.h +++ b/libevmcore/Assembly.h @@ -111,7 +111,7 @@ private: bool _inJsonFormat ) const; std::ostream& streamAsm(std::ostream& _out, std::string const& _prefix, StringMap const& _sourceCodes) const; - Json::Value createJsonValue(std::string _name, int _locationX, int _locationY, std::string _value = std::string(), std::string _jumpType = std::string()) const; + Json::Value createJsonValue(std::string _name, int _begin, int _end, std::string _value = std::string(), std::string _jumpType = std::string()) const; protected: unsigned m_usedTags = 0; From ebd4be49f6d38ad8544f47edf5aa5ac029dc718a Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Thu, 16 Apr 2015 12:54:58 +0200 Subject: [PATCH 32/65] changed the format of json output --- libevmcore/Assembly.cpp | 56 ++++++++++++++--------------------------- 1 file changed, 19 insertions(+), 37 deletions(-) diff --git a/libevmcore/Assembly.cpp b/libevmcore/Assembly.cpp index b4081776d..1f8307f81 100644 --- a/libevmcore/Assembly.cpp +++ b/libevmcore/Assembly.cpp @@ -177,6 +177,13 @@ Json::Value Assembly::createJsonValue(string _name, int _begin, int _end, string return value; } +string toStringInHex(u256 _value) +{ + std::stringstream hexStr; + hexStr << hex << _value; + return hexStr.str(); +} + Json::Value Assembly::streamAsmJson(ostream& _out, string const& _prefix, StringMap const& _sourceCodes, bool _inJsonFormat) const { Json::Value root; @@ -192,24 +199,16 @@ Json::Value Assembly::streamAsmJson(ostream& _out, string const& _prefix, String createJsonValue(instructionInfo(i.instruction()).name, i.getLocation().start, i.getLocation().end, i.getJumpTypeAsString())); break; case Push: - { - std::stringstream hexStr; - hexStr << hex << i.data(); currentCollection.push_back( - createJsonValue(string("PUSH"), i.getLocation().start, i.getLocation().end, hexStr.str(), i.getJumpTypeAsString())); - } + createJsonValue(string("PUSH"), i.getLocation().start, i.getLocation().end, toStringInHex(i.data()), i.getJumpTypeAsString())); break; case PushString: currentCollection.push_back( createJsonValue(string("PUSH tag"), i.getLocation().start, i.getLocation().end, m_strings.at((h256)i.data()))); break; case PushTag: - { - std::stringstream hexStr; - hexStr << hex << i.data(); currentCollection.push_back( - createJsonValue(string("PUSH [tag]"), i.getLocation().start, i.getLocation().end, hexStr.str())); - } + createJsonValue(string("PUSH [tag]"), i.getLocation().start, i.getLocation().end, toStringInHex(i.data()))); break; case PushSub: currentCollection.push_back( @@ -225,24 +224,17 @@ Json::Value Assembly::streamAsmJson(ostream& _out, string const& _prefix, String break; case Tag: { - Json::Value collection(Json::arrayValue); - for (auto it: currentCollection) - collection.append(it); - currentCollection.clear(); - root[currentArrayName] = collection; - currentArrayName = "tag" + string(i.data()); - Json::Value jumpdest; - jumpdest["name"] = "JUMDEST"; - currentCollection.push_back(jumpdest); + currentCollection.push_back( + createJsonValue(string("tag"), i.getLocation().start, i.getLocation().end, string(i.data()))); + currentCollection.push_back( + createJsonValue(string("JUMDEST"), -1, -1)); } break; case PushData: { Json::Value pushData; pushData["name"] = "PUSH hex"; - std::stringstream hexStr; - hexStr << hex << i.data(); - currentCollection.push_back(createJsonValue(string("PUSH hex"), i.getLocation().start, i.getLocation().end, hexStr.str())); + currentCollection.push_back(createJsonValue(string("PUSH hex"), i.getLocation().start, i.getLocation().end, toStringInHex(i.data()))); } break; default: @@ -257,30 +249,20 @@ Json::Value Assembly::streamAsmJson(ostream& _out, string const& _prefix, String if (!m_data.empty() || !m_subs.empty()) { - Json::Value dataCollection(Json::arrayValue); + Json::Value data; for (auto const& i: m_data) if (u256(i.first) >= m_subs.size()) - { - std::stringstream hexStr; - hexStr << _prefix << hex << (u256)i.first << ": " << toHex(i.second); - Json::Value data; - data["value"] = hexStr.str(); - dataCollection.append(data); - } + data[toStringInHex((u256)i.first)] = toHex(i.second); for (size_t i = 0; i < m_subs.size(); ++i) { std::stringstream hexStr; - hexStr << _prefix << hex << i; - Json::Value num; - num["sub assembly"] = hexStr.str(); - dataCollection.append(num); - dataCollection.append(m_subs[i].stream(_out, _prefix + " ", _sourceCodes, _inJsonFormat)); + hexStr << hex << i; + data[hexStr.str()] = m_subs[i].stream(_out, _prefix + " ", _sourceCodes, _inJsonFormat); } - root[_prefix + ".data"] = dataCollection; + root[".data"] = data; _out << root; } - return root; } From 78bb6deadbf04557158ec4275f7b568deab43207 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Fri, 17 Apr 2015 15:45:30 +0200 Subject: [PATCH 33/65] style fixes --- libevmcore/Assembly.cpp | 50 +++++++++++++++++++---------------------- libevmcore/Assembly.h | 4 +--- 2 files changed, 24 insertions(+), 30 deletions(-) diff --git a/libevmcore/Assembly.cpp b/libevmcore/Assembly.cpp index 1f8307f81..d21167e6b 100644 --- a/libevmcore/Assembly.cpp +++ b/libevmcore/Assembly.cpp @@ -184,57 +184,56 @@ string toStringInHex(u256 _value) return hexStr.str(); } -Json::Value Assembly::streamAsmJson(ostream& _out, string const& _prefix, StringMap const& _sourceCodes, bool _inJsonFormat) const +Json::Value Assembly::streamAsmJson(ostream& _out, StringMap const& _sourceCodes, bool _inJsonFormat) const { Json::Value root; - string currentArrayName = ".code"; - std::vector currentCollection; + Json::Value collection(Json::arrayValue); for (AssemblyItem const& i: m_items) { switch (i.type()) { case Operation: - currentCollection.push_back( + collection.append( createJsonValue(instructionInfo(i.instruction()).name, i.getLocation().start, i.getLocation().end, i.getJumpTypeAsString())); break; case Push: - currentCollection.push_back( - createJsonValue(string("PUSH"), i.getLocation().start, i.getLocation().end, toStringInHex(i.data()), i.getJumpTypeAsString())); + collection.append( + createJsonValue("PUSH", i.getLocation().start, i.getLocation().end, toStringInHex(i.data()), i.getJumpTypeAsString())); break; case PushString: - currentCollection.push_back( - createJsonValue(string("PUSH tag"), i.getLocation().start, i.getLocation().end, m_strings.at((h256)i.data()))); + collection.append( + createJsonValue("PUSH tag", i.getLocation().start, i.getLocation().end, m_strings.at((h256)i.data()))); break; case PushTag: - currentCollection.push_back( - createJsonValue(string("PUSH [tag]"), i.getLocation().start, i.getLocation().end, toStringInHex(i.data()))); + collection.append( + createJsonValue("PUSH [tag]", i.getLocation().start, i.getLocation().end, toStringInHex(i.data()))); break; case PushSub: - currentCollection.push_back( - createJsonValue(string("PUSH [$]"), i.getLocation().start, i.getLocation().end, dev::toString(h256(i.data())))); + collection.append( + createJsonValue("PUSH [$]", i.getLocation().start, i.getLocation().end, dev::toString(h256(i.data())))); break; case PushSubSize: - currentCollection.push_back( - createJsonValue(string("PUSH #[$]"), i.getLocation().start, i.getLocation().end, dev::toString(h256(i.data())))); + collection.append( + createJsonValue("PUSH #[$]", i.getLocation().start, i.getLocation().end, dev::toString(h256(i.data())))); break; case PushProgramSize: - currentCollection.push_back( - createJsonValue(string("PUSHSIZE"), i.getLocation().start, i.getLocation().end)); + collection.append( + createJsonValue("PUSHSIZE", i.getLocation().start, i.getLocation().end)); break; case Tag: { - currentCollection.push_back( - createJsonValue(string("tag"), i.getLocation().start, i.getLocation().end, string(i.data()))); - currentCollection.push_back( - createJsonValue(string("JUMDEST"), -1, -1)); + collection.append( + createJsonValue("tag", i.getLocation().start, i.getLocation().end, string(i.data()))); + collection.append( + createJsonValue("JUMDEST", i.getLocation().start, i.getLocation().end)); } break; case PushData: { Json::Value pushData; pushData["name"] = "PUSH hex"; - currentCollection.push_back(createJsonValue(string("PUSH hex"), i.getLocation().start, i.getLocation().end, toStringInHex(i.data()))); + collection.append(createJsonValue("PUSH hex", i.getLocation().start, i.getLocation().end, toStringInHex(i.data()))); } break; default: @@ -242,10 +241,7 @@ Json::Value Assembly::streamAsmJson(ostream& _out, string const& _prefix, String } } - Json::Value collection(Json::arrayValue); - for (auto it: currentCollection) - collection.append(it); - root[currentArrayName] = collection; + root[".code"] = collection; if (!m_data.empty() || !m_subs.empty()) { @@ -258,7 +254,7 @@ Json::Value Assembly::streamAsmJson(ostream& _out, string const& _prefix, String { std::stringstream hexStr; hexStr << hex << i; - data[hexStr.str()] = m_subs[i].stream(_out, _prefix + " ", _sourceCodes, _inJsonFormat); + data[hexStr.str()] = m_subs[i].stream(_out, "", _sourceCodes, _inJsonFormat); } root[".data"] = data; _out << root; @@ -269,7 +265,7 @@ Json::Value Assembly::streamAsmJson(ostream& _out, string const& _prefix, String Json::Value Assembly::stream(ostream& _out, string const& _prefix, StringMap const& _sourceCodes, bool _inJsonFormat) const { if (_inJsonFormat) - return streamAsmJson(_out, _prefix, _sourceCodes, _inJsonFormat); + return streamAsmJson(_out, _sourceCodes, _inJsonFormat); else { streamAsm(_out, _prefix, _sourceCodes); diff --git a/libevmcore/Assembly.h b/libevmcore/Assembly.h index d0eb43a20..60df34215 100644 --- a/libevmcore/Assembly.h +++ b/libevmcore/Assembly.h @@ -104,9 +104,7 @@ protected: unsigned bytesRequired() const; private: - Json::Value streamAsmJson( - std::ostream& _out, - const std::string &_prefix, + Json::Value streamAsmJson(std::ostream& _out, const StringMap &_sourceCodes, bool _inJsonFormat ) const; From 254c845490ecbfbf5799bb408d32cf2ea2e09643 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Fri, 17 Apr 2015 16:40:40 +0200 Subject: [PATCH 34/65] removed unused parameter from streamAsmJson --- libevmcore/Assembly.cpp | 6 +++--- libevmcore/Assembly.h | 5 +---- libsolidity/CompilerStack.cpp | 2 +- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/libevmcore/Assembly.cpp b/libevmcore/Assembly.cpp index d21167e6b..ae8567e2a 100644 --- a/libevmcore/Assembly.cpp +++ b/libevmcore/Assembly.cpp @@ -184,7 +184,7 @@ string toStringInHex(u256 _value) return hexStr.str(); } -Json::Value Assembly::streamAsmJson(ostream& _out, StringMap const& _sourceCodes, bool _inJsonFormat) const +Json::Value Assembly::streamAsmJson(ostream& _out, StringMap const& _sourceCodes) const { Json::Value root; @@ -254,7 +254,7 @@ Json::Value Assembly::streamAsmJson(ostream& _out, StringMap const& _sourceCodes { std::stringstream hexStr; hexStr << hex << i; - data[hexStr.str()] = m_subs[i].stream(_out, "", _sourceCodes, _inJsonFormat); + data[hexStr.str()] = m_subs[i].stream(_out, "", _sourceCodes, true); } root[".data"] = data; _out << root; @@ -265,7 +265,7 @@ Json::Value Assembly::streamAsmJson(ostream& _out, StringMap const& _sourceCodes Json::Value Assembly::stream(ostream& _out, string const& _prefix, StringMap const& _sourceCodes, bool _inJsonFormat) const { if (_inJsonFormat) - return streamAsmJson(_out, _sourceCodes, _inJsonFormat); + return streamAsmJson(_out, _sourceCodes); else { streamAsm(_out, _prefix, _sourceCodes); diff --git a/libevmcore/Assembly.h b/libevmcore/Assembly.h index 60df34215..4ac873682 100644 --- a/libevmcore/Assembly.h +++ b/libevmcore/Assembly.h @@ -104,10 +104,7 @@ protected: unsigned bytesRequired() const; private: - Json::Value streamAsmJson(std::ostream& _out, - const StringMap &_sourceCodes, - bool _inJsonFormat - ) const; + Json::Value streamAsmJson(std::ostream& _out, const StringMap &_sourceCodes) const; std::ostream& streamAsm(std::ostream& _out, std::string const& _prefix, StringMap const& _sourceCodes) const; Json::Value createJsonValue(std::string _name, int _begin, int _end, std::string _value = std::string(), std::string _jumpType = std::string()) const; diff --git a/libsolidity/CompilerStack.cpp b/libsolidity/CompilerStack.cpp index 592f61276..d6274e2c7 100644 --- a/libsolidity/CompilerStack.cpp +++ b/libsolidity/CompilerStack.cpp @@ -188,7 +188,7 @@ void CompilerStack::streamAssembly(ostream& _outStream, string const& _contractN { Contract const& contract = getContract(_contractName); if (contract.compiler) - contract(_contractName).compiler->streamAssembly(_outStream, _sourceCodes, _inJsonFormat); + contract.compiler->streamAssembly(_outStream, _sourceCodes, _inJsonFormat); else _outStream << "Contract not fully implemented" << endl; } From 36889fe0570d7312bad9f3e6b12e3bc25f19afdc Mon Sep 17 00:00:00 2001 From: chriseth Date: Fri, 17 Apr 2015 17:59:05 +0200 Subject: [PATCH 35/65] Add jsoncpp dependency for solidity-js. --- solc/docker_emscripten/Dockerfile | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/solc/docker_emscripten/Dockerfile b/solc/docker_emscripten/Dockerfile index 06467a2c5..1ad1875d7 100644 --- a/solc/docker_emscripten/Dockerfile +++ b/solc/docker_emscripten/Dockerfile @@ -43,7 +43,14 @@ RUN sed -i 's/$(archiver\[1\])/\/home\/user\/emsdk_portable\/emscripten\/master\ RUN sed -i 's/$(ranlib\[1\])/\/home\/user\/emsdk_portable\/emscripten\/master\/emranlib/g' ./tools/build/src/tools/gcc.jam RUN ./b2 link=static variant=release threading=single runtime-link=static thread system regex -# Build soljs +# Json-CPP +WORKDIR /home/user +RUN git clone https://github.com/open-source-parsers/jsoncpp.git +WORKDIR /home/user/jsoncpp +RUN emcmake cmake -DJSONCPP_LIB_BUILD_STATIC=ON -DJSONCPP_LIB_BUILD_SHARED=OFF -DJSONCPP_WITH_TESTS=OFF -DJSONCPP_WITH_POST_BUILD_UNITTEST=OFF -G "Unix Makefiles" . +RUN emmake make + +## Build soljs WORKDIR /home/user ADD https://api.github.com/repos/ethereum/cpp-ethereum/git/refs/heads/develop unused.txt RUN git clone --depth=1 https://github.com/ethereum/cpp-ethereum @@ -55,8 +62,10 @@ RUN git remote add -f solidityjs https://github.com/chriseth/cpp-ethereum # TODO this should be a proper merge but somehow causes problems # NOTE that we only get the latest commit of that branch RUN git cherry-pick solidityjs/solidity-js -RUN emcmake cmake -DETH_STATIC=1 -DONLY_SOLIDITY=1 -DHEADLESS=1 -DCMAKE_CXX_COMPILER=/home/user/emsdk_portable/emscripten/master/em++ -DCMAKE_C_COMPILER=/home/user/emsdk_portable/emscripten/master/emcc +RUN emcmake cmake -DETH_STATIC=1 -DSOLIDITY=ON -DGUI=0 -DCMAKE_CXX_COMPILER=/home/user/emsdk_portable/emscripten/master/em++ -DCMAKE_C_COMPILER=/home/user/emsdk_portable/emscripten/master/emcc RUN emmake make -j 6 soljs -ENTRYPOINT cat soljs/soljs.js +WORKDIR /home/user/cpp-ethereum/soljs +# somehow it does not work to pipe out both files +#ENTRYPOINT tar -c soljs.js soljs.js.mem | base64 From 923620241cc26afb295248d00eb9424d75e36ede Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Fri, 17 Apr 2015 18:41:27 +0200 Subject: [PATCH 36/65] 0x -> 0x0 for numbers --- test/TestHelper.cpp | 8 ++++---- test/blockchain.cpp | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index 92a8258ac..49c6bb023 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -123,7 +123,7 @@ json_spirit::mObject& ImportTest::makeAllFieldsHex(json_spirit::mObject& _o) { static const set hashes {"bloom" , "coinbase", "hash", "mixHash", "parentHash", "receiptTrie", "stateRoot", "transactionsTrie", "uncleHash", "currentCoinbase", - "previousHash", "to", "address", "caller", "origin", "secretKey"}; + "previousHash", "to", "address", "caller", "origin", "secretKey", "data"}; for (auto& i: _o) { @@ -140,7 +140,7 @@ json_spirit::mObject& ImportTest::makeAllFieldsHex(json_spirit::mObject& _o) str = value.get_str(); else continue; - _o[key] = (str.substr(0, 2) == "0x") ? str : "0x" + toHex(toCompactBigEndian(toInt(str))); + _o[key] = (str.substr(0, 2) == "0x") ? str : "0x" + (toHex(toCompactBigEndian(toInt(str))).empty() ? "0" : toHex(toCompactBigEndian(toInt(str)))); } return _o; } @@ -363,8 +363,8 @@ json_spirit::mObject fillJsonWithState(State _state) for (auto const& a: _state.addresses()) { json_spirit::mObject o; - o["balance"] = "0x" + toHex(toCompactBigEndian(_state.balance(a.first))); - o["nonce"] = "0x" + toHex(toCompactBigEndian(_state.transactionsFrom(a.first))); + o["balance"] = "0x" + (toHex(toCompactBigEndian(_state.balance(a.first))).empty() ? "0" : toHex(toCompactBigEndian(_state.balance(a.first)))); + o["nonce"] = "0x" + (toHex(toCompactBigEndian(_state.transactionsFrom(a.first))).empty() ? "0" : toHex(toCompactBigEndian(_state.transactionsFrom(a.first)))); { json_spirit::mObject store; for (auto const& s: _state.storage(a.first)) diff --git a/test/blockchain.cpp b/test/blockchain.cpp index b144abe62..502182074 100644 --- a/test/blockchain.cpp +++ b/test/blockchain.cpp @@ -625,11 +625,11 @@ void writeBlockHeaderToJson(mObject& _o, BlockInfo const& _bi) _o["transactionsTrie"] = toString(_bi.transactionsRoot); _o["receiptTrie"] = toString(_bi.receiptsRoot); _o["bloom"] = toString(_bi.logBloom); - _o["difficulty"] = "0x" + toHex(toCompactBigEndian(_bi.difficulty)); - _o["number"] = "0x" + toHex(toCompactBigEndian(_bi.number)); - _o["gasLimit"] = "0x" + toHex(toCompactBigEndian(_bi.gasLimit)); - _o["gasUsed"] = "0x" + toHex(toCompactBigEndian(_bi.gasUsed)); - _o["timestamp"] = "0x" + toHex(toCompactBigEndian(_bi.timestamp)); + _o["difficulty"] = "0x" + (toHex(toCompactBigEndian(_bi.difficulty)).empty() ? "0" : toHex(toCompactBigEndian(_bi.difficulty))); + _o["number"] = "0x" + (toHex(toCompactBigEndian(_bi.number)).empty() ? "0" : toHex(toCompactBigEndian(_bi.number))); + _o["gasLimit"] = "0x" + (toHex(toCompactBigEndian(_bi.gasLimit)).empty() ? "0" : toHex(toCompactBigEndian(_bi.gasLimit))); + _o["gasUsed"] = "0x" + (toHex(toCompactBigEndian(_bi.gasUsed)).empty() ? "0" : toHex(toCompactBigEndian(_bi.gasUsed))); + _o["timestamp"] = "0x" + (toHex(toCompactBigEndian(_bi.timestamp)).empty() ? "0" : toHex(toCompactBigEndian(_bi.timestamp))); _o["extraData"] ="0x" + toHex(_bi.extraData); _o["mixHash"] = toString(_bi.mixHash); _o["nonce"] = toString(_bi.nonce); From 5f5db7b2d24205472ab135d89671f92136e8368f Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Fri, 17 Apr 2015 22:44:26 +0200 Subject: [PATCH 37/65] simplification --- test/TestHelper.cpp | 6 +++--- test/blockchain.cpp | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index 49c6bb023..ed844e961 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -140,7 +140,7 @@ json_spirit::mObject& ImportTest::makeAllFieldsHex(json_spirit::mObject& _o) str = value.get_str(); else continue; - _o[key] = (str.substr(0, 2) == "0x") ? str : "0x" + (toHex(toCompactBigEndian(toInt(str))).empty() ? "0" : toHex(toCompactBigEndian(toInt(str)))); + _o[key] = (str.substr(0, 2) == "0x") ? str : "0x" + toHex(toCompactBigEndian(toInt(str), 1)); } return _o; } @@ -363,8 +363,8 @@ json_spirit::mObject fillJsonWithState(State _state) for (auto const& a: _state.addresses()) { json_spirit::mObject o; - o["balance"] = "0x" + (toHex(toCompactBigEndian(_state.balance(a.first))).empty() ? "0" : toHex(toCompactBigEndian(_state.balance(a.first)))); - o["nonce"] = "0x" + (toHex(toCompactBigEndian(_state.transactionsFrom(a.first))).empty() ? "0" : toHex(toCompactBigEndian(_state.transactionsFrom(a.first)))); + o["balance"] = "0x" + toHex(toCompactBigEndian(_state.balance(a.first), 1)); + o["nonce"] = "0x" + toHex(toCompactBigEndian(_state.transactionsFrom(a.first), 1)); { json_spirit::mObject store; for (auto const& s: _state.storage(a.first)) diff --git a/test/blockchain.cpp b/test/blockchain.cpp index 502182074..ec8fb7539 100644 --- a/test/blockchain.cpp +++ b/test/blockchain.cpp @@ -625,11 +625,11 @@ void writeBlockHeaderToJson(mObject& _o, BlockInfo const& _bi) _o["transactionsTrie"] = toString(_bi.transactionsRoot); _o["receiptTrie"] = toString(_bi.receiptsRoot); _o["bloom"] = toString(_bi.logBloom); - _o["difficulty"] = "0x" + (toHex(toCompactBigEndian(_bi.difficulty)).empty() ? "0" : toHex(toCompactBigEndian(_bi.difficulty))); - _o["number"] = "0x" + (toHex(toCompactBigEndian(_bi.number)).empty() ? "0" : toHex(toCompactBigEndian(_bi.number))); - _o["gasLimit"] = "0x" + (toHex(toCompactBigEndian(_bi.gasLimit)).empty() ? "0" : toHex(toCompactBigEndian(_bi.gasLimit))); - _o["gasUsed"] = "0x" + (toHex(toCompactBigEndian(_bi.gasUsed)).empty() ? "0" : toHex(toCompactBigEndian(_bi.gasUsed))); - _o["timestamp"] = "0x" + (toHex(toCompactBigEndian(_bi.timestamp)).empty() ? "0" : toHex(toCompactBigEndian(_bi.timestamp))); + _o["difficulty"] = "0x" + toHex(toCompactBigEndian(_bi.difficulty), 1); + _o["number"] = "0x" + toHex(toCompactBigEndian(_bi.number), 1); + _o["gasLimit"] = "0x" + toHex(toCompactBigEndian(_bi.gasLimit), 1); + _o["gasUsed"] = "0x" + toHex(toCompactBigEndian(_bi.gasUsed), 1); + _o["timestamp"] = "0x" + toHex(toCompactBigEndian(_bi.timestamp), 1); _o["extraData"] ="0x" + toHex(_bi.extraData); _o["mixHash"] = toString(_bi.mixHash); _o["nonce"] = toString(_bi.nonce); From a5f2dc881ef4348694ad77ba949dc57cd7249c91 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 18 Apr 2015 19:06:27 +0200 Subject: [PATCH 38/65] New strategy - send all new blocks out, even when (re)syncing (though only when resyncing < 20 blocks). Make a note of bad transactions to avoid re-importing when bad nodes pass them to us. --- cmake/scripts/jsonrpcstub.cmake | 1 - libdevcore/Common.cpp | 2 +- libethereum/Client.cpp | 19 ++++++++++++------- libethereum/Client.h | 1 + libethereum/EthereumHost.cpp | 28 +++++++++++++++++++--------- libethereum/EthereumPeer.cpp | 2 +- libethereum/TransactionQueue.cpp | 8 ++++++-- libethereum/TransactionQueue.h | 12 +++++++----- libp2p/NodeTable.cpp | 10 +++++----- 9 files changed, 52 insertions(+), 31 deletions(-) diff --git a/cmake/scripts/jsonrpcstub.cmake b/cmake/scripts/jsonrpcstub.cmake index 39f850e53..64ca7864c 100644 --- a/cmake/scripts/jsonrpcstub.cmake +++ b/cmake/scripts/jsonrpcstub.cmake @@ -42,4 +42,3 @@ else() replace_if_different("${SERVER_TMPFILE}" "${SERVER_OUTFILE}") replace_if_different("${CLIENT_TMPFILE}" "${CLIENT_OUTFILE}") endif() - diff --git a/libdevcore/Common.cpp b/libdevcore/Common.cpp index 649e79310..230c9e4ff 100644 --- a/libdevcore/Common.cpp +++ b/libdevcore/Common.cpp @@ -27,7 +27,7 @@ using namespace dev; namespace dev { -char const* Version = "0.9.10"; +char const* Version = "0.9.11"; } diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 1684ef54d..6959aaa81 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -395,6 +395,9 @@ ExecutionResult Client::call(Address _dest, bytes const& _data, u256 _gas, u256 ProofOfWork::WorkPackage Client::getWork() { + // lock the work so a later submission isn't invalidated by processing a transaction elsewhere. + // this will be reset as soon as a new block arrives, allowing more transactions to be processed. + m_remoteWorking = true; return ProofOfWork::package(m_miningInfo); } @@ -448,7 +451,7 @@ void Client::syncTransactionQueue() appendFromNewPending(newPendingReceipts[i], changeds, m_postMine.pending()[i].sha3()); changeds.insert(PendingChangedFilter); - // TODO: Tell farm about new transaction (i.e. restartProofOfWork mining). + // Tell farm about new transaction (i.e. restartProofOfWork mining). onPostStateChanged(); // Tell watches about the new transactions. @@ -468,7 +471,7 @@ void Client::onChainChanged(ImportRoute const& _ir) for (auto const& t: m_bc.transactions(h)) { clog(ClientNote) << "Resubmitting transaction " << Transaction(t, CheckTransaction::None); - m_tq.import(t); + m_tq.import(t, TransactionQueue::ImportCallback(), IfDropped::Retry); } } @@ -525,6 +528,7 @@ void Client::onPostStateChanged() } m_farm.setWork(m_miningInfo); } + m_remoteWorking = false; } void Client::startMining() @@ -561,16 +565,17 @@ void Client::doWork() // TODO: Use condition variable rather than this rubbish. bool t = true; - if (m_syncTransactionQueue.compare_exchange_strong(t, false)) - syncTransactionQueue(); - - t = true; if (m_syncBlockQueue.compare_exchange_strong(t, false)) syncBlockQueue(); + t = true; + if (m_syncTransactionQueue.compare_exchange_strong(t, false) && !m_remoteWorking) + syncTransactionQueue(); + tick(); - this_thread::sleep_for(chrono::milliseconds(20)); + if (!m_syncBlockQueue && !m_syncTransactionQueue) + this_thread::sleep_for(chrono::milliseconds(20)); } void Client::tick() diff --git a/libethereum/Client.h b/libethereum/Client.h index aa2dd61b8..5bab1a76e 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -277,6 +277,7 @@ private: mutable SharedMutex x_postMine; ///< Lock on the OverlayDB and other attributes of m_postMine. State m_postMine; ///< The state of the client which we're mining (i.e. it'll have all the rewards added). BlockInfo m_miningInfo; ///< The header we're attempting to mine on (derived from m_postMine). + bool m_remoteWorking = false; ///< Is there an acive and valid remote worker? std::weak_ptr m_host; ///< Our Ethereum Host. Don't do anything if we can't lock. diff --git a/libethereum/EthereumHost.cpp b/libethereum/EthereumHost.cpp index 6ef293d5a..792eb3026 100644 --- a/libethereum/EthereumHost.cpp +++ b/libethereum/EthereumHost.cpp @@ -242,18 +242,28 @@ std::vector> EthereumHost::randomSelection(unsigne void EthereumHost::maintainBlocks(h256 _currentHash) { // Send any new blocks. - if (m_chain.details(m_latestBlockSent).totalDifficulty < m_chain.details(_currentHash).totalDifficulty) + auto detailsFrom = m_chain.details(m_latestBlockSent); + auto detailsTo = m_chain.details(_currentHash); + if (detailsFrom.totalDifficulty < detailsTo.totalDifficulty) { - clog(NetMessageSummary) << "Sending a new block (current is" << _currentHash << ", was" << m_latestBlockSent << ")"; - - for (auto const& p: randomSelection(25, [&](EthereumPeer* p){return !p->m_knownBlocks.count(_currentHash); })) + if (diff(detailsFrom.number, detailsTo.number) < 20) { - RLPStream ts; - p->prep(ts, NewBlockPacket, 2).appendRaw(m_chain.block(), 1).append(m_chain.details().totalDifficulty); + // don't be sending more than 20 "new" blocks. if there are any more we were probably waaaay behind. + clog(NetMessageSummary) << "Sending a new block (current is" << _currentHash << ", was" << m_latestBlockSent << ")"; + + h256s blocks = get<0>(m_chain.treeRoute(m_latestBlockSent, _currentHash, false, false, true)); + + for (auto const& p: randomSelection(25, [&](EthereumPeer* p){return !p->m_knownBlocks.count(_currentHash); })) + for (auto const& b: blocks) + if (!p->m_knownBlocks.count(b)) + { + RLPStream ts; + p->prep(ts, NewBlockPacket, 2).appendRaw(m_chain.block(b), 1).append(m_chain.details(b).totalDifficulty); - Guard l(p->x_knownBlocks); - p->sealAndSend(ts); - p->m_knownBlocks.clear(); + Guard l(p->x_knownBlocks); + p->sealAndSend(ts); + p->m_knownBlocks.clear(); + } } m_latestBlockSent = _currentHash; } diff --git a/libethereum/EthereumPeer.cpp b/libethereum/EthereumPeer.cpp index 3da4402ac..e859f0e54 100644 --- a/libethereum/EthereumPeer.cpp +++ b/libethereum/EthereumPeer.cpp @@ -142,7 +142,7 @@ void EthereumPeer::transition(Asking _a, bool _force) clog(NetNote) << "Difficulty of hashchain HIGHER. Grabbing" << m_syncingNeededBlocks.size() << "blocks [latest now" << m_syncingLatestHash.abridged() << ", was" << host()->m_latestBlockSent.abridged() << "]"; host()->m_man.resetToChain(m_syncingNeededBlocks); - host()->m_latestBlockSent = m_syncingLatestHash; +// host()->m_latestBlockSent = m_syncingLatestHash; } else { diff --git a/libethereum/TransactionQueue.cpp b/libethereum/TransactionQueue.cpp index 506de2d2f..c23fd8db4 100644 --- a/libethereum/TransactionQueue.cpp +++ b/libethereum/TransactionQueue.cpp @@ -28,7 +28,7 @@ using namespace std; using namespace dev; using namespace dev::eth; -ImportResult TransactionQueue::import(bytesConstRef _transactionRLP, ImportCallback const& _cb) +ImportResult TransactionQueue::import(bytesConstRef _transactionRLP, ImportCallback const& _cb, IfDropped _ik) { // Check if we already know this transaction. h256 h = sha3(_transactionRLP); @@ -39,6 +39,9 @@ ImportResult TransactionQueue::import(bytesConstRef _transactionRLP, ImportCallb if (m_known.count(h)) return ImportResult::AlreadyKnown; + if (m_dropped.count(h) && _ik == IfDropped::Ignore) + return ImportResult::AlreadyInChain; + try { // Check validity of _transactionRLP as a transaction. To do this we just deserialise and attempt to determine the sender. @@ -88,7 +91,7 @@ void TransactionQueue::noteGood(std::pair const& _t) m_unknown.erase(r.first, r.second); } -void TransactionQueue::drop(h256 _txHash) +void TransactionQueue::drop(h256 const& _txHash) { UpgradableGuard l(m_lock); @@ -96,6 +99,7 @@ void TransactionQueue::drop(h256 _txHash) return; UpgradeGuard ul(l); + m_dropped.insert(_txHash); m_known.erase(_txHash); if (m_current.count(_txHash)) diff --git a/libethereum/TransactionQueue.h b/libethereum/TransactionQueue.h index c3df00d25..e2d1c3aee 100644 --- a/libethereum/TransactionQueue.h +++ b/libethereum/TransactionQueue.h @@ -22,7 +22,6 @@ #pragma once #include -#include #include #include #include @@ -39,6 +38,8 @@ class BlockChain; struct TransactionQueueChannel: public LogChannel { static const char* name() { return "->Q"; } static const int verbosity = 4; }; #define ctxq dev::LogOutputStream() +enum class IfDropped { Ignore, Retry }; + /** * @brief A queue of Transactions, each stored as RLP. * @threadsafe @@ -48,10 +49,10 @@ class TransactionQueue public: using ImportCallback = std::function; - ImportResult import(bytes const& _tx, ImportCallback const& _cb = ImportCallback()) { return import(&_tx, _cb); } - ImportResult import(bytesConstRef _tx, ImportCallback const& _cb = ImportCallback()); + ImportResult import(bytes const& _tx, ImportCallback const& _cb = ImportCallback(), IfDropped _ik = IfDropped::Ignore) { return import(&_tx, _cb, _ik); } + ImportResult import(bytesConstRef _tx, ImportCallback const& _cb = ImportCallback(), IfDropped _ik = IfDropped::Ignore); - void drop(h256 _txHash); + void drop(h256 const& _txHash); std::map transactions() const { ReadGuard l(m_lock); return m_current; } std::pair items() const { ReadGuard l(m_lock); return std::make_pair(m_current.size(), m_unknown.size()); } @@ -63,11 +64,12 @@ public: template Handler onReady(T const& _t) { return m_onReady.add(_t); } private: - mutable boost::shared_mutex m_lock; ///< General lock. + mutable SharedMutex m_lock; ///< General lock. std::set m_known; ///< Hashes of transactions in both sets. std::map m_current; ///< Map of SHA3(tx) to tx. std::multimap> m_unknown; ///< For transactions that have a future nonce; we map their sender address to the tx stuff, and insert once the sender has a valid TX. std::map> m_callbacks; ///< Called once. + std::set m_dropped; ///< Transactions that have previously been dropped. Signal m_onReady; ///< Called when a subsequent call to import transactions will return a non-empty container. Be nice and exit fast. }; diff --git a/libp2p/NodeTable.cpp b/libp2p/NodeTable.cpp index 447a7f3c9..4d46af37e 100644 --- a/libp2p/NodeTable.cpp +++ b/libp2p/NodeTable.cpp @@ -384,7 +384,7 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes // h256 + Signature + type + RLP (smallest possible packet is empty neighbours packet which is 3 bytes) if (_packet.size() < h256::size + Signature::size + 1 + 3) { - clog(NodeTableWarn) << "Invalid Message size from " << _from.address().to_string() << ":" << _from.port(); + clog(NodeTableWarn) << "Invalid message size from " << _from.address().to_string() << ":" << _from.port(); return; } @@ -392,7 +392,7 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes h256 hashSigned(sha3(hashedBytes)); if (!_packet.cropped(0, h256::size).contentsEqual(hashSigned.asBytes())) { - clog(NodeTableWarn) << "Invalid Message hash from " << _from.address().to_string() << ":" << _from.port(); + clog(NodeTableWarn) << "Invalid message hash from " << _from.address().to_string() << ":" << _from.port(); return; } @@ -404,7 +404,7 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes Public nodeid(dev::recover(*(Signature const*)sigBytes.data(), sha3(signedBytes))); if (!nodeid) { - clog(NodeTableWarn) << "Invalid Message signature from " << _from.address().to_string() << ":" << _from.port(); + clog(NodeTableWarn) << "Invalid message signature from " << _from.address().to_string() << ":" << _from.port(); return; } @@ -471,7 +471,7 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes if (!expected) { - clog(NetConnect) << "Dropping unsolicited Neighbours packet from " << _from.address(); + clog(NetConnect) << "Dropping unsolicited neighbours packet from " << _from.address(); break; } @@ -518,7 +518,7 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes } default: - clog(NodeTableWarn) << "Invalid Message, " << hex << packetType << ", received from " << _from.address().to_string() << ":" << dec << _from.port(); + clog(NodeTableWarn) << "Invalid message, " << hex << packetType << ", received from " << _from.address().to_string() << ":" << dec << _from.port(); return; } From 86384ad0ad33205212e53b9cfd7de8fd3860758e Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 18 Apr 2015 19:19:48 +0200 Subject: [PATCH 39/65] Use default path if none given when rebuilding chain. --- eth/main.cpp | 4 ++-- libethereum/BlockChain.cpp | 14 ++++++++------ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/eth/main.cpp b/eth/main.cpp index 5de9290ae..394e26bc9 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -121,7 +121,7 @@ void help() << " --json-rpc-port Specify JSON-RPC server port (implies '-j', default: " << SensibleHttpPort << ")." << endl #endif << " -K,--kill First kill the blockchain." << endl - << " -R,--rebuild First rebuild the blockchain from the existing database." << endl + << " -R,--rebuild Rebuild the blockchain from the existing database." << endl << " -s,--secret Set the secret key for use with send command (default: auto)." << endl << " -S,--session-secret Set the secret key for use with send command, for this session only." << endl << "Client transacting:" << endl @@ -598,7 +598,7 @@ int main(int argc, char** argv) } else if (arg == "-K" || arg == "--kill-blockchain" || arg == "--kill") killChain = WithExisting::Kill; - else if (arg == "-B" || arg == "--rebuild") + else if (arg == "-R" || arg == "--rebuild") killChain = WithExisting::Verify; else if ((arg == "-c" || arg == "--client-name") && i + 1 < argc) { diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 01cd876ab..a76435ada 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -185,6 +185,8 @@ void BlockChain::close() void BlockChain::rebuild(std::string const& _path, std::function const& _progress) { + std::string path = _path.empty() ? Defaults::get()->m_dbPath : _path; + #if ETH_PROFILING_GPERF ProfilerStart("BlockChain_rebuild.log"); #endif @@ -195,16 +197,16 @@ void BlockChain::rebuild(std::string const& _path, std::function From 6aaee1f711081d70423697401e4fb7c9226528ab Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 18 Apr 2015 23:50:39 +0200 Subject: [PATCH 40/65] Avoid threading issues. --- libdevcore/Log.cpp | 78 +++++++++++++++++++++++++++++++++- libdevcore/Log.h | 22 ++++++---- libdevcore/Worker.cpp | 87 +++++++++++++++++++++++--------------- libdevcore/Worker.h | 28 ++++++++---- libethcore/Ethash.cpp | 5 ++- libethereum/Farm.h | 15 ++++--- libp2p/Session.cpp | 2 + libwhisper/WhisperHost.cpp | 2 +- 8 files changed, 179 insertions(+), 60 deletions(-) diff --git a/libdevcore/Log.cpp b/libdevcore/Log.cpp index 7196ea358..0edc3e039 100644 --- a/libdevcore/Log.cpp +++ b/libdevcore/Log.cpp @@ -23,6 +23,7 @@ #include #include +#include #include "Guards.h" using namespace std; using namespace dev; @@ -31,13 +32,87 @@ using namespace dev; int dev::g_logVerbosity = 5; map dev::g_logOverride; -ThreadLocalLogName dev::t_logThreadName("main"); +/// Associate a name with each thread for nice logging. +struct ThreadLocalLogName +{ + ThreadLocalLogName(std::string const& _name) { m_name.reset(new string(_name)); } + boost::thread_specific_ptr m_name; +}; + +/// Associate a name with each thread for nice logging. +struct ThreadLocalLogContext +{ + ThreadLocalLogContext() = default; + + void push(std::string const& _name) + { + if (!m_contexts.get()) + m_contexts.reset(new vector); + m_contexts->push_back(_name); + } + + void pop() + { + m_contexts->pop_back(); + } + + string join(string const& _prior) + { + string ret; + if (m_contexts.get()) + for (auto const& i: *m_contexts) + ret += _prior + i; + return ret; + } + + boost::thread_specific_ptr> m_contexts; +}; + +ThreadLocalLogContext g_logThreadContext; + +ThreadLocalLogName g_logThreadName("main"); + +void dev::ThreadContext::push(string const& _n) +{ + g_logThreadContext.push(_n); +} + +void dev::ThreadContext::pop() +{ + g_logThreadContext.pop(); +} + +string dev::ThreadContext::join(string const& _prior) +{ + return g_logThreadContext.join(_prior); +} // foward declare without all of Windows.h #ifdef _WIN32 extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA(const char* lpOutputString); #endif +string dev::getThreadName() +{ +#ifdef __linux__ + char buffer[128]; + pthread_getname_np(pthread_self(), buffer, 127); + buffer[127] = 0; + return buffer; +#else + return g_logThreadName.m_name.get() ? *g_logThreadName.m_name.get() : ""; +#endif +} + +void dev::setThreadName(string const& _n) +{ +#ifdef __linux__ + pthread_setname_np(pthread_self(), _n.c_str()); +#else + g_logThreadName.m_name.reset(new std::string(_n)); +#endif +} + void dev::simpleDebugOut(std::string const& _s, char const*) { static Mutex s_lock; @@ -55,4 +130,3 @@ void dev::simpleDebugOut(std::string const& _s, char const*) } std::function dev::g_logPost = simpleDebugOut; - diff --git a/libdevcore/Log.h b/libdevcore/Log.h index 2e111332c..812ec0886 100644 --- a/libdevcore/Log.h +++ b/libdevcore/Log.h @@ -53,18 +53,24 @@ extern std::function g_logPost; /// or equal to the currently output verbosity (g_logVerbosity). extern std::map g_logOverride; -/// Associate a name with each thread for nice logging. -struct ThreadLocalLogName +#define ETH_THREAD_CONTEXT(name) for (std::pair __eth_thread_context(name, true); p.second; p.second = false) + +class ThreadContext { - ThreadLocalLogName(std::string _name) { m_name.reset(new std::string(_name)); }; - boost::thread_specific_ptr m_name; +public: + ThreadContext(std::string const& _info) { push(_info); } + ~ThreadContext() { pop(); } + + static void push(std::string const& _n); + static void pop(); + static std::string join(std::string const& _prior); }; -/// The current thread's name. -extern ThreadLocalLogName t_logThreadName; +/// Set the current thread's log name. +void setThreadName(std::string const& _n); /// Set the current thread's log name. -inline void setThreadName(char const* _n) { t_logThreadName.m_name.reset(new std::string(_n)); } +std::string getThreadName(); /// The default logging channels. Each has an associated verbosity and three-letter prefix (name() ). /// Channels should inherit from LogChannel and define name() and verbosity. @@ -92,7 +98,7 @@ public: char buf[24]; if (strftime(buf, 24, "%X", localtime(&rawTime)) == 0) buf[0] = '\0'; // empty if case strftime fails - m_sstr << Id::name() << " [ " << buf << " | " << (t_logThreadName.m_name.get() ? *t_logThreadName.m_name.get() : std::string("")) << (_term ? " ] " : ""); + m_sstr << Id::name() << " [ " << buf << " | " << getThreadName() << ThreadContext::join(" | ") << (_term ? " ] " : ""); } } diff --git a/libdevcore/Worker.cpp b/libdevcore/Worker.cpp index 0f30a0aff..19c0d9751 100644 --- a/libdevcore/Worker.cpp +++ b/libdevcore/Worker.cpp @@ -27,54 +27,75 @@ using namespace std; using namespace dev; -void Worker::startWorking(IfRunning _ir) +void Worker::startWorking() { // cnote << "startWorking for thread" << m_name; Guard l(x_work); - - if (m_work && m_work->joinable()) - try { - if (_ir == IfRunning::Detach) - m_work->detach(); - else if (_ir == IfRunning::Join) - m_work->join(); - else - return; - } catch (...) {} - cnote << "Spawning" << m_name; - m_stop = false; - m_stopped = false; - m_work.reset(new thread([&]() + m_state = WorkerState::Starting; + if (!m_work) { - setThreadName(m_name.c_str()); - startedWorking(); - workLoop(); - cnote << "Finishing up worker thread"; - doneWorking(); - ETH_GUARDED(x_work) - m_work->detach(); - m_stopped = true; - })); + m_work.reset(new thread([&]() + { + setThreadName(m_name.c_str()); + while (m_state != WorkerState::Killing) + { + WorkerState ex = WorkerState::Starting; + m_state.compare_exchange_strong(ex, WorkerState::Started); + + startedWorking(); + workLoop(); + cnote << "Finishing up worker thread"; + doneWorking(); + +// ex = WorkerState::Stopping; +// m_state.compare_exchange_strong(ex, WorkerState::Stopped); + + ex = m_state.exchange(WorkerState::Stopped); + if (ex == WorkerState::Killing) + m_state.exchange(ex); + + while (m_state == WorkerState::Stopped) + this_thread::sleep_for(chrono::milliseconds(20)); + } + })); + cnote << "Spawning" << m_name; + } + while (m_state != WorkerState::Started) + this_thread::sleep_for(chrono::microseconds(20)); } void Worker::stopWorking() { // cnote << "stopWorking for thread" << m_name; ETH_GUARDED(x_work) - if (!m_work || !m_work->joinable()) - return; - cnote << "Stopping" << m_name; - m_stop = true; - while (!m_stopped) - this_thread::sleep_for(chrono::microseconds(50)); + if (m_work) + { + cnote << "Stopping" << m_name; + WorkerState ex = WorkerState::Started; + m_state.compare_exchange_strong(ex, WorkerState::Stopping); + + while (m_state != WorkerState::Stopped) + this_thread::sleep_for(chrono::microseconds(20)); + } +} + +void Worker::terminate() +{ +// cnote << "stopWorking for thread" << m_name; ETH_GUARDED(x_work) - m_work.reset(); - cnote << "Stopped" << m_name; + if (m_work) + { + cnote << "Terminating" << m_name; + m_state.exchange(WorkerState::Killing); + + m_work->join(); + m_work.reset(); + } } void Worker::workLoop() { - while (!m_stop) + while (m_state == WorkerState::Started) { if (m_idleWaitMs) this_thread::sleep_for(chrono::milliseconds(m_idleWaitMs)); diff --git a/libdevcore/Worker.h b/libdevcore/Worker.h index aad1dfc0e..fbc4d7042 100644 --- a/libdevcore/Worker.h +++ b/libdevcore/Worker.h @@ -36,6 +36,15 @@ enum class IfRunning Detach }; +enum class WorkerState +{ + Starting, + Started, + Stopping, + Stopped, + Killing +}; + class Worker { protected: @@ -47,19 +56,19 @@ protected: /// Move-assignment. Worker& operator=(Worker&& _m) { std::swap(m_name, _m.m_name); return *this; } - virtual ~Worker() { stopWorking(); } + virtual ~Worker() { terminate(); } /// Allows changing worker name if work is stopped. void setName(std::string _n) { if (!isWorking()) m_name = _n; } /// Starts worker thread; causes startedWorking() to be called. - void startWorking(IfRunning _ir = IfRunning::Fail); + void startWorking(); /// Stop worker thread; causes call to stopWorking(). void stopWorking(); - + /// Returns if worker thread is present. - bool isWorking() const { Guard l(x_work); return !!m_work && m_work->joinable(); } + bool isWorking() const { Guard l(x_work); return m_state == WorkerState::Started; } /// Called after thread is started from startWorking(). virtual void startedWorking() {} @@ -69,22 +78,25 @@ protected: /// Overrides doWork(); should call shouldStop() often and exit when true. virtual void workLoop(); - bool shouldStop() const { return m_stop; } + bool shouldStop() const { return m_state != WorkerState::Started; } /// Called when is to be stopped, just prior to thread being joined. virtual void doneWorking() {} /// Blocks caller into worker thread has finished. - void join() const { Guard l(x_work); try { if (m_work) m_work->join(); } catch (...) {} } +// void join() const { Guard l(x_work); try { if (m_work) m_work->join(); } catch (...) {} } private: + /// Stop and never start again. + void terminate(); + std::string m_name; + unsigned m_idleWaitMs = 0; mutable Mutex x_work; ///< Lock for the network existance. std::unique_ptr m_work; ///< The network thread. - std::atomic m_stop = {false}; - std::atomic m_stopped = {false}; + std::atomic m_state = {WorkerState::Starting}; }; } diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index 16d17b1e8..8e31b3c51 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -237,7 +237,7 @@ protected: return true; } } - return false; + return m_owner->shouldStop(); } virtual bool searched(uint64_t _startNonce, uint32_t _count) override @@ -246,7 +246,7 @@ protected: // std::cerr << "Searched " << _count << " from " << _startNonce << std::endl; m_owner->accumulateHashes(_count); m_last = _startNonce + _count; - if (m_abort) + if (m_abort || m_owner->shouldStop()) { m_aborted = true; return true; @@ -266,6 +266,7 @@ unsigned Ethash::GPUMiner::s_deviceId = 0; Ethash::GPUMiner::GPUMiner(ConstructionInfo const& _ci): Miner(_ci), + Worker("gpuminer"), m_hook(new EthashCLHook(this)) { } diff --git a/libethereum/Farm.h b/libethereum/Farm.h index 6263faf1b..fda9d64c3 100644 --- a/libethereum/Farm.h +++ b/libethereum/Farm.h @@ -155,12 +155,15 @@ private: { if (m_onSolutionFound && m_onSolutionFound(_s)) { - WriteGuard ul(x_minerWork); - for (std::shared_ptr const& m: m_miners) - if (m.get() != _m) - m->setWork(); - m_work.reset(); - return true; + if (x_minerWork.try_lock()) + { + for (std::shared_ptr const& m: m_miners) + if (m.get() != _m) + m->setWork(); + m_work.reset(); + x_minerWork.unlock(); + return true; + } } return false; } diff --git a/libp2p/Session.cpp b/libp2p/Session.cpp index 0ea7c33e2..06cd7f7a1 100644 --- a/libp2p/Session.cpp +++ b/libp2p/Session.cpp @@ -398,6 +398,7 @@ void Session::doRead() auto self(shared_from_this()); ba::async_read(m_socket, boost::asio::buffer(m_data, h256::size), [this,self](boost::system::error_code ec, std::size_t length) { + ThreadContext tc(toString(socketId())); if (ec && ec.category() != boost::asio::error::get_misc_category() && ec.value() != boost::asio::error::eof) { clogS(NetWarn) << "Error reading: " << ec.message(); @@ -433,6 +434,7 @@ void Session::doRead() auto tlen = frameSize + ((16 - (frameSize % 16)) % 16) + h128::size; ba::async_read(m_socket, boost::asio::buffer(m_data, tlen), [this, self, headerRLP, frameSize, tlen](boost::system::error_code ec, std::size_t length) { + ThreadContext tc(toString(socketId())); if (ec && ec.category() != boost::asio::error::get_misc_category() && ec.value() != boost::asio::error::eof) { clogS(NetWarn) << "Error reading: " << ec.message(); diff --git a/libwhisper/WhisperHost.cpp b/libwhisper/WhisperHost.cpp index 97a24e112..281ad2bc5 100644 --- a/libwhisper/WhisperHost.cpp +++ b/libwhisper/WhisperHost.cpp @@ -34,7 +34,7 @@ using namespace dev::shh; #endif #define clogS(X) dev::LogOutputStream(false) << "| " << std::setw(2) << session()->socketId() << "] " -WhisperHost::WhisperHost() +WhisperHost::WhisperHost(): Worker("shh") { } From 04a346460681c4d680415c1560e7e632411d8279 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 18 Apr 2015 23:57:20 +0200 Subject: [PATCH 41/65] JSON build fix. Removal of unneeded code. --- exp/CMakeLists.txt | 7 +++-- libethereum/EthereumPeer.cpp | 55 ++++++++++++++++-------------------- libp2p/Capability.cpp | 9 ++---- libp2p/Session.cpp | 48 +++++++++++++++---------------- libwhisper/Interface.cpp | 5 ---- libwhisper/WhisperHost.cpp | 5 ---- libwhisper/WhisperPeer.cpp | 7 +---- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/exp/CMakeLists.txt b/exp/CMakeLists.txt index d2a0e9ead..bfcd0e658 100644 --- a/exp/CMakeLists.txt +++ b/exp/CMakeLists.txt @@ -3,6 +3,7 @@ set(CMAKE_AUTOMOC OFF) aux_source_directory(. SRC_LIST) +include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS}) include_directories(BEFORE ..) include_directories(${LEVELDB_INCLUDE_DIRS}) @@ -24,9 +25,9 @@ target_link_libraries(${EXECUTABLE} webthree) target_link_libraries(${EXECUTABLE} ethereum) target_link_libraries(${EXECUTABLE} p2p) if (ETHASHCL) -target_link_libraries(${EXECUTABLE} ethash-cl) -target_link_libraries(${EXECUTABLE} ethash) -target_link_libraries(${EXECUTABLE} OpenCL) + target_link_libraries(${EXECUTABLE} ethash-cl) + target_link_libraries(${EXECUTABLE} ethash) + target_link_libraries(${EXECUTABLE} OpenCL) endif() install( TARGETS ${EXECUTABLE} DESTINATION bin) diff --git a/libethereum/EthereumPeer.cpp b/libethereum/EthereumPeer.cpp index e859f0e54..a83d15080 100644 --- a/libethereum/EthereumPeer.cpp +++ b/libethereum/EthereumPeer.cpp @@ -34,11 +34,6 @@ using namespace dev; using namespace dev::eth; using namespace p2p; -#if defined(clogS) -#undef clogS -#endif -#define clogS(X) dev::LogOutputStream(false) << "| " << std::setw(2) << session()->socketId() << "] " - EthereumPeer::EthereumPeer(Session* _s, HostCapabilityFace* _h, unsigned _i): Capability(_s, _h, _i), m_sub(host()->m_man) @@ -48,7 +43,7 @@ EthereumPeer::EthereumPeer(Session* _s, HostCapabilityFace* _h, unsigned _i): EthereumPeer::~EthereumPeer() { - clogS(NetMessageSummary) << "Aborting Sync :-("; + clog(NetMessageSummary) << "Aborting Sync :-("; abortSync(); } @@ -81,7 +76,7 @@ string toString(Asking _a) void EthereumPeer::transition(Asking _a, bool _force) { - clogS(NetMessageSummary) << "Transition!" << ::toString(_a) << "from" << ::toString(m_asking) << ", " << (isSyncing() ? "syncing" : "holding") << (needsSyncing() ? "& needed" : ""); + clog(NetMessageSummary) << "Transition!" << ::toString(_a) << "from" << ::toString(m_asking) << ", " << (isSyncing() ? "syncing" : "holding") << (needsSyncing() ? "& needed" : ""); if (m_asking == Asking::State && _a != Asking::State) m_requireTransactions = true; @@ -108,7 +103,7 @@ void EthereumPeer::transition(Asking _a, bool _force) if (m_asking == Asking::State || m_asking == Asking::Nothing) { if (isSyncing()) - clogS(NetWarn) << "Bad state: not asking for Hashes, yet syncing!"; + clog(NetWarn) << "Bad state: not asking for Hashes, yet syncing!"; m_syncingLatestHash = m_latestHash; m_syncingTotalDifficulty = m_totalDifficulty; @@ -123,7 +118,7 @@ void EthereumPeer::transition(Asking _a, bool _force) else if (m_asking == Asking::Hashes) { if (!isSyncing()) - clogS(NetWarn) << "Bad state: asking for Hashes yet not syncing!"; + clog(NetWarn) << "Bad state: asking for Hashes yet not syncing!"; setAsking(_a, true); prep(s, GetBlockHashesPacket, 2) << m_syncingNeededBlocks.back() << c_maxHashesAsk; @@ -136,7 +131,7 @@ void EthereumPeer::transition(Asking _a, bool _force) if (m_asking == Asking::Hashes) { if (!isSyncing()) - clogS(NetWarn) << "Bad state: asking for Hashes yet not syncing!"; + clog(NetWarn) << "Bad state: asking for Hashes yet not syncing!"; if (shouldGrabBlocks()) { clog(NetNote) << "Difficulty of hashchain HIGHER. Grabbing" << m_syncingNeededBlocks.size() << "blocks [latest now" << m_syncingLatestHash.abridged() << ", was" << host()->m_latestBlockSent.abridged() << "]"; @@ -174,7 +169,7 @@ void EthereumPeer::transition(Asking _a, bool _force) { if (m_asking == Asking::Blocks) { - clogS(NetNote) << "Finishing blocks fetch..."; + clog(NetNote) << "Finishing blocks fetch..."; // a bit overkill given that the other nodes may yet have the needed blocks, but better to be safe than sorry. if (isSyncing()) @@ -187,7 +182,7 @@ void EthereumPeer::transition(Asking _a, bool _force) } else if (m_asking == Asking::Hashes) { - clogS(NetNote) << "Finishing hashes fetch..."; + clog(NetNote) << "Finishing hashes fetch..."; setAsking(Asking::Nothing, false); } @@ -202,7 +197,7 @@ void EthereumPeer::transition(Asking _a, bool _force) return; } - clogS(NetWarn) << "Invalid state transition:" << ::toString(_a) << "from" << ::toString(m_asking) << ", " << (isSyncing() ? "syncing" : "holding") << (needsSyncing() ? "& needed" : ""); + clog(NetWarn) << "Invalid state transition:" << ::toString(_a) << "from" << ::toString(m_asking) << ", " << (isSyncing() ? "syncing" : "holding") << (needsSyncing() ? "& needed" : ""); } void EthereumPeer::setAsking(Asking _a, bool _isSyncing) @@ -270,14 +265,14 @@ void EthereumPeer::attemptSync() { if (m_asking != Asking::Nothing) { - clogS(NetAllDetail) << "Can't synced with this peer - outstanding asks."; + clog(NetAllDetail) << "Can't synced with this peer - outstanding asks."; return; } // if already done this, then ignore. if (!needsSyncing()) { - clogS(NetAllDetail) << "Already synced with this peer."; + clog(NetAllDetail) << "Already synced with this peer."; return; } @@ -285,16 +280,16 @@ void EthereumPeer::attemptSync() unsigned n = host()->m_chain.number(); u256 td = host()->m_chain.details().totalDifficulty; - clogS(NetAllDetail) << "Attempt chain-grab? Latest:" << c.abridged() << ", number:" << n << ", TD:" << td << " versus " << m_totalDifficulty; + clog(NetAllDetail) << "Attempt chain-grab? Latest:" << c.abridged() << ", number:" << n << ", TD:" << td << " versus " << m_totalDifficulty; if (td >= m_totalDifficulty) { - clogS(NetAllDetail) << "No. Our chain is better."; + clog(NetAllDetail) << "No. Our chain is better."; resetNeedsSyncing(); transition(Asking::Nothing); } else { - clogS(NetAllDetail) << "Yes. Their chain is better."; + clog(NetAllDetail) << "Yes. Their chain is better."; transition(Asking::Hashes); } } @@ -315,7 +310,7 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r) m_latestHash = _r[3].toHash(); auto genesisHash = _r[4].toHash(); - clogS(NetMessageSummary) << "Status:" << m_protocolVersion << "/" << m_networkId << "/" << genesisHash.abridged() << ", TD:" << m_totalDifficulty << "=" << m_latestHash.abridged(); + clog(NetMessageSummary) << "Status:" << m_protocolVersion << "/" << m_networkId << "/" << genesisHash.abridged() << ", TD:" << m_totalDifficulty << "=" << m_latestHash.abridged(); if (genesisHash != host()->m_chain.genesisHash()) disable("Invalid genesis hash"); @@ -334,7 +329,7 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r) case GetTransactionsPacket: break; // DEPRECATED. case TransactionsPacket: { - clogS(NetAllDetail) << "Transactions (" << dec << _r.itemCount() << "entries)"; + clog(NetAllDetail) << "Transactions (" << dec << _r.itemCount() << "entries)"; Guard l(x_knownTransactions); for (unsigned i = 0; i < _r.itemCount(); ++i) { @@ -363,7 +358,7 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r) { h256 later = _r[0].toHash(); unsigned limit = _r[1].toInt(); - clogS(NetMessageSummary) << "GetBlockHashes (" << limit << "entries," << later.abridged() << ")"; + clog(NetMessageSummary) << "GetBlockHashes (" << limit << "entries," << later.abridged() << ")"; unsigned c = min(host()->m_chain.number(later), limit); @@ -378,7 +373,7 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r) } case BlockHashesPacket: { - clogS(NetMessageSummary) << "BlockHashes (" << dec << _r.itemCount() << "entries)" << (_r.itemCount() ? "" : ": NoMoreHashes"); + clog(NetMessageSummary) << "BlockHashes (" << dec << _r.itemCount() << "entries)" << (_r.itemCount() ? "" : ": NoMoreHashes"); if (m_asking != Asking::Hashes) { @@ -408,7 +403,7 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r) } case GetBlocksPacket: { - clogS(NetMessageSummary) << "GetBlocks (" << dec << _r.itemCount() << "entries)"; + clog(NetMessageSummary) << "GetBlocks (" << dec << _r.itemCount() << "entries)"; // return the requested blocks. bytes rlp; unsigned n = 0; @@ -429,10 +424,10 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r) } case BlocksPacket: { - clogS(NetMessageSummary) << "Blocks (" << dec << _r.itemCount() << "entries)" << (_r.itemCount() ? "" : ": NoMoreBlocks"); + clog(NetMessageSummary) << "Blocks (" << dec << _r.itemCount() << "entries)" << (_r.itemCount() ? "" : ": NoMoreBlocks"); if (m_asking != Asking::Blocks) - clogS(NetWarn) << "Unexpected Blocks received!"; + clog(NetWarn) << "Unexpected Blocks received!"; if (_r.itemCount() == 0) { @@ -485,7 +480,7 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r) } } - clogS(NetMessageSummary) << dec << success << "imported OK," << unknown << "with unknown parents," << future << "with future timestamps," << got << " already known," << repeated << " repeats received."; + clog(NetMessageSummary) << dec << success << "imported OK," << unknown << "with unknown parents," << future << "with future timestamps," << got << " already known," << repeated << " repeats received."; if (m_asking == Asking::Blocks) { @@ -499,7 +494,7 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r) case NewBlockPacket: { auto h = BlockInfo::headerHash(_r[0].data()); - clogS(NetMessageSummary) << "NewBlock: " << h.abridged(); + clog(NetMessageSummary) << "NewBlock: " << h.abridged(); if (_r.itemCount() != 2) disable("NewBlock without 2 data fields."); @@ -524,7 +519,7 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r) break; case ImportResult::UnknownParent: - clogS(NetMessageSummary) << "Received block with no known parent. Resyncing..."; + clog(NetMessageSummary) << "Received block with no known parent. Resyncing..."; setNeedsSyncing(h, _r[1].toInt()); break; } @@ -540,11 +535,11 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r) } catch (Exception const& _e) { - clogS(NetWarn) << "Peer causing an Exception:" << _e.what() << _r; + clog(NetWarn) << "Peer causing an Exception:" << _e.what() << _r; } catch (std::exception const& _e) { - clogS(NetWarn) << "Peer causing an exception:" << _e.what() << _r; + clog(NetWarn) << "Peer causing an exception:" << _e.what() << _r; } return true; diff --git a/libp2p/Capability.cpp b/libp2p/Capability.cpp index f59fd8cdd..ecc458730 100644 --- a/libp2p/Capability.cpp +++ b/libp2p/Capability.cpp @@ -27,19 +27,14 @@ using namespace std; using namespace dev; using namespace dev::p2p; -#if defined(clogS) -#undef clogS -#endif -#define clogS(X) dev::LogOutputStream(false) << "| " << std::setw(2) << session()->socketId() << "] " - Capability::Capability(Session* _s, HostCapabilityFace* _h, unsigned _idOffset): m_session(_s), m_host(_h), m_idOffset(_idOffset) { - clogS(NetConnect) << "New session for capability" << m_host->name() << "; idOffset:" << m_idOffset; + clog(NetConnect) << "New session for capability" << m_host->name() << "; idOffset:" << m_idOffset; } void Capability::disable(std::string const& _problem) { - clogS(NetWarn) << "DISABLE: Disabling capability '" << m_host->name() << "'. Reason:" << _problem; + clog(NetWarn) << "DISABLE: Disabling capability '" << m_host->name() << "'. Reason:" << _problem; m_enabled = false; } diff --git a/libp2p/Session.cpp b/libp2p/Session.cpp index 04ea91028..11b19daae 100644 --- a/libp2p/Session.cpp +++ b/libp2p/Session.cpp @@ -33,11 +33,6 @@ using namespace std; using namespace dev; using namespace dev::p2p; -#if defined(clogS) -#undef clogS -#endif -#define clogS(X) dev::LogOutputStream(false) << "| " << std::setw(2) << m_socket.native_handle() << "] " - Session::Session(Host* _s, RLPXFrameIO* _io, std::shared_ptr const& _n, PeerSessionInfo _info): m_server(_s), m_io(_io), @@ -53,7 +48,7 @@ Session::Session(Host* _s, RLPXFrameIO* _io, std::shared_ptr const& _n, Pe Session::~Session() { - clogS(NetMessageSummary) << "Closing Peer Session :-("; + clog(NetMessageSummary) << "Closing Peer Session :-("; m_peer->m_lastConnected = m_peer->m_lastAttempted - chrono::seconds(1); // Read-chain finished for one reason or another. @@ -139,7 +134,7 @@ void Session::serviceNodesRequest() auto rs = randomSelection(peers, 10); for (auto const& i: rs) { - clogS(NetTriviaDetail) << "Sending peer " << i.id.abridged() << i.endpoint; + clog(NetTriviaDetail) << "Sending peer " << i.id.abridged() << i.endpoint; if (i.endpoint.address.is_v4()) s.appendList(3) << bytesConstRef(i.endpoint.address.to_v4().to_bytes().data(), 4) << i.endpoint.tcpPort << i.id; else// if (i.second.address().is_v6()) - assumed @@ -154,7 +149,7 @@ bool Session::interpret(PacketType _t, RLP const& _r) { m_lastReceived = chrono::steady_clock::now(); - clogS(NetRight) << _t << _r; + clog(NetRight) << _t << _r; try // Generic try-catch block designed to capture RLP format errors - TODO: give decent diagnostics, make a bit more specific over what is caught. { switch (_t) @@ -168,28 +163,28 @@ bool Session::interpret(PacketType _t, RLP const& _r) else { reason = reasonOf(r); - clogS(NetMessageSummary) << "Disconnect (reason: " << reason << ")"; + clog(NetMessageSummary) << "Disconnect (reason: " << reason << ")"; drop(DisconnectRequested); } break; } case PingPacket: { - clogS(NetTriviaSummary) << "Ping"; + clog(NetTriviaSummary) << "Ping"; RLPStream s; sealAndSend(prep(s, PongPacket)); break; } case PongPacket: m_info.lastPing = std::chrono::steady_clock::now() - m_ping; - clogS(NetTriviaSummary) << "Latency: " << chrono::duration_cast(m_info.lastPing).count() << " ms"; + clog(NetTriviaSummary) << "Latency: " << chrono::duration_cast(m_info.lastPing).count() << " ms"; break; case GetPeersPacket: // Disabled for interop testing. // GetPeers/PeersPacket will be modified to only exchange new nodes which it's peers are interested in. break; - clogS(NetTriviaSummary) << "GetPeers"; + clog(NetTriviaSummary) << "GetPeers"; m_theyRequestedNodes = true; serviceNodesRequest(); break; @@ -198,7 +193,7 @@ bool Session::interpret(PacketType _t, RLP const& _r) // GetPeers/PeersPacket will be modified to only exchange new nodes which it's peers are interested in. break; - clogS(NetTriviaSummary) << "Peers (" << dec << (_r.itemCount() - 1) << " entries)"; + clog(NetTriviaSummary) << "Peers (" << dec << (_r.itemCount() - 1) << " entries)"; m_weRequestedNodes = false; for (unsigned i = 0; i < _r.itemCount(); ++i) { @@ -216,7 +211,7 @@ bool Session::interpret(PacketType _t, RLP const& _r) auto ep = bi::tcp::endpoint(peerAddress, _r[i][1].toInt()); NodeId id = _r[i][2].toHash(); - clogS(NetAllDetail) << "Checking: " << ep << "(" << id.abridged() << ")"; + clog(NetAllDetail) << "Checking: " << ep << "(" << id.abridged() << ")"; if (!isPublicAddress(peerAddress)) goto CONTINUE; // Private address. Ignore. @@ -239,7 +234,7 @@ bool Session::interpret(PacketType _t, RLP const& _r) // OK passed all our checks. Assume it's good. addRating(1000); m_server->addNode(id, NodeIPEndpoint(ep.address(), ep.port(), ep.port())); - clogS(NetTriviaDetail) << "New peer: " << ep << "(" << id .abridged()<< ")"; + clog(NetTriviaDetail) << "New peer: " << ep << "(" << id .abridged()<< ")"; CONTINUE:; LAMEPEER:; } @@ -258,7 +253,7 @@ bool Session::interpret(PacketType _t, RLP const& _r) } catch (std::exception const& _e) { - clogS(NetWarn) << "Peer causing an exception:" << _e.what() << _r; + clog(NetWarn) << "Peer causing an exception:" << _e.what() << _r; disconnect(BadProtocol); return true; } @@ -298,11 +293,11 @@ bool Session::checkPacket(bytesConstRef _msg) void Session::send(bytes&& _msg) { - clogS(NetLeft) << RLP(bytesConstRef(&_msg).cropped(1)); + clog(NetLeft) << RLP(bytesConstRef(&_msg).cropped(1)); bytesConstRef msg(&_msg); if (!checkPacket(msg)) - clogS(NetWarn) << "INVALID PACKET CONSTRUCTED!"; + clog(NetWarn) << "INVALID PACKET CONSTRUCTED!"; if (!m_socket.is_open()) return; @@ -328,7 +323,7 @@ void Session::write() // must check queue, as write callback can occur following dropped() if (ec) { - clogS(NetWarn) << "Error sending: " << ec.message(); + clog(NetWarn) << "Error sending: " << ec.message(); drop(TCPError); return; } @@ -350,7 +345,7 @@ void Session::drop(DisconnectReason _reason) if (m_socket.is_open()) try { - clogS(NetConnect) << "Closing " << m_socket.remote_endpoint() << "(" << reasonOf(_reason) << ")"; + clog(NetConnect) << "Closing " << m_socket.remote_endpoint() << "(" << reasonOf(_reason) << ")"; boost::system::error_code ec; m_socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec); m_socket.close(); @@ -368,7 +363,7 @@ void Session::drop(DisconnectReason _reason) void Session::disconnect(DisconnectReason _reason) { - clogS(NetConnect) << "Disconnecting (our reason:" << reasonOf(_reason) << ")"; + clog(NetConnect) << "Disconnecting (our reason:" << reasonOf(_reason) << ")"; StructuredLogger::p2pDisconnected( m_info.id.abridged(), m_peer->endpoint, // TODO: may not be 100% accurate @@ -401,7 +396,7 @@ void Session::doRead() ThreadContext tc(toString(socketId())); if (ec && ec.category() != boost::asio::error::get_misc_category() && ec.value() != boost::asio::error::eof) { - clogS(NetWarn) << "Error reading: " << ec.message(); + clog(NetWarn) << "Error reading: " << ec.message(); drop(TCPError); } else if (ec && length == 0) @@ -434,10 +429,11 @@ void Session::doRead() auto tlen = frameSize + ((16 - (frameSize % 16)) % 16) + h128::size; ba::async_read(m_socket, boost::asio::buffer(m_data, tlen), [this, self, headerRLP, frameSize, tlen](boost::system::error_code ec, std::size_t length) { - ThreadContext tc(toString(socketId())); + ThreadContext tc1(toString(socketId())); + ThreadContext tc2(toString(info().clientVersion)); if (ec && ec.category() != boost::asio::error::get_misc_category() && ec.value() != boost::asio::error::eof) { - clogS(NetWarn) << "Error reading: " << ec.message(); + clog(NetWarn) << "Error reading: " << ec.message(); drop(TCPError); } else if (ec && length == 0) @@ -455,7 +451,7 @@ void Session::doRead() if (!checkPacket(frame)) { cerr << "Received " << frame.size() << ": " << toHex(frame) << endl; - clogS(NetWarn) << "INVALID MESSAGE RECEIVED"; + clog(NetWarn) << "INVALID MESSAGE RECEIVED"; disconnect(BadProtocol); return; } @@ -464,7 +460,7 @@ void Session::doRead() auto packetType = (PacketType)RLP(frame.cropped(0, 1)).toInt(); RLP r(frame.cropped(1)); if (!interpret(packetType, r)) - clogS(NetWarn) << "Couldn't interpret packet." << RLP(r); + clog(NetWarn) << "Couldn't interpret packet." << RLP(r); } doRead(); } diff --git a/libwhisper/Interface.cpp b/libwhisper/Interface.cpp index 72bca9785..a95cfa13e 100644 --- a/libwhisper/Interface.cpp +++ b/libwhisper/Interface.cpp @@ -29,11 +29,6 @@ using namespace dev; using namespace dev::p2p; using namespace dev::shh; -#if defined(clogS) -#undef clogS -#endif -#define clogS(X) dev::LogOutputStream(false) << "| " << std::setw(2) << session()->socketId() << "] " - Interface::~Interface() { } diff --git a/libwhisper/WhisperHost.cpp b/libwhisper/WhisperHost.cpp index 281ad2bc5..ab3576292 100644 --- a/libwhisper/WhisperHost.cpp +++ b/libwhisper/WhisperHost.cpp @@ -29,11 +29,6 @@ using namespace dev; using namespace dev::p2p; using namespace dev::shh; -#if defined(clogS) -#undef clogS -#endif -#define clogS(X) dev::LogOutputStream(false) << "| " << std::setw(2) << session()->socketId() << "] " - WhisperHost::WhisperHost(): Worker("shh") { } diff --git a/libwhisper/WhisperPeer.cpp b/libwhisper/WhisperPeer.cpp index 53ea91a9e..9bef25140 100644 --- a/libwhisper/WhisperPeer.cpp +++ b/libwhisper/WhisperPeer.cpp @@ -29,11 +29,6 @@ using namespace dev; using namespace dev::p2p; using namespace dev::shh; -#if defined(clogS) -#undef clogS -#endif -#define clogS(X) dev::LogOutputStream(false) << "| " << std::setw(2) << session()->socketId() << "] " - WhisperPeer::WhisperPeer(Session* _s, HostCapabilityFace* _h, unsigned _i): Capability(_s, _h, _i) { RLPStream s; @@ -57,7 +52,7 @@ bool WhisperPeer::interpret(unsigned _id, RLP const& _r) { auto protocolVersion = _r[0].toInt(); - clogS(NetMessageSummary) << "Status: " << protocolVersion; + clog(NetMessageSummary) << "Status: " << protocolVersion; if (protocolVersion != version()) disable("Invalid protocol version."); From 616cb14385454ae2a804adaa85aa9cdeaf5b8e23 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 19 Apr 2015 00:35:29 +0200 Subject: [PATCH 42/65] Nicer logging. Much nicer. --- libethereum/State.cpp | 6 ++++-- libethereum/State.h | 2 +- libp2p/Session.cpp | 11 +++++++---- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/libethereum/State.cpp b/libethereum/State.cpp index ec5023ff8..2b5918f56 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -467,7 +467,7 @@ bool State::cull(TransactionQueue& _tq) const return ret; } -TransactionReceipts State::sync(BlockChain const& _bc, TransactionQueue& _tq, GasPricer const& _gp, bool* o_transactionQueueChanged) +TransactionReceipts State::sync(BlockChain const& _bc, TransactionQueue& _tq, GasPricer const& _gp, bool* o_transactionQueueChanged, unsigned msTimeout) { // TRANSACTIONS TransactionReceipts ret; @@ -475,7 +475,9 @@ TransactionReceipts State::sync(BlockChain const& _bc, TransactionQueue& _tq, Ga LastHashes lh; - for (int goodTxs = 1; goodTxs;) + auto deadline = chrono::steady_clock::now() + chrono::milliseconds(msTimeout); + + for (int goodTxs = 1; goodTxs && chrono::steady_clock::now() < deadline; ) { goodTxs = 0; for (auto const& i: ts) diff --git a/libethereum/State.h b/libethereum/State.h index c7ad1e0e6..a3e2ddff1 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -205,7 +205,7 @@ public: /// @returns a list of receipts one for each transaction placed from the queue into the state. /// @a o_transactionQueueChanged boolean pointer, the value of which will be set to true if the transaction queue /// changed and the pointer is non-null - TransactionReceipts sync(BlockChain const& _bc, TransactionQueue& _tq, GasPricer const& _gp, bool* o_transactionQueueChanged = nullptr); + TransactionReceipts sync(BlockChain const& _bc, TransactionQueue& _tq, GasPricer const& _gp, bool* o_transactionQueueChanged = nullptr, unsigned _msTimeout = 100); /// Like sync but only operate on _tq, killing the invalid/old ones. bool cull(TransactionQueue& _tq) const; diff --git a/libp2p/Session.cpp b/libp2p/Session.cpp index 11b19daae..cd4bccbf0 100644 --- a/libp2p/Session.cpp +++ b/libp2p/Session.cpp @@ -48,7 +48,8 @@ Session::Session(Host* _s, RLPXFrameIO* _io, std::shared_ptr const& _n, Pe Session::~Session() { - clog(NetMessageSummary) << "Closing Peer Session :-("; + ThreadContext tc(info().id.abridged() + " | " + info().clientVersion); + clog(NetMessageSummary) << "Closing peer session :-("; m_peer->m_lastConnected = m_peer->m_lastAttempted - chrono::seconds(1); // Read-chain finished for one reason or another. @@ -116,6 +117,8 @@ void Session::ensureNodesRequested() void Session::serviceNodesRequest() { + ThreadContext tc(info().id.abridged() + "/" + info().clientVersion); + if (!m_theyRequestedNodes) return; @@ -320,6 +323,7 @@ void Session::write() auto self(shared_from_this()); ba::async_write(m_socket, ba::buffer(bytes), [this, self](boost::system::error_code ec, std::size_t /*length*/) { + ThreadContext tc(info().id.abridged() + " | " + info().clientVersion); // must check queue, as write callback can occur following dropped() if (ec) { @@ -393,7 +397,7 @@ void Session::doRead() auto self(shared_from_this()); ba::async_read(m_socket, boost::asio::buffer(m_data, h256::size), [this,self](boost::system::error_code ec, std::size_t length) { - ThreadContext tc(toString(socketId())); + ThreadContext tc(info().id.abridged() + " | " + info().clientVersion); if (ec && ec.category() != boost::asio::error::get_misc_category() && ec.value() != boost::asio::error::eof) { clog(NetWarn) << "Error reading: " << ec.message(); @@ -429,8 +433,7 @@ void Session::doRead() auto tlen = frameSize + ((16 - (frameSize % 16)) % 16) + h128::size; ba::async_read(m_socket, boost::asio::buffer(m_data, tlen), [this, self, headerRLP, frameSize, tlen](boost::system::error_code ec, std::size_t length) { - ThreadContext tc1(toString(socketId())); - ThreadContext tc2(toString(info().clientVersion)); + ThreadContext tc(info().id.abridged() + " | " + info().clientVersion); if (ec && ec.category() != boost::asio::error::get_misc_category() && ec.value() != boost::asio::error::eof) { clog(NetWarn) << "Error reading: " << ec.message(); From c07e43b4ad5b5b48be9a7ea201c7a90d320b6a46 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 19 Apr 2015 00:51:04 +0200 Subject: [PATCH 43/65] Don't create full if missing when just verifying. --- libethcore/EthashAux.cpp | 11 ++++++----- libethcore/EthashAux.h | 4 ++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index 465ae17da..68c5f3057 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -138,12 +138,12 @@ EthashAux::LightAllocation::~LightAllocation() } -EthashAux::FullType EthashAux::full(BlockInfo const& _header, bytesRef _dest) +EthashAux::FullType EthashAux::full(BlockInfo const& _header, bytesRef _dest, bool _createIfMissing) { - return full(_header.seedHash(), _dest); + return full(_header.seedHash(), _dest, _createIfMissing); } -EthashAux::FullType EthashAux::full(h256 const& _seedHash, bytesRef _dest) +EthashAux::FullType EthashAux::full(h256 const& _seedHash, bytesRef _dest, bool _createIfMissing) { RecursiveGuard l(get()->x_this); FullType ret = get()->m_fulls[_seedHash].lock(); @@ -180,6 +180,8 @@ EthashAux::FullType EthashAux::full(h256 const& _seedHash, bytesRef _dest) bytesRef r = contentsNew(memoFile, _dest); if (!r) { + if (!_createIfMissing) + return FullType(); // file didn't exist. if (_dest) // buffer was passed in - no insertion into cache nor need to allocate @@ -221,8 +223,7 @@ Ethash::Result EthashAux::LightAllocation::compute(h256 const& _seedHash, h256 c Ethash::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) { - // TODO: should be EthashAux::get()->haveFull(_seedHash) - if (auto dag = EthashAux::get()->full(_seedHash)) + if (auto dag = EthashAux::get()->full(_seedHash, bytesRef(), false)) return dag->compute(_seedHash, _headerHash, _nonce); return EthashAux::get()->light(_seedHash)->compute(_seedHash, _headerHash, _nonce); } diff --git a/libethcore/EthashAux.h b/libethcore/EthashAux.h index 98a6554ad..40dd88e16 100644 --- a/libethcore/EthashAux.h +++ b/libethcore/EthashAux.h @@ -60,8 +60,8 @@ public: static ethash_params params(unsigned _n); static LightType light(BlockInfo const& _header); static LightType light(h256 const& _seedHash); - static FullType full(BlockInfo const& _header, bytesRef _dest = bytesRef()); - static FullType full(h256 const& _header, bytesRef _dest = bytesRef()); + static FullType full(BlockInfo const& _header, bytesRef _dest = bytesRef(), bool _createIfMissing = true); + static FullType full(h256 const& _header, bytesRef _dest = bytesRef(), bool _createIfMissing = true); static Ethash::Result eval(BlockInfo const& _header) { return eval(_header, _header.nonce); } static Ethash::Result eval(BlockInfo const& _header, Nonce const& _nonce); From 081ecb5c9c6740cecd33967234f6d5611e4fd7c6 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 19 Apr 2015 01:26:56 +0200 Subject: [PATCH 44/65] Broadcast everything to everyone. --- libethereum/EthereumHost.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libethereum/EthereumHost.cpp b/libethereum/EthereumHost.cpp index 792eb3026..fde2ae745 100644 --- a/libethereum/EthereumHost.cpp +++ b/libethereum/EthereumHost.cpp @@ -189,7 +189,7 @@ void EthereumHost::maintainTransactions() for (auto const& i: ts) { bool unsent = !m_transactionsSent.count(i.first); - for (auto const& p: randomSelection(25, [&](EthereumPeer* p) { return p->m_requireTransactions || (unsent && !p->m_knownTransactions.count(i.first)); })) + for (auto const& p: randomSelection(100, [&](EthereumPeer* p) { return p->m_requireTransactions || (unsent && !p->m_knownTransactions.count(i.first)); })) peerTransactions[p].push_back(i.first); } for (auto const& t: ts) @@ -253,7 +253,7 @@ void EthereumHost::maintainBlocks(h256 _currentHash) h256s blocks = get<0>(m_chain.treeRoute(m_latestBlockSent, _currentHash, false, false, true)); - for (auto const& p: randomSelection(25, [&](EthereumPeer* p){return !p->m_knownBlocks.count(_currentHash); })) + for (auto const& p: randomSelection(100, [&](EthereumPeer* p){return !p->m_knownBlocks.count(_currentHash); })) for (auto const& b: blocks) if (!p->m_knownBlocks.count(b)) { From d7fb14b95b26804e2c5175bf00517fc9d12cc2f0 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 19 Apr 2015 11:30:41 +0200 Subject: [PATCH 45/65] Diagnostics for tracking down source of apparently corrupt block insertion. --- libethereum/EthereumPeer.cpp | 16 +++++++++++----- libethereum/State.cpp | 24 ++++++++++++++++++++++-- 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/libethereum/EthereumPeer.cpp b/libethereum/EthereumPeer.cpp index a83d15080..82097995b 100644 --- a/libethereum/EthereumPeer.cpp +++ b/libethereum/EthereumPeer.cpp @@ -403,19 +403,25 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r) } case GetBlocksPacket: { - clog(NetMessageSummary) << "GetBlocks (" << dec << _r.itemCount() << "entries)"; + unsigned count = _r.itemCount(); + clog(NetMessageSummary) << "GetBlocks (" << dec << count << "entries)"; // return the requested blocks. bytes rlp; unsigned n = 0; - for (unsigned i = 0; i < _r.itemCount() && i <= c_maxBlocks; ++i) + for (unsigned i = 0; i < min(count, c_maxBlocks); ++i) { - auto b = host()->m_chain.block(_r[i].toHash()); - if (b.size()) + auto h = _r[i].toHash(); + if (host()->m_chain.isKnown(h)) { - rlp += b; + rlp += host()->m_chain.block(_r[i].toHash()); ++n; } } + if (count > 20 && n == 0) + clog(NetWarn) << "all" << count << "unknown blocks requested; peer on different chain?"; + else + clog(NetMessageSummary) << n << "blocks known and returned;" << (min(count, c_maxBlocks) - n) << "blocks unknown;" << (c_maxBlocks > count ? c_maxBlocks - count : 0) << "blocks ignored"; + addRating(0); RLPStream s; prep(s, BlocksPacket, n).appendRaw(rlp, n); diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 2b5918f56..278002c87 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -276,6 +276,7 @@ bool State::sync(BlockChain const& _bc) bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi, ImportRequirements::value _ir) { + (void)_ir; bool ret = false; // BLOCK BlockInfo bi = _bi ? _bi : _bc.info(_block); @@ -315,6 +316,24 @@ bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi, Impor // No change since last sync. // Carry on as we were. } + else + { + // New blocks available, or we've switched to a different branch. All change. + // Find most recent state dump and replay what's left. + // (Most recent state dump might end up being genesis.) + + if (m_db.lookup(bi.stateRoot).empty()) + { + cwarn << "Unable to sync to" << bi.hash().abridged() << "; state root" << bi.stateRoot.abridged() << "not found in database."; + cwarn << "Database corrupt: contains block without stateRoot:" << bi; + cwarn << "Bailing."; + exit(-1); + } + m_previousBlock = bi; + resetCurrent(); + ret = true; + } +#if ALLOW_REBUILD else { // New blocks available, or we've switched to a different branch. All change. @@ -352,6 +371,7 @@ bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi, Impor resetCurrent(); ret = true; } +#endif return ret; } @@ -692,9 +712,9 @@ void State::cleanup(bool _fullCommit) paranoia("immediately before database commit", true); // Commit the new trie to disk. - cnote << "Commiting to disk..."; + cnote << "Committing to disk: stateRoot" << m_currentBlock.stateRoot.abridged() << "=" << rootHash().abridged() << "=" << toHex(asBytes(m_db.lookup(rootHash()))); m_db.commit(); - cnote << "Committed."; + cnote << "Committed: stateRoot" << m_currentBlock.stateRoot.abridged() << "=" << rootHash().abridged() << "=" << toHex(asBytes(m_db.lookup(rootHash()))); paranoia("immediately after database commit", true); m_previousBlock = m_currentBlock; From dd0b508d53026affbd4a2be13de771e4205fd5df Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 19 Apr 2015 12:04:17 +0200 Subject: [PATCH 46/65] Don't forget the transaction queue! --- libethereum/BlockChain.h | 3 +- libethereum/Client.cpp | 2 +- libethereum/EthereumPeer.cpp | 2 +- libethereum/State.cpp | 82 ++++++++++++++++-------------------- libethereum/State.h | 9 +--- 5 files changed, 43 insertions(+), 55 deletions(-) diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 2c3ef40a8..0529e305e 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -98,7 +98,8 @@ public: /// To be called from main loop every 100ms or so. void process(); - /// Sync the chain with any incoming blocks. All blocks should, if processed in order + /// Sync the chain with any incoming blocks. All blocks should, if processed in order. + /// @returns fresh blocks, dead blocks and true iff there are additional blocks to be processed waiting. std::tuple sync(BlockQueue& _bq, OverlayDB const& _stateDB, unsigned _max); /// Attempt to import the given block directly into the CanonBlockChain and sync with the state DB. diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 6959aaa81..b4b92c713 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -441,7 +441,7 @@ void Client::syncTransactionQueue() TransactionReceipts newPendingReceipts; ETH_WRITE_GUARDED(x_postMine) - newPendingReceipts = m_postMine.sync(m_bc, m_tq, *m_gp); + tie(newPendingReceipts, m_syncTransactionQueue) = m_postMine.sync(m_bc, m_tq, *m_gp); if (newPendingReceipts.empty()) return; diff --git a/libethereum/EthereumPeer.cpp b/libethereum/EthereumPeer.cpp index 82097995b..83fe22a71 100644 --- a/libethereum/EthereumPeer.cpp +++ b/libethereum/EthereumPeer.cpp @@ -420,7 +420,7 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r) if (count > 20 && n == 0) clog(NetWarn) << "all" << count << "unknown blocks requested; peer on different chain?"; else - clog(NetMessageSummary) << n << "blocks known and returned;" << (min(count, c_maxBlocks) - n) << "blocks unknown;" << (c_maxBlocks > count ? c_maxBlocks - count : 0) << "blocks ignored"; + clog(NetMessageSummary) << n << "blocks known and returned;" << (min(count, c_maxBlocks) - n) << "blocks unknown;" << (count > c_maxBlocks ? count - c_maxBlocks : 0) << "blocks ignored"; addRating(0); RLPStream s; diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 278002c87..19cec8614 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -461,43 +461,19 @@ void State::resetCurrent() paranoia("begin resetCurrent", true); } -bool State::cull(TransactionQueue& _tq) const -{ - bool ret = false; - auto ts = _tq.transactions(); - for (auto const& i: ts) - { - if (!m_transactionSet.count(i.first)) - { - try - { - if (i.second.nonce() < transactionsFrom(i.second.sender())) - { - _tq.drop(i.first); - ret = true; - } - } - catch (...) - { - _tq.drop(i.first); - ret = true; - } - } - } - return ret; -} - -TransactionReceipts State::sync(BlockChain const& _bc, TransactionQueue& _tq, GasPricer const& _gp, bool* o_transactionQueueChanged, unsigned msTimeout) +pair State::sync(BlockChain const& _bc, TransactionQueue& _tq, GasPricer const& _gp, unsigned msTimeout) { // TRANSACTIONS - TransactionReceipts ret; + pair ret; + ret.second = false; + auto ts = _tq.transactions(); LastHashes lh; auto deadline = chrono::steady_clock::now() + chrono::milliseconds(msTimeout); - for (int goodTxs = 1; goodTxs && chrono::steady_clock::now() < deadline; ) + for (int goodTxs = 1; goodTxs; ) { goodTxs = 0; for (auto const& i: ts) @@ -511,51 +487,67 @@ TransactionReceipts State::sync(BlockChain const& _bc, TransactionQueue& _tq, Ga if (lh.empty()) lh = _bc.lastHashes(); execute(lh, i.second); - ret.push_back(m_receipts.back()); + ret.first.push_back(m_receipts.back()); _tq.noteGood(i); ++goodTxs; // cnote << "TX took:" << t.elapsed() * 1000; } + else if (i.second.gasPrice() < _gp.ask(*this) * 9 / 10) + { + // less than 90% of our ask price for gas. drop. + cnote << i.first.abridged() << "Dropping El Cheapo transaction (<90% of ask price)"; + _tq.drop(i.first); + } } -#if ETH_DEBUG catch (InvalidNonce const& in) { - bigint const* req = boost::get_error_info(in); - bigint const* got = boost::get_error_info(in); + bigint const& req = *boost::get_error_info(in); + bigint const& got = *boost::get_error_info(in); - if (*req > *got) + if (req > got) { // too old + cnote << i.first.abridged() << "Dropping old transaction (nonce too low)"; + _tq.drop(i.first); + } + else if (got > req + 5) + { + // too new + cnote << i.first.abridged() << "Dropping new transaction (> 5 nonces ahead)"; _tq.drop(i.first); - if (o_transactionQueueChanged) - *o_transactionQueueChanged = true; } else _tq.setFuture(i); } catch (BlockGasLimitReached const& e) { - _tq.setFuture(i); + bigint const& got = *boost::get_error_info(e); + if (got > m_currentBlock.gasLimit) + { + cnote << i.first.abridged() << "Dropping over-gassy transaction (gas > block's gas limit)"; + _tq.drop(i.first); + } + else + _tq.setFuture(i); } -#endif catch (Exception const& _e) { // Something else went wrong - drop it. + cnote << i.first.abridged() << "Dropping invalid transaction:" << diagnostic_information(_e); _tq.drop(i.first); - if (o_transactionQueueChanged) - *o_transactionQueueChanged = true; - cnote << "Dropping invalid transaction:"; - cnote << diagnostic_information(_e); } catch (std::exception const&) { // Something else went wrong - drop it. _tq.drop(i.first); - if (o_transactionQueueChanged) - *o_transactionQueueChanged = true; - cnote << "Transaction caused low-level exception :("; + cnote << i.first.abridged() << "Transaction caused low-level exception :("; } } + if (chrono::steady_clock::now() > deadline) + { + ret.second = true; + break; + } } return ret; } diff --git a/libethereum/State.h b/libethereum/State.h index a3e2ddff1..28b005243 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -200,14 +200,9 @@ public: /// Only valid after mine() returns true. bytes const& blockData() const { return m_currentBytes; } - // TODO: Cleaner interface. /// Sync our transactions, killing those from the queue that we have and assimilating those that we don't. - /// @returns a list of receipts one for each transaction placed from the queue into the state. - /// @a o_transactionQueueChanged boolean pointer, the value of which will be set to true if the transaction queue - /// changed and the pointer is non-null - TransactionReceipts sync(BlockChain const& _bc, TransactionQueue& _tq, GasPricer const& _gp, bool* o_transactionQueueChanged = nullptr, unsigned _msTimeout = 100); - /// Like sync but only operate on _tq, killing the invalid/old ones. - bool cull(TransactionQueue& _tq) const; + /// @returns a list of receipts one for each transaction placed from the queue into the state and bool, true iff there are more transactions to be processed. + std::pair sync(BlockChain const& _bc, TransactionQueue& _tq, GasPricer const& _gp, unsigned _msTimeout = 100); /// Execute a given transaction. /// This will append @a _t to the transaction list and change the state accordingly. From 9671c5405b59a7ddc819e7215f1236855b73d4f3 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 19 Apr 2015 12:39:33 +0200 Subject: [PATCH 47/65] Harsher penalty for screwing the DB. --- libethereum/BlockChain.cpp | 14 ++++++++++++-- libethereum/BlockChain.h | 1 + libethereum/EthereumPeer.cpp | 7 +++++++ libp2p/Common.h | 1 + 4 files changed, 21 insertions(+), 2 deletions(-) diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index a76435ada..352739626 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -398,9 +398,11 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import if (!pd) { auto pdata = pd.rlp(); - cwarn << "Odd: details is returning false despite block known:" << RLP(pdata); + clog(BlockChainDebug) << "Details is returning false despite block known:" << RLP(pdata); auto parentBlock = block(bi.parentHash); - cwarn << "Block:" << RLP(parentBlock); + clog(BlockChainDebug) << "Block:" << RLP(parentBlock); + clog(BlockChainDebug) << "DATABASE CORRUPTION: CRITICAL FAILURE"; + exit(-1); } // Check it's not crazy @@ -620,6 +622,14 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import cnote << "checkBest:" << checkBest; #endif + if (isKnown(bi.hash()) && !details(bi.hash())) + { + clog(BlockChainDebug) << "Known block just inserted has no details."; + clog(BlockChainDebug) << "Block:" << bi; + clog(BlockChainDebug) << "DATABASE CORRUPTION: CRITICAL FAILURE"; + exit(-1); + } + h256s fresh; h256s dead; bool isOld = true; diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 0529e305e..70a9f93db 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -59,6 +59,7 @@ struct FutureTime: virtual Exception {}; struct BlockChainChat: public LogChannel { static const char* name() { return "-B-"; } static const int verbosity = 7; }; struct BlockChainNote: public LogChannel { static const char* name() { return "=B="; } static const int verbosity = 4; }; struct BlockChainWarn: public LogChannel { static const char* name() { return "=B="; } static const int verbosity = 1; }; +struct BlockChainDebug: public LogChannel { static const char* name() { return "#B#"; } static const int verbosity = 0; }; // TODO: Move all this Genesis stuff into Genesis.h/.cpp std::map const& genesisState(); diff --git a/libethereum/EthereumPeer.cpp b/libethereum/EthereumPeer.cpp index 83fe22a71..9fbbdd61e 100644 --- a/libethereum/EthereumPeer.cpp +++ b/libethereum/EthereumPeer.cpp @@ -405,6 +405,13 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r) { unsigned count = _r.itemCount(); clog(NetMessageSummary) << "GetBlocks (" << dec << count << "entries)"; + + if (!count) + { + clog(NetImpolite) << "Zero-entry GetBlocks: Not replying."; + addRating(-10); + break; + } // return the requested blocks. bytes rlp; unsigned n = 0; diff --git a/libp2p/Common.h b/libp2p/Common.h index 9ad5bb206..691ef7fb3 100644 --- a/libp2p/Common.h +++ b/libp2p/Common.h @@ -77,6 +77,7 @@ struct InvalidHostIPAddress: virtual dev::Exception {}; struct NetWarn: public LogChannel { static const char* name() { return "!N!"; } static const int verbosity = 0; }; struct NetNote: public LogChannel { static const char* name() { return "*N*"; } static const int verbosity = 1; }; +struct NetImpolite: public LogChannel { static const char* name() { return "#!*"; } static const int verbosity = 1; }; struct NetMessageSummary: public LogChannel { static const char* name() { return "-N-"; } static const int verbosity = 2; }; struct NetConnect: public LogChannel { static const char* name() { return "+N+"; } static const int verbosity = 10; }; struct NetMessageDetail: public LogChannel { static const char* name() { return "=N="; } static const int verbosity = 5; }; From 292c35ce49a2165c9527e2d207cb9edf50d40b3b Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 19 Apr 2015 13:19:15 +0200 Subject: [PATCH 48/65] Don't grab queue up blocks we already know about. --- libethcore/Common.h | 3 ++- libethereum/BlockQueue.h | 3 +++ libethereum/EthereumPeer.cpp | 5 ++++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/libethcore/Common.h b/libethcore/Common.h index 199057f91..789390033 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -90,7 +90,8 @@ enum class ImportResult AlreadyInChain, AlreadyKnown, Malformed, - BadChain + BadChain, + Unknown }; struct ImportRequirements diff --git a/libethereum/BlockQueue.h b/libethereum/BlockQueue.h index 631877292..47370221a 100644 --- a/libethereum/BlockQueue.h +++ b/libethereum/BlockQueue.h @@ -86,6 +86,9 @@ public: /// Get some infomration on the current status. BlockQueueStatus status() const { ReadGuard l(m_lock); return BlockQueueStatus{m_ready.size(), m_future.size(), m_unknown.size(), m_knownBad.size()}; } + /// Get some infomration on the given block's status regarding us. + ImportResult blockStatus(h256 const& _h) const { ReadGuard l(m_lock); return m_readySet.count(_h) || m_drainingSet.count(_h) ? ImportResult::AlreadyKnown : m_unknownSet.count(_h) ? ImportResult::UnknownParent : m_knownBad.count(_h) ? ImportResult::BadChain : ImportResult::Unknown; } + template Handler onReady(T const& _t) { return m_onReady.add(_t); } private: diff --git a/libethereum/EthereumPeer.cpp b/libethereum/EthereumPeer.cpp index 9fbbdd61e..3a9879ac6 100644 --- a/libethereum/EthereumPeer.cpp +++ b/libethereum/EthereumPeer.cpp @@ -389,7 +389,7 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r) { addRating(1); auto h = _r[i].toHash(); - if (host()->m_chain.isKnown(h)) + if (host()->m_bq.blockStatus(h) != ImportResult::Unknown || host()->m_chain.isKnown(h)) { transition(Asking::Blocks); return true; @@ -484,6 +484,8 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r) case ImportResult::UnknownParent: unknown++; break; + + default:; } } else @@ -535,6 +537,7 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r) clog(NetMessageSummary) << "Received block with no known parent. Resyncing..."; setNeedsSyncing(h, _r[1].toInt()); break; + default:; } Guard l(x_knownBlocks); From cb9e3189e16620ab6f004a9ec7b7eb08af3529b2 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 19 Apr 2015 14:51:19 +0200 Subject: [PATCH 49/65] Additional activity reporting. --- libdevcore/CommonIO.h | 2 +- libethereum/BlockQueue.cpp | 32 +++++++++++++++++++++++++++----- libethereum/Client.cpp | 10 ++++++++++ libethereum/Client.h | 12 ++++++++++++ 4 files changed, 50 insertions(+), 6 deletions(-) diff --git a/libdevcore/CommonIO.h b/libdevcore/CommonIO.h index 3889f6171..7fe86627d 100644 --- a/libdevcore/CommonIO.h +++ b/libdevcore/CommonIO.h @@ -76,7 +76,7 @@ template inline std::ostream& operator<<(std::ostream& _out, template inline std::ostream& operator<<(std::ostream& _out, std::multimap const& _e); template _S& operator<<(_S& _out, std::shared_ptr<_T> const& _p); -template inline std::string toString(std::chrono::time_point const& _e, std::string _format = "") +template inline std::string toString(std::chrono::time_point const& _e, std::string _format = "%F %T") { unsigned long milliSecondsSinceEpoch = std::chrono::duration_cast(_e.time_since_epoch()).count(); auto const durationSinceEpoch = std::chrono::milliseconds(milliSecondsSinceEpoch); diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index 70ea8753b..6a6a68bfa 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -74,7 +74,11 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo if (bi.timestamp > (u256)time(0)/* && !_isOurs*/) { m_future.insert(make_pair((unsigned)bi.timestamp, _block.toBytes())); - cblockq << "OK - queued for future."; + char buf[24]; + time_t bit = (unsigned)bi.timestamp; + if (strftime(buf, 24, "%X", localtime(&bit)) == 0) + buf[0] = '\0'; // empty if case strftime fails + cblockq << "OK - queued for future [" << bi.timestamp << "vs" << time(0) << "] - will wait until" << buf; return ImportResult::FutureTime; } else @@ -132,12 +136,30 @@ bool BlockQueue::doneDrain(h256s const& _bad) void BlockQueue::tick(BlockChain const& _bc) { + if (m_future.empty()) + return; + + cblockq << "Checking past-future blocks..."; + unsigned t = time(0); - for (auto i = m_future.begin(); i != m_future.end() && i->first < t; ++i) - import(&(i->second), _bc); + if (t < m_future.begin()->first) + return; - WriteGuard l(m_lock); - m_future.erase(m_future.begin(), m_future.upper_bound(t)); + cblockq << "Past-future blocks ready."; + + vector todo; + { + WriteGuard l(m_lock); + auto end = m_future.upper_bound(t); + for (auto i = m_future.begin(); i != end; ++i) + todo.push_back(move(i->second)); + m_future.erase(m_future.begin(), end); + } + + cblockq << "Importing" << todo.size() << "past-future blocks."; + + for (auto const& b: todo) + import(&b, _bc); } template T advanced(T _t, unsigned _n) diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index b4b92c713..52adb613a 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -117,6 +117,13 @@ void BasicGasPricer::update(BlockChain const& _bc) } } +std::ostream& dev::eth::operator<<(std::ostream& _out, ActivityReport const& _r) +{ + _out << "Since " << toString(_r.since) << " (" << std::chrono::duration_cast(std::chrono::system_clock::now() - _r.since).count(); + _out << "): " << _r.ticks << "ticks"; + return _out; +} + Client::Client(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId): Worker("eth"), m_vc(_dbPath), @@ -582,9 +589,12 @@ void Client::tick() { if (chrono::system_clock::now() - m_lastTick > chrono::seconds(1)) { + m_report.ticks++; checkWatchGarbage(); m_bq.tick(m_bc); m_lastTick = chrono::system_clock::now(); + if (m_report.ticks == 15) + cnote << activityReport(); } } diff --git a/libethereum/Client.h b/libethereum/Client.h index 5bab1a76e..96afe0030 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -97,6 +97,14 @@ struct ClientChat: public LogChannel { static const char* name() { return "=C="; struct ClientTrace: public LogChannel { static const char* name() { return "-C-"; } static const int verbosity = 7; }; struct ClientDetail: public LogChannel { static const char* name() { return " C "; } static const int verbosity = 14; }; +struct ActivityReport +{ + unsigned ticks = 0; + std::chrono::system_clock::time_point since = std::chrono::system_clock::now(); +}; + +std::ostream& operator<<(std::ostream& _out, ActivityReport const& _r); + /** * @brief Main API hub for interfacing with Ethereum. */ @@ -204,6 +212,8 @@ public: void killChain(); /// Retries all blocks with unknown parents. void retryUnkonwn() { m_bq.retryAllUnknown(); } + /// Get a report of activity. + ActivityReport activityReport() { ActivityReport ret; std::swap(m_report, ret); return ret; } protected: /// InterfaceStub methods @@ -295,6 +305,8 @@ private: mutable std::chrono::system_clock::time_point m_lastTick = std::chrono::system_clock::now(); ///< When did we last tick()? + ActivityReport m_report; + // TODO!!!!!! REPLACE WITH A PROPER X-THREAD ASIO SIGNAL SYSTEM (could just be condition variables) std::atomic m_syncTransactionQueue = {false}; std::atomic m_syncBlockQueue = {false}; From 6b8b94fda06edcd8d8987cb18ed0218a34e9b57a Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 19 Apr 2015 15:53:37 +0200 Subject: [PATCH 50/65] Fix subsequence side bug. --- libethereum/BlockQueue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index 6a6a68bfa..844fbf632 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -150,7 +150,7 @@ void BlockQueue::tick(BlockChain const& _bc) vector todo; { WriteGuard l(m_lock); - auto end = m_future.upper_bound(t); + auto end = m_future.lower_bound(t); for (auto i = m_future.begin(); i != end; ++i) todo.push_back(move(i->second)); m_future.erase(m_future.begin(), end); From 2d72554db9f0dee1b7ed05da79098228b0a41372 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 19 Apr 2015 16:26:51 +0200 Subject: [PATCH 51/65] Pesky <= bug fixed. --- libethereum/BlockQueue.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index 844fbf632..06fa3dd2b 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -136,20 +136,21 @@ bool BlockQueue::doneDrain(h256s const& _bad) void BlockQueue::tick(BlockChain const& _bc) { + UpgradableGuard l(m_lock); if (m_future.empty()) return; cblockq << "Checking past-future blocks..."; unsigned t = time(0); - if (t < m_future.begin()->first) + if (t <= m_future.begin()->first) return; cblockq << "Past-future blocks ready."; vector todo; { - WriteGuard l(m_lock); + UpgradeGuard l2(l); auto end = m_future.lower_bound(t); for (auto i = m_future.begin(); i != end; ++i) todo.push_back(move(i->second)); From 05227444ea29c24a8703aec9fe21e182afc28774 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 19 Apr 2015 16:27:24 +0200 Subject: [PATCH 52/65] Version bump. --- libdevcore/Common.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libdevcore/Common.cpp b/libdevcore/Common.cpp index 230c9e4ff..1f0d188fa 100644 --- a/libdevcore/Common.cpp +++ b/libdevcore/Common.cpp @@ -27,7 +27,7 @@ using namespace dev; namespace dev { -char const* Version = "0.9.11"; +char const* Version = "0.9.12"; } From e1797817284706ab0d134a094adfac464b182d98 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 19 Apr 2015 17:08:25 +0200 Subject: [PATCH 53/65] More sophisticated (and correct) BlockHashes handling. --- libdevcore/RLP.cpp | 15 +++++++++++++++ libdevcore/RLP.h | 7 ++++++- libethcore/Common.h | 3 +-- libethereum/BlockChain.cpp | 2 +- libethereum/BlockQueue.cpp | 15 +++++++++++++++ libethereum/BlockQueue.h | 11 ++++++++++- libethereum/EthereumPeer.cpp | 11 +++++++++-- 7 files changed, 57 insertions(+), 7 deletions(-) diff --git a/libdevcore/RLP.cpp b/libdevcore/RLP.cpp index 994aac265..25e843c77 100644 --- a/libdevcore/RLP.cpp +++ b/libdevcore/RLP.cpp @@ -111,10 +111,24 @@ unsigned RLP::actualSize() const return 0; } +void RLP::requireGood() const +{ + if (isNull()) + BOOST_THROW_EXCEPTION(BadRLP()); + byte n = m_data[0]; + if (n != c_rlpDataImmLenStart + 1) + return; + if (m_data.size() < 2) + BOOST_THROW_EXCEPTION(BadRLP()); + if (m_data[1] < c_rlpDataImmLenStart) + BOOST_THROW_EXCEPTION(BadRLP()); +} + bool RLP::isInt() const { if (isNull()) return false; + requireGood(); byte n = m_data[0]; if (n < c_rlpDataImmLenStart) return !!n; @@ -141,6 +155,7 @@ unsigned RLP::length() const { if (isNull()) return 0; + requireGood(); unsigned ret = 0; byte n = m_data[0]; if (n < c_rlpDataImmLenStart) diff --git a/libdevcore/RLP.h b/libdevcore/RLP.h index caaf10b6a..c99d1a358 100644 --- a/libdevcore/RLP.h +++ b/libdevcore/RLP.h @@ -253,6 +253,7 @@ public: /// Converts to int of type given; if isString(), decodes as big-endian bytestream. @returns 0 if not an int or string. template _T toInt(int _flags = Strict) const { + requireGood(); if ((!isInt() && !(_flags & AllowNonCanon)) || isList() || isNull()) if (_flags & ThrowOnFail) BOOST_THROW_EXCEPTION(BadCast()); @@ -273,6 +274,7 @@ public: template _N toHash(int _flags = Strict) const { + requireGood(); if (!isData() || (length() > _N::size && (_flags & FailIfTooBig)) || (length() < _N::size && (_flags & FailIfTooSmall))) if (_flags & ThrowOnFail) BOOST_THROW_EXCEPTION(BadCast()); @@ -290,7 +292,7 @@ public: RLPs toList() const; /// @returns the data payload. Valid for all types. - bytesConstRef payload() const { return m_data.cropped(payloadOffset()); } + bytesConstRef payload() const { auto l = length(); if (l > m_data.size()) throw BadRLP(); return m_data.cropped(payloadOffset(), l); } /// @returns the theoretical size of this item. /// @note Under normal circumstances, is equivalent to m_data.size() - use that unless you know it won't work. @@ -300,6 +302,9 @@ private: /// Disable construction from rvalue explicit RLP(bytes const&&) {} + /// Throws if is non-canonical data (i.e. single byte done in two bytes that could be done in one). + void requireGood() const; + /// Single-byte data payload. bool isSingleByte() const { return !isNull() && m_data[0] < c_rlpDataImmLenStart; } diff --git a/libethcore/Common.h b/libethcore/Common.h index 789390033..199057f91 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -90,8 +90,7 @@ enum class ImportResult AlreadyInChain, AlreadyKnown, Malformed, - BadChain, - Unknown + BadChain }; struct ImportRequirements diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 352739626..2e089dd3b 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -310,7 +310,7 @@ tuple BlockChain::sync(BlockQueue& _bq, OverlayDB const& _st fresh += r.first; dead += r.second; } - catch (UnknownParent) + catch (dev::eth::UnknownParent) { cwarn << "ODD: Import queue contains block with unknown parent." << boost::current_exception_diagnostic_information(); // NOTE: don't reimport since the queue should guarantee everything in the right order. diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index 06fa3dd2b..153d11ac4 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -169,6 +169,21 @@ template T advanced(T _t, unsigned _n) return _t; } +QueueStatus BlockQueue::blockStatus(h256 const& _h) const +{ + ReadGuard l(m_lock); + return + m_readySet.count(_h) ? + QueueStatus::Ready : + m_drainingSet.count(_h) ? + QueueStatus::Importing : + m_unknownSet.count(_h) ? + QueueStatus::UnknownParent : + m_knownBad.count(_h) ? + QueueStatus::Bad : + QueueStatus::Unknown; +} + void BlockQueue::drain(std::vector& o_out, unsigned _max) { WriteGuard l(m_lock); diff --git a/libethereum/BlockQueue.h b/libethereum/BlockQueue.h index 47370221a..1932b2f66 100644 --- a/libethereum/BlockQueue.h +++ b/libethereum/BlockQueue.h @@ -46,6 +46,15 @@ struct BlockQueueStatus size_t bad; }; +enum class QueueStatus +{ + Ready, + Importing, + UnknownParent, + Bad, + Unknown +}; + /** * @brief A queue of blocks. Sits between network or other I/O and the BlockChain. * Sorts them ready for blockchain insertion (with the BlockChain::sync() method). @@ -87,7 +96,7 @@ public: BlockQueueStatus status() const { ReadGuard l(m_lock); return BlockQueueStatus{m_ready.size(), m_future.size(), m_unknown.size(), m_knownBad.size()}; } /// Get some infomration on the given block's status regarding us. - ImportResult blockStatus(h256 const& _h) const { ReadGuard l(m_lock); return m_readySet.count(_h) || m_drainingSet.count(_h) ? ImportResult::AlreadyKnown : m_unknownSet.count(_h) ? ImportResult::UnknownParent : m_knownBad.count(_h) ? ImportResult::BadChain : ImportResult::Unknown; } + QueueStatus blockStatus(h256 const& _h) const; template Handler onReady(T const& _t) { return m_onReady.add(_t); } diff --git a/libethereum/EthereumPeer.cpp b/libethereum/EthereumPeer.cpp index 3a9879ac6..4d50a12ae 100644 --- a/libethereum/EthereumPeer.cpp +++ b/libethereum/EthereumPeer.cpp @@ -389,12 +389,19 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r) { addRating(1); auto h = _r[i].toHash(); - if (host()->m_bq.blockStatus(h) != ImportResult::Unknown || host()->m_chain.isKnown(h)) + auto status = host()->m_bq.blockStatus(h); + if (status == QueueStatus::Importing || status == QueueStatus::Ready || host()->m_chain.isKnown(h)) { transition(Asking::Blocks); return true; } - else + else if (status == QueueStatus::Bad) + { + cwarn << "BAD hash chain discovered. Ignoring."; + transition(Asking::Nothing); + return true; + } + else if (status == QueueStatus::Unknown) m_syncingNeededBlocks.push_back(h); } // run through - ask for more. From bd2a0e6026c104ecb42518dab37a6363b20c297d Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 19 Apr 2015 17:31:56 +0200 Subject: [PATCH 54/65] Minor fix for integration tests. --- test/stateOriginal.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/stateOriginal.cpp b/test/stateOriginal.cpp index e1a3c7c4a..7f3371484 100644 --- a/test/stateOriginal.cpp +++ b/test/stateOriginal.cpp @@ -60,7 +60,7 @@ BOOST_AUTO_TEST_CASE(Complex) CanonBlockChain bc; cout << bc; - State s(stateDB, BaseState::Empty, myMiner.address()); + State s(stateDB, BaseState::CanonGenesis, myMiner.address()); cout << s; // Sync up - this won't do much until we use the last state. @@ -80,7 +80,7 @@ BOOST_AUTO_TEST_CASE(Complex) cout << s; // Inject a transaction to transfer funds from miner to me. - Transaction t(1000, 10000, 10000, me.address(), bytes(), s.transactionsFrom(myMiner.address()), myMiner.secret()); + Transaction t(1000, 10000, 100000, me.address(), bytes(), s.transactionsFrom(myMiner.address()), myMiner.secret()); assert(t.sender() == myMiner.address()); s.execute(bc.lastHashes(), t); From de138069628299c1535aded56b40b7bc8cdb2e09 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 19 Apr 2015 18:15:20 +0200 Subject: [PATCH 55/65] Avoid deadlock when have past future blocks. --- libethereum/BlockQueue.cpp | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index 153d11ac4..4fd63aa86 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -136,27 +136,28 @@ bool BlockQueue::doneDrain(h256s const& _bad) void BlockQueue::tick(BlockChain const& _bc) { - UpgradableGuard l(m_lock); - if (m_future.empty()) - return; + vector todo; + { + UpgradableGuard l(m_lock); + if (m_future.empty()) + return; - cblockq << "Checking past-future blocks..."; + cblockq << "Checking past-future blocks..."; - unsigned t = time(0); - if (t <= m_future.begin()->first) - return; + unsigned t = time(0); + if (t <= m_future.begin()->first) + return; - cblockq << "Past-future blocks ready."; + cblockq << "Past-future blocks ready."; - vector todo; - { - UpgradeGuard l2(l); - auto end = m_future.lower_bound(t); - for (auto i = m_future.begin(); i != end; ++i) - todo.push_back(move(i->second)); - m_future.erase(m_future.begin(), end); + { + UpgradeGuard l2(l); + auto end = m_future.lower_bound(t); + for (auto i = m_future.begin(); i != end; ++i) + todo.push_back(move(i->second)); + m_future.erase(m_future.begin(), end); + } } - cblockq << "Importing" << todo.size() << "past-future blocks."; for (auto const& b: todo) From 5a9a59a91b038d8ca69ca9ba37a034cd6da33a67 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 19 Apr 2015 18:41:47 +0200 Subject: [PATCH 56/65] Fix unordered sync issue. --- libethereum/EthereumPeer.cpp | 14 ++++++++++++-- libethereum/EthereumPeer.h | 1 + 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/libethereum/EthereumPeer.cpp b/libethereum/EthereumPeer.cpp index 4d50a12ae..d730771a0 100644 --- a/libethereum/EthereumPeer.cpp +++ b/libethereum/EthereumPeer.cpp @@ -121,7 +121,7 @@ void EthereumPeer::transition(Asking _a, bool _force) clog(NetWarn) << "Bad state: asking for Hashes yet not syncing!"; setAsking(_a, true); - prep(s, GetBlockHashesPacket, 2) << m_syncingNeededBlocks.back() << c_maxHashesAsk; + prep(s, GetBlockHashesPacket, 2) << m_syncingLastReceivedHash << c_maxHashesAsk; sealAndSend(s); return; } @@ -385,6 +385,8 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r) transition(Asking::Blocks); return true; } + unsigned knowns = 0; + unsigned unknowns = 0; for (unsigned i = 0; i < _r.itemCount(); ++i) { addRating(1); @@ -392,18 +394,26 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r) auto status = host()->m_bq.blockStatus(h); if (status == QueueStatus::Importing || status == QueueStatus::Ready || host()->m_chain.isKnown(h)) { + clog(NetMessageSummary) << "block hash ready:" << h << ". Start blocks download..."; transition(Asking::Blocks); return true; } else if (status == QueueStatus::Bad) { - cwarn << "BAD hash chain discovered. Ignoring."; + cwarn << "block hash bad!" << h << ". Bailing..."; transition(Asking::Nothing); return true; } else if (status == QueueStatus::Unknown) + { + unknowns++; m_syncingNeededBlocks.push_back(h); + } + else + knowns++; + m_syncingLastReceivedHash = h; } + clog(NetMessageSummary) << knowns << "knowns," << unknowns << "unknowns; now at" << m_syncingLastReceivedHash.abridged(); // run through - ask for more. transition(Asking::Hashes); break; diff --git a/libethereum/EthereumPeer.h b/libethereum/EthereumPeer.h index da144134b..a80d5dadd 100644 --- a/libethereum/EthereumPeer.h +++ b/libethereum/EthereumPeer.h @@ -129,6 +129,7 @@ private: /// This is built as we ask for hashes. Once no more hashes are given, we present this to the /// host who initialises the DownloadMan and m_sub becomes active for us to begin asking for blocks. h256s m_syncingNeededBlocks; ///< The blocks that we should download from this peer. + h256 m_syncingLastReceivedHash; ///< Hash more recently received from peer. h256 m_syncingLatestHash; ///< Peer's latest block's hash, as of the current sync. u256 m_syncingTotalDifficulty; ///< Peer's latest block's total difficulty, as of the current sync. From 4708a73e19314c260298fdb8533ec6c5bbdeea02 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 19 Apr 2015 22:59:57 +0200 Subject: [PATCH 57/65] Remote miner fixes. --- eth/Farm.h | 3 +- eth/farm.json | 2 +- eth/main.cpp | 61 ++++++++++++++------- libdevcore/Worker.cpp | 3 +- libethcore/Ethash.cpp | 5 +- libethereum/CommonNet.h | 12 ++-- libweb3jsonrpc/WebThreeStubServerBase.cpp | 2 +- libweb3jsonrpc/WebThreeStubServerBase.h | 2 +- libweb3jsonrpc/abstractwebthreestubserver.h | 6 +- libweb3jsonrpc/spec.json | 2 +- test/webthreestubclient.h | 3 +- 11 files changed, 63 insertions(+), 38 deletions(-) diff --git a/eth/Farm.h b/eth/Farm.h index c061449e3..ae2ef5a7d 100644 --- a/eth/Farm.h +++ b/eth/Farm.h @@ -22,11 +22,12 @@ class Farm : public jsonrpc::Client else throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); } - bool eth_submitWork(const std::string& param1, const std::string& param2) throw (jsonrpc::JsonRpcException) + bool eth_submitWork(const std::string& param1, const std::string& param2, const std::string& param3) throw (jsonrpc::JsonRpcException) { Json::Value p; p.append(param1); p.append(param2); + p.append(param3); Json::Value result = this->CallMethod("eth_submitWork",p); if (result.isBool()) return result.asBool(); diff --git a/eth/farm.json b/eth/farm.json index 24f0c163e..1f4142d00 100644 --- a/eth/farm.json +++ b/eth/farm.json @@ -1,4 +1,4 @@ [ { "name": "eth_getWork", "params": [], "order": [], "returns": []}, - { "name": "eth_submitWork", "params": ["", ""], "order": [], "returns": true} + { "name": "eth_submitWork", "params": ["", "", ""], "order": [], "returns": true} ] diff --git a/eth/main.cpp b/eth/main.cpp index f47243972..a85e14485 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -339,6 +339,9 @@ void doBenchmark(MinerType _m, bool _phoneHome, unsigned _warmupDuration = 15, u exit(0); } +struct HappyChannel: public LogChannel { static const char* name() { return ":-D"; } static const int verbosity = 1; }; +struct SadChannel: public LogChannel { static const char* name() { return ":-("; } static const int verbosity = 1; }; + void doFarm(MinerType _m, string const& _remote, unsigned _recheckPeriod) { (void)_m; @@ -347,9 +350,7 @@ void doFarm(MinerType _m, string const& _remote, unsigned _recheckPeriod) #if ETH_JSONRPC || !ETH_TRUE jsonrpc::HttpClient client(_remote); Farm rpc(client); - GenericFarm f; - if (_m == MinerType::CPU) f.startCPU(); else if (_m == MinerType::GPU) @@ -357,29 +358,47 @@ void doFarm(MinerType _m, string const& _remote, unsigned _recheckPeriod) ProofOfWork::WorkPackage current; while (true) - { - bool completed = false; - ProofOfWork::Solution solution; - f.onSolutionFound([&](ProofOfWork::Solution sol) - { - solution = sol; - return completed = true; - }); - for (unsigned i = 0; !completed; ++i) + try { - Json::Value v = rpc.eth_getWork(); - h256 hh(v[0].asString()); - if (hh != current.headerHash) + bool completed = false; + ProofOfWork::Solution solution; + f.onSolutionFound([&](ProofOfWork::Solution sol) + { + solution = sol; + return completed = true; + }); + for (unsigned i = 0; !completed; ++i) { - current.headerHash = hh; - current.seedHash = h256(v[1].asString()); - current.boundary = h256(v[2].asString()); - f.setWork(current); + if (current) + cnote << "Mining on PoWhash" << current.headerHash.abridged() << ": " << f.miningProgress(); + else + cnote << "Getting work package..."; + Json::Value v = rpc.eth_getWork(); + h256 hh(v[0].asString()); + if (hh != current.headerHash) + { + current.headerHash = hh; + current.seedHash = h256(v[1].asString()); + current.boundary = h256(v[2].asString()); + cnote << "Got new work package."; + f.setWork(current); + } + this_thread::sleep_for(chrono::milliseconds(_recheckPeriod)); } - this_thread::sleep_for(chrono::milliseconds(_recheckPeriod)); + cnote << "Solution found; submitting [" << solution.nonce << "," << current.headerHash.abridged() << "," << solution.mixHash.abridged() << "] to" << _remote << "..."; + bool ok = rpc.eth_submitWork("0x" + toString(solution.nonce), "0x" + toString(current.headerHash), "0x" + toString(solution.mixHash)); + if (ok) + clog(HappyChannel) << "Submitted and accepted."; + else + clog(SadChannel) << "Not accepted."; + current.reset(); + } + catch (jsonrpc::JsonRpcException&) + { + for (auto i = 10; --i; this_thread::sleep_for(chrono::seconds(1))) + cerr << "JSON-RPC problem. Probably couldn't connect. Retrying in " << i << "... \r"; + cerr << endl; } - rpc.eth_submitWork("0x" + toString(solution.nonce), "0x" + toString(solution.mixHash)); - } #endif exit(0); } diff --git a/libdevcore/Worker.cpp b/libdevcore/Worker.cpp index 19c0d9751..7fe320420 100644 --- a/libdevcore/Worker.cpp +++ b/libdevcore/Worker.cpp @@ -43,8 +43,9 @@ void Worker::startWorking() m_state.compare_exchange_strong(ex, WorkerState::Started); startedWorking(); + cnote << "Entering work loop..."; workLoop(); - cnote << "Finishing up worker thread"; + cnote << "Finishing up worker thread..."; doneWorking(); // ex = WorkerState::Stopping; diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index c61529017..7ff35fd2b 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -314,7 +314,10 @@ void Ethash::GPUMiner::workLoop() uint64_t upper64OfBoundary = (uint64_t)(u64)((u256)w.boundary >> 192); m_miner->search(w.headerHash.data(), upper64OfBoundary, *m_hook); } - catch (...) {} + catch (...) + { + cwarn << "Error GPU mining. GPU memory fragmentation?"; + } } void Ethash::GPUMiner::pause() diff --git a/libethereum/CommonNet.h b/libethereum/CommonNet.h index 2ee260650..2083e9919 100644 --- a/libethereum/CommonNet.h +++ b/libethereum/CommonNet.h @@ -37,13 +37,13 @@ namespace eth { #if ETH_DEBUG -static const unsigned c_maxHashes = 64; ///< Maximum number of hashes BlockHashes will ever send. -static const unsigned c_maxHashesAsk = 64; ///< Maximum number of hashes GetBlockHashes will ever ask for. -static const unsigned c_maxBlocks = 32; ///< Maximum number of blocks Blocks will ever send. -static const unsigned c_maxBlocksAsk = 32; ///< Maximum number of blocks we ask to receive in Blocks (when using GetChain). +static const unsigned c_maxHashes = 2048; ///< Maximum number of hashes BlockHashes will ever send. +static const unsigned c_maxHashesAsk = 2048; ///< Maximum number of hashes GetBlockHashes will ever ask for. +static const unsigned c_maxBlocks = 128; ///< Maximum number of blocks Blocks will ever send. +static const unsigned c_maxBlocksAsk = 128; ///< Maximum number of blocks we ask to receive in Blocks (when using GetChain). #else -static const unsigned c_maxHashes = 256; ///< Maximum number of hashes BlockHashes will ever send. -static const unsigned c_maxHashesAsk = 256; ///< Maximum number of hashes GetBlockHashes will ever ask for. +static const unsigned c_maxHashes = 2048; ///< Maximum number of hashes BlockHashes will ever send. +static const unsigned c_maxHashesAsk = 2048; ///< Maximum number of hashes GetBlockHashes will ever ask for. static const unsigned c_maxBlocks = 128; ///< Maximum number of blocks Blocks will ever send. static const unsigned c_maxBlocksAsk = 128; ///< Maximum number of blocks we ask to receive in Blocks (when using GetChain). #endif diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index 7fc68c27f..212f3728b 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -775,7 +775,7 @@ Json::Value WebThreeStubServerBase::eth_getWork() return ret; } -bool WebThreeStubServerBase::eth_submitWork(string const& _nonce, string const& _mixHash) +bool WebThreeStubServerBase::eth_submitWork(string const& _nonce, string const&, string const& _mixHash) { try { diff --git a/libweb3jsonrpc/WebThreeStubServerBase.h b/libweb3jsonrpc/WebThreeStubServerBase.h index 22a31a762..9180c8ef7 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.h +++ b/libweb3jsonrpc/WebThreeStubServerBase.h @@ -113,7 +113,7 @@ public: virtual Json::Value eth_getFilterLogs(std::string const& _filterId); virtual Json::Value eth_getLogs(Json::Value const& _json); virtual Json::Value eth_getWork(); - virtual bool eth_submitWork(std::string const& _nonce, std::string const& _mixHash); + virtual bool eth_submitWork(std::string const& _nonce, std::string const&, std::string const& _mixHash); virtual std::string eth_register(std::string const& _address); virtual bool eth_unregister(std::string const& _accountId); virtual Json::Value eth_fetchQueuedTransactions(std::string const& _accountId); diff --git a/libweb3jsonrpc/abstractwebthreestubserver.h b/libweb3jsonrpc/abstractwebthreestubserver.h index 0860ecaee..8da47d0fc 100644 --- a/libweb3jsonrpc/abstractwebthreestubserver.h +++ b/libweb3jsonrpc/abstractwebthreestubserver.h @@ -53,7 +53,7 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServerbindAndAddMethod(jsonrpc::Procedure("eth_getFilterLogs", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getFilterLogsI); this->bindAndAddMethod(jsonrpc::Procedure("eth_getLogs", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::eth_getLogsI); this->bindAndAddMethod(jsonrpc::Procedure("eth_getWork", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, NULL), &AbstractWebThreeStubServer::eth_getWorkI); - this->bindAndAddMethod(jsonrpc::Procedure("eth_submitWork", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_submitWorkI); + this->bindAndAddMethod(jsonrpc::Procedure("eth_submitWork", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING,"param3",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_submitWorkI); this->bindAndAddMethod(jsonrpc::Procedure("eth_register", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_registerI); this->bindAndAddMethod(jsonrpc::Procedure("eth_unregister", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_unregisterI); this->bindAndAddMethod(jsonrpc::Procedure("eth_fetchQueuedTransactions", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_fetchQueuedTransactionsI); @@ -250,7 +250,7 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServereth_submitWork(request[0u].asString(), request[1u].asString()); + response = this->eth_submitWork(request[0u].asString(), request[1u].asString(), request[2u].asString()); } inline virtual void eth_registerI(const Json::Value &request, Json::Value &response) { @@ -350,7 +350,7 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServerCallMethod("eth_submitWork",p); if (result.isBool()) return result.asBool(); From 3efa477be69519da7a0b672e6bade40b564e2994 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 20 Apr 2015 00:13:08 +0200 Subject: [PATCH 58/65] Avoid div by zero. Always prepare work, even when not apparently mining. --- eth/main.cpp | 6 +++--- libethcore/BlockInfo.cpp | 2 +- libethcore/Miner.h | 6 ++++++ libethereum/Client.cpp | 6 +++--- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/eth/main.cpp b/eth/main.cpp index a85e14485..0344e66d6 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -379,8 +379,8 @@ void doFarm(MinerType _m, string const& _remote, unsigned _recheckPeriod) { current.headerHash = hh; current.seedHash = h256(v[1].asString()); - current.boundary = h256(v[2].asString()); - cnote << "Got new work package."; + current.boundary = h256(fromHex(v[2].asString()), h256::AlignRight); + cnote << "Got work package:" << current.headerHash.abridged() << " < " << current.boundary; f.setWork(current); } this_thread::sleep_for(chrono::milliseconds(_recheckPeriod)); @@ -395,7 +395,7 @@ void doFarm(MinerType _m, string const& _remote, unsigned _recheckPeriod) } catch (jsonrpc::JsonRpcException&) { - for (auto i = 10; --i; this_thread::sleep_for(chrono::seconds(1))) + for (auto i = 3; --i; this_thread::sleep_for(chrono::seconds(1))) cerr << "JSON-RPC problem. Probably couldn't connect. Retrying in " << i << "... \r"; cerr << endl; } diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index b45bdc57e..e9ce070dc 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -77,7 +77,7 @@ h256 const& BlockInfo::hash() const h256 const& BlockInfo::boundary() const { - if (!m_boundary) + if (!m_boundary && difficulty) m_boundary = (h256)(u256)((bigint(1) << 256) / difficulty); return m_boundary; } diff --git a/libethcore/Miner.h b/libethcore/Miner.h index 71e952d5c..3a68491ff 100644 --- a/libethcore/Miner.h +++ b/libethcore/Miner.h @@ -24,7 +24,9 @@ #include #include #include +#include #include +#include #include #include @@ -105,8 +107,12 @@ public: } if (!!_work) { + boost::timer t; pause(); + cdebug << "pause took" << t.elapsed(); + t.restart(); kickOff(); + cdebug << "kickOff took" << t.elapsed(); } else if (!_work && !!old) pause(); diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 2c53bf81c..d84acf42f 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -530,15 +530,15 @@ void Client::onChainChanged(ImportRoute const& _ir) void Client::onPostStateChanged() { cnote << "Post state changed: Restarting mining..."; - if (isMining()) - { +// if (isMining()) +// { { WriteGuard l(x_postMine); m_postMine.commitToMine(m_bc); m_miningInfo = m_postMine.info(); } m_farm.setWork(m_miningInfo); - } +// } m_remoteWorking = false; } From 66a4752cf2e127b93b0cdb2c1ec52288edb4c55a Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 20 Apr 2015 01:09:13 +0200 Subject: [PATCH 59/65] Don't prep mining if no need. --- libethereum/Client.cpp | 12 +++++++++--- libethereum/Client.h | 4 +++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index d84acf42f..7ab4a99f4 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -408,6 +408,7 @@ ProofOfWork::WorkPackage Client::getWork() { // lock the work so a later submission isn't invalidated by processing a transaction elsewhere. // this will be reset as soon as a new block arrives, allowing more transactions to be processed. + m_lastGetWork = chrono::system_clock::now(); m_remoteWorking = true; return ProofOfWork::package(m_miningInfo); } @@ -527,18 +528,23 @@ void Client::onChainChanged(ImportRoute const& _ir) noteChanged(changeds); } +bool Client::remoteActive() const +{ + return chrono::system_clock::now() - m_lastGetWork < chrono::seconds(30); +} + void Client::onPostStateChanged() { cnote << "Post state changed: Restarting mining..."; -// if (isMining()) -// { + if (isMining() || remoteActive()) + { { WriteGuard l(x_postMine); m_postMine.commitToMine(m_bc); m_miningInfo = m_postMine.info(); } m_farm.setWork(m_miningInfo); -// } + } m_remoteWorking = false; } diff --git a/libethereum/Client.h b/libethereum/Client.h index 96afe0030..b1cfaf4ac 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -287,7 +287,9 @@ private: mutable SharedMutex x_postMine; ///< Lock on the OverlayDB and other attributes of m_postMine. State m_postMine; ///< The state of the client which we're mining (i.e. it'll have all the rewards added). BlockInfo m_miningInfo; ///< The header we're attempting to mine on (derived from m_postMine). - bool m_remoteWorking = false; ///< Is there an acive and valid remote worker? + bool remoteActive() const; ///< Is there an active and valid remote worker? + bool m_remoteWorking = false; ///< Has the remote worker recently been reset? + std::chrono::system_clock::time_point m_lastGetWork = std::chrono::system_clock::time_point::min(); ///< Is there an active and valid remote worker? std::weak_ptr m_host; ///< Our Ethereum Host. Don't do anything if we can't lock. From 4e4fc4d11cb20549e38ca90c2e0056f3d9a7d84e Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 20 Apr 2015 11:10:19 +0200 Subject: [PATCH 60/65] Fixes for reimporting. --- libethereum/BlockChain.cpp | 14 +++++++++----- libethereum/BlockChain.h | 4 ++-- libethereum/State.cpp | 8 ++++---- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 2e089dd3b..4e3349a31 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -218,7 +218,11 @@ void BlockChain::rebuild(std::string const& _path, std::functionPut(m_writeOptions, toSlice(m_lastBlockHash, ExtraDetails), (ldb::Slice)dev::ref(m_details[m_lastBlockHash].rlp())); + + h256 lastHash = m_lastBlockHash; boost::timer t; for (unsigned d = 1; d < originalNumber; ++d) { @@ -240,7 +244,7 @@ void BlockChain::rebuild(std::string const& _path, std::function (u256)time(0)) { - clog(BlockChainNote) << bi.hash() << ": Future time " << bi.timestamp << " (now at " << time(0) << ")"; + clog(BlockChainChat) << bi.hash() << ": Future time " << bi.timestamp << " (now at " << time(0) << ")"; // Block has a timestamp in the future. This is no good. BOOST_THROW_EXCEPTION(FutureTime()); } - clog(BlockChainNote) << "Attempting import of " << bi.hash().abridged() << "..."; + clog(BlockChainChat) << "Attempting import of " << bi.hash().abridged() << "..."; #if ETH_TIMED_IMPORTS preliminaryChecks = t.elapsed(); @@ -609,7 +613,7 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import } else { - clog(BlockChainNote) << " Imported but not best (oTD:" << details(last).totalDifficulty << " > TD:" << td << ")"; + clog(BlockChainChat) << " Imported but not best (oTD:" << details(last).totalDifficulty << " > TD:" << td << ")"; } #if ETH_TIMED_IMPORTS diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 70a9f93db..8061487d7 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -56,8 +56,8 @@ struct AlreadyHaveBlock: virtual Exception {}; struct UnknownParent: virtual Exception {}; struct FutureTime: virtual Exception {}; -struct BlockChainChat: public LogChannel { static const char* name() { return "-B-"; } static const int verbosity = 7; }; -struct BlockChainNote: public LogChannel { static const char* name() { return "=B="; } static const int verbosity = 4; }; +struct BlockChainChat: public LogChannel { static const char* name() { return "-B-"; } static const int verbosity = 5; }; +struct BlockChainNote: public LogChannel { static const char* name() { return "=B="; } static const int verbosity = 3; }; struct BlockChainWarn: public LogChannel { static const char* name() { return "=B="; } static const int verbosity = 1; }; struct BlockChainDebug: public LogChannel { static const char* name() { return "#B#"; } static const int verbosity = 0; }; diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 19cec8614..598dac37d 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -663,7 +663,7 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement uncle.verifyParent(uncleParent); nonces.insert(uncle.nonce); - tdIncrease += uncle.difficulty; +// tdIncrease += uncle.difficulty; rewarded.push_back(uncle); } @@ -704,15 +704,15 @@ void State::cleanup(bool _fullCommit) paranoia("immediately before database commit", true); // Commit the new trie to disk. - cnote << "Committing to disk: stateRoot" << m_currentBlock.stateRoot.abridged() << "=" << rootHash().abridged() << "=" << toHex(asBytes(m_db.lookup(rootHash()))); + clog(StateTrace) << "Committing to disk: stateRoot" << m_currentBlock.stateRoot.abridged() << "=" << rootHash().abridged() << "=" << toHex(asBytes(m_db.lookup(rootHash()))); m_db.commit(); - cnote << "Committed: stateRoot" << m_currentBlock.stateRoot.abridged() << "=" << rootHash().abridged() << "=" << toHex(asBytes(m_db.lookup(rootHash()))); + clog(StateTrace) << "Committed: stateRoot" << m_currentBlock.stateRoot.abridged() << "=" << rootHash().abridged() << "=" << toHex(asBytes(m_db.lookup(rootHash()))); paranoia("immediately after database commit", true); m_previousBlock = m_currentBlock; m_currentBlock.populateFromParent(m_previousBlock); - cdebug << "finalising enactment. current -> previous, hash is" << m_previousBlock.hash().abridged(); + clog(StateTrace) << "finalising enactment. current -> previous, hash is" << m_previousBlock.hash().abridged(); } else m_db.rollback(); From 30e42521b5a11e93e9581faf90ae82dc43651947 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 20 Apr 2015 11:10:51 +0200 Subject: [PATCH 61/65] Minor protocol version bump to force rebuilding DB. --- libethcore/Common.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libethcore/Common.cpp b/libethcore/Common.cpp index a0ceb389e..56120471b 100644 --- a/libethcore/Common.cpp +++ b/libethcore/Common.cpp @@ -34,7 +34,7 @@ namespace eth { const unsigned c_protocolVersion = 60; -const unsigned c_minorProtocolVersion = 0; +const unsigned c_minorProtocolVersion = 1; const unsigned c_databaseBaseVersion = 9; #if ETH_FATDB const unsigned c_databaseVersionModifier = 1; From 43ca7292dec5bbff2c9e72709f74c22b7cf11af2 Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 20 Apr 2015 11:36:57 +0200 Subject: [PATCH 62/65] - Bugfix: #1672 - Return the right line nb in error (WebPreview.qml) --- mix/qml/LogsPane.qml | 7 +++++-- mix/qml/StatusPane.qml | 7 +++++++ mix/qml/WebPreview.qml | 2 +- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/mix/qml/LogsPane.qml b/mix/qml/LogsPane.qml index eb8669df6..c9d0ef67e 100644 --- a/mix/qml/LogsPane.qml +++ b/mix/qml/LogsPane.qml @@ -6,12 +6,15 @@ import org.ethereum.qml.SortFilterProxyModel 1.0 Rectangle { + property variant statusPane property variant currentStatus property int contentXPos: logStyle.generic.layout.dateWidth + logStyle.generic.layout.typeWidth - 70 function clear() { logsModel.clear(); + statusPane.clear(); + currentStatus = undefined; } function push(_level, _type, _content) @@ -22,7 +25,7 @@ Rectangle onVisibleChanged: { - if (visible && (logsModel.count === 0 || (logsModel.get(0).date !== currentStatus.date && logsModel.get(0).content !== currentStatus.content))) + if (currentStatus && visible && (logsModel.count === 0 || logsModel.get(0).content !== currentStatus.content || logsModel.get(0).date !== currentStatus.date)) logsModel.insert(0, { "type": currentStatus.type, "date": currentStatus.date, "content": currentStatus.content, "level": currentStatus.level }); else if (!visible) { @@ -533,7 +536,7 @@ Rectangle enabled: logsModel.count > 0 tooltip: qsTr("Clear") onTriggered: { - logsModel.clear(); + logsPane.clear() } } } diff --git a/mix/qml/StatusPane.qml b/mix/qml/StatusPane.qml index d36b6fa75..0c01caeb1 100644 --- a/mix/qml/StatusPane.qml +++ b/mix/qml/StatusPane.qml @@ -55,6 +55,12 @@ Rectangle { currentStatus = { "type": type, "date": Qt.formatDateTime(new Date(), "hh:mm:ss"), "content": text, "level": "error" } } + function clear() + { + status.state = ""; + status.text = ""; + } + StatusPaneStyle { id: statusPaneStyle } @@ -359,6 +365,7 @@ Rectangle { LogsPane { id: logPane; + statusPane: statusHeader onContentXPosChanged: { parent.move(); diff --git a/mix/qml/WebPreview.qml b/mix/qml/WebPreview.qml index 6db727e3b..72cb88401 100644 --- a/mix/qml/WebPreview.qml +++ b/mix/qml/WebPreview.qml @@ -317,7 +317,7 @@ Item { experimental.settings.localContentCanAccessRemoteUrls: true onJavaScriptConsoleMessage: { console.log(sourceID + ":" + lineNumber + ": " + message); - webPreview.javaScriptMessage(level, sourceID, lineNumber, message); + webPreview.javaScriptMessage(level, sourceID, lineNumber - 1, message); } onLoadingChanged: { if (!loading) { From 8328220471475b2733a9f4a2cc4c3710ee2d7d5c Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 20 Apr 2015 11:49:37 +0200 Subject: [PATCH 63/65] Fixes for reimporting, make block availability atomic. --- alethzero/MainWin.cpp | 2 +- libethcore/EthashAux.cpp | 6 +++--- libethereum/BlockChain.cpp | 38 +++++++++++++++++++++++++++----------- libethereum/BlockChain.h | 3 ++- 4 files changed, 33 insertions(+), 16 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 270996a30..3ec5febd2 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -164,7 +164,7 @@ Main::Main(QWidget *parent) : statusBar()->addPermanentWidget(ui->chainStatus); statusBar()->addPermanentWidget(ui->blockCount); - ui->blockCount->setText(QString("PV%2 D%3 %4-%5 v%6").arg(eth::c_protocolVersion).arg(c_databaseVersion).arg(QString::fromStdString(ProofOfWork::name())).arg(ProofOfWork::revision()).arg(dev::Version)); + ui->blockCount->setText(QString("PV%1.%2 D%3 %4-%5 v%6").arg(eth::c_protocolVersion).arg(eth::c_minorProtocolVersion).arg(c_databaseVersion).arg(QString::fromStdString(ProofOfWork::name())).arg(ProofOfWork::revision()).arg(dev::Version)); connect(ui->ourAccounts->model(), SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)), SLOT(ourAccountsRowsMoved())); diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index 68c5f3057..750d80082 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -75,11 +75,11 @@ h256 EthashAux::seedHash(unsigned _number) n = get()->m_seedHashes.size() - 1; } get()->m_seedHashes.resize(epoch + 1); - cdebug << "Searching for seedHash of epoch " << epoch; +// cdebug << "Searching for seedHash of epoch " << epoch; for (; n <= epoch; ++n, ret = sha3(ret)) { get()->m_seedHashes[n] = ret; - cdebug << "Epoch" << n << "is" << ret.abridged(); +// cdebug << "Epoch" << n << "is" << ret.abridged(); } } return get()->m_seedHashes[epoch]; @@ -95,7 +95,7 @@ ethash_params EthashAux::params(h256 const& _seedHash) } catch (...) { - cdebug << "Searching for seedHash " << _seedHash.abridged(); +// cdebug << "Searching for seedHash " << _seedHash.abridged(); for (h256 h; h != _seedHash && epoch < 2048; ++epoch, h = sha3(h), get()->m_epochs[h] = epoch) {} if (epoch == 2048) { diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 4e3349a31..6705349f4 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -167,6 +167,7 @@ void BlockChain::open(std::string const& _path, WithExisting _we) std::string l; m_extrasDB->Get(m_readOptions, ldb::Slice("best"), &l); m_lastBlockHash = l.empty() ? m_genesisHash : *(h256*)l.data(); + m_lastBlockNumber = number(m_lastBlockHash); cnote << "Opened blockchain DB. Latest: " << currentHash(); } @@ -177,6 +178,7 @@ void BlockChain::close() delete m_extrasDB; delete m_blocksDB; m_lastBlockHash = m_genesisHash; + m_lastBlockNumber = 0; m_details.clear(); m_blocks.clear(); } @@ -191,8 +193,7 @@ void BlockChain::rebuild(std::string const& _path, std::functionPut(m_writeOptions, ldb::Slice("best"), ldb::Slice((char const*)&(bi.hash()), 32)); // Most of the time these two will be equal - only when we're doing a chain revert will they not be if (common != last) @@ -601,6 +597,14 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import m_extrasDB->Put(m_writeOptions, toSlice(h, ExtraTransactionAddress), (ldb::Slice)dev::ref(m_transactionAddresses[h].rlp())); } + // FINALLY! change our best hash. + { + WriteGuard l(x_lastBlockHash); + m_lastBlockHash = bi.hash(); + m_lastBlockNumber = (unsigned)bi.number; + m_extrasDB->Put(m_writeOptions, ldb::Slice("best"), ldb::Slice((char const*)&(bi.hash()), 32)); + } + clog(BlockChainNote) << " Imported and best" << td << " (#" << bi.number << "). Has" << (details(bi.parentHash).children.size() - 1) << "siblings. Route:" << toString(route); noteCanonChanged(); @@ -960,14 +964,26 @@ bool BlockChain::isKnown(h256 const& _hash) const { if (_hash == m_genesisHash) return true; + { ReadGuard l(x_blocks); - if (m_blocks.count(_hash)) - return true; + auto it = m_blocks.find(_hash); + if (it != m_blocks.end()) + { + noteUsed(_hash); + BlockInfo bi(it->second, CheckNothing, _hash); + return bi.number <= m_lastBlockNumber; // TODO: m_lastBlockNumber + } } + string d; m_blocksDB->Get(m_readOptions, toSlice(_hash), &d); - return !!d.size(); + + if (!d.size()) + return false; + + BlockInfo bi(bytesConstRef(&d), CheckNothing, _hash); + return bi.number <= m_lastBlockNumber; // TODO: m_lastBlockNumber } bytes BlockChain::block(h256 const& _hash) const diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 8061487d7..be5b931ee 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -185,7 +185,7 @@ public: /// Get a number for the given hash (or the most recent mined if none given). Thread-safe. unsigned number(h256 const& _hash) const { return details(_hash).number; } - unsigned number() const { return number(currentHash()); } + unsigned number() const { return m_lastBlockNumber; } /// Get a given block (RLP format). Thread-safe. h256 currentHash() const { ReadGuard l(x_lastBlockHash); return m_lastBlockHash; } @@ -315,6 +315,7 @@ private: /// Hash of the last (valid) block on the longest chain. mutable boost::shared_mutex x_lastBlockHash; h256 m_lastBlockHash; + unsigned m_lastBlockNumber = 0; /// Genesis block info. h256 m_genesisHash; From 86804fedf1b81e2136b07e9f3d896f7cd6d80a6a Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 20 Apr 2015 12:22:35 +0200 Subject: [PATCH 64/65] Fix deadlock. --- libethereum/BlockChain.cpp | 22 +++++++++++----------- libp2p/NodeTable.cpp | 6 +++--- libp2p/RLPxHandshake.cpp | 6 +++--- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 6705349f4..6a483a228 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -965,24 +965,24 @@ bool BlockChain::isKnown(h256 const& _hash) const if (_hash == m_genesisHash) return true; + BlockInfo bi; + { ReadGuard l(x_blocks); auto it = m_blocks.find(_hash); if (it != m_blocks.end()) - { - noteUsed(_hash); - BlockInfo bi(it->second, CheckNothing, _hash); - return bi.number <= m_lastBlockNumber; // TODO: m_lastBlockNumber - } + bi = BlockInfo(it->second, CheckNothing, _hash); } - string d; - m_blocksDB->Get(m_readOptions, toSlice(_hash), &d); - - if (!d.size()) - return false; + if (!bi) + { + string d; + m_blocksDB->Get(m_readOptions, toSlice(_hash), &d); + if (!d.size()) + return false; + bi = BlockInfo(bytesConstRef(&d), CheckNothing, _hash); + } - BlockInfo bi(bytesConstRef(&d), CheckNothing, _hash); return bi.number <= m_lastBlockNumber; // TODO: m_lastBlockNumber } diff --git a/libp2p/NodeTable.cpp b/libp2p/NodeTable.cpp index 1f48d52b7..e65c6660b 100644 --- a/libp2p/NodeTable.cpp +++ b/libp2p/NodeTable.cpp @@ -382,7 +382,7 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes // h256 + Signature + type + RLP (smallest possible packet is empty neighbours packet which is 3 bytes) if (_packet.size() < h256::size + Signature::size + 1 + 3) { - clog(NodeTableWarn) << "Invalid message size from " << _from.address().to_string() << ":" << _from.port(); + clog(NodeTableTriviaSummary) << "Invalid message size from " << _from.address().to_string() << ":" << _from.port(); return; } @@ -390,7 +390,7 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes h256 hashSigned(sha3(hashedBytes)); if (!_packet.cropped(0, h256::size).contentsEqual(hashSigned.asBytes())) { - clog(NodeTableWarn) << "Invalid message hash from " << _from.address().to_string() << ":" << _from.port(); + clog(NodeTableTriviaSummary) << "Invalid message hash from " << _from.address().to_string() << ":" << _from.port(); return; } @@ -402,7 +402,7 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes Public nodeid(dev::recover(*(Signature const*)sigBytes.data(), sha3(signedBytes))); if (!nodeid) { - clog(NodeTableWarn) << "Invalid message signature from " << _from.address().to_string() << ":" << _from.port(); + clog(NodeTableTriviaSummary) << "Invalid message signature from " << _from.address().to_string() << ":" << _from.port(); return; } diff --git a/libp2p/RLPxHandshake.cpp b/libp2p/RLPxHandshake.cpp index bb9af2ef7..fbf0d9fdf 100644 --- a/libp2p/RLPxHandshake.cpp +++ b/libp2p/RLPxHandshake.cpp @@ -249,7 +249,7 @@ void RLPXHandshake::transition(boost::system::error_code _ech) bytesRef frame(&m_handshakeInBuffer); if (!m_io->authAndDecryptFrame(frame)) { - clog(NetWarn) << (m_originated ? "p2p.connect.egress" : "p2p.connect.ingress") << "hello frame: decrypt failed"; + clog(NetTriviaSummary) << (m_originated ? "p2p.connect.egress" : "p2p.connect.ingress") << "hello frame: decrypt failed"; m_nextState = Error; transition(); return; @@ -258,13 +258,13 @@ void RLPXHandshake::transition(boost::system::error_code _ech) PacketType packetType = (PacketType)(frame[0] == 0x80 ? 0x0 : frame[0]); if (packetType != 0) { - clog(NetWarn) << (m_originated ? "p2p.connect.egress" : "p2p.connect.ingress") << "hello frame: invalid packet type"; + clog(NetTriviaSummary) << (m_originated ? "p2p.connect.egress" : "p2p.connect.ingress") << "hello frame: invalid packet type"; m_nextState = Error; transition(); return; } - clog(NetNote) << (m_originated ? "p2p.connect.egress" : "p2p.connect.ingress") << "hello frame: success. starting session."; + clog(NetTriviaSummary) << (m_originated ? "p2p.connect.egress" : "p2p.connect.ingress") << "hello frame: success. starting session."; RLP rlp(frame.cropped(1), RLP::ThrowOnFail | RLP::FailIfTooSmall); m_host->startPeerSession(m_remote, rlp, m_io, m_socket->remoteEndpoint()); } From 6b0a6e1043beccf6f41d3f40694dee1e10c5b7b8 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 20 Apr 2015 13:16:58 +0200 Subject: [PATCH 65/65] Inject block data in AZ. --- alethzero/Main.ui | 6 ++++++ alethzero/MainWin.cpp | 19 +++++++++++++++++++ alethzero/MainWin.h | 1 + 3 files changed, 26 insertions(+) diff --git a/alethzero/Main.ui b/alethzero/Main.ui index 8e48793c9..1fd9669e9 100644 --- a/alethzero/Main.ui +++ b/alethzero/Main.ui @@ -176,6 +176,7 @@ + @@ -1685,6 +1686,11 @@ font-size: 14pt Retry Unknown Parent Blocks + + + In&ject Block + + diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 3ec5febd2..64fca6a05 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1448,6 +1448,25 @@ void Main::on_inject_triggered() } } +void Main::on_injectBlock_triggered() +{ + QString s = QInputDialog::getText(this, "Inject Block", "Enter block dump in hex"); + try + { + bytes b = fromHex(s.toStdString(), WhenError::Throw); + ethereum()->injectBlock(b); + } + catch (BadHexCharacter& _e) + { + cwarn << "invalid hex character, transaction rejected"; + cwarn << boost::diagnostic_information(_e); + } + catch (...) + { + cwarn << "block rejected"; + } +} + void Main::on_blocks_currentItemChanged() { ui->info->clear(); diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index a8579ed01..1a53ec62b 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -159,6 +159,7 @@ private slots: void on_killBlockchain_triggered(); void on_clearPending_triggered(); void on_inject_triggered(); + void on_injectBlock_triggered(); void on_forceMining_triggered(); void on_usePrivate_triggered(); void on_turboMining_triggered();