From 197837b1f6db83ebf4f077f0196234c75b3564c4 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Tue, 9 Jun 2015 13:20:42 +0200 Subject: [PATCH 01/18] style fixes --- libsolidity/InterfaceHandler.cpp | 109 ++++++++++++++++++------------- 1 file changed, 62 insertions(+), 47 deletions(-) diff --git a/libsolidity/InterfaceHandler.cpp b/libsolidity/InterfaceHandler.cpp index 9a2acd5ba..8ad7b7c6e 100644 --- a/libsolidity/InterfaceHandler.cpp +++ b/libsolidity/InterfaceHandler.cpp @@ -16,8 +16,10 @@ InterfaceHandler::InterfaceHandler() m_lastTag = DocTagType::None; } -std::unique_ptr InterfaceHandler::getDocumentation(ContractDefinition const& _contractDef, - DocumentationType _type) +unique_ptr InterfaceHandler::getDocumentation( + ContractDefinition const& _contractDef, + DocumentationType _type +) { switch(_type) { @@ -35,7 +37,7 @@ std::unique_ptr InterfaceHandler::getDocumentation(ContractDefiniti return nullptr; } -std::unique_ptr InterfaceHandler::getABIInterface(ContractDefinition const& _contractDef) +unique_ptr InterfaceHandler::getABIInterface(ContractDefinition const& _contractDef) { Json::Value abi(Json::arrayValue); @@ -101,7 +103,7 @@ std::unique_ptr InterfaceHandler::getABIInterface(ContractDefinitio event["inputs"] = params; abi.append(event); } - return std::unique_ptr(new std::string(Json::FastWriter().write(abi))); + return unique_ptr(new string(Json::FastWriter().write(abi))); } unique_ptr InterfaceHandler::getABISolidityInterface(ContractDefinition const& _contractDef) @@ -141,7 +143,7 @@ unique_ptr InterfaceHandler::getABISolidityInterface(ContractDefinition return unique_ptr(new string(ret + "}")); } -std::unique_ptr InterfaceHandler::getUserDocumentation(ContractDefinition const& _contractDef) +unique_ptr InterfaceHandler::getUserDocumentation(ContractDefinition const& _contractDef) { Json::Value doc; Json::Value methods(Json::objectValue); @@ -163,10 +165,10 @@ std::unique_ptr InterfaceHandler::getUserDocumentation(ContractDefi } doc["methods"] = methods; - return std::unique_ptr(new std::string(Json::FastWriter().write(doc))); + return unique_ptr(new string(Json::FastWriter().write(doc))); } -std::unique_ptr InterfaceHandler::getDevDocumentation(ContractDefinition const& _contractDef) +unique_ptr InterfaceHandler::getDevDocumentation(ContractDefinition const& _contractDef) { // LTODO: Somewhere in this function warnings for mismatch of param names // should be thrown @@ -203,7 +205,7 @@ std::unique_ptr InterfaceHandler::getDevDocumentation(ContractDefin method["author"] = m_author; Json::Value params(Json::objectValue); - std::vector paramNames = it.second->getParameterNames(); + vector paramNames = it.second->getParameterNames(); for (auto const& pair: m_params) { if (find(paramNames.begin(), paramNames.end(), pair.first) == paramNames.end()) @@ -227,7 +229,7 @@ std::unique_ptr InterfaceHandler::getDevDocumentation(ContractDefin } doc["methods"] = methods; - return std::unique_ptr(new std::string(Json::FastWriter().write(doc))); + return unique_ptr(new string(Json::FastWriter().write(doc))); } /* -- private -- */ @@ -244,48 +246,54 @@ void InterfaceHandler::resetDev() m_params.clear(); } -static inline std::string::const_iterator skipLineOrEOS(std::string::const_iterator _nlPos, - std::string::const_iterator _end) +static inline string::const_iterator skipLineOrEOS(string::const_iterator _nlPos, + string::const_iterator _end) { return (_nlPos == _end) ? _end : ++_nlPos; } -std::string::const_iterator InterfaceHandler::parseDocTagLine(std::string::const_iterator _pos, - std::string::const_iterator _end, - std::string& _tagString, - DocTagType _tagType, - bool _appending) +string::const_iterator InterfaceHandler::parseDocTagLine( + string::const_iterator _pos, + string::const_iterator _end, + string& _tagString, + DocTagType _tagType, + bool _appending +) { - auto nlPos = std::find(_pos, _end, '\n'); + auto nlPos = find(_pos, _end, '\n'); if (_appending && _pos < _end && *_pos != ' ') _tagString += " "; - std::copy(_pos, nlPos, back_inserter(_tagString)); + copy(_pos, nlPos, back_inserter(_tagString)); m_lastTag = _tagType; return skipLineOrEOS(nlPos, _end); } -std::string::const_iterator InterfaceHandler::parseDocTagParam(std::string::const_iterator _pos, - std::string::const_iterator _end) +string::const_iterator InterfaceHandler::parseDocTagParam( + string::const_iterator _pos, + string::const_iterator _end +) { // find param name - auto currPos = std::find(_pos, _end, ' '); + auto currPos = find(_pos, _end, ' '); if (currPos == _end) - BOOST_THROW_EXCEPTION(DocstringParsingError() << errinfo_comment("End of param name not found" + std::string(_pos, _end))); + BOOST_THROW_EXCEPTION(DocstringParsingError() << errinfo_comment("End of param name not found" + string(_pos, _end))); - auto paramName = std::string(_pos, currPos); + auto paramName = string(_pos, currPos); currPos += 1; - auto nlPos = std::find(currPos, _end, '\n'); - auto paramDesc = std::string(currPos, nlPos); - m_params.push_back(std::make_pair(paramName, paramDesc)); + auto nlPos = find(currPos, _end, '\n'); + auto paramDesc = string(currPos, nlPos); + m_params.push_back(make_pair(paramName, paramDesc)); m_lastTag = DocTagType::Param; return skipLineOrEOS(nlPos, _end); } -std::string::const_iterator InterfaceHandler::appendDocTagParam(std::string::const_iterator _pos, - std::string::const_iterator _end) +string::const_iterator InterfaceHandler::appendDocTagParam( + string::const_iterator _pos, + string::const_iterator _end +) { // Should never be called with an empty vector solAssert(!m_params.empty(), "Internal: Tried to append to empty parameter"); @@ -293,18 +301,20 @@ std::string::const_iterator InterfaceHandler::appendDocTagParam(std::string::con auto pair = m_params.back(); if (_pos < _end && *_pos != ' ') pair.second += " "; - auto nlPos = std::find(_pos, _end, '\n'); - std::copy(_pos, nlPos, back_inserter(pair.second)); + auto nlPos = find(_pos, _end, '\n'); + copy(_pos, nlPos, back_inserter(pair.second)); m_params.at(m_params.size() - 1) = pair; return skipLineOrEOS(nlPos, _end); } -std::string::const_iterator InterfaceHandler::parseDocTag(std::string::const_iterator _pos, - std::string::const_iterator _end, - std::string const& _tag, - CommentOwner _owner) +string::const_iterator InterfaceHandler::parseDocTag( + string::const_iterator _pos, + string::const_iterator _end, + string const& _tag, + CommentOwner _owner +) { // LTODO: need to check for @(start of a tag) between here and the end of line // for all cases. Also somehow automate list of acceptable tags for each @@ -345,9 +355,11 @@ std::string::const_iterator InterfaceHandler::parseDocTag(std::string::const_ite return appendDocTag(_pos, _end, _owner); } -std::string::const_iterator InterfaceHandler::appendDocTag(std::string::const_iterator _pos, - std::string::const_iterator _end, - CommentOwner _owner) +string::const_iterator InterfaceHandler::appendDocTag( + string::const_iterator _pos, + string::const_iterator _end, + CommentOwner _owner +) { switch (m_lastTag) { @@ -379,33 +391,36 @@ std::string::const_iterator InterfaceHandler::appendDocTag(std::string::const_it } } -static inline std::string::const_iterator getFirstSpaceOrNl(std::string::const_iterator _pos, - std::string::const_iterator _end) +static inline string::const_iterator getFirstSpaceOrNl( + string::const_iterator _pos, + string::const_iterator _end +) { - auto spacePos = std::find(_pos, _end, ' '); - auto nlPos = std::find(_pos, _end, '\n'); + auto spacePos = find(_pos, _end, ' '); + auto nlPos = find(_pos, _end, '\n'); return (spacePos < nlPos) ? spacePos : nlPos; } -void InterfaceHandler::parseDocString(std::string const& _string, CommentOwner _owner) +void InterfaceHandler::parseDocString(string const& _string, CommentOwner _owner) { auto currPos = _string.begin(); auto end = _string.end(); while (currPos != end) { - auto tagPos = std::find(currPos, end, '@'); - auto nlPos = std::find(currPos, end, '\n'); + auto tagPos = find(currPos, end, '@'); + auto nlPos = find(currPos, end, '\n'); if (tagPos != end && tagPos < nlPos) { // we found a tag auto tagNameEndPos = getFirstSpaceOrNl(tagPos, end); if (tagNameEndPos == end) - BOOST_THROW_EXCEPTION(DocstringParsingError() << - errinfo_comment("End of tag " + std::string(tagPos, tagNameEndPos) + "not found")); + BOOST_THROW_EXCEPTION( + DocstringParsingError() << + errinfo_comment("End of tag " + string(tagPos, tagNameEndPos) + "not found")); - currPos = parseDocTag(tagNameEndPos + 1, end, std::string(tagPos + 1, tagNameEndPos), _owner); + currPos = parseDocTag(tagNameEndPos + 1, end, string(tagPos + 1, tagNameEndPos), _owner); } else if (m_lastTag != DocTagType::None) // continuation of the previous tag currPos = appendDocTag(currPos, end, _owner); From f61f429f346c3db56fed350eee470c31ba8425e1 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Tue, 9 Jun 2015 13:22:36 +0200 Subject: [PATCH 02/18] style fixes --- libsolidity/InterfaceHandler.cpp | 6 ++-- libsolidity/InterfaceHandler.h | 48 ++++++++++++++++++++------------ 2 files changed, 34 insertions(+), 20 deletions(-) diff --git a/libsolidity/InterfaceHandler.cpp b/libsolidity/InterfaceHandler.cpp index 8ad7b7c6e..a9d54cdc6 100644 --- a/libsolidity/InterfaceHandler.cpp +++ b/libsolidity/InterfaceHandler.cpp @@ -246,8 +246,10 @@ void InterfaceHandler::resetDev() m_params.clear(); } -static inline string::const_iterator skipLineOrEOS(string::const_iterator _nlPos, - string::const_iterator _end) +static inline string::const_iterator skipLineOrEOS( + string::const_iterator _nlPos, + string::const_iterator _end +) { return (_nlPos == _end) ? _end : ++_nlPos; } diff --git a/libsolidity/InterfaceHandler.h b/libsolidity/InterfaceHandler.h index 405181890..ca9807d7e 100644 --- a/libsolidity/InterfaceHandler.h +++ b/libsolidity/InterfaceHandler.h @@ -67,8 +67,10 @@ public: /// types provided by @c DocumentationType /// @return A unique pointer contained string with the json /// representation of provided type - std::unique_ptr getDocumentation(ContractDefinition const& _contractDef, - DocumentationType _type); + std::unique_ptr getDocumentation( + ContractDefinition const& _contractDef, + DocumentationType _type + ); /// Get the ABI Interface of the contract /// @param _contractDef The contract definition /// @return A unique pointer contained string with the json @@ -90,23 +92,33 @@ private: void resetUser(); void resetDev(); - std::string::const_iterator parseDocTagLine(std::string::const_iterator _pos, - std::string::const_iterator _end, - std::string& _tagString, - DocTagType _tagType, - bool _appending); - std::string::const_iterator parseDocTagParam(std::string::const_iterator _pos, - std::string::const_iterator _end); - std::string::const_iterator appendDocTagParam(std::string::const_iterator _pos, - std::string::const_iterator _end); + std::string::const_iterator parseDocTagLine( + std::string::const_iterator _pos, + std::string::const_iterator _end, + std::string& _tagString, + DocTagType _tagType, + bool _appending + ); + std::string::const_iterator parseDocTagParam( + std::string::const_iterator _pos, + std::string::const_iterator _end + ); + std::string::const_iterator appendDocTagParam( + std::string::const_iterator _pos, + std::string::const_iterator _end + ); void parseDocString(std::string const& _string, CommentOwner _owner); - std::string::const_iterator appendDocTag(std::string::const_iterator _pos, - std::string::const_iterator _end, - CommentOwner _owner); - std::string::const_iterator parseDocTag(std::string::const_iterator _pos, - std::string::const_iterator _end, - std::string const& _tag, - CommentOwner _owner); + std::string::const_iterator appendDocTag( + std::string::const_iterator _pos, + std::string::const_iterator _end, + CommentOwner _owner + ); + std::string::const_iterator parseDocTag( + std::string::const_iterator _pos, + std::string::const_iterator _end, + std::string const& _tag, + CommentOwner _owner + ); // internal state DocTagType m_lastTag; From 2c71cea5d987aac25ce39c347837f233db91ad3a Mon Sep 17 00:00:00 2001 From: arkpar Date: Tue, 9 Jun 2015 17:29:44 +0200 Subject: [PATCH 03/18] handle missing status field gracefully --- libethereum/EthereumPeer.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/libethereum/EthereumPeer.cpp b/libethereum/EthereumPeer.cpp index 50ed76d9b..497513b46 100644 --- a/libethereum/EthereumPeer.cpp +++ b/libethereum/EthereumPeer.cpp @@ -186,8 +186,16 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r) m_genesisHash = _r[4].toHash(); if (m_peerCapabilityVersion == host()->protocolVersion()) { - m_protocolVersion = host()->protocolVersion(); - m_latestBlockNumber = _r[5].toInt(); + if (_r.itemCount() != 6) + { + clog(NetImpolite) << "Peer does not support PV61+ status extension."; + m_protocolVersion = EthereumHost::c_oldProtocolVersion; + } + else + { + m_protocolVersion = host()->protocolVersion(); + m_latestBlockNumber = _r[5].toInt(); + } } clog(NetMessageSummary) << "Status:" << m_protocolVersion << "/" << m_networkId << "/" << m_genesisHash << "/" << m_latestBlockNumber << ", TD:" << m_totalDifficulty << "=" << m_latestHash; From afd84b0b4b8600970559af03353b6203c19d8ba3 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 10 Jun 2015 00:52:12 +0900 Subject: [PATCH 04/18] Expand eth cli Fixes #2125 --- eth/main.cpp | 185 ++++++++++++++++++++++++++++++++++++++++- libdevcore/FixedHash.h | 2 +- libethereum/Client.h | 2 + 3 files changed, 187 insertions(+), 2 deletions(-) diff --git a/eth/main.cpp b/eth/main.cpp index 2c5d938aa..5497a2cda 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -84,15 +84,24 @@ void interactiveHelp() << " minestop Stops mining." << endl << " mineforce Forces mining, even when there are no transactions." << endl << " block Gives the current block height." << endl + << " blockhashfromnumber Gives the block hash with the givne number." << endl + << " numberfromblockhash Gives the block number with the given hash." << endl + << " blockqueue Gives the current block queue status." << endl + << " findblock Searches for the block in the blockchain and blockqueue." << endl + << " firstunknown Gives the first unknown block from the blockqueue." << endl + << " retryunknown retries to import all unknown blocks from the blockqueue." << endl << " accounts Gives information on all owned accounts (balances, mining beneficiary and default signer)." << endl << " newaccount Creates a new account with the given name." << endl << " transact Execute a given transaction." << endl + << " txcreate Execute a given contract creation transaction." << endl << " send Execute a given transaction with current secret." << endl << " contract Create a new contract with current secret." << endl << " peers List the peers that are connected" << endl #if ETH_FATDB || !ETH_TRUE << " listaccounts List the accounts on the network." << endl << " listcontracts List the contracts on the network." << endl + << " balanceat
Gives the balance of the given account." << endl + << " codeat
Gives the code of the given account." << endl #endif << " setsigningkey Set the address with which to sign transactions." << endl << " setaddress Set the coinbase (mining payout) address." << endl @@ -971,9 +980,88 @@ int main(int argc, char** argv) cout << "Current mining beneficiary:" << endl << beneficiary << endl; cout << "Current signing account:" << endl << signingKey << endl; } + else if (c && cmd == "blockhashfromnumber") + { + if (iss.peek() != -1) + { + unsigned number; + iss >> number; + cout << " hash of block: " << c->hashFromNumber(number).hex() << endl; + } + } + else if (c && cmd == "numberfromblockhash") + { + if (iss.peek() != -1) + { + string stringHash; + iss >> stringHash; + + h256 hash = h256(fromHex(stringHash)); + cout << " number of block: " << c->numberFromHash(hash) << endl; + } + } else if (c && cmd == "block") { - cout << "Current block: " <blockChain().details().number << endl; + cout << "Current block: " << c->blockChain().details().number << endl; + } + else if (c && cmd == "blockqueue") + { + cout << "Current blockqueue status: " << endl << c->blockQueueStatus() << endl; + } + else if (c && cmd == "findblock") + { + if (iss.peek() != -1) + { + string stringHash; + iss >> stringHash; + + h256 hash = h256(fromHex(stringHash)); + + // search in blockchain + cout << "search in blockchain... " << endl; + try + { + cout << c->blockInfo(hash) << endl; + } + catch(Exception& _e) + { + cout << "block not in blockchain" << endl; + cout << boost::diagnostic_information(_e) << endl; + } + + cout << "search in blockqueue... " << endl; + + switch(c->blockQueue().blockStatus(hash)) + { + case QueueStatus::Ready: + cout << "Ready" << endl; + break; + case QueueStatus::Importing: + cout << "Importing" << endl; + break; + case QueueStatus::UnknownParent: + cout << "UnknownParent" << endl; + break; + case QueueStatus::Bad: + cout << "Bad" << endl; + break; + case QueueStatus::Unknown: + cout << "Unknown" << endl; + break; + default: + cout << "invalid queueStatus" << endl; + } + } + else + cwarn << "Require parameter: findblock HASH"; + } + else if (c && cmd == "firstunknown") + { + cout << "first unknown blockhash: " << c->blockQueue().firstUnknown().hex() << endl; + } + else if (c && cmd == "retryunknown") + { + c->retryUnkonwn(); } else if (cmd == "peers") { @@ -1087,6 +1175,64 @@ int main(int argc, char** argv) else cwarn << "Require parameters: submitTransaction ADDRESS AMOUNT GASPRICE GAS SECRET DATA"; } + else if (c && cmd == "txcreate") + { + auto const& bc =c->blockChain(); + auto h = bc.currentHash(); + auto blockData = bc.block(h); + BlockInfo info(blockData); + if (iss.peek() != -1) + { + u256 amount; + u256 gasPrice; + u256 gas; + string sechex; + string sdata; + + iss >> amount >> gasPrice >> gas >> sechex >> sdata; + + if (!gasPrice) + gasPrice = gasPricer->bid(priority); + + cnote << "Data:"; + cnote << sdata; + bytes data = dev::eth::parseData(sdata); + cnote << "Bytes:"; + string sbd = asString(data); + bytes bbd = asBytes(sbd); + stringstream ssbd; + ssbd << bbd; + cnote << ssbd.str(); + int ssize = sechex.length(); + u256 minGas = (u256)Transaction::gasRequired(data, 0); + if (gas < minGas) + cwarn << "Minimum gas amount is" << minGas; + else if (ssize < 40) + { + if (ssize > 0) + cwarn << "Invalid secret length:" << ssize; + } + else + { + try + { + Secret secret = h256(fromHex(sechex)); + cout << " new contract address : " << c->submitTransaction(secret, amount, data, gas, gasPrice) << endl; + } + catch (BadHexCharacter& _e) + { + cwarn << "invalid hex character, transaction rejected"; + cwarn << boost::diagnostic_information(_e); + } + catch (...) + { + cwarn << "transaction rejected"; + } + } + } + else + cwarn << "Require parameters: submitTransaction ADDRESS AMOUNT GASPRICE GAS SECRET INIT"; + } #if ETH_FATDB else if (c && cmd == "listcontracts") { @@ -1110,6 +1256,43 @@ int main(int argc, char** argv) cout << ss << endl; } } + else if (c && cmd == "balanceat") + { + if (iss.peek() != -1) + { + string stringHash; + iss >> stringHash; + + Address address = h160(fromHex(stringHash)); + + cout << "balance of " << stringHash << " is: " << toString(c->balanceAt(address)) << endl; + } + } + // TODO implement << operator for std::unorderd_map +// else if (c && cmd == "storageat") +// { +// if (iss.peek() != -1) +// { +// string stringHash; +// iss >> stringHash; + +// Address address = h160(fromHex(stringHash)); + +// cout << "storage at " << stringHash << " is: " << c->storageAt(address) << endl; +// } +// } + else if (c && cmd == "codeat") + { + if (iss.peek() != -1) + { + string stringHash; + iss >> stringHash; + + Address address = h160(fromHex(stringHash)); + + cout << "code at " << stringHash << " is: " << toHex(c->codeAt(address)) << endl; + } + } #endif else if (c && cmd == "send") { diff --git a/libdevcore/FixedHash.h b/libdevcore/FixedHash.h index 9b25837af..88bc0fe95 100644 --- a/libdevcore/FixedHash.h +++ b/libdevcore/FixedHash.h @@ -113,7 +113,7 @@ public: /// @returns an abridged version of the hash as a user-readable hex string. std::string abridged() const { return toHex(ref().cropped(0, 4)) + "\342\200\246"; } - /// @returns an abridged version of the hash as a user-readable hex string. + /// @returns the hash as a user-readable hex string. std::string hex() const { return toHex(ref()); } /// @returns a mutable byte vector_ref to the object's data. diff --git a/libethereum/Client.h b/libethereum/Client.h index 6251fbc9c..2de6e9403 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -158,6 +158,8 @@ public: BlockQueueStatus blockQueueStatus() const { return m_bq.status(); } /// Get some information on the block queue. HashChainStatus hashChainStatus() const; + /// Get the block queue. + BlockQueue const& blockQueue() const { return m_bq; } // Mining stuff: From 50d98864265b4e574af8bf7cb0b6a52a6b5fdb82 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 10 Jun 2015 09:24:35 +0900 Subject: [PATCH 05/18] Fixed #2133 --- ethminer/CMakeLists.txt | 4 ++++ libethereum/CMakeLists.txt | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/ethminer/CMakeLists.txt b/ethminer/CMakeLists.txt index 3ec92fc14..df828bc47 100644 --- a/ethminer/CMakeLists.txt +++ b/ethminer/CMakeLists.txt @@ -22,6 +22,10 @@ target_link_libraries(${EXECUTABLE} ${Boost_REGEX_LIBRARIES}) if (JSONRPC) target_link_libraries(${EXECUTABLE} ${JSON_RPC_CPP_CLIENT_LIBRARIES}) + target_link_libraries(${EXECUTABLE} ${CURL_LIBRARIES}) + if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW) + eth_copy_dlls(${EXECUTABLE} CURL_DLLS) + endif() endif() target_link_libraries(${EXECUTABLE} ethcore) diff --git a/libethereum/CMakeLists.txt b/libethereum/CMakeLists.txt index 7d8f27ee7..6598e1bd7 100644 --- a/libethereum/CMakeLists.txt +++ b/libethereum/CMakeLists.txt @@ -36,6 +36,10 @@ target_link_libraries(${EXECUTABLE} ${Boost_REGEX_LIBRARIES}) target_link_libraries(${EXECUTABLE} secp256k1) if (JSONRPC) target_link_libraries(${EXECUTABLE} ${JSON_RPC_CPP_CLIENT_LIBRARIES}) + target_link_libraries(${EXECUTABLE} ${CURL_LIBRARIES}) + if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW) + eth_copy_dlls(${EXECUTABLE} CURL_DLLS) + endif() endif() if (CMAKE_COMPILER_IS_MINGW) From 9a01dd57fdf18f641f3cf7f68a3027e022eb1571 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 10 Jun 2015 10:19:09 +0900 Subject: [PATCH 06/18] Avoid miner crashes. --- libethcore/Ethash.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index f715d6912..f4a8c25c4 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -340,6 +340,7 @@ void Ethash::GPUMiner::workLoop() if (shouldStop()) { delete m_miner; + m_miner = nullptr; return; } cnote << "Awaiting DAG"; @@ -354,6 +355,8 @@ void Ethash::GPUMiner::workLoop() } catch (cl::Error const& _e) { + delete m_miner; + m_miner = nullptr; cwarn << "Error GPU mining: " << _e.what() << "(" << _e.err() << ")"; } } From f8740e8e4fd81710b57f8c1af88dadcb358c5590 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 10 Jun 2015 12:02:29 +0900 Subject: [PATCH 07/18] Avoid enabling JITVM when not compiled in. --- alethzero/MainWin.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index fce3200cb..06b9cb014 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -240,6 +240,10 @@ Main::Main(QWidget *parent) : #if !ETH_FATDB removeDockWidget(ui->dockWidget_accounts); +#endif +#if !ETH_EVMJIT + ui->jitvm->setEnabled(false); + ui->jitvm->setChecked(false); #endif installWatches(); startTimer(100); From 4e17c58938ae116cb642750401ee330623f236d3 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 10 Jun 2015 12:23:26 +0900 Subject: [PATCH 08/18] Remove all other support code in favour of exception information. --- libdevcore/Exceptions.h | 4 +- libethcore/Common.cpp | 29 ++++---- libethcore/Common.h | 2 - libethereum/BlockChain.cpp | 10 +-- libethereum/Client.cpp | 142 +++++++++++++++++++----------------- libethereum/State.cpp | 50 ++----------- libethereum/Transaction.cpp | 21 ------ libethereum/Transaction.h | 3 - third/MainWin.cpp | 2 +- 9 files changed, 105 insertions(+), 158 deletions(-) diff --git a/libdevcore/Exceptions.h b/libdevcore/Exceptions.h index 7d6fae77c..b0bab7d81 100644 --- a/libdevcore/Exceptions.h +++ b/libdevcore/Exceptions.h @@ -41,11 +41,11 @@ private: std::string m_message; }; -#define DEV_SIMPLE_EXCEPTION(X) struct X: virtual Exception { public: X(): Exception(#X) {} } +#define DEV_SIMPLE_EXCEPTION(X) struct X: virtual Exception { const char* what() const noexcept override { return #X; } } /// Base class for all RLP exceptions. struct RLPException: virtual Exception { RLPException(std::string _message = std::string()): Exception(_message) {} }; -#define DEV_SIMPLE_EXCEPTION_RLP(X) struct X: virtual RLPException { public: X(): RLPException(#X) {} } +#define DEV_SIMPLE_EXCEPTION_RLP(X) struct X: virtual RLPException { const char* what() const noexcept override { return #X; } } DEV_SIMPLE_EXCEPTION_RLP(BadCast); DEV_SIMPLE_EXCEPTION_RLP(BadRLP); diff --git a/libethcore/Common.cpp b/libethcore/Common.cpp index 63f4a19f9..618703e22 100644 --- a/libethcore/Common.cpp +++ b/libethcore/Common.cpp @@ -112,25 +112,26 @@ std::string formatBalance(bigint const& _b) static void badBlockInfo(BlockInfo const& _bi, string const& _err) { - cwarn << EthRedBold << "========================================================================"; - cwarn << EthRedBold << "== Software Failure " + _err + string(max(0, 44 - _err.size()), ' ') + " =="; + string const c_line = EthReset EthOnMaroon + string(80, ' '); + string const c_border = EthReset EthOnMaroon + string(2, ' ') + EthReset EthMaroonBold; + string const c_space = c_border + string(76, ' ') + c_border; + stringstream ss; + ss << c_line << endl; + ss << c_space << endl; + ss << c_border + " Import Failure " + _err + string(max(0, 53 - _err.size()), ' ') + " " + c_border << endl; + ss << c_space << endl; string bin = toString(_bi.number); - cwarn << EthRedBold << ("== Guru Meditation #" + string(max(0, 8 - bin.size()), '0') + bin + "." + _bi.hash().abridged() + " =="); - cwarn << EthRedBold << "========================================================================"; + ss << c_border + (" Guru Meditation #" + string(max(0, 8 - bin.size()), '0') + bin + "." + _bi.hash().abridged() + " ") + c_border << endl; + ss << c_space << endl; + ss << c_line; + cwarn << "\n" + ss.str(); } void badBlock(bytesConstRef _block, string const& _err) { - badBlockInfo(BlockInfo(_block, CheckNothing), _err); - cwarn << " Block:" << toHex(_block); - cwarn << " Block RLP:" << RLP(_block); -} - -void badBlockHeader(bytesConstRef _header, string const& _err) -{ - badBlockInfo(BlockInfo::fromHeader(_header, CheckNothing), _err); - cwarn << " Header:" << toHex(_header); - cwarn << " Header RLP:" << RLP(_header);; + BlockInfo bi; + DEV_IGNORE_EXCEPTIONS(bi = BlockInfo(_block, CheckNothing)); + badBlockInfo(bi, _err); } } diff --git a/libethcore/Common.h b/libethcore/Common.h index 87ebffab7..131feed4b 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -156,8 +156,6 @@ struct TransactionSkeleton u256 gasPrice = UndefinedU256; }; -void badBlockHeader(bytesConstRef _header, std::string const& _err); -inline void badBlockHeader(bytes const& _header, std::string const& _err) { badBlockHeader(&_header, _err); } void badBlock(bytesConstRef _header, std::string const& _err); inline void badBlock(bytes const& _header, std::string const& _err) { badBlock(&_header, _err); } diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 226b7aa06..36c50e8dd 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -1074,8 +1074,6 @@ VerifiedBlockRef BlockChain::verifyBlock(bytes const& _block, function(_ex); - if (!&block) + bytes const* block = boost::get_error_info(_ex); + if (!block) { cwarn << "ODD: onBadBlock called but exception has no block in it."; return; } - badBlock(block, _ex.what()); - cwarn << boost::diagnostic_information(_ex, true); + badBlock(*block, _ex.what()); #if ETH_JSONRPC || !ETH_TRUE - if (!m_sentinel.empty()) + Json::Value report; + + report["client"] = "cpp"; + report["version"] = Version; + report["protocolVersion"] = c_protocolVersion; + report["databaseVersion"] = c_databaseVersion; + report["errortype"] = _ex.what(); + report["block"] = toHex(*block); + + // add the various hints. + if (unsigned const* uncleIndex = boost::get_error_info(_ex)) { - Json::Value report; - - report["client"] = "cpp"; - report["version"] = Version; - report["protocolVersion"] = c_protocolVersion; - report["databaseVersion"] = c_databaseVersion; - report["errortype"] = _ex.what(); - report["block"] = toHex(block); - report["hint"] = Json::Value(Json::objectValue); - - // add the various hints. - if (unsigned const* uncleIndex = boost::get_error_info(_ex)) - { - // uncle that failed. - report["hints"]["uncleIndex"] = *uncleIndex; - } - else if (unsigned const* txIndex = boost::get_error_info(_ex)) - { - // transaction that failed. - report["hints"]["transactionIndex"] = *txIndex; - } - else - { - // general block failure. - } + // uncle that failed. + report["hints"]["uncleIndex"] = *uncleIndex; + } + else if (unsigned const* txIndex = boost::get_error_info(_ex)) + { + // transaction that failed. + report["hints"]["transactionIndex"] = *txIndex; + } + else + { + // general block failure. + } - if (string const* vmtraceJson = boost::get_error_info(_ex)) - Json::Reader().parse(*vmtraceJson, report["hints"]["vmtrace"]); - if (vector const* receipts = boost::get_error_info(_ex)) - { - report["hints"]["receipts"] = Json::arrayValue; - for (auto const& r: *receipts) - report["hints"]["receipts"].append(toHex(r)); - } - if (h256Hash const* excluded = boost::get_error_info(_ex)) - { - report["hints"]["unclesExcluded"] = Json::arrayValue; - for (auto const& r: h256Set() + *excluded) - report["hints"]["unclesExcluded"].append(Json::Value(r.hex())); - } + if (string const* vmtraceJson = boost::get_error_info(_ex)) + Json::Reader().parse(*vmtraceJson, report["hints"]["vmtrace"]); + if (vector const* receipts = boost::get_error_info(_ex)) + { + report["hints"]["receipts"] = Json::arrayValue; + for (auto const& r: *receipts) + report["hints"]["receipts"].append(toHex(r)); + } + if (h256Hash const* excluded = boost::get_error_info(_ex)) + { + report["hints"]["unclesExcluded"] = Json::arrayValue; + for (auto const& r: h256Set() + *excluded) + report["hints"]["unclesExcluded"].append(Json::Value(r.hex())); + } #define DEV_HINT_ERRINFO(X) \ - if (auto const* n = boost::get_error_info(_ex)) \ - report["hints"][#X] = toString(*n) + if (auto const* n = boost::get_error_info(_ex)) \ + report["hints"][#X] = toString(*n) #define DEV_HINT_ERRINFO_HASH(X) \ - if (auto const* n = boost::get_error_info(_ex)) \ - report["hints"][#X] = n->hex() - - DEV_HINT_ERRINFO_HASH(hash256); - DEV_HINT_ERRINFO(uncleNumber); - DEV_HINT_ERRINFO(currentNumber); - DEV_HINT_ERRINFO(now); - DEV_HINT_ERRINFO(invalidSymbol); - DEV_HINT_ERRINFO(wrongAddress); - DEV_HINT_ERRINFO(comment); - DEV_HINT_ERRINFO(min); - DEV_HINT_ERRINFO(max); - - DEV_HINT_ERRINFO(required); - DEV_HINT_ERRINFO(got); - DEV_HINT_ERRINFO_HASH(required_LogBloom); - DEV_HINT_ERRINFO_HASH(got_LogBloom); - DEV_HINT_ERRINFO_HASH(required_h256); - DEV_HINT_ERRINFO_HASH(got_h256); + if (auto const* n = boost::get_error_info(_ex)) \ + report["hints"][#X] = n->hex() + + DEV_HINT_ERRINFO_HASH(hash256); + DEV_HINT_ERRINFO(uncleNumber); + DEV_HINT_ERRINFO(currentNumber); + DEV_HINT_ERRINFO(now); + DEV_HINT_ERRINFO(invalidSymbol); + DEV_HINT_ERRINFO(wrongAddress); + DEV_HINT_ERRINFO(comment); + DEV_HINT_ERRINFO(min); + DEV_HINT_ERRINFO(max); + DEV_HINT_ERRINFO(name); + DEV_HINT_ERRINFO(field); + DEV_HINT_ERRINFO(data); + DEV_HINT_ERRINFO_HASH(nonce); + DEV_HINT_ERRINFO(difficulty); + DEV_HINT_ERRINFO(target); + DEV_HINT_ERRINFO_HASH(seedHash); + DEV_HINT_ERRINFO_HASH(mixHash); + if (tuple const* r = boost::get_error_info(_ex)) + { + report["hints"]["ethashResult"]["value"] = get<0>(*r).hex(); + report["hints"]["ethashResult"]["mixHash"] = get<1>(*r).hex(); + } + DEV_HINT_ERRINFO(required); + DEV_HINT_ERRINFO(got); + DEV_HINT_ERRINFO_HASH(required_LogBloom); + DEV_HINT_ERRINFO_HASH(got_LogBloom); + DEV_HINT_ERRINFO_HASH(required_h256); + DEV_HINT_ERRINFO_HASH(got_h256); + cwarn << ("Report: \n" + Json::StyledWriter().write(report)); + + if (!m_sentinel.empty()) + { jsonrpc::HttpClient client(m_sentinel); Sentinel rpc(client); try diff --git a/libethereum/State.cpp b/libethereum/State.cpp index dc3c857fe..38b2de2ce 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -641,11 +641,6 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR } catch (Exception& ex) { - badBlock(_block.block, "Invalid transaction: " + toString(toTransactionException(ex))); - cwarn << " Transaction Index:" << i; - LogOverride o(true); - DEV_IGNORE_EXCEPTIONS(execute(lh, tr)); - ex << errinfo_transactionIndex(i); throw; } @@ -659,19 +654,6 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR auto receiptsRoot = orderedTrieRoot(receipts); if (receiptsRoot != m_currentBlock.receiptsRoot) { - badBlock(_block.block, "Bad receipts state root"); - cwarn << " Received: " << toString(m_currentBlock.receiptsRoot); - cwarn << " Expected: " << toString(receiptsRoot) << " which is:"; - for (unsigned j = 0; j < i; ++j) - { - auto b = receipts[j]; - cwarn << j << ": "; - cwarn << " RLP: " << RLP(b); - cwarn << " Hex: " << toHex(b); - cwarn << " " << TransactionReceipt(&b); - } - cwarn << " VMTrace:\n" << vmTrace(_block.block, _bc, _ir); - InvalidReceiptsStateRoot ex; ex << Hash256RequirementError(receiptsRoot, m_currentBlock.receiptsRoot); ex << errinfo_receipts(receipts); @@ -681,14 +663,6 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR if (m_currentBlock.logBloom != logBloom()) { - badBlock(_block.block, "Bad log bloom"); - cwarn << " Receipt blooms:"; - for (unsigned j = 0; j < i; ++j) - { - auto b = receipts[j]; - cwarn << " " << j << ":" << TransactionReceipt(&b).bloom().hex(); - } - cwarn << " Final bloom:" << m_currentBlock.logBloom.hex(); InvalidLogBloom ex; ex << LogBloomRequirementError(logBloom(), m_currentBlock.logBloom); ex << errinfo_receipts(receipts); @@ -701,8 +675,10 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR // Check uncles & apply their rewards to state. if (rlp[2].itemCount() > 2) { - badBlock(_block.block, "Too many uncles"); - BOOST_THROW_EXCEPTION(TooManyUncles() << errinfo_max(2) << errinfo_got(rlp[2].itemCount())); + TooManyUncles ex; + ex << errinfo_max(2); + ex << errinfo_got(rlp[2].itemCount()); + BOOST_THROW_EXCEPTION(ex); } vector rewarded; @@ -717,7 +693,6 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR auto h = sha3(i.data()); if (excluded.count(h)) { - badBlock(_block.block, "Invalid uncle included"); UncleInChain ex; ex << errinfo_comment("Uncle in block already mentioned"); ex << errinfo_unclesExcluded(excluded); @@ -726,19 +701,15 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR } excluded.insert(h); - BlockInfo uncle; + BlockInfo uncle = BlockInfo::fromHeader(i.data(), (_ir & ImportRequirements::CheckUncles) ? CheckEverything : IgnoreNonce, h); + BlockInfo uncleParent; - uncle = BlockInfo::fromHeader(i.data(), (_ir & ImportRequirements::CheckUncles) ? CheckEverything : IgnoreNonce, h); if (!_bc.isKnown(uncle.parentHash)) BOOST_THROW_EXCEPTION(UnknownParent()); - uncleParent = BlockInfo(_bc.block(uncle.parentHash)); + if ((bigint)uncleParent.number < (bigint)m_currentBlock.number - 7) { - badBlock(_block.block, "Uncle too old"); - cwarn << " Uncle number: " << uncle.number; - cwarn << " Uncle parent number: " << uncleParent.number; - cwarn << " Block number: " << m_currentBlock.number; UncleTooOld ex; ex << errinfo_uncleNumber(uncle.number); ex << errinfo_currentNumber(m_currentBlock.number); @@ -746,10 +717,6 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR } else if (uncle.number == m_currentBlock.number) { - badBlock(_block.block, "Uncle is brother"); - cwarn << " Uncle number: " << uncle.number; - cwarn << " Uncle parent number: " << uncleParent.number; - cwarn << " Block number: " << m_currentBlock.number; UncleIsBrother ex; ex << errinfo_uncleNumber(uncle.number); ex << errinfo_currentNumber(m_currentBlock.number); @@ -757,7 +724,6 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR } uncle.verifyParent(uncleParent); -// tdIncrease += uncle.difficulty; rewarded.push_back(uncle); ++ii; } @@ -776,7 +742,6 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR // Hash the state trie and check against the state_root hash in m_currentBlock. if (m_currentBlock.stateRoot != m_previousBlock.stateRoot && m_currentBlock.stateRoot != rootHash()) { - badBlock(_block.block, "Bad state root"); m_db.rollback(); BOOST_THROW_EXCEPTION(InvalidStateRoot() << Hash256RequirementError(rootHash(), m_currentBlock.stateRoot)); } @@ -784,7 +749,6 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR if (m_currentBlock.gasUsed != gasUsed()) { // Rollback the trie. - badBlock(_block.block, "Invalid gas used"); m_db.rollback(); BOOST_THROW_EXCEPTION(InvalidGasUsed() << RequirementError(bigint(gasUsed()), bigint(m_currentBlock.gasUsed))); } diff --git a/libethereum/Transaction.cpp b/libethereum/Transaction.cpp index 65c18f4fd..58ecc44fa 100644 --- a/libethereum/Transaction.cpp +++ b/libethereum/Transaction.cpp @@ -39,27 +39,6 @@ std::ostream& dev::eth::operator<<(std::ostream& _out, ExecutionResult const& _e return _out; } -std::string badTransaction(bytesConstRef _tx, string const& _err) -{ - stringstream ret; - ret << "========================================================================" << endl; - ret << "== Software Failure " << (_err + string(max(0, 44 - _err.size()), ' ')) << " ==" << endl; - ret << "== Guru Meditation " << sha3(_tx).abridged() << " ==" << endl; - ret << "========================================================================" << endl; - ret << " Transaction: " << toHex(_tx) << endl; - ret << " Transaction RLP: "; - try { - ret << RLP(_tx); - } - catch (Exception& _e) - { - ret << "Invalid: " << _e.what(); - } - ret << endl; - - return ret.str(); -} - TransactionException dev::eth::toTransactionException(Exception const& _e) { // Basic Transaction exceptions diff --git a/libethereum/Transaction.h b/libethereum/Transaction.h index fb5566d9a..e9b1cbf80 100644 --- a/libethereum/Transaction.h +++ b/libethereum/Transaction.h @@ -228,8 +228,5 @@ inline std::ostream& operator<<(std::ostream& _out, Transaction const& _t) return _out; } -void badTransaction(bytesConstRef _tx, std::string const& _err); -inline void badTransaction(bytes const& _tx, std::string const& _err) { badTransaction(&_tx, _err); } - } } diff --git a/third/MainWin.cpp b/third/MainWin.cpp index 3cfc016e3..f2a90cc0b 100644 --- a/third/MainWin.cpp +++ b/third/MainWin.cpp @@ -100,7 +100,7 @@ Main::Main(QWidget *parent) : setWindowFlags(Qt::Window); ui->setupUi(this); - cerr << "State root: " << CanonBlockChain::genesis().stateRoot << endl; + cerr << "State root: " << CanonBlockChain::genesis().stateRoot << endl; auto gb = CanonBlockChain::createGenesisBlock(); cerr << "Block Hash: " << sha3(gb) << endl; cerr << "Block RLP: " << RLP(gb) << endl; From 87cf8dd5d698605458b208c3c565e1a47e05036b Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 10 Jun 2015 16:21:25 +0900 Subject: [PATCH 09/18] VM provides information on its performance. Make guarding of DB optional. Various updates to syncing. Start of a holistic reputation manager. --- alethzero/MainWin.cpp | 4 +- libdevcore/MemoryDB.cpp | 43 ++++++++++ libdevcore/MemoryDB.h | 8 +- libdevcrypto/OverlayDB.cpp | 6 ++ libethereum/BlockChain.cpp | 25 +++--- libethereum/BlockQueue.cpp | 1 + libethereum/BlockQueue.h | 3 +- libethereum/EthereumHost.cpp | 29 ++++--- libethereum/EthereumHost.h | 5 +- libethereum/EthereumPeer.cpp | 29 ++++--- libethereum/EthereumPeer.h | 11 +-- libethereum/State.cpp | 147 +++++++++++++++++++++-------------- libp2p/Capability.cpp | 12 ++- libp2p/Capability.h | 8 +- libp2p/Host.cpp | 19 +++++ libp2p/Host.h | 40 ++++++++++ libp2p/Session.cpp | 6 ++ libp2p/Session.h | 2 + 18 files changed, 282 insertions(+), 116 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 06b9cb014..4d96b77ff 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1246,8 +1246,8 @@ void Main::refreshBlockCount() auto d = ethereum()->blockChain().details(); BlockQueueStatus b = ethereum()->blockQueueStatus(); HashChainStatus h = ethereum()->hashChainStatus(); - ui->chainStatus->setText(QString("%9/%10%11 hashes %3 ready %4 verifying %5 unverified %6 future %7 unknown %8 bad %1 #%2") - .arg(m_privateChain.size() ? "[" + m_privateChain + "] " : "testnet").arg(d.number).arg(b.verified).arg(b.verifying).arg(b.unverified).arg(b.future).arg(b.unknown).arg(b.bad).arg(h.received).arg(h.estimated ? "~" : "").arg(h.total)); + ui->chainStatus->setText(QString("%10/%11%12 hashes %3 importing %4 ready %5 verifying %6 unverified %7 future %8 unknown %9 bad %1 #%2") + .arg(m_privateChain.size() ? "[" + m_privateChain + "] " : "testnet").arg(d.number).arg(b.importing).arg(b.verified).arg(b.verifying).arg(b.unverified).arg(b.future).arg(b.unknown).arg(b.bad).arg(h.received).arg(h.estimated ? "~" : "").arg(h.total)); } void Main::on_turboMining_triggered() diff --git a/libdevcore/MemoryDB.cpp b/libdevcore/MemoryDB.cpp index 2cf56475b..f71931bdd 100644 --- a/libdevcore/MemoryDB.cpp +++ b/libdevcore/MemoryDB.cpp @@ -32,7 +32,9 @@ const char* DBWarn::name() { return "TDB"; } std::unordered_map MemoryDB::get() const { +#if DEV_GUARDED_DB ReadGuard l(x_this); +#endif std::unordered_map ret; for (auto const& i: m_main) if (!m_enforceRefs || i.second.second > 0) @@ -44,8 +46,10 @@ MemoryDB& MemoryDB::operator=(MemoryDB const& _c) { if (this == &_c) return *this; +#if DEV_GUARDED_DB ReadGuard l(_c.x_this); WriteGuard l2(x_this); +#endif m_main = _c.m_main; m_aux = _c.m_aux; return *this; @@ -53,7 +57,9 @@ MemoryDB& MemoryDB::operator=(MemoryDB const& _c) std::string MemoryDB::lookup(h256 const& _h) const { +#if DEV_GUARDED_DB ReadGuard l(x_this); +#endif auto it = m_main.find(_h); if (it != m_main.end()) { @@ -67,7 +73,9 @@ std::string MemoryDB::lookup(h256 const& _h) const bool MemoryDB::exists(h256 const& _h) const { +#if DEV_GUARDED_DB ReadGuard l(x_this); +#endif auto it = m_main.find(_h); if (it != m_main.end() && (!m_enforceRefs || it->second.second > 0)) return true; @@ -76,7 +84,9 @@ bool MemoryDB::exists(h256 const& _h) const void MemoryDB::insert(h256 const& _h, bytesConstRef _v) { +#if DEV_GUARDED_DB WriteGuard l(x_this); +#endif auto it = m_main.find(_h); if (it != m_main.end()) { @@ -92,7 +102,9 @@ void MemoryDB::insert(h256 const& _h, bytesConstRef _v) bool MemoryDB::kill(h256 const& _h) { +#if DEV_GUARDED_DB ReadGuard l(x_this); +#endif if (m_main.count(_h)) { if (m_main[_h].second > 0) @@ -117,9 +129,38 @@ bool MemoryDB::kill(h256 const& _h) return false; } +bytes MemoryDB::lookupAux(h256 const& _h) const +{ +#if DEV_GUARDED_DB + ReadGuard l(x_this); +#endif + auto it = m_aux.find(_h); + if (it != m_aux.end() && (!m_enforceRefs || it->second.second)) + return it->second.first; + return bytes(); +} + +void MemoryDB::removeAux(h256 const& _h) +{ +#if DEV_GUARDED_DB + WriteGuard l(x_this); +#endif + m_aux[_h].second = false; +} + +void MemoryDB::insertAux(h256 const& _h, bytesConstRef _v) +{ +#if DEV_GUARDED_DB + WriteGuard l(x_this); +#endif + m_aux[_h] = make_pair(_v.toBytes(), true); +} + void MemoryDB::purge() { +#if DEV_GUARDED_DB WriteGuard l(x_this); +#endif for (auto it = m_main.begin(); it != m_main.end(); ) if (it->second.second) ++it; @@ -129,7 +170,9 @@ void MemoryDB::purge() h256Hash MemoryDB::keys() const { +#if DEV_GUARDED_DB ReadGuard l(x_this); +#endif h256Hash ret; for (auto const& i: m_main) if (i.second.second) diff --git a/libdevcore/MemoryDB.h b/libdevcore/MemoryDB.h index 169682815..a39c0efd0 100644 --- a/libdevcore/MemoryDB.h +++ b/libdevcore/MemoryDB.h @@ -57,14 +57,16 @@ public: bool kill(h256 const& _h); void purge(); - bytes lookupAux(h256 const& _h) const { ReadGuard l(x_this); auto it = m_aux.find(_h); if (it != m_aux.end() && (!m_enforceRefs || it->second.second)) return it->second.first; return bytes(); } - void removeAux(h256 const& _h) { WriteGuard l(x_this); m_aux[_h].second = false; } - void insertAux(h256 const& _h, bytesConstRef _v) { WriteGuard l(x_this); m_aux[_h] = make_pair(_v.toBytes(), true); } + bytes lookupAux(h256 const& _h) const; + void removeAux(h256 const& _h); + void insertAux(h256 const& _h, bytesConstRef _v); h256Hash keys() const; protected: +#if DEV_GUARDED_DB mutable SharedMutex x_this; +#endif std::unordered_map> m_main; std::unordered_map> m_aux; diff --git a/libdevcrypto/OverlayDB.cpp b/libdevcrypto/OverlayDB.cpp index 05b9877ad..a6aa684f2 100644 --- a/libdevcrypto/OverlayDB.cpp +++ b/libdevcrypto/OverlayDB.cpp @@ -50,7 +50,9 @@ void OverlayDB::commit() { ldb::WriteBatch batch; // cnote << "Committing nodes to disk DB:"; +#if DEV_GUARDED_DB DEV_READ_GUARDED(x_this) +#endif { for (auto const& i: m_main) { @@ -83,7 +85,9 @@ void OverlayDB::commit() cwarn << "Sleeping for" << (i + 1) << "seconds, then retrying."; this_thread::sleep_for(chrono::seconds(i + 1)); } +#if DEV_GUARDED_DB DEV_WRITE_GUARDED(x_this) +#endif { m_aux.clear(); m_main.clear(); @@ -107,7 +111,9 @@ bytes OverlayDB::lookupAux(h256 const& _h) const void OverlayDB::rollback() { +#if DEV_GUARDED_DB WriteGuard l(x_this); +#endif m_main.clear(); } diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 36c50e8dd..479524f89 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -50,7 +50,7 @@ using namespace dev::eth; namespace js = json_spirit; #define ETH_CATCH 1 -#define ETH_TIMED_IMPORTS 0 +#define ETH_TIMED_IMPORTS 1 #ifdef _WIN32 const char* BlockChainDebug::name() { return EthBlue "8" EthWhite " <>"; } @@ -534,11 +534,6 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& } catch (Exception& ex) { - clog(BlockChainWarn) << " Malformed block: " << diagnostic_information(ex); - clog(BlockChainWarn) << "Block: " << _block.info.hash(); - clog(BlockChainWarn) << _block.info; - clog(BlockChainWarn) << "Block parent: " << _block.info.parentHash; - clog(BlockChainWarn) << BlockInfo(block(_block.info.parentHash)); ex << errinfo_now(time(0)); ex << errinfo_block(_block.block.toBytes()); throw; @@ -641,7 +636,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& m_blocksDB->Write(m_writeOptions, &blocksBatch); m_extrasDB->Write(m_writeOptions, &extrasBatch); -#if ETH_DEBUG || !ETH_TRUE +#if ETH_PARANOIA || !ETH_TRUE if (isKnown(_block.info.hash()) && !details(_block.info.hash())) { clog(BlockChainDebug) << "Known block just inserted has no details."; @@ -676,12 +671,16 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& #if ETH_TIMED_IMPORTS checkBest = t.elapsed(); - cnote << "Import took:" << total.elapsed(); - cnote << "preliminaryChecks:" << preliminaryChecks; - cnote << "enactment:" << enactment; - cnote << "collation:" << collation; - cnote << "writing:" << writing; - cnote << "checkBest:" << checkBest; + if (total.elapsed() > 1.0) + { + cnote << "SLOW IMPORT:" << _block.info.hash(); + cnote << " Import took:" << total.elapsed(); + cnote << " preliminaryChecks:" << preliminaryChecks; + cnote << " enactment:" << enactment; + cnote << " collation:" << collation; + cnote << " writing:" << writing; + cnote << " checkBest:" << checkBest; + } #endif if (!route.empty()) diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index 74c7670be..f055f911a 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -374,6 +374,7 @@ void BlockQueue::retryAllUnknown() std::ostream& dev::eth::operator<<(std::ostream& _out, BlockQueueStatus const& _bqs) { + _out << "importing: " << _bqs.importing << endl; _out << "verified: " << _bqs.verified << endl; _out << "verifying: " << _bqs.verifying << endl; _out << "unverified: " << _bqs.unverified << endl; diff --git a/libethereum/BlockQueue.h b/libethereum/BlockQueue.h index a0b410df0..0e3e640b1 100644 --- a/libethereum/BlockQueue.h +++ b/libethereum/BlockQueue.h @@ -46,6 +46,7 @@ struct BlockQueueChannel: public LogChannel { static const char* name(); static struct BlockQueueStatus { + size_t importing; size_t verified; size_t verifying; size_t unverified; @@ -104,7 +105,7 @@ public: h256 firstUnknown() const { ReadGuard l(m_lock); return m_unknownSet.size() ? *m_unknownSet.begin() : h256(); } /// Get some infomration on the current status. - BlockQueueStatus status() const { ReadGuard l(m_lock); Guard l2(m_verification); return BlockQueueStatus{m_verified.size(), m_verifying.size(), m_unverified.size(), m_future.size(), m_unknown.size(), m_knownBad.size()}; } + BlockQueueStatus status() const { ReadGuard l(m_lock); Guard l2(m_verification); return BlockQueueStatus{m_drainingSet.size(), m_verified.size(), m_verifying.size(), m_unverified.size(), m_future.size(), m_unknown.size(), m_knownBad.size()}; } /// Get some infomration on the given block's status regarding us. QueueStatus blockStatus(h256 const& _h) const; diff --git a/libethereum/EthereumHost.cpp b/libethereum/EthereumHost.cpp index d205394ac..a5a03297f 100644 --- a/libethereum/EthereumHost.cpp +++ b/libethereum/EthereumHost.cpp @@ -277,13 +277,6 @@ void EthereumHost::estimatePeerHashes(EthereumPeer* _peer) _peer->m_expectedHashes = blockCount; } -void EthereumHost::noteRude(p2p::NodeId const& _id, std::string const& _client) -{ - cwarn << "RUDE node/client: " << _id << _client; - m_rudeNodes.insert(_id); - m_rudeClients.insert(_client); -} - void EthereumHost::onPeerHashes(EthereumPeer* _peer, h256s const& _hashes) { RecursiveGuard l(x_sync); @@ -577,10 +570,11 @@ void EthereumHost::onPeerTransactions(EthereumPeer* _peer, RLP const& _r) void EthereumHost::onPeerAborting(EthereumPeer* _peer) { RecursiveGuard l(x_sync); - if (_peer->isSyncing()) + if (_peer->isConversing()) { _peer->setIdle(); - _peer->setRude(); + if (_peer->isCriticalSyncing()) + _peer->setRude(); continueSync(); } } @@ -647,18 +641,23 @@ void EthereumHost::continueSync(EthereumPeer* _peer) _peer->setIdle(); } } - else if (m_needSyncBlocks && peerShouldGrabBlocks(_peer)) // Check if this peer can help with downloading blocks + else if (m_needSyncBlocks && peerCanHelp(_peer)) // Check if this peer can help with downloading blocks _peer->requestBlocks(); else _peer->setIdle(); } -bool EthereumHost::peerShouldGrabBlocks(EthereumPeer* _peer) const +bool EthereumHost::peerCanHelp(EthereumPeer* _peer) const { - // Early exit if this peer has proved unreliable. - if (_peer->isRude()) - return false; + (void)_peer; + return true; +} +bool EthereumHost::peerShouldGrabBlocks(EthereumPeer* _peer) const +{ + // this is only good for deciding whether to go ahead and grab a particular peer's hash chain, + // yet it's being used in determining whether to allow a peer help with downloading an existing + // chain of blocks. auto td = _peer->m_totalDifficulty; auto lh = m_syncingLatestHash; auto ctd = m_chain.details().totalDifficulty; @@ -710,6 +709,6 @@ HashChainStatus EthereumHost::status() RecursiveGuard l(x_sync); if (m_syncingV61) return HashChainStatus { static_cast(m_hashMan.chainSize()), static_cast(m_hashMan.gotCount()), false }; - return HashChainStatus { m_estimatedHashes, static_cast(m_hashes.size()), true }; + return HashChainStatus { m_estimatedHashes - 30000, static_cast(m_hashes.size()), true }; } diff --git a/libethereum/EthereumHost.h b/libethereum/EthereumHost.h index 8c25a86c6..df17b1e4e 100644 --- a/libethereum/EthereumHost.h +++ b/libethereum/EthereumHost.h @@ -72,8 +72,6 @@ public: DownloadMan const& downloadMan() const { return m_man; } bool isSyncing() const { RecursiveGuard l(x_sync); return isSyncing_UNSAFE(); } bool isBanned(p2p::NodeId const& _id) const { return !!m_banned.count(_id); } - void noteRude(p2p::NodeId const& _id, std::string const& _client); - bool isRude(p2p::NodeId const& _id, std::string const& _client) const { return m_rudeClients.count(_client) && m_rudeNodes.count(_id); } void noteNewTransactions() { m_newTransactions = true; } void noteNewBlocks() { m_newBlocks = true; } @@ -126,6 +124,7 @@ private: void onPeerHashes(EthereumPeer* _peer, h256s const& _hashes, bool _complete); bool peerShouldGrabBlocks(EthereumPeer* _peer) const; bool peerShouldGrabChain(EthereumPeer* _peer) const; + bool peerCanHelp(EthereumPeer* _peer) const; void estimatePeerHashes(EthereumPeer* _peer); BlockChain const& m_chain; @@ -153,8 +152,6 @@ private: h256s m_hashes; ///< List of hashes with unknown block numbers. Used for PV60 chain downloading and catching up to a particular unknown unsigned m_estimatedHashes = 0; ///< Number of estimated hashes for the last peer over PV60. Used for status reporting only. bool m_syncingV61 = false; ///< True if recent activity was over pv61+. Used for status reporting only. - std::unordered_set m_rudeNodes; ///< Nodes that were impolite while syncing. We avoid syncing from these if possible. - std::unordered_set m_rudeClients; ///< Nodes that were impolite while syncing. We avoid syncing from these if possible. }; } diff --git a/libethereum/EthereumPeer.cpp b/libethereum/EthereumPeer.cpp index 497513b46..8167baeda 100644 --- a/libethereum/EthereumPeer.cpp +++ b/libethereum/EthereumPeer.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include "BlockChain.h" #include "EthereumHost.h" #include "TransactionQueue.h" @@ -40,8 +41,7 @@ EthereumPeer::EthereumPeer(Session* _s, HostCapabilityFace* _h, unsigned _i, Cap m_hashSub(host()->hashDownloadMan()), m_peerCapabilityVersion(_cap.second) { - m_isRude = host()->isRude(session()->id(), session()->info().clientVersion); - session()->addNote("manners", m_isRude ? "RUDE" : "nice"); + session()->addNote("manners", isRude() ? "RUDE" : "nice"); m_syncHashNumber = host()->chain().number() + 1; requestStatus(); } @@ -52,16 +52,20 @@ EthereumPeer::~EthereumPeer() abortSync(); } -void EthereumPeer::abortSync() +bool EthereumPeer::isRude() const { - host()->onPeerAborting(this); + return repMan().isRude(*session(), name()); } void EthereumPeer::setRude() { - m_isRude = true; - host()->noteRude(session()->id(), session()->info().clientVersion); - session()->addNote("manners", m_isRude ? "RUDE" : "nice"); + repMan().noteRude(*session(), name()); + session()->addNote("manners", "RUDE"); +} + +void EthereumPeer::abortSync() +{ + host()->onPeerAborting(this); } EthereumHost* EthereumPeer::host() const @@ -136,7 +140,7 @@ void EthereumPeer::requestHashes(h256 const& _lastHash) void EthereumPeer::requestBlocks() { setAsking(Asking::Blocks); - auto blocks = m_sub.nextFetch(c_maxBlocksAsk); + auto blocks = m_sub.nextFetch(isRude() ? 1 : c_maxBlocksAsk); if (blocks.size()) { RLPStream s; @@ -156,7 +160,7 @@ void EthereumPeer::setAsking(Asking _a) m_lastAsk = chrono::system_clock::now(); session()->addNote("ask", _a == Asking::Nothing ? "nothing" : _a == Asking::State ? "state" : _a == Asking::Hashes ? "hashes" : _a == Asking::Blocks ? "blocks" : "?"); - session()->addNote("sync", string(isSyncing() ? "ongoing" : "holding") + (needsSyncing() ? " & needed" : "")); + session()->addNote("sync", string(isCriticalSyncing() ? "ONGOING" : "holding") + (needsSyncing() ? " & needed" : "")); } void EthereumPeer::tick() @@ -166,11 +170,16 @@ void EthereumPeer::tick() session()->disconnect(PingTimeout); } -bool EthereumPeer::isSyncing() const +bool EthereumPeer::isConversing() const { return m_asking != Asking::Nothing; } +bool EthereumPeer::isCriticalSyncing() const +{ + return m_asking == Asking::Hashes || m_asking == Asking::State || (m_asking == Asking::Blocks && m_protocolVersion == 60); +} + bool EthereumPeer::interpret(unsigned _id, RLP const& _r) { try diff --git a/libethereum/EthereumPeer.h b/libethereum/EthereumPeer.h index 128612f29..a12b7a197 100644 --- a/libethereum/EthereumPeer.h +++ b/libethereum/EthereumPeer.h @@ -83,7 +83,7 @@ public: void requestBlocks(); /// Check if this node is rude. - bool isRude() const { return m_isRude; } + bool isRude() const; /// Set that it's a rude node. void setRude(); @@ -109,8 +109,11 @@ private: /// Do we presently need syncing with this peer? bool needsSyncing() const { return !isRude() && !!m_latestHash; } - /// Are we presently syncing with this peer? - bool isSyncing() const; + /// Are we presently in the process of communicating with this peer? + bool isConversing() const; + + /// Are we presently in a critical part of the syncing process with this peer? + bool isCriticalSyncing() const; /// Runs period checks to check up on the peer. void tick(); @@ -152,8 +155,6 @@ private: h256Hash m_knownBlocks; ///< Blocks that the peer already knows about (that don't need to be sent to them). Mutex x_knownTransactions; h256Hash m_knownTransactions; ///< Transactions that the peer already knows of. - - bool m_isRude; ///< True if this node has been rude in the past. }; } diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 38b2de2ce..464cba9d4 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -607,6 +607,8 @@ string State::vmTrace(bytesConstRef _block, BlockChain const& _bc, ImportRequire u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportRequirements::value _ir) { + DEV_TIMED_FUNCTION_ABOVE(500); + // m_currentBlock is assumed to be prepopulated and reset. #if !ETH_RELEASE assert(m_previousBlock.hash() == _block.info.parentHash); @@ -625,33 +627,40 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR // cnote << "playback begins:" << m_state.root(); // cnote << m_state; - LastHashes lh = _bc.lastHashes((unsigned)m_previousBlock.number); + LastHashes lh; + DEV_TIMED_ABOVE(lastHashes, 500) + lh = _bc.lastHashes((unsigned)m_previousBlock.number); + RLP rlp(_block.block); vector receipts; // All ok with the block generally. Play back the transactions now... unsigned i = 0; - for (auto const& tr: _block.transactions) - { - try + DEV_TIMED_ABOVE(txEcec, 500) + for (auto const& tr: _block.transactions) { - LogOverride o(false); - execute(lh, tr); - } - catch (Exception& ex) - { - ex << errinfo_transactionIndex(i); - throw; + try + { + LogOverride o(false); + execute(lh, tr); + } + catch (Exception& ex) + { + ex << errinfo_transactionIndex(i); + throw; + } + + RLPStream receiptRLP; + m_receipts.back().streamRLP(receiptRLP); + receipts.push_back(receiptRLP.out()); + ++i; } - RLPStream receiptRLP; - m_receipts.back().streamRLP(receiptRLP); - receipts.push_back(receiptRLP.out()); - ++i; - } + h256 receiptsRoot; + DEV_TIMED_ABOVE(receiptsRoot, 500) + receiptsRoot = orderedTrieRoot(receipts); - auto receiptsRoot = orderedTrieRoot(receipts); if (receiptsRoot != m_currentBlock.receiptsRoot) { InvalidReceiptsStateRoot ex; @@ -682,62 +691,67 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR } vector rewarded; - h256Hash excluded = _bc.allKinFrom(m_currentBlock.parentHash, 6); + h256Hash excluded; + DEV_TIMED_ABOVE(allKin, 500) + excluded = _bc.allKinFrom(m_currentBlock.parentHash, 6); excluded.insert(m_currentBlock.hash()); unsigned ii = 0; - for (auto const& i: rlp[2]) - { - try + DEV_TIMED_ABOVE(uncleCheck, 500) + for (auto const& i: rlp[2]) { - auto h = sha3(i.data()); - if (excluded.count(h)) + try { - UncleInChain ex; - ex << errinfo_comment("Uncle in block already mentioned"); - ex << errinfo_unclesExcluded(excluded); - ex << errinfo_hash256(sha3(i.data())); - BOOST_THROW_EXCEPTION(ex); - } - excluded.insert(h); + auto h = sha3(i.data()); + if (excluded.count(h)) + { + UncleInChain ex; + ex << errinfo_comment("Uncle in block already mentioned"); + ex << errinfo_unclesExcluded(excluded); + ex << errinfo_hash256(sha3(i.data())); + BOOST_THROW_EXCEPTION(ex); + } + excluded.insert(h); - BlockInfo uncle = BlockInfo::fromHeader(i.data(), (_ir & ImportRequirements::CheckUncles) ? CheckEverything : IgnoreNonce, h); + BlockInfo uncle = BlockInfo::fromHeader(i.data(), (_ir & ImportRequirements::CheckUncles) ? CheckEverything : IgnoreNonce, h); - BlockInfo uncleParent; - if (!_bc.isKnown(uncle.parentHash)) - BOOST_THROW_EXCEPTION(UnknownParent()); - uncleParent = BlockInfo(_bc.block(uncle.parentHash)); + BlockInfo uncleParent; + if (!_bc.isKnown(uncle.parentHash)) + BOOST_THROW_EXCEPTION(UnknownParent()); + uncleParent = BlockInfo(_bc.block(uncle.parentHash)); - if ((bigint)uncleParent.number < (bigint)m_currentBlock.number - 7) - { - UncleTooOld ex; - ex << errinfo_uncleNumber(uncle.number); - ex << errinfo_currentNumber(m_currentBlock.number); - BOOST_THROW_EXCEPTION(ex); + if ((bigint)uncleParent.number < (bigint)m_currentBlock.number - 7) + { + UncleTooOld ex; + ex << errinfo_uncleNumber(uncle.number); + ex << errinfo_currentNumber(m_currentBlock.number); + BOOST_THROW_EXCEPTION(ex); + } + else if (uncle.number == m_currentBlock.number) + { + UncleIsBrother ex; + ex << errinfo_uncleNumber(uncle.number); + ex << errinfo_currentNumber(m_currentBlock.number); + BOOST_THROW_EXCEPTION(ex); + } + uncle.verifyParent(uncleParent); + + rewarded.push_back(uncle); + ++ii; } - else if (uncle.number == m_currentBlock.number) + catch (Exception& ex) { - UncleIsBrother ex; - ex << errinfo_uncleNumber(uncle.number); - ex << errinfo_currentNumber(m_currentBlock.number); - BOOST_THROW_EXCEPTION(ex); + ex << errinfo_uncleIndex(ii); + throw; } - uncle.verifyParent(uncleParent); - - rewarded.push_back(uncle); - ++ii; } - catch (Exception& ex) - { - ex << errinfo_uncleIndex(ii); - throw; - } - } - applyRewards(rewarded); + DEV_TIMED_ABOVE(applyRewards, 500) + applyRewards(rewarded); // Commit all cached state changes to the state trie. - commit(); + DEV_TIMED_ABOVE(commit, 500) + commit(); // Hash the state trie and check against the state_root hash in m_currentBlock. if (m_currentBlock.stateRoot != m_previousBlock.stateRoot && m_currentBlock.stateRoot != rootHash()) @@ -1165,6 +1179,8 @@ bool State::isTrieGood(bool _enforceRefs, bool _requireNoLeftOvers) const return true; } +#define ETH_VMTIMER 1 + ExecutionResult State::execute(LastHashes const& _lh, Transaction const& _t, Permanence _p, OnOpFunc const& _onOp) { #if ETH_PARANOIA @@ -1198,6 +1214,21 @@ ExecutionResult State::execute(LastHashes const& _lh, Transaction const& _t, Per else e.go(_onOp); } +#elif ETH_VMTIMER + { + (void)_onOp; + boost::timer t; + unordered_map counts; + unsigned total = 0; + e.go([&](uint64_t, Instruction inst, bigint, bigint, bigint, VM*, ExtVMFace const*) { + counts[(byte)inst]++; + total++; + }); + cnote << total << "total in" << t.elapsed(); + for (auto const& c: {Instruction::SSTORE, Instruction::SLOAD, Instruction::CALL, Instruction::CREATE, Instruction::CALLCODE, Instruction::MSTORE8, Instruction::MSTORE, Instruction::MLOAD, Instruction::SHA3}) + cnote << instructionInfo(c).name << counts[(byte)c]; + cnote; + } #else e.go(_onOp); #endif diff --git a/libp2p/Capability.cpp b/libp2p/Capability.cpp index ecc458730..bc4aa0b04 100644 --- a/libp2p/Capability.cpp +++ b/libp2p/Capability.cpp @@ -23,18 +23,19 @@ #include #include "Session.h" +#include "Host.h" using namespace std; using namespace dev; using namespace dev::p2p; -Capability::Capability(Session* _s, HostCapabilityFace* _h, unsigned _idOffset): m_session(_s), m_host(_h), m_idOffset(_idOffset) +Capability::Capability(Session* _s, HostCapabilityFace* _h, unsigned _idOffset): m_session(_s), m_hostCap(_h), m_idOffset(_idOffset) { - clog(NetConnect) << "New session for capability" << m_host->name() << "; idOffset:" << m_idOffset; + clog(NetConnect) << "New session for capability" << m_hostCap->name() << "; idOffset:" << m_idOffset; } void Capability::disable(std::string const& _problem) { - clog(NetWarn) << "DISABLE: Disabling capability '" << m_host->name() << "'. Reason:" << _problem; + clog(NetWarn) << "DISABLE: Disabling capability '" << m_hostCap->name() << "'. Reason:" << _problem; m_enabled = false; } @@ -52,3 +53,8 @@ void Capability::addRating(int _r) { m_session->addRating(_r); } + +ReputationManager& Capability::repMan() const +{ + return host()->repMan(); +} diff --git a/libp2p/Capability.h b/libp2p/Capability.h index d09391655..b4f59b243 100644 --- a/libp2p/Capability.h +++ b/libp2p/Capability.h @@ -29,6 +29,8 @@ namespace dev namespace p2p { +class ReputationManager; + class Capability { friend class Session; @@ -43,7 +45,9 @@ public: static unsigned messageCount() { return 0; } */ Session* session() const { return m_session; } - HostCapabilityFace* hostCapability() const { return m_host; } + HostCapabilityFace* hostCapability() const { return m_hostCap; } + Host* host() const { return m_hostCap->host(); } + ReputationManager& repMan() const; protected: virtual bool interpret(unsigned _id, RLP const&) = 0; @@ -56,7 +60,7 @@ protected: private: Session* m_session; - HostCapabilityFace* m_host; + HostCapabilityFace* m_hostCap; bool m_enabled = true; unsigned m_idOffset; }; diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index f47db3c2b..f4cceebf2 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -55,6 +55,25 @@ void HostNodeTableHandler::processEvent(NodeId const& _n, NodeTableEventType con m_host.onNodeTableEvent(_n, _e); } +ReputationManager::ReputationManager() +{ +} + +void ReputationManager::noteRude(Session const& _s, std::string const& _sub) +{ + m_nodes[make_pair(_s.id(), _s.info().clientVersion)].subs[_sub].isRude = true; +} + +bool ReputationManager::isRude(Session const& _s, std::string const& _sub) const +{ + auto nit = m_nodes.find(make_pair(_s.id(), _s.info().clientVersion)); + if (nit == m_nodes.end()) + return false; + auto sit = nit->second.subs.find(_sub); + bool ret = sit == nit->second.subs.end() ? false : sit->second.isRude; + return _sub.empty() ? ret : (ret || isRude(_s)); +} + Host::Host(std::string const& _clientVersion, NetworkPreferences const& _n, bytesConstRef _restoreNetwork): Worker("p2p", 0), m_restoreNetwork(_restoreNetwork.toBytes()), diff --git a/libp2p/Host.h b/libp2p/Host.h index 3c7ce257a..c7514cf19 100644 --- a/libp2p/Host.h +++ b/libp2p/Host.h @@ -45,6 +45,18 @@ namespace ba = boost::asio; namespace bi = ba::ip; +namespace std +{ +template<> struct hash> +{ + size_t operator()(pair const& _value) const + { + size_t ret = hash()(_value.first); + return ret ^ hash()(_value.second) + 0x9e3779b9 + (ret << 6) + (ret >> 2); + } +}; +} + namespace dev { @@ -66,6 +78,29 @@ private: Host& m_host; }; +struct SubReputation +{ + bool isRude = false; + int utility = 0; +}; + +struct Reputation +{ + std::unordered_map subs; +}; + +class ReputationManager +{ +public: + ReputationManager(); + + void noteRude(Session const& _s, std::string const& _sub = std::string()); + bool isRude(Session const& _s, std::string const& _sub = std::string()) const; + +private: + std::unordered_map, Reputation> m_nodes; ///< Nodes that were impolite while syncing. We avoid syncing from these if possible. +}; + /** * @brief The Host class * Capabilities should be registered prior to startNetwork, since m_capabilities is not thread-safe. @@ -152,6 +187,9 @@ public: /// @returns if network has been started. bool isStarted() const { return isWorking(); } + /// @returns our reputation manager. + ReputationManager& repMan() { return m_repMan; } + /// @returns if network is started and interactive. bool haveNetwork() const { return m_run && !!m_nodeTable; } @@ -255,6 +293,8 @@ private: std::chrono::steady_clock::time_point m_lastPing; ///< Time we sent the last ping to all peers. bool m_accepting = false; bool m_dropPeers = false; + + ReputationManager m_repMan; }; } diff --git a/libp2p/Session.cpp b/libp2p/Session.cpp index 462fea7b1..6400a5849 100644 --- a/libp2p/Session.cpp +++ b/libp2p/Session.cpp @@ -70,6 +70,11 @@ Session::~Session() delete m_io; } +ReputationManager& Session::repMan() const +{ + return m_server->repMan(); +} + NodeId Session::id() const { return m_peer ? m_peer->id : NodeId(); @@ -450,6 +455,7 @@ void Session::doRead() else if (ec && length < tlen) { clog(NetWarn) << "Error reading - Abrupt peer disconnect: " << ec.message(); + repMan().noteRude(*this); drop(TCPError); return; } diff --git a/libp2p/Session.h b/libp2p/Session.h index bcbf8022b..1e5d69ee0 100644 --- a/libp2p/Session.h +++ b/libp2p/Session.h @@ -43,6 +43,7 @@ namespace p2p { class Peer; +class ReputationManager; /** * @brief The Session class @@ -75,6 +76,7 @@ public: static RLPStream& prep(RLPStream& _s, PacketType _t, unsigned _args = 0); void sealAndSend(RLPStream& _s); + ReputationManager& repMan() const; int rating() const; void addRating(int _r); From fbf77ea8d919800f30e3052f328290c4da09fc18 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 10 Jun 2015 16:50:27 +0900 Subject: [PATCH 10/18] Compile fix. --- libp2p/Host.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libp2p/Host.h b/libp2p/Host.h index c7514cf19..132dd379a 100644 --- a/libp2p/Host.h +++ b/libp2p/Host.h @@ -52,7 +52,7 @@ template<> struct hash> size_t operator()(pair const& _value) const { size_t ret = hash()(_value.first); - return ret ^ hash()(_value.second) + 0x9e3779b9 + (ret << 6) + (ret >> 2); + return ret ^ (hash()(_value.second) + 0x9e3779b9 + (ret << 6) + (ret >> 2)); } }; } From de56964a2e81f5995b9d1314dde5682955234adf Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Wed, 10 Jun 2015 10:58:53 +0200 Subject: [PATCH 11/18] Do create DAG if missing --- libethcore/Ethash.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index f4a8c25c4..4fa05f4cc 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -335,7 +335,7 @@ void Ethash::GPUMiner::workLoop() EthashAux::FullType dag; while (true) { - if ((dag = EthashAux::full(w.seedHash, false))) + if ((dag = EthashAux::full(w.seedHash, true))) break; if (shouldStop()) { From fe8bcb39fba1e2e892430f52b723508db8159e1e Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 10 Jun 2015 18:08:11 +0900 Subject: [PATCH 12/18] Useful EVM CLI tool. --- CMakeLists.txt | 1 + ethvm/CMakeLists.txt | 19 +++++++ ethvm/main.cpp | 127 ++++++++++++++++++++++++++++++++++++++++++ libethereum/State.cpp | 15 ----- 4 files changed, 147 insertions(+), 15 deletions(-) create mode 100644 ethvm/CMakeLists.txt create mode 100644 ethvm/main.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index a5c4fe930..8a2ac51a5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -421,6 +421,7 @@ if (TOOLS) add_subdirectory(rlp) add_subdirectory(abi) + add_subdirectory(ethvm) add_subdirectory(eth) if("x${CMAKE_BUILD_TYPE}" STREQUAL "xDebug") diff --git a/ethvm/CMakeLists.txt b/ethvm/CMakeLists.txt new file mode 100644 index 000000000..ed093061c --- /dev/null +++ b/ethvm/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_policy(SET CMP0015 NEW) +set(CMAKE_AUTOMOC OFF) + +aux_source_directory(. SRC_LIST) + +include_directories(BEFORE ..) +include_directories(${LEVELDB_INCLUDE_DIRS}) + +set(EXECUTABLE ethvm) + +add_executable(${EXECUTABLE} ${SRC_LIST}) + +target_link_libraries(${EXECUTABLE} ethereum) + +if (APPLE) + install(TARGETS ${EXECUTABLE} DESTINATION bin) +else() + eth_install_executable(${EXECUTABLE}) +endif() diff --git a/ethvm/main.cpp b/ethvm/main.cpp new file mode 100644 index 000000000..e00f03430 --- /dev/null +++ b/ethvm/main.cpp @@ -0,0 +1,127 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file main.cpp + * @author Gav Wood + * @date 2014 + * EVM Execution tool. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +using namespace std; +using namespace dev; +using namespace eth; + +void help() +{ + cout + << "Usage ethvm " << endl + << "Options:" << endl + ; + exit(0); +} + +void version() +{ + cout << "evm version " << dev::Version << endl; + exit(0); +} + +int main(int argc, char** argv) +{ + string incoming = "--"; + + State state; + Address sender = Address(69); + Address origin = Address(69); + u256 value = 0; + u256 gas = state.gasLimitRemaining(); + u256 gasPrice = 0; + + for (int i = 1; i < argc; ++i) + { + string arg = argv[i]; + if (arg == "-h" || arg == "--help") + help(); + else if (arg == "-V" || arg == "--version") + version(); + else + incoming = arg; + } + + bytes code; + if (incoming == "--" || incoming.empty()) + for (int i = cin.get(); i != -1; i = cin.get()) + code.push_back((char)i); + else + code = contents(incoming); + bytes data = fromHex(boost::trim_copy(asString(code))); + if (data.empty()) + data = code; + + state.addBalance(sender, value); + Executive executive(state, eth::LastHashes(), 0); + ExecutionResult res; + executive.setResultRecipient(res); + Transaction t = eth::Transaction(value, gasPrice, gas, data, 0); + t.forceSender(sender); + + unordered_map> counts; + unsigned total = 0; + bigint memTotal; + auto onOp = [&](uint64_t, Instruction inst, bigint m, bigint gasCost, bigint, VM*, ExtVMFace const*) { + counts[(byte)inst].first++; + counts[(byte)inst].second += gasCost; + total++; + if (m > 0) + memTotal = m; + }; + + executive.initialize(t); + executive.create(sender, value, gasPrice, gas, &data, origin); + boost::timer timer; + executive.go(onOp); + double execTime = timer.elapsed(); + executive.finalize(); + bytes output = std::move(res.output); + LogEntries logs = executive.logs(); + + cout << "Gas used: " << res.gasUsed << " (+" << t.gasRequired() << " for transaction, -" << res.gasRefunded << " refunded)" << endl; + cout << "Output: " << toHex(output) << endl; + cout << logs.size() << " logs" << (logs.empty() ? "." : ":") << endl; + for (LogEntry const& l: logs) + { + cout << " " << l.address.hex() << ": " << toHex(t.data()) << endl; + for (h256 const& t: l.topics) + cout << " " << t.hex() << endl; + } + + cout << total << " operations in " << execTime << " seconds." << endl; + cout << "Maximum memory usage: " << memTotal * 32 << " bytes" << endl; + cout << "Expensive operations:" << endl; + for (auto const& c: {Instruction::SSTORE, Instruction::SLOAD, Instruction::CALL, Instruction::CREATE, Instruction::CALLCODE, Instruction::MSTORE8, Instruction::MSTORE, Instruction::MLOAD, Instruction::SHA3}) + if (!!counts[(byte)c].first) + cout << " " << instructionInfo(c).name << " x " << counts[(byte)c].first << " (" << counts[(byte)c].second << " gas)" << endl; + + return 0; +} diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 464cba9d4..c05210cb3 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -1214,21 +1214,6 @@ ExecutionResult State::execute(LastHashes const& _lh, Transaction const& _t, Per else e.go(_onOp); } -#elif ETH_VMTIMER - { - (void)_onOp; - boost::timer t; - unordered_map counts; - unsigned total = 0; - e.go([&](uint64_t, Instruction inst, bigint, bigint, bigint, VM*, ExtVMFace const*) { - counts[(byte)inst]++; - total++; - }); - cnote << total << "total in" << t.elapsed(); - for (auto const& c: {Instruction::SSTORE, Instruction::SLOAD, Instruction::CALL, Instruction::CREATE, Instruction::CALLCODE, Instruction::MSTORE8, Instruction::MSTORE, Instruction::MLOAD, Instruction::SHA3}) - cnote << instructionInfo(c).name << counts[(byte)c]; - cnote; - } #else e.go(_onOp); #endif From 4f70cfb09a4ff347dead1e6a1ccb730847500104 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 10 Jun 2015 19:09:19 +0900 Subject: [PATCH 13/18] Fix for isChannelVisible link error. --- libdevcore/Log.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libdevcore/Log.cpp b/libdevcore/Log.cpp index 1e5c2d8ab..1db86cf9c 100644 --- a/libdevcore/Log.cpp +++ b/libdevcore/Log.cpp @@ -40,7 +40,7 @@ mutex x_logOverride; /// or equal to the currently output verbosity (g_logVerbosity). static map s_logOverride; -bool isLogVisible(std::type_info const* _ch, bool _default) +bool isChannelVisible(std::type_info const* _ch, bool _default) { Guard l(x_logOverride); if (s_logOverride.count(_ch)) From d91bde3504f77910e0978a0ec24fc96b163ad5ca Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 10 Jun 2015 19:13:03 +0900 Subject: [PATCH 14/18] More ethvm CLI options. --- ethvm/main.cpp | 109 +++++++++++++++++++++++++++++--------- libethereum/Executive.cpp | 27 ++++++---- libethereum/Executive.h | 5 +- 3 files changed, 104 insertions(+), 37 deletions(-) diff --git a/ethvm/main.cpp b/ethvm/main.cpp index e00f03430..ca77d8963 100644 --- a/ethvm/main.cpp +++ b/ethvm/main.cpp @@ -35,28 +35,51 @@ using namespace eth; void help() { cout - << "Usage ethvm " << endl - << "Options:" << endl - ; + << "Usage ethvm [trace|stats|output] (|--)" << endl + << "Transaction options:" << endl + << " --value Transaction should transfer the wei (default: 0)." << endl + << " --gas Transaction should be given gas (default: block gas limit)." << endl + << " --gas-price Transaction's gas price' should be (default: 0)." << endl + << " --sender Transaction sender should be (default: 0000...0069)." << endl + << " --origin Transaction origin should be (default: 0000...0069)." << endl + << "Options for trace:" << endl + << " --flat Minimal whitespace in the JSON." << endl + << " --mnemonics Show instruction mnemonics in the trace (non-standard)." << endl + << endl + << "General options:" << endl + << " -V,--version Show the version and exit." << endl + << " -h,--help Show this help message and exit." << endl; exit(0); } void version() { - cout << "evm version " << dev::Version << endl; + cout << "ethvm version " << dev::Version << endl; + cout << "By Gav Wood, 2015." << endl; + cout << "Build: " << DEV_QUOTED(ETH_BUILD_PLATFORM) << "/" << DEV_QUOTED(ETH_BUILD_TYPE) << endl; exit(0); } +enum class Mode +{ + Trace, + Statistics, + OutputOnly +}; + int main(int argc, char** argv) { string incoming = "--"; + Mode mode = Mode::Statistics; State state; Address sender = Address(69); Address origin = Address(69); u256 value = 0; u256 gas = state.gasLimitRemaining(); u256 gasPrice = 0; + bool styledJson = true; + StandardTrace st; for (int i = 1; i < argc; ++i) { @@ -65,6 +88,30 @@ int main(int argc, char** argv) help(); else if (arg == "-V" || arg == "--version") version(); + else if (arg == "--mnemonics") + st.setShowMnemonics(); + else if (arg == "--flat") + styledJson = false; + else if (arg == "--value" && i + 1 < argc) + value = u256(argv[++i]); + else if (arg == "--sender" && i + 1 < argc) + sender = Address(argv[++i]); + else if (arg == "--origin" && i + 1 < argc) + origin = Address(argv[++i]); + else if (arg == "--gas" && i + 1 < argc) + gas = u256(argv[++i]); + else if (arg == "--gas-price" && i + 1 < argc) + gasPrice = u256(argv[++i]); + else if (arg == "--value" && i + 1 < argc) + value = u256(argv[++i]); + else if (arg == "--value" && i + 1 < argc) + value = u256(argv[++i]); + else if (arg == "stats") + mode = Mode::Statistics; + else if (arg == "output") + mode = Mode::OutputOnly; + else if (arg == "trace") + mode = Mode::Trace; else incoming = arg; } @@ -89,12 +136,17 @@ int main(int argc, char** argv) unordered_map> counts; unsigned total = 0; bigint memTotal; - auto onOp = [&](uint64_t, Instruction inst, bigint m, bigint gasCost, bigint, VM*, ExtVMFace const*) { - counts[(byte)inst].first++; - counts[(byte)inst].second += gasCost; - total++; - if (m > 0) - memTotal = m; + auto onOp = [&](uint64_t step, Instruction inst, bigint m, bigint gasCost, bigint gas, VM* vm, ExtVMFace const* extVM) { + if (mode == Mode::Statistics) + { + counts[(byte)inst].first++; + counts[(byte)inst].second += gasCost; + total++; + if (m > 0) + memTotal = m; + } + else if (mode == Mode::Trace) + st(step, inst, m, gasCost, gas, vm, extVM); }; executive.initialize(t); @@ -104,24 +156,31 @@ int main(int argc, char** argv) double execTime = timer.elapsed(); executive.finalize(); bytes output = std::move(res.output); - LogEntries logs = executive.logs(); - cout << "Gas used: " << res.gasUsed << " (+" << t.gasRequired() << " for transaction, -" << res.gasRefunded << " refunded)" << endl; - cout << "Output: " << toHex(output) << endl; - cout << logs.size() << " logs" << (logs.empty() ? "." : ":") << endl; - for (LogEntry const& l: logs) + if (mode == Mode::Statistics) { - cout << " " << l.address.hex() << ": " << toHex(t.data()) << endl; - for (h256 const& t: l.topics) - cout << " " << t.hex() << endl; - } + cout << "Gas used: " << res.gasUsed << " (+" << t.gasRequired() << " for transaction, -" << res.gasRefunded << " refunded)" << endl; + cout << "Output: " << toHex(output) << endl; + LogEntries logs = executive.logs(); + cout << logs.size() << " logs" << (logs.empty() ? "." : ":") << endl; + for (LogEntry const& l: logs) + { + cout << " " << l.address.hex() << ": " << toHex(t.data()) << endl; + for (h256 const& t: l.topics) + cout << " " << t.hex() << endl; + } - cout << total << " operations in " << execTime << " seconds." << endl; - cout << "Maximum memory usage: " << memTotal * 32 << " bytes" << endl; - cout << "Expensive operations:" << endl; - for (auto const& c: {Instruction::SSTORE, Instruction::SLOAD, Instruction::CALL, Instruction::CREATE, Instruction::CALLCODE, Instruction::MSTORE8, Instruction::MSTORE, Instruction::MLOAD, Instruction::SHA3}) - if (!!counts[(byte)c].first) - cout << " " << instructionInfo(c).name << " x " << counts[(byte)c].first << " (" << counts[(byte)c].second << " gas)" << endl; + cout << total << " operations in " << execTime << " seconds." << endl; + cout << "Maximum memory usage: " << memTotal * 32 << " bytes" << endl; + cout << "Expensive operations:" << endl; + for (auto const& c: {Instruction::SSTORE, Instruction::SLOAD, Instruction::CALL, Instruction::CREATE, Instruction::CALLCODE, Instruction::MSTORE8, Instruction::MSTORE, Instruction::MLOAD, Instruction::SHA3}) + if (!!counts[(byte)c].first) + cout << " " << instructionInfo(c).name << " x " << counts[(byte)c].first << " (" << counts[(byte)c].second << " gas)" << endl; + } + else if (mode == Mode::Trace) + cout << st.json(styledJson); + else if (mode == Mode::OutputOnly) + cout << toHex(output); return 0; } diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index 4e741795c..c8f922561 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -46,6 +46,8 @@ bool changesMemory(Instruction _inst) return _inst == Instruction::MSTORE || _inst == Instruction::MSTORE8 || + _inst == Instruction::MLOAD || + _inst == Instruction::CREATE || _inst == Instruction::CALL || _inst == Instruction::CALLCODE || _inst == Instruction::SHA3 || @@ -71,6 +73,7 @@ void StandardTrace::operator()(uint64_t _steps, Instruction inst, bigint newMemS stack.append(toHex(toCompactBigEndian(i), 1)); r["stack"] = stack; + bool returned = false; bool newContext = false; Instruction lastInst = Instruction::STOP; @@ -84,6 +87,7 @@ void StandardTrace::operator()(uint64_t _steps, Instruction inst, bigint newMemS else if (m_lastInst.size() == ext.depth + 2) { // returned from old context + returned = true; m_lastInst.pop_back(); lastInst = m_lastInst.back(); } @@ -91,6 +95,7 @@ void StandardTrace::operator()(uint64_t _steps, Instruction inst, bigint newMemS { // continuing in previous context lastInst = m_lastInst.back(); + m_lastInst.back() = inst; } else { @@ -100,12 +105,7 @@ void StandardTrace::operator()(uint64_t _steps, Instruction inst, bigint newMemS } if (changesMemory(lastInst) || newContext) - { - Json::Value mem(Json::arrayValue); - for (auto const& i: vm.memory()) - mem.append(toHex(toCompactBigEndian(i), 1)); - r["memory"] = mem; - } + r["memory"] = toHex(vm.memory()); if (changesStorage(lastInst) || newContext) { @@ -115,21 +115,26 @@ void StandardTrace::operator()(uint64_t _steps, Instruction inst, bigint newMemS r["storage"] = storage; } - r["depth"] = ext.depth; - r["address"] = ext.myAddress.hex(); + if (returned) + r["depth"] = ext.depth; + if (newContext) + r["address"] = ext.myAddress.hex(); r["steps"] = (unsigned)_steps; r["inst"] = (unsigned)inst; + if (m_showMnemonics) + r["instname"] = instructionInfo(inst).name; r["pc"] = toString(vm.curPC()); r["gas"] = toString(gas); r["gascost"] = toString(gasCost); - r["memexpand"] = toString(newMemSize); + if (!!newMemSize) + r["memexpand"] = toString(newMemSize); m_trace->append(r); } -string StandardTrace::json() const +string StandardTrace::json(bool _styled) const { - return Json::FastWriter().write(*m_trace); + return _styled ? Json::StyledWriter().write(*m_trace) : Json::FastWriter().write(*m_trace); } Executive::Executive(State& _s, BlockChain const& _bc, unsigned _level): diff --git a/libethereum/Executive.h b/libethereum/Executive.h index e2c910cd0..aee0880ad 100644 --- a/libethereum/Executive.h +++ b/libethereum/Executive.h @@ -49,9 +49,12 @@ public: StandardTrace(); void operator()(uint64_t _steps, Instruction _inst, bigint _newMemSize, bigint _gasCost, bigint _gas, VM* _vm, ExtVMFace const* _extVM); - std::string json() const; + void setShowMnemonics() { m_showMnemonics = true; } + + std::string json(bool _styled = false) const; private: + bool m_showMnemonics = false; std::vector m_lastInst; std::shared_ptr m_trace; }; From 29fb1f2d238a7aaafaa292c5e5c24963a1f0b4b8 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 10 Jun 2015 19:14:17 +0900 Subject: [PATCH 15/18] Space out options. --- ethvm/main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/ethvm/main.cpp b/ethvm/main.cpp index ca77d8963..195661868 100644 --- a/ethvm/main.cpp +++ b/ethvm/main.cpp @@ -42,6 +42,7 @@ void help() << " --gas-price Transaction's gas price' should be (default: 0)." << endl << " --sender Transaction sender should be (default: 0000...0069)." << endl << " --origin Transaction origin should be (default: 0000...0069)." << endl + << endl << "Options for trace:" << endl << " --flat Minimal whitespace in the JSON." << endl << " --mnemonics Show instruction mnemonics in the trace (non-standard)." << endl From 3840388d203483fdb0ed2a330493d10b98a8a6fc Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 10 Jun 2015 20:03:23 +0900 Subject: [PATCH 16/18] Use sha3memory to avoid phoning home with huge messages. --- ethvm/main.cpp | 13 +++++++++++++ libethereum/Executive.cpp | 7 ++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/ethvm/main.cpp b/ethvm/main.cpp index 195661868..08a1b4508 100644 --- a/ethvm/main.cpp +++ b/ethvm/main.cpp @@ -28,6 +28,7 @@ #include #include #include +#include using namespace std; using namespace dev; using namespace eth; @@ -42,6 +43,12 @@ void help() << " --gas-price Transaction's gas price' should be (default: 0)." << endl << " --sender Transaction sender should be (default: 0000...0069)." << endl << " --origin Transaction origin should be (default: 0000...0069)." << endl +#if ETH_EVMJIT || !ETH_TRUE + << endl + << "VM options:" << endl + << " -J,--jit Enable LLVM VM (default: off)." << endl + << " --smart Enable smart VM (default: off)." << endl +#endif << endl << "Options for trace:" << endl << " --flat Minimal whitespace in the JSON." << endl @@ -89,6 +96,12 @@ int main(int argc, char** argv) help(); else if (arg == "-V" || arg == "--version") version(); +#if ETH_EVMJIT + else if (arg == "-J" || arg == "--jit") + VMFactory::setKind(VMKind::JIT); + else if (arg == "--smart") + VMFactory::setKind(VMKind::Smart); +#endif else if (arg == "--mnemonics") st.setShowMnemonics(); else if (arg == "--flat") diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index c8f922561..434be215a 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -105,7 +105,12 @@ void StandardTrace::operator()(uint64_t _steps, Instruction inst, bigint newMemS } if (changesMemory(lastInst) || newContext) - r["memory"] = toHex(vm.memory()); + { + if (vm.memory().size() < 1024) + r["memory"] = toHex(vm.memory()); + else + r["sha3memory"] = sha3(vm.memory()).hex(); + } if (changesStorage(lastInst) || newContext) { From c507d9fd391381b6349fc617e5e1e3e044f42ae5 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 10 Jun 2015 20:57:50 +0900 Subject: [PATCH 17/18] More aggressive bad-block policy. --- libethereum/BlockChain.cpp | 67 ++++++++++++++++++++------------------ libethereum/BlockQueue.cpp | 25 +++++--------- 2 files changed, 44 insertions(+), 48 deletions(-) diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 479524f89..afcb7fc96 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -315,41 +315,44 @@ tuple BlockChain::sync(BlockQueue& _bq, OverlayDB const& _st h256s fresh; h256s dead; h256s badBlocks; - for (auto const& block: blocks) - { - try - { - // Nonce & uncle nonces already verified in verification thread at this point. - ImportRoute r; - DEV_TIMED_ABOVE(Block import, 500) - r = import(block.verified, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidNonce & ~ImportRequirements::CheckUncles); - fresh += r.first; - dead += r.second; - } - catch (dev::eth::UnknownParent) - { - cwarn << "ODD: Import queue contains block with unknown parent." << LogTag::Error << boost::current_exception_diagnostic_information(); - // NOTE: don't reimport since the queue should guarantee everything in the right order. - // Can't continue - chain bad. + for (VerifiedBlock const& block: blocks) + if (!badBlocks.empty()) badBlocks.push_back(block.verified.info.hash()); - } - catch (dev::eth::FutureTime) - { - cwarn << "ODD: Import queue contains a block with future time." << LogTag::Error << boost::current_exception_diagnostic_information(); - // NOTE: don't reimport since the queue should guarantee everything in the past. - // Can't continue - chain bad. - badBlocks.push_back(block.verified.info.hash()); - } - catch (Exception& ex) + else { - cnote << "Exception while importing block. Someone (Jeff? That you?) seems to be giving us dodgy blocks!" << LogTag::Error << diagnostic_information(ex); - if (m_onBad) - m_onBad(ex); - // NOTE: don't reimport since the queue should guarantee everything in the right order. - // Can't continue - chain bad. - badBlocks.push_back(block.verified.info.hash()); + try + { + // Nonce & uncle nonces already verified in verification thread at this point. + ImportRoute r; + DEV_TIMED_ABOVE(Block import, 500) + r = import(block.verified, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidNonce & ~ImportRequirements::CheckUncles); + fresh += r.first; + dead += r.second; + } + catch (dev::eth::UnknownParent) + { + cwarn << "ODD: Import queue contains block with unknown parent." << LogTag::Error << boost::current_exception_diagnostic_information(); + // NOTE: don't reimport since the queue should guarantee everything in the right order. + // Can't continue - chain bad. + badBlocks.push_back(block.verified.info.hash()); + } + catch (dev::eth::FutureTime) + { + cwarn << "ODD: Import queue contains a block with future time." << LogTag::Error << boost::current_exception_diagnostic_information(); + // NOTE: don't reimport since the queue should guarantee everything in the past. + // Can't continue - chain bad. + badBlocks.push_back(block.verified.info.hash()); + } + catch (Exception& ex) + { + cnote << "Exception while importing block. Someone (Jeff? That you?) seems to be giving us dodgy blocks!" << LogTag::Error << diagnostic_information(ex); + if (m_onBad) + m_onBad(ex); + // NOTE: don't reimport since the queue should guarantee everything in the right order. + // Can't continue - chain bad. + badBlocks.push_back(block.verified.info.hash()); + } } - } return make_tuple(fresh, dead, _bq.doneDrain(badBlocks)); } diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index f055f911a..70f739be4 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -99,7 +99,7 @@ void BlockQueue::verifierBody() m_verifying.erase(it); goto OK1; } - cwarn << "GAA BlockQueue corrupt: job cancelled but cannot be found in m_verifying queue."; + cwarn << "BlockQueue missing our job: was there a GM?"; OK1:; continue; } @@ -127,7 +127,7 @@ void BlockQueue::verifierBody() i = move(res); goto OK; } - cwarn << "GAA BlockQueue corrupt: job finished but cannot be found in m_verifying queue."; + cwarn << "BlockQueue missing our job: was there a GM?"; OK:; } } @@ -229,23 +229,16 @@ bool BlockQueue::doneDrain(h256s const& _bad) DEV_INVARIANT_CHECK; m_drainingSet.clear(); if (_bad.size()) - { - vector old; + // one of them was bad. since they all rely on their parent, all following are bad. DEV_GUARDED(m_verification) - swap(m_verified, old); - for (auto& b: old) { - if (m_knownBad.count(b.verified.info.parentHash)) - { - m_knownBad.insert(b.verified.info.hash()); - m_readySet.erase(b.verified.info.hash()); - } - else - DEV_GUARDED(m_verification) - m_verified.push_back(std::move(b)); + m_knownBad += _bad; + m_knownBad += m_readySet; + m_readySet.clear(); + m_verified.clear(); + m_verifying.clear(); + m_unverified.clear(); } - } - m_knownBad += _bad; return !m_readySet.empty(); } From 36e57f09a2d775c20f124458cb8c8fa73322d23b Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 10 Jun 2015 21:01:43 +0900 Subject: [PATCH 18/18] Fix for previous. --- libethereum/BlockQueue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index 70f739be4..115e8c9aa 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -107,7 +107,7 @@ void BlockQueue::verifierBody() bool ready = false; { unique_lock l(m_verification); - if (m_verifying.front().verified.info.mixHash == work.first) + if (!m_verifying.empty() && m_verifying.front().verified.info.mixHash == work.first) { // we're next! m_verifying.pop_front();