diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index e8aa0618e..260a81732 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -360,12 +360,13 @@ void Client::setupState(State& _s) cwork << "SETUP MINE"; _s = m_postMine; } + _s.setUncles(m_bc); if (m_paranoia) { if (_s.amIJustParanoid(m_bc)) { cnote << "I'm just paranoid. Block is fine."; - _s.commitToMine(m_bc); + _s.commitToMine(); } else { @@ -373,7 +374,7 @@ void Client::setupState(State& _s) } } else - _s.commitToMine(m_bc); + _s.commitToMine(); } void Client::transact(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 5232144c2..831696beb 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -639,7 +639,8 @@ void State::uncommitToMine() bool State::amIJustParanoid(BlockChain const& _bc) { - commitToMine(_bc); + setUncles(_bc); + commitToMine(); // Update difficulty according to timestamp. m_currentBlock.difficulty = m_currentBlock.calculateDifficulty(m_previousBlock); @@ -682,22 +683,8 @@ LogBloom State::logBloom() const return ret; } -// @returns the block that represents the difference between m_previousBlock and m_currentBlock. -// (i.e. all the transactions we executed). -void State::commitToMine(BlockChain const& _bc) +void State::setUncles(BlockChain const& _bc) { - uncommitToMine(); - -// cnote << "Committing to mine on block" << m_previousBlock.hash.abridged(); -#ifdef ETH_PARANOIA - commit(); - cnote << "Pre-reward stateRoot:" << m_state.root(); -#endif - - m_lastTx = m_db; - - Addresses uncleAddresses; - RLPStream unclesData; unsigned unclesCount = 0; if (m_previousBlock != BlockChain::genesis()) @@ -716,11 +703,26 @@ void State::commitToMine(BlockChain const& _bc) BlockInfo ubi(_bc.block(u)); ubi.streamRLP(unclesData, WithNonce); ++unclesCount; - uncleAddresses.push_back(ubi.coinbaseAddress); } } } + RLPStream(unclesCount).appendRaw(unclesData.out(), unclesCount).swapOut(m_currentUncles); + m_currentBlock.sha3Uncles = sha3(m_currentUncles); +} + +void State::commitToMine() +{ + uncommitToMine(); + +// cnote << "Committing to mine on block" << m_previousBlock.hash.abridged(); +#ifdef ETH_PARANOIA + commit(); + cnote << "Pre-reward stateRoot:" << m_state.root(); +#endif + + m_lastTx = m_db; + MemoryDB tm; GenericTrieDB transactionsTrie(&tm); transactionsTrie.init(); @@ -750,12 +752,13 @@ void State::commitToMine(BlockChain const& _bc) txs.swapOut(m_currentTxs); - RLPStream(unclesCount).appendRaw(unclesData.out(), unclesCount).swapOut(m_currentUncles); - m_currentBlock.transactionsRoot = transactionsTrie.root(); m_currentBlock.receiptsRoot = receiptsTrie.root(); m_currentBlock.logBloom = logBloom(); - m_currentBlock.sha3Uncles = sha3(m_currentUncles); + + Addresses uncleAddresses; + for (const auto& r: RLP(m_currentUncles)) + uncleAddresses.push_back(BlockInfo::fromHeader(r.data()).coinbaseAddress); // Apply rewards last of all. applyRewards(uncleAddresses); diff --git a/libethereum/State.h b/libethereum/State.h index 85abd9366..313cc5c44 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -105,13 +105,16 @@ public: /// @returns true if all is ok. If it's false, worry. bool amIJustParanoid(BlockChain const& _bc); + /// @brief Loads current block uncles from blockchain + void setUncles(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. /// The only thing left to do after this is to actually mine(). /// /// This may be called multiple times and without issue. - void commitToMine(BlockChain const& _bc); + void commitToMine(); /// 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. @@ -123,7 +126,7 @@ public: * Typically looks like: * @code * // lock - * commitToMine(blockchain); + * commitToMine(); * // unlock * MineInfo info; * for (info.complete = false; !info.complete; info = mine()) {} diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index 0e95fa429..5c6917505 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -56,12 +56,16 @@ void MixClient::resetState(u256 _balance) genesis.state = m_state; Block open; m_blocks = Blocks { genesis, open }; //last block contains a list of pending transactions to be finalized + m_lastHashes.clear(); + m_lastHashes.resize(256); + m_lastHashes[0] = genesis.hash; } void MixClient::executeTransaction(Transaction const& _t, State& _state) { bytes rlp = _t.rlp(); - Executive execution(_state, LastHashes(), 0); + + Executive execution(_state, m_lastHashes, 0); execution.setup(&rlp); std::vector machineStates; std::vector levels; @@ -163,12 +167,15 @@ void MixClient::mine() Block& block = m_blocks.back(); m_state.mine(0, true); m_state.completeMine(); - m_state.commitToMine(BlockChain()); - m_state.cleanup(true); + m_state.commitToMine(); block.state = m_state; block.info = m_state.info(); block.hash = block.info.hash; + m_state.cleanup(true); m_blocks.push_back(Block()); + m_lastHashes.insert(m_lastHashes.begin(), block.hash); + m_lastHashes.resize(256); + h256Set changed { dev::eth::PendingChangedFilter, dev::eth::ChainChangedFilter }; noteChanged(changed); } diff --git a/mix/MixClient.h b/mix/MixClient.h index fede1891e..dceb9ce7b 100644 --- a/mix/MixClient.h +++ b/mix/MixClient.h @@ -145,6 +145,7 @@ private: std::map m_filters; std::map m_watches; Blocks m_blocks; + eth::LastHashes m_lastHashes; }; } diff --git a/test/stateOriginal.cpp b/test/stateOriginal.cpp index a49c55061..f4804c43b 100644 --- a/test/stateOriginal.cpp +++ b/test/stateOriginal.cpp @@ -51,7 +51,7 @@ int stateTest() cout << s; // Mine to get some ether! - s.commitToMine(bc); + s.commitToMine(); while (!s.mine(100).completed) {} s.completeMine(); bc.attemptImport(s.blockData(), stateDB); @@ -74,7 +74,7 @@ int stateTest() cout << s; // Mine to get some ether and set in stone. - s.commitToMine(bc); + s.commitToMine(); while (!s.mine(100).completed) {} s.completeMine(); bc.attemptImport(s.blockData(), stateDB);