From c82dd4842bebab5cc2fd79f87785123b5fb89c74 Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 10 Jul 2015 14:07:59 +0200 Subject: [PATCH 1/2] state cleanup --- libethereum/BlockChain.cpp | 6 ++- libethereum/State.cpp | 80 +++++++------------------------------- libethereum/State.h | 44 ++++++++------------- 3 files changed, 35 insertions(+), 95 deletions(-) diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 43b115c49..03ebcb56e 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -696,8 +696,10 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& exit(-1); } - try { - State canary(_db, *this, _block.info.hash(), ImportRequirements::DontHave); + try + { + State canary(_db, BaseState::Empty); + canary.populateFromChain(*this, _block.info.hash(), ImportRequirements::DontHave); } catch (...) { diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 10d637509..fac587557 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -214,10 +214,6 @@ State& State::operator=(State const& _s) return *this; } -State::~State() -{ -} - StateDiff State::diff(State const& _c, bool _quick) const { StateDiff ret; @@ -265,12 +261,12 @@ StateDiff State::diff(State const& _c, bool _quick) const return ret; } -void State::ensureCached(Address _a, bool _requireCode, bool _forceCreate) const +void State::ensureCached(Address const& _a, bool _requireCode, bool _forceCreate) const { ensureCached(m_cache, _a, _requireCode, _forceCreate); } -void State::ensureCached(std::unordered_map& _cache, Address _a, bool _requireCode, bool _forceCreate) const +void State::ensureCached(std::unordered_map& _cache, const Address& _a, bool _requireCode, bool _forceCreate) const { auto it = _cache.find(_a); if (it == _cache.end()) @@ -827,43 +823,6 @@ void State::uncommitToMine() } } -bool State::amIJustParanoid(BlockChain const& _bc) -{ - commitToMine(_bc); - - // Update difficulty according to timestamp. - m_currentBlock.difficulty = m_currentBlock.calculateDifficulty(m_previousBlock); - - // Compile block: - RLPStream block; - block.appendList(3); - m_currentBlock.streamRLP(block, WithNonce); - block.appendRaw(m_currentTxs); - block.appendRaw(m_currentUncles); - - State s(*this); - s.resetCurrent(); - try - { - cnote << "PARANOIA root:" << s.rootHash(); -// s.m_currentBlock.populate(&block.out(), false); -// s.m_currentBlock.verifyInternals(&block.out()); - s.enact(BlockChain::verifyBlock(block.out()), _bc, false); // don't check nonce for this since we haven't mined it yet. - s.cleanup(false); - return true; - } - catch (Exception const& _e) - { - cwarn << "Bad block: " << diagnostic_information(_e); - } - catch (std::exception const& _e) - { - cwarn << "Bad block: " << _e.what(); - } - - return false; -} - LogBloom State::logBloom() const { LogBloom ret; @@ -991,7 +950,7 @@ void State::completeMine() m_lastTx = m_db; } -bool State::addressInUse(Address _id) const +bool State::addressInUse(Address const& _id) const { ensureCached(_id, false, false); auto it = m_cache.find(_id); @@ -1000,7 +959,7 @@ bool State::addressInUse(Address _id) const return true; } -bool State::addressHasCode(Address _id) const +bool State::addressHasCode(Address const& _id) const { ensureCached(_id, false, false); auto it = m_cache.find(_id); @@ -1009,7 +968,7 @@ bool State::addressHasCode(Address _id) const return it->second.isFreshCode() || it->second.codeHash() != EmptySHA3; } -u256 State::balance(Address _id) const +u256 State::balance(Address const& _id) const { ensureCached(_id, false, false); auto it = m_cache.find(_id); @@ -1018,7 +977,7 @@ u256 State::balance(Address _id) const return it->second.balance(); } -void State::noteSending(Address _id) +void State::noteSending(Address const& _id) { ensureCached(_id, false, false); auto it = m_cache.find(_id); @@ -1032,7 +991,7 @@ void State::noteSending(Address _id) it->second.incNonce(); } -void State::addBalance(Address _id, u256 _amount) +void State::addBalance(Address const& _id, u256 const& _amount) { ensureCached(_id, false, false); auto it = m_cache.find(_id); @@ -1042,7 +1001,7 @@ void State::addBalance(Address _id, u256 _amount) it->second.addBalance(_amount); } -void State::subBalance(Address _id, bigint _amount) +void State::subBalance(Address const& _id, bigint const& _amount) { ensureCached(_id, false, false); auto it = m_cache.find(_id); @@ -1052,7 +1011,7 @@ void State::subBalance(Address _id, bigint _amount) it->second.addBalance(-_amount); } -Address State::newContract(u256 _balance, bytes const& _code) +Address State::newContract(u256 const& _balance, bytes const& _code) { auto h = sha3(_code); m_db.insert(h, &_code); @@ -1069,7 +1028,7 @@ Address State::newContract(u256 _balance, bytes const& _code) } } -u256 State::transactionsFrom(Address _id) const +u256 State::transactionsFrom(Address const& _id) const { ensureCached(_id, false, false); auto it = m_cache.find(_id); @@ -1079,7 +1038,7 @@ u256 State::transactionsFrom(Address _id) const return it->second.nonce(); } -u256 State::storage(Address _id, u256 _memory) const +u256 State::storage(Address const& _id, u256 const& _memory) const { ensureCached(_id, false, false); auto it = m_cache.find(_id); @@ -1101,7 +1060,7 @@ u256 State::storage(Address _id, u256 _memory) const return ret; } -unordered_map State::storage(Address _id) const +unordered_map State::storage(Address const& _id) const { unordered_map ret; @@ -1127,18 +1086,7 @@ unordered_map State::storage(Address _id) const return ret; } -h256 State::storageRoot(Address _id) const -{ - string s = m_state.at(_id); - if (s.size()) - { - RLP r(s); - return r[2].toHash(); - } - return EmptyTrie; -} - -bytes const& State::code(Address _contract) const +bytes const& State::code(Address const& _contract) const { if (!addressHasCode(_contract)) return NullBytes; @@ -1146,7 +1094,7 @@ bytes const& State::code(Address _contract) const return m_cache[_contract].code(); } -h256 State::codeHash(Address _contract) const +h256 State::codeHash(Address const& _contract) const { if (!addressHasCode(_contract)) return EmptySHA3; diff --git a/libethereum/State.h b/libethereum/State.h index ef8a3251a..594212162 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -122,8 +122,6 @@ public: /// Copy state object. State& operator=(State const& _s); - ~State(); - /// Construct state object from arbitrary point in blockchain. PopulationStatistics populateFromChain(BlockChain const& _bc, h256 const& _hash, ImportRequirements::value _ir = ImportRequirements::Default); @@ -145,11 +143,6 @@ public: /// Get the header information on the present block. BlockInfo const& info() const { return m_currentBlock; } - /// @brief Checks that mining the current object will result in a valid block. - /// Effectively attempts to import the serialised block. - /// @returns true if all is ok. If it's false, worry. - bool amIJustParanoid(BlockChain const& _bc); - /// Prepares the current state for mining. /// Commits all transactions into the trie, compiles uncles and transactions list, applies all /// rewards and populates the current block header with the appropriate hashes. @@ -158,9 +151,6 @@ public: /// This may be called multiple times and without issue. void commitToMine(BlockChain const& _bc, bytes const& _extraData = {}); - /// @returns true iff commitToMine() has been called without any subsequest transactions added &c. - bool isCommittedToMine() const { return m_committedToMine; } - /// Pass in a solution to the proof-of-work. /// @returns true iff we were previously committed to mining. template @@ -196,24 +186,24 @@ public: u256 gasLimitRemaining() const { return m_currentBlock.gasLimit - gasUsed(); } /// Check if the address is in use. - bool addressInUse(Address _address) const; + bool addressInUse(Address const& _address) const; /// Check if the address contains executable code. - bool addressHasCode(Address _address) const; + bool addressHasCode(Address const& _address) const; /// Get an account's balance. /// @returns 0 if the address has never been used. - u256 balance(Address _id) const; + u256 balance(Address const& _id) const; /// Add some amount to balance. /// Will initialise the address if it has never been used. - void addBalance(Address _id, u256 _amount); + void addBalance(Address const& _id, u256 const& _amount); /** Subtract some amount from balance. * @throws NotEnoughCash if balance of @a _id is less than @a _value (or has never been used). * @note We use bigint here as we don't want any accidental problems with negative numbers. */ - void subBalance(Address _id, bigint _value); + void subBalance(Address const& _id, bigint const& _value); /** * @brief Transfers "the balance @a _value between two accounts. @@ -221,40 +211,40 @@ public: * @param _to Account to which @a _value will be added. * @param _value Amount to be transferred. */ - void transferBalance(Address _from, Address _to, u256 _value) { subBalance(_from, _value); addBalance(_to, _value); } + void transferBalance(Address const& _from, Address const& _to, u256 const& _value) { subBalance(_from, _value); addBalance(_to, _value); } /// Get the root of the storage of an account. - h256 storageRoot(Address _contract) const; + h256 storageRoot(Address const& _contract) const; /// Get the value of a storage position of an account. /// @returns 0 if no account exists at that address. - u256 storage(Address _contract, u256 _memory) const; + u256 storage(Address const& _contract, u256 const& _memory) const; /// Set the value of a storage position of an account. - void setStorage(Address _contract, u256 _location, u256 _value) { m_cache[_contract].setStorage(_location, _value); } + void setStorage(Address const& _contract, u256 const& _location, u256 const& _value) { m_cache[_contract].setStorage(_location, _value); } /// Create a new contract. - Address newContract(u256 _balance, bytes const& _code); + Address newContract(u256 const& _balance, bytes const& _code); /// Get the storage of an account. /// @note This is expensive. Don't use it unless you need to. /// @returns std::unordered_map if no account exists at that address. - std::unordered_map storage(Address _contract) const; + std::unordered_map storage(Address const& _contract) const; /// Get the code of an account. /// @returns bytes() if no account exists at that address. - bytes const& code(Address _contract) const; + bytes const& code(Address const& _contract) const; /// Get the code hash of an account. /// @returns EmptySHA3 if no account exists at that address or if there is no code associated with the address. - h256 codeHash(Address _contract) const; + h256 codeHash(Address const& _contract) const; /// Note that the given address is sending a transaction and thus increment the associated ticker. - void noteSending(Address _id); + void noteSending(Address const& _id); /// Get the number of transactions a particular address has sent (used for the transaction nonce). /// @returns 0 if the address has never been used. - u256 transactionsFrom(Address _address) const; + u256 transactionsFrom(Address const& _address) const; /// The hash of the root of our state tree. h256 rootHash() const { return m_state.root(); } @@ -333,10 +323,10 @@ private: /// If _requireMemory is true, grab the full memory should it be a contract item. /// If _forceCreate is true, then insert a default item into the cache, in the case it doesn't /// exist in the DB. - void ensureCached(Address _a, bool _requireCode, bool _forceCreate) const; + void ensureCached(Address const& _a, bool _requireCode, bool _forceCreate) const; /// Retrieve all information about a given address into a cache. - void ensureCached(std::unordered_map& _cache, Address _a, bool _requireCode, bool _forceCreate) const; + void ensureCached(std::unordered_map& _cache, Address const& _a, bool _requireCode, bool _forceCreate) const; /// Execute the given block, assuming it corresponds to m_currentBlock. /// Throws on failure. From 3db5d9571658553f34cf738ea3177b8a2d173279 Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 13 Jul 2015 15:34:03 +0200 Subject: [PATCH 2/2] State and Client minor cleanup --- libdevcore/TrieDB.h | 4 +-- libethcore/Exceptions.h | 1 + libethereum/Client.cpp | 22 +++++----------- libethereum/Client.h | 1 - libethereum/State.cpp | 57 +++++++++++++++++++++-------------------- 5 files changed, 38 insertions(+), 47 deletions(-) diff --git a/libdevcore/TrieDB.h b/libdevcore/TrieDB.h index 55ca81023..beb12fe0c 100644 --- a/libdevcore/TrieDB.h +++ b/libdevcore/TrieDB.h @@ -158,8 +158,6 @@ public: iterator lower_bound(bytesConstRef _key) const { return iterator(this, _key); } - void debugPrint() {} - /// Used for debugging, scans the whole trie. void descendKey(h256 const& _k, h256Hash& _keyMask, bool _wasExt, std::ostream* _out, int _indent = 0) const { @@ -332,6 +330,7 @@ public: void insert(KeyType _k, bytesConstRef _value) { Generic::insert(bytesConstRef((byte const*)&_k, sizeof(KeyType)), _value); } void insert(KeyType _k, bytes const& _value) { insert(_k, bytesConstRef(&_value)); } void remove(KeyType _k) { Generic::remove(bytesConstRef((byte const*)&_k, sizeof(KeyType))); } + void debugStructure(std::ostream& _out) const { Generic::debugStructure(_out); } class iterator: public Generic::iterator { @@ -386,6 +385,7 @@ public: using Super::leftOvers; using Super::check; + using Super::debugStructure; std::string at(bytesConstRef _key) const { return Super::at(sha3(_key)); } bool contains(bytesConstRef _key) { return Super::contains(sha3(_key)); } diff --git a/libethcore/Exceptions.h b/libethcore/Exceptions.h index 0ac9df5b2..8715507ba 100644 --- a/libethcore/Exceptions.h +++ b/libethcore/Exceptions.h @@ -71,6 +71,7 @@ DEV_SIMPLE_EXCEPTION(InvalidBlockHeaderItemCount); DEV_SIMPLE_EXCEPTION(InvalidBlockNonce); DEV_SIMPLE_EXCEPTION(InvalidParentHash); DEV_SIMPLE_EXCEPTION(InvalidNumber); +DEV_SIMPLE_EXCEPTION(BlockNotFound); DEV_SIMPLE_EXCEPTION(DatabaseAlreadyOpen); DEV_SIMPLE_EXCEPTION(DAGCreationFailure); diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 2295904cc..574cf2efb 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -38,6 +38,8 @@ #include "Executive.h" #include "EthereumHost.h" #include "Utility.h" +#include "TransactionQueue.h" + using namespace std; using namespace dev; using namespace dev::eth; @@ -459,20 +461,8 @@ uint64_t Client::hashrate() const std::list Client::miningHistory() { - std::list ret; -/* ReadGuard l(x_localMiners); - if (m_localMiners.empty()) - return ret; - ret = m_localMiners[0].miningHistory(); - for (unsigned i = 1; i < m_localMiners.size(); ++i) - { - auto l = m_localMiners[i].miningHistory(); - auto ri = ret.begin(); - auto li = l.begin(); - for (; ri != ret.end() && li != l.end(); ++ri, ++li) - ri->combine(*li); - }*/ - return ret; + //TODO: reimplement for CPU/GPU miner + return std::list {}; } ExecutionResult Client::call(Address _dest, bytes const& _data, u256 _gas, u256 _value, u256 _gasPrice, Address const& _from) @@ -481,7 +471,7 @@ ExecutionResult Client::call(Address _dest, bytes const& _data, u256 _gas, u256 try { State temp; -// clog(ClientTrace) << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret)); + clog(ClientDetail) << "Nonce at " << _dest << " pre:" << m_preMine.transactionsFrom(_dest) << " post:" << m_postMine.transactionsFrom(_dest); DEV_READ_GUARDED(x_postMine) temp = m_postMine; temp.addBalance(_from, _value + _gasPrice * _gas); @@ -493,7 +483,7 @@ ExecutionResult Client::call(Address _dest, bytes const& _data, u256 _gas, u256 } catch (...) { - // TODO: Some sort of notification of failure. + cwarn << "Client::call failed: " << boost::current_exception_diagnostic_information(); } return ret; } diff --git a/libethereum/Client.h b/libethereum/Client.h index d433ecb6d..398bf64a4 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -40,7 +40,6 @@ #include #include #include "CanonBlockChain.h" -#include "TransactionQueue.h" #include "State.h" #include "CommonNet.h" #include "ClientBase.h" diff --git a/libethereum/State.cpp b/libethereum/State.cpp index fac587557..cfe468daa 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -72,8 +72,8 @@ OverlayDB State::openDB(std::string const& _basePath, WithExisting _we) o.max_open_files = 256; o.create_if_missing = true; ldb::DB* db = nullptr; - ldb::DB::Open(o, path + "/state", &db); - if (!db) + ldb::Status status = ldb::DB::Open(o, path + "/state", &db); + if (!status.ok() || !db) { if (boost::filesystem::space(path + "/state").available < 1024) { @@ -82,6 +82,7 @@ OverlayDB State::openDB(std::string const& _basePath, WithExisting _we) } else { + cwarn << status.ToString(); cwarn << "Database already open. You appear to have another instance of ethereum running. Bailing."; BOOST_THROW_EXCEPTION(DatabaseAlreadyOpen()); } @@ -129,7 +130,7 @@ PopulationStatistics State::populateFromChain(BlockChain const& _bc, h256 const& { // Might be worth throwing here. cwarn << "Invalid block given for state population: " << _h; - return ret; + BOOST_THROW_EXCEPTION(BlockNotFound() << errinfo_target(_h)); } auto b = _bc.block(_h); @@ -244,9 +245,6 @@ StateDiff State::diff(State const& _c, bool _quick) const for (auto const& i: _c.m_cache) ads.insert(i.first); -// cnote << *this; -// cnote << _c; - for (auto const& i: ads) { auto it = m_cache.find(i); @@ -305,14 +303,14 @@ bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi, Impor bool ret = false; // BLOCK BlockInfo bi = _bi ? _bi : _bc.info(_block); -/* if (!bi) +#if ETH_PARANOIA + if (!bi) while (1) { try { auto b = _bc.block(_block); bi.populate(b); -// bi.verifyInternals(_bc.block(_block)); // Unneeded - we already verify on import into the blockchain. break; } catch (Exception const& _e) @@ -327,7 +325,8 @@ bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi, Impor cerr << "ERROR: Corrupt block-chain! Delete your block-chain DB and restart." << endl; cerr << _e.what() << endl; } - }*/ + } +#endif if (bi == m_currentBlock) { // We mined the last block. @@ -352,7 +351,7 @@ bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi, Impor cwarn << "Unable to sync to" << bi.hash() << "; state root" << bi.stateRoot << "not found in database."; cwarn << "Database corrupt: contains block without stateRoot:" << bi; cwarn << "Bailing."; - exit(-1); + BOOST_THROW_EXCEPTION(InvalidStateRoot() << errinfo_target(bi.stateRoot)); } m_previousBlock = bi; resetCurrent(); @@ -477,7 +476,6 @@ void State::resetCurrent() m_currentBlock.sha3Uncles = h256(); m_currentBlock.populateFromParent(m_previousBlock); - // Update timestamp according to clock. // TODO: check. m_lastTx = m_db; @@ -557,7 +555,6 @@ pair State::sync(BlockChain const& _bc, TransactionQu // Temporarily no gas left in current block. // OPTIMISE: could note this and then we don't evaluate until a block that does have the gas left. // for now, just leave alone. -// _tq.setFuture(t.sha3()); } } catch (Exception const& _e) @@ -782,7 +779,8 @@ void State::cleanup(bool _fullCommit) if (isChannelVisible()) // Avoid calling toHex if not needed clog(StateTrace) << "Committing to disk: stateRoot" << m_currentBlock.stateRoot << "=" << rootHash() << "=" << toHex(asBytes(m_db.lookup(rootHash()))); - try { + try + { EnforceRefs er(m_db, true); rootHash(); } @@ -835,12 +833,6 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData) { uncommitToMine(); -// cnote << "Committing to mine on block" << m_previousBlock.hash; -#if ETH_PARANOIA && 0 - commit(); - cnote << "Pre-reward stateRoot:" << m_state.root(); -#endif - m_lastTx = m_db; vector uncleBlockHeaders; @@ -850,7 +842,7 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData) if (m_previousBlock.number != 0) { // Find great-uncles (or second-cousins or whatever they are) - children of great-grandparents, great-great-grandparents... that were not already uncles in previous generations. -// cout << "Checking " << m_previousBlock.hash << ", parent=" << m_previousBlock.parentHash << endl; + clog(StateDetail) << "Checking " << m_previousBlock.hash() << ", parent=" << m_previousBlock.parentHash; h256Hash excluded = _bc.allKinFrom(m_currentBlock.parentHash, 6); auto p = m_previousBlock.parentHash; for (unsigned gen = 0; gen < 6 && p != _bc.genesisHash() && unclesCount < 2; ++gen, p = _bc.details(p).parent) @@ -907,9 +899,9 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData) // Commit any and all changes to the trie that are in the cache, then update the state root accordingly. commit(); -// cnote << "Post-reward stateRoot:" << m_state.root(); -// cnote << m_state; -// cnote << *this; + clog(StateDetail) << "Post-reward stateRoot:" << m_state.root(); + clog(StateDetail) << m_state; + clog(StateDetail) << *this; m_currentBlock.gasUsed = gasUsed(); m_currentBlock.stateRoot = m_state.root(); @@ -923,7 +915,7 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData) void State::completeMine() { - cdebug << "Completing mine!"; + clog(StateDetail) << "Completing mine!"; // Got it! // Compile block: @@ -1086,6 +1078,17 @@ unordered_map State::storage(Address const& _id) const return ret; } +h256 State::storageRoot(Address const& _id) const +{ + string s = m_state.at(_id); + if (s.size()) + { + RLP r(s); + return r[2].toHash(); + } + return EmptyTrie; +} + bytes const& State::code(Address const& _contract) const { if (!addressHasCode(_contract)) @@ -1115,7 +1118,7 @@ bool State::isTrieGood(bool _enforceRefs, bool _requireNoLeftOvers) const cwarn << "LEFTOVERS" << (e ? "[enforced" : "[unenforced") << "refs]"; cnote << "Left:" << lo; cnote << "Keys:" << m_db.keys(); -// m_state.debugStructure(cerr); + m_state.debugStructure(cerr); return false; } // TODO: Enable once fixed. @@ -1132,14 +1135,12 @@ bool State::isTrieGood(bool _enforceRefs, bool _requireNoLeftOvers) const { cwarn << "BAD TRIE" << (e ? "[enforced" : "[unenforced") << "refs]"; cnote << m_db.keys(); -// m_state.debugStructure(cerr); + m_state.debugStructure(cerr); return false; } return true; } -#define ETH_VMTIMER 1 - ExecutionResult State::execute(LastHashes const& _lh, Transaction const& _t, Permanence _p, OnOpFunc const& _onOp) { #if ETH_PARANOIA