diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 1c2774aa7..ba6cac3c7 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -267,6 +267,7 @@ void Client::work() { // Import block. lock_guard l(m_lock); + m_postMine.completeMine(); m_bc.attemptImport(m_postMine.blockData(), m_stateDB); m_changed = true; } diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 90c9cd7d6..210604932 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -750,30 +750,32 @@ MineInfo State::mine(uint _msTimeout) m_currentBlock.difficulty = m_currentBlock.calculateDifficulty(m_previousBlock); // TODO: Miner class that keeps dagger between mine calls (or just non-polling mining). - MineInfo ret = m_dagger.mine(/*out*/m_currentBlock.nonce, m_currentBlock.headerHashWithoutNonce(), m_currentBlock.difficulty, _msTimeout); - if (ret.completed) - { - // Got it! - - // Commit to disk. - m_db.commit(); + auto ret = m_dagger.mine(/*out*/m_currentBlock.nonce, m_currentBlock.headerHashWithoutNonce(), m_currentBlock.difficulty, _msTimeout); - // Compile block: - RLPStream ret; - ret.appendList(3); - m_currentBlock.fillStream(ret, true); - ret.appendRaw(m_currentTxs); - ret.appendRaw(m_currentUncles); - ret.swapOut(m_currentBytes); - m_currentBlock.hash = sha3(m_currentBytes); - cnote << "Mined " << m_currentBlock.hash << "(parent: " << m_currentBlock.parentHash << ")"; - } - else + if (!ret.completed) m_currentBytes.clear(); return ret; } +void State::completeMine() +{ + // Got it! + + // Commit to disk. + m_db.commit(); + + // Compile block: + RLPStream ret; + ret.appendList(3); + m_currentBlock.fillStream(ret, true); + ret.appendRaw(m_currentTxs); + ret.appendRaw(m_currentUncles); + ret.swapOut(m_currentBytes); + m_currentBlock.hash = sha3(m_currentBytes); + cnote << "Mined " << m_currentBlock.hash << "(parent: " << m_currentBlock.parentHash << ")"; +} + bool State::addressInUse(Address _id) const { ensureCached(_id, false, false); @@ -943,9 +945,18 @@ bool State::isTrieGood(bool _enforceRefs, bool _requireNoLeftOvers) const return true; } -// TODO: kill temp nodes automatically in TrieDB +// TODO: run this often. +// POSSIBLE RACE CONDITION: check if mining clears intermediate nodes in trie before clearing pending. +// HOW DID TRIE NODES GO BUT PENDING STAY? +void State::checkPendingInTrie() const +{ + bool x = true; + + + assert(x); +} + // TODO: maintain node overlay revisions for stateroots -> each commit gives a stateroot + OverlayDB; allow overlay copying for rewind operations. -// TODO: TransactionReceipt trie should be MemoryDB and built as necessary u256 State::execute(bytesConstRef _rlp) { diff --git a/libethereum/State.h b/libethereum/State.h index 50edb46e2..bce267bb4 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -149,11 +149,26 @@ public: void commitToMine(BlockChain const& _bc); /// Attempt to find valid nonce for block that this state represents. + /// This function is thread-safe. You can safely have other interactions with this object while it is happening. /// @param _msTimeout Timeout before return in milliseconds. - /// @returns a non-empty byte array containing the block if it got lucky. In this case, call blockData() - /// to get the block if you need it later. + /// @returns Information on the mining. MineInfo mine(uint _msTimeout = 1000); + /** Commit to DB and build the final block if the previous call to mine()'s result is completion. + * Typically looks like: + * @code + * // lock + * commitToMine(blockchain); + * // unlock + * MineInfo info; + * for (info.complete = false; !info.complete; info = mine()) {} + * // lock + * completeMine(); + * // unlock + * @endcode + */ + void completeMine(); + /// Get the complete current block, including valid nonce. /// Only valid after mine() returns true. bytes const& blockData() const { return m_currentBytes; } @@ -309,6 +324,7 @@ private: bool isTrieGood(bool _enforceRefs, bool _requireNoLeftOvers) const; void paranoia(std::string const& _when, bool _enforceRefs = false) const; + void checkPendingInTrie() const; OverlayDB m_db; ///< Our overlay for the state tree. TrieDB m_state; ///< Our state tree, as an OverlayDB DB. diff --git a/test/state.cpp b/test/state.cpp index 92b274ecc..8d82b0c2b 100644 --- a/test/state.cpp +++ b/test/state.cpp @@ -51,7 +51,8 @@ int stateTest() // Mine to get some ether! s.commitToMine(bc); - while (s.mine(100).completed) {} + while (!s.mine(100).completed) {} + s.completeMine(); bc.attemptImport(s.blockData(), stateDB); cout << bc; @@ -77,7 +78,8 @@ int stateTest() // Mine to get some ether and set in stone. s.commitToMine(bc); - while (s.mine(100).completed) {} + while (!s.mine(100).completed) {} + s.completeMine(); bc.attemptImport(s.blockData(), stateDB); cout << bc;