diff --git a/README.md b/README.md index f370b2309..7529fed50 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ See the [Wiki](https://github.com/ethereum/cpp-ethereum/wiki) for build instruct ### Testing -To run the tests, make sure you clone the tests repository from github.com/ethereum to tests is a sibling to cpp-ethereum-build. +To run the tests, make sure you clone the tests repository from github.com/ethereum to tests as a sibling to cpp-ethereum. ### Yet To Do diff --git a/alethzero/Main.ui b/alethzero/Main.ui index b8612df11..adca65854 100644 --- a/alethzero/Main.ui +++ b/alethzero/Main.ui @@ -165,6 +165,7 @@ + @@ -1430,6 +1431,14 @@ font-family: Monospace, Ubuntu Mono, Lucida Console, Courier New &Load Javascript... + + + Single Step &Backwards + + + Shift+F10 + + diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 00264e539..d45599cd3 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -674,17 +674,12 @@ void Main::refresh(bool _override) } } -string Main::renderDiff(eth::State const& fs, eth::State const& ts) const +string Main::renderDiff(eth::StateDiff const& _d) const { stringstream s; - eth::StateDiff d = fs.diff(ts); - - s << "Pre: " << fs.rootHash() << "
"; - s << "Post: " << ts.rootHash() << ""; - auto indent = " "; - for (auto const& i: d.accounts) + for (auto const& i: _d.accounts) { s << "
"; @@ -773,9 +768,10 @@ void Main::on_transactionQueue_currentItemChanged() } s << "
"; - eth::State fs = m_client->postState().fromPending(i); - eth::State ts = m_client->postState().fromPending(i + 1); - s << renderDiff(fs, ts); +// s << "Pre: " << fs.rootHash() << "
"; +// s << "Post: " << ts.rootHash() << ""; + + s << renderDiff(m_client->postState().pendingDiff(i)); } ui->pendingInfo->setHtml(QString::fromStdString(s.str())); @@ -872,15 +868,25 @@ void Main::on_blocks_currentItemChanged() if (tx.data.size()) s << eth::memDump(tx.data, 16, true); } - s << "

"; -/* BlockInfo parentBlockInfo(); - eth::State s = m_client->state(); - s.resetTo(bi.); - s <<*/ - -// eth::State s = m_client->blockChain().stateAt(h); -// StateDiff d = s.pendingDiff(txi); - // TODO: Make function: BlockChain::stateAt (grabs block's parent's stateRoot, playback()'s transactions), then use State::fromPending(). Maybe even make a State::pendingDiff(). + auto st = eth::State(m_client->state().db(), m_client->blockChain(), h); + s << renderDiff(st.pendingDiff(txi)); + + m_executiveState = st.fromPending(txi); + m_currentExecution = unique_ptr(new Executive(m_executiveState)); + Transaction t = st.pending()[txi]; + auto r = t.rlp(); + + debugFinished(); + bool done = m_currentExecution->setup(&r); + if (!done) + { + auto startGas = m_currentExecution->vm().gas(); + for (; !done; done = m_currentExecution->go(1)) + m_history.append(WorldState({m_currentExecution->vm().curPC(), m_currentExecution->vm().gas(), startGas - m_currentExecution->vm().gas(), m_currentExecution->vm().stack(), m_currentExecution->vm().memory(), m_currentExecution->state().storage(m_currentExecution->ext().myAddress)})); + initDebugger(); + updateDebugger(); + } + m_currentExecution.reset(); } @@ -1210,14 +1216,15 @@ void Main::on_debug_clicked() t.receiveAddress = isCreation() ? Address() : fromString(ui->destination->currentText()); t.sign(s); auto r = t.rlp(); - m_currentExecution->setup(&r); + m_currentExecution->setup(&r); m_pcWarp.clear(); m_history.clear(); bool ok = true; + auto gasBegin = m_currentExecution->vm().gas(); while (ok) { - m_history.append(WorldState({m_currentExecution->vm().curPC(), m_currentExecution->vm().gas(), m_currentExecution->vm().stack(), m_currentExecution->vm().memory(), m_currentExecution->state().storage(m_currentExecution->ext().myAddress)})); + m_history.append(WorldState({m_currentExecution->vm().curPC(), m_currentExecution->vm().gas(), gasBegin - m_currentExecution->vm().gas(), m_currentExecution->vm().stack(), m_currentExecution->vm().memory(), m_currentExecution->state().storage(m_currentExecution->ext().myAddress)})); ok = !m_currentExecution->go(1); } initDebugger(); @@ -1244,6 +1251,11 @@ void Main::on_debugStep_triggered() ui->debugTimeline->setValue(ui->debugTimeline->value() + 1); } +void Main::on_debugStepback_triggered() +{ + ui->debugTimeline->setValue(ui->debugTimeline->value() - 1); +} + void Main::debugFinished() { m_pcWarp.clear(); @@ -1255,6 +1267,7 @@ void Main::debugFinished() ui->debugStateInfo->setText(""); // ui->send->setEnabled(true); ui->debugStep->setEnabled(false); + ui->debugStepback->setEnabled(false); ui->debugPanel->setEnabled(false); } @@ -1262,6 +1275,7 @@ void Main::initDebugger() { // ui->send->setEnabled(false); ui->debugStep->setEnabled(true); + ui->debugStepback->setEnabled(true); ui->debugPanel->setEnabled(true); ui->debugCode->setEnabled(false); ui->debugTimeline->setMinimum(0); diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index ea96d51be..c372a7b5a 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -46,6 +46,7 @@ struct WorldState { eth::u256 curPC; eth::u256 gas; + eth::u256 gasUsed; eth::u256s stack; eth::bytes memory; std::map storage; @@ -101,6 +102,7 @@ private slots: void on_quit_triggered() { close(); } void on_urlEdit_returnPressed(); void on_debugStep_triggered(); + void on_debugStepback_triggered(); void on_debug_clicked(); void on_debugTimeline_valueChanged(); void on_jsInput_returnPressed(); @@ -131,7 +133,7 @@ private: void debugFinished(); QString render(eth::Address _a) const; eth::Address fromString(QString const& _a) const; - std::string renderDiff(eth::State const& fs, eth::State const& ts) const; + std::string renderDiff(eth::StateDiff const& _d) const; eth::State const& state() const; diff --git a/libethereum/AddressState.h b/libethereum/AddressState.h index 3984dd498..2ccdbd53b 100644 --- a/libethereum/AddressState.h +++ b/libethereum/AddressState.h @@ -46,7 +46,7 @@ public: u256 const& nonce() const { return m_nonce; } void incNonce() { m_nonce++; } - h256 oldRoot() const { return m_storageRoot; } + h256 baseRoot() const { return m_storageRoot; } std::map const& storage() const { return m_storageOverlay; } void setStorage(u256 _p, u256 _v) { m_storageOverlay[_p] = _v; } diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 809f3a90a..5a5804637 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -234,19 +234,11 @@ void BlockChain::import(bytes const& _block, OverlayDB const& _db) try #endif { - // Check family: - BlockInfo biParent(block(bi.parentHash)); - bi.verifyParent(biParent); - // Check transactions are valid and that they result in a state equivalent to our state_root. - State s(bi.coinbaseAddress, _db); - s.sync(*this, bi.parentHash); - // Get total difficulty increase and update state, checking it. - BlockInfo biGrandParent; - if (pd.number) - biGrandParent.populate(block(pd.parent)); - auto tdIncrease = s.playback(&_block, bi, biParent, biGrandParent, true); + State s(bi.coinbaseAddress, _db); + auto tdIncrease = s.enactOn(&_block, bi, *this); + s.cleanup(true); td = pd.totalDifficulty + tdIncrease; #if ETH_PARANOIA diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index c76fbb663..daa19f783 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -55,6 +55,7 @@ typedef std::map BlockDetailsHash; static const BlockDetails NullBlockDetails; static const h256s NullH256s; +class State; class OverlayDB; class AlreadyHaveBlock: public std::exception {}; diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index 274c55f08..faabee133 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -40,7 +40,7 @@ u256 Executive::gasUsed() const return m_t.gas - m_endGas; } -void Executive::setup(bytesConstRef _rlp) +bool Executive::setup(bytesConstRef _rlp) { // Entry point for a user-executed transaction. m_t = Transaction(_rlp); @@ -95,12 +95,12 @@ void Executive::setup(bytesConstRef _rlp) m_s.subBalance(m_sender, cost); if (m_t.isCreation()) - create(m_sender, m_t.value, m_t.gasPrice, m_t.gas - gasCost, &m_t.data, m_sender); + return create(m_sender, m_t.value, m_t.gasPrice, m_t.gas - gasCost, &m_t.data, m_sender); else - call(m_t.receiveAddress, m_sender, m_t.value, m_t.gasPrice, bytesConstRef(&m_t.data), m_t.gas - gasCost, m_sender); + return call(m_t.receiveAddress, m_sender, m_t.value, m_t.gasPrice, bytesConstRef(&m_t.data), m_t.gas - gasCost, m_sender); } -void Executive::call(Address _receiveAddress, Address _senderAddress, u256 _value, u256 _gasPrice, bytesConstRef _data, u256 _gas, Address _originAddress) +bool Executive::call(Address _receiveAddress, Address _senderAddress, u256 _value, u256 _gasPrice, bytesConstRef _data, u256 _gas, Address _originAddress) { // cnote << "Transferring" << formatBalance(_value) << "to receiver."; m_s.addBalance(_receiveAddress, _value); @@ -110,12 +110,16 @@ void Executive::call(Address _receiveAddress, Address _senderAddress, u256 _valu m_vm = new VM(_gas); bytes const& c = m_s.code(_receiveAddress); m_ext = new ExtVM(m_s, _receiveAddress, _senderAddress, _originAddress, _value, _gasPrice, _data, &c); + return false; } else + { m_endGas = _gas; + return true; + } } -void Executive::create(Address _sender, u256 _endowment, u256 _gasPrice, u256 _gas, bytesConstRef _init, Address _origin) +bool Executive::create(Address _sender, u256 _endowment, u256 _gasPrice, u256 _gas, bytesConstRef _init, Address _origin) { m_newAddress = right160(sha3(rlpList(_sender, m_s.transactionsFrom(_sender) - 1))); while (m_s.addressInUse(m_newAddress)) @@ -127,6 +131,7 @@ void Executive::create(Address _sender, u256 _endowment, u256 _gasPrice, u256 _g // Execute _init. m_vm = new VM(_gas); m_ext = new ExtVM(m_s, m_newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _init); + return _init.empty(); } bool Executive::go(uint64_t _steps) diff --git a/libethereum/Executive.h b/libethereum/Executive.h index 8a4e976bf..5dd31b69a 100644 --- a/libethereum/Executive.h +++ b/libethereum/Executive.h @@ -40,9 +40,9 @@ public: Executive(State& _s): m_s(_s) {} ~Executive(); - void setup(bytesConstRef _transaction); - void create(Address _txSender, u256 _endowment, u256 _gasPrice, u256 _gas, bytesConstRef _code, Address _originAddress); - void call(Address _myAddress, Address _txSender, u256 _txValue, u256 _gasPrice, bytesConstRef _txData, u256 _gas, Address _originAddress); + bool setup(bytesConstRef _transaction); + bool create(Address _txSender, u256 _endowment, u256 _gasPrice, u256 _gas, bytesConstRef _code, Address _originAddress); + bool call(Address _myAddress, Address _txSender, u256 _txValue, u256 _gasPrice, bytesConstRef _txData, u256 _gas, Address _originAddress); bool go(uint64_t _steps = (uint64_t)-1); void finalize(); u256 gasUsed() const; diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 86b433a8e..07e71dc28 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -37,6 +37,8 @@ using namespace eth; #define ctrace clog(StateTrace) +static const u256 c_blockReward = 1500 * finney; + OverlayDB State::openDB(std::string _path, bool _killExisting) { if (_path.empty()) @@ -57,10 +59,9 @@ OverlayDB State::openDB(std::string _path, bool _killExisting) State::State(Address _coinbaseAddress, OverlayDB const& _db): m_db(_db), m_state(&m_db), - m_ourAddress(_coinbaseAddress) + m_ourAddress(_coinbaseAddress), + m_blockReward(c_blockReward) { - m_blockReward = 1500 * finney; - secp256k1_start(); // Initialise to the state entailed by the genesis block; this guarantees the trie is built correctly. @@ -81,6 +82,31 @@ State::State(Address _coinbaseAddress, OverlayDB const& _db): paranoia("end of normal construction.", true); } +State::State(OverlayDB const& _db, BlockChain const& _bc, h256 _h): + m_db(_db), + m_state(&m_db), + m_blockReward(c_blockReward) +{ + secp256k1_start(); + + // TODO THINK: is this necessary? + m_state.init(); + + auto b = _bc.block(_h); + BlockInfo bi; + BlockInfo bip; + if (_h) + bi.populate(b); + if (bi && bi.number) + bip.populate(_bc.block(bi.parentHash)); + if (!_h || !bip) + return; + m_ourAddress = bi.coinbaseAddress; + + sync(_bc, bi.parentHash, bip); + enact(b); +} + State::State(State const& _s): m_db(_s.m_db), m_state(&m_db, _s.m_state.root()), @@ -280,16 +306,19 @@ bool State::sync(BlockChain const& _bc) return sync(_bc, _bc.currentHash()); } -bool State::sync(BlockChain const& _bc, h256 _block) +bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi) { bool ret = false; // BLOCK - BlockInfo bi; + BlockInfo bi = _bi; try { - auto b = _bc.block(_block); - bi.populate(b); -// bi.verifyInternals(_bc.block(_block)); // Unneeded - we already verify on import into the blockchain. + if (!bi) + { + auto b = _bc.block(_block); + bi.populate(b); +// bi.verifyInternals(_bc.block(_block)); // Unneeded - we already verify on import into the blockchain. + } } catch (...) { @@ -328,8 +357,23 @@ bool State::sync(BlockChain const& _bc, h256 _block) resetCurrent(); // Iterate through in reverse, playing back each of the blocks. - for (auto it = chain.rbegin(); it != chain.rend(); ++it) - trustedPlayback(_bc.block(*it), true); + try + { + for (auto it = chain.rbegin(); it != chain.rend(); ++it) + { + auto b = _bc.block(*it); + m_currentBlock.populate(b); + m_currentBlock.verifyInternals(b); + enact(b, BlockInfo()); + cleanup(true); + } + } + catch (...) + { + // TODO: Slightly nicer handling? :-) + cerr << "ERROR: Corrupt block-chain! Delete your block-chain DB and restart." << endl; + exit(1); + } resetCurrent(); ret = true; @@ -337,6 +381,21 @@ bool State::sync(BlockChain const& _bc, h256 _block) return ret; } +u256 State::enactOn(bytesConstRef _block, BlockInfo const& _bi, BlockChain const& _bc) +{ + // Check family: + BlockInfo biParent(_bc.block(_bi.parentHash)); + _bi.verifyParent(biParent); + BlockInfo biGrandParent; + if (biParent.number) + biGrandParent.populate(_bc.block(biParent.parentHash)); + sync(_bc, _bi.parentHash); + resetCurrent(); + m_currentBlock = _bi; + m_previousBlock = biParent; + return enact(_block, biGrandParent); +} + map State::addresses() const { map ret; @@ -366,7 +425,7 @@ void State::resetCurrent() // TODO: check. m_lastTx = m_db; - m_state.setRoot(m_currentBlock.stateRoot); + m_state.setRoot(m_previousBlock.stateRoot); paranoia("begin resetCurrent", true); } @@ -448,33 +507,16 @@ bool State::sync(TransactionQueue& _tq, bool* _changed) return ret; } -u256 State::playback(bytesConstRef _block, BlockInfo const& _bi, BlockInfo const& _parent, BlockInfo const& _grandParent, bool _fullCommit) +u256 State::enact(bytesConstRef _block, BlockInfo const& _grandParent) { - resetCurrent(); - m_currentBlock = _bi; - m_previousBlock = _parent; - return playbackRaw(_block, _grandParent, _fullCommit); -} + // m_currentBlock is assumed to be prepopulated and reset. -u256 State::trustedPlayback(bytesConstRef _block, bool _fullCommit) -{ - try - { - m_currentBlock.populate(_block); - m_currentBlock.verifyInternals(_block); - return playbackRaw(_block, BlockInfo(), _fullCommit); - } - catch (...) - { - // TODO: Slightly nicer handling? :-) - cerr << "ERROR: Corrupt block-chain! Delete your block-chain DB and restart." << endl; - exit(1); - } -} - -u256 State::playbackRaw(bytesConstRef _block, BlockInfo const& _grandParent, bool _fullCommit) -{ - // m_currentBlock is assumed to be prepopulated. +#if !RELEASE + BlockInfo bi(_block); + assert(m_previousBlock.hash == bi.parentHash); + assert(m_currentBlock.parentHash == bi.parentHash); + assert(rootHash() == m_previousBlock.stateRoot); +#endif if (m_currentBlock.parentHash != m_previousBlock.hash) throw InvalidParentHash(); @@ -503,15 +545,12 @@ u256 State::playbackRaw(bytesConstRef _block, BlockInfo const& _grandParent, boo } if (tr[2].toInt() != gasUsed()) throw InvalidTransactionGasUsed(); - if (_fullCommit) - { - bytes k = rlp(i); - transactionManifest.insert(&k, tr.data()); - } + bytes k = rlp(i); + transactionManifest.insert(&k, tr.data()); ++i; } - if (transactionManifest.root() != m_currentBlock.transactionsRoot) + if (m_currentBlock.transactionsRoot && transactionManifest.root() != m_currentBlock.transactionsRoot) { cwarn << "Bad transactions state root!"; throw InvalidTransactionStateRoot(); @@ -521,7 +560,6 @@ u256 State::playbackRaw(bytesConstRef _block, BlockInfo const& _grandParent, boo u256 tdIncrease = m_currentBlock.difficulty; // Check uncles & apply their rewards to state. - // TODO: Check for uniqueness of uncles. set nonces = { m_currentBlock.nonce }; Addresses rewarded; for (auto const& i: RLP(_block)[2]) @@ -545,7 +583,7 @@ u256 State::playbackRaw(bytesConstRef _block, BlockInfo const& _grandParent, boo commit(); // Hash the state trie and check against the state_root hash in m_currentBlock. - if (m_currentBlock.stateRoot != rootHash()) + if (m_currentBlock.stateRoot != m_previousBlock.stateRoot && m_currentBlock.stateRoot != rootHash()) { cwarn << "Bad state root!"; cnote << "Given to be:" << m_currentBlock.stateRoot; @@ -558,6 +596,11 @@ u256 State::playbackRaw(bytesConstRef _block, BlockInfo const& _grandParent, boo throw InvalidStateRoot(); } + return tdIncrease; +} + +void State::cleanup(bool _fullCommit) +{ if (_fullCommit) { paranoia("immediately before database commit", true); @@ -574,8 +617,6 @@ u256 State::playbackRaw(bytesConstRef _block, BlockInfo const& _grandParent, boo } resetCurrent(); - - return tdIncrease; } void State::uncommitToMine() @@ -614,7 +655,8 @@ bool State::amIJustParanoid(BlockChain const& _bc) cnote << "PARANOIA root:" << s.rootHash(); s.m_currentBlock.populate(&block.out(), false); // don't check nonce for this since we haven't mined it yet. s.m_currentBlock.verifyInternals(&block.out()); - s.playbackRaw(&block.out(), BlockInfo(), false); + s.enact(&block.out(), BlockInfo()); + s.cleanup(false); return true; } catch (Exception const& e) @@ -813,7 +855,7 @@ u256 State::storage(Address _id, u256 _memory) const return mit->second; // Not in the storage cache - go to the DB. - TrieDB memdb(const_cast(&m_db), it->second.oldRoot()); // promise we won't change the overlay! :) + TrieDB memdb(const_cast(&m_db), it->second.baseRoot()); // promise we won't change the overlay! :) string payload = memdb.at(_memory); u256 ret = payload.size() ? RLP(payload).toInt() : 0; it->second.setStorage(_memory, ret); @@ -829,9 +871,9 @@ map State::storage(Address _id) const if (it != m_cache.end()) { // Pull out all values from trie storage. - if (it->second.oldRoot()) + if (it->second.baseRoot()) { - TrieDB memdb(const_cast(&m_db), it->second.oldRoot()); // promise we won't alter the overlay! :) + TrieDB memdb(const_cast(&m_db), it->second.baseRoot()); // promise we won't alter the overlay! :) for (auto const& i: memdb) ret[i.first] = RLP(i.second).toInt(); } diff --git a/libethereum/State.h b/libethereum/State.h index afccec91f..fd3fc89e5 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -113,6 +113,9 @@ public: /// Construct state object. State(Address _coinbaseAddress = Address(), OverlayDB const& _db = OverlayDB()); + /// Construct state object from arbitrary point in blockchain. + State(OverlayDB const& _db, BlockChain const& _bc, h256 _hash); + /// Copy state object. State(State const& _s); @@ -127,6 +130,7 @@ public: /// Open a DB - useful for passing into the constructor & keeping for other states that are necessary. static OverlayDB openDB(std::string _path, bool _killExisting = false); static OverlayDB openDB(bool _killExisting = false) { return openDB(std::string(), _killExisting); } + OverlayDB const& db() const { return m_db; } /// @returns the set containing all addresses currently in use in Ethereum. std::map addresses() const; @@ -154,13 +158,6 @@ public: /// Only valid after mine() returns true. bytes const& blockData() const { return m_currentBytes; } - /// Sync our state with the block chain. - /// This basically involves wiping ourselves if we've been superceded and rebuilding from the transaction queue. - bool sync(BlockChain const& _bc); - - /// Sync with the block chain, but rather than synching to the latest block, instead sync to the given block. - bool sync(BlockChain const& _bc, h256 _blockHash); - // TODO: Cleaner interface. /// Sync our transactions, killing those from the queue that we have and assimilating those that we don't. /// @returns true if we uncommitted from mining during the operation. @@ -232,11 +229,11 @@ public: /// If (_i == pending().size()) returns the final state of the block, prior to rewards. State fromPending(unsigned _i) const; - /// Execute all transactions within a given block. - /// @returns the additional total difficulty. - /// If the _grandParent is passed, it will check the validity of each of the uncles. - /// This might throw. - u256 playback(bytesConstRef _block, BlockInfo const& _bi, BlockInfo const& _parent, BlockInfo const& _grandParent, bool _fullCommit); + /// @returns the StateDiff caused by the pending transaction of index @a _i. + StateDiff pendingDiff(unsigned _i) const { return fromPending(_i).diff(fromPending(_i + 1)); } + + /// @return the difference between this state (origin) and @a _c (destination). + StateDiff diff(State const& _c) const; /// Get the fee associated for a transaction with the given data. u256 txGas(uint _dataCount, u256 _gas = 0) const { return c_txDataGas * _dataCount + c_txGas + _gas; } @@ -247,8 +244,26 @@ public: /// Get the fee associated for a normal transaction. u256 callGas(uint _dataCount, u256 _gas = 0) const { return txGas(_dataCount, _gas); } - /// @return the difference between this state (origin) and @a _c (destination). - StateDiff diff(State const& _c) const; + /// Sync our state with the block chain. + /// This basically involves wiping ourselves if we've been superceded and rebuilding from the transaction queue. + bool sync(BlockChain const& _bc); + + /// Sync with the block chain, but rather than synching to the latest block, instead sync to the given block. + bool sync(BlockChain const& _bc, h256 _blockHash, BlockInfo const& _bi = BlockInfo()); + + /// Execute all transactions within a given block. + /// @warning We must already have been sync()ed with said block. + /// @returns the additional total difficulty. + /// If the @a _grandParent is passed, it will check the validity of each of the uncles. + /// @throws if there are any validation errors. + u256 playback(bytesConstRef _block, BlockInfo const& _bi, BlockInfo const& _parent, BlockInfo const& _grandParent = BlockInfo()); + + u256 enactOn(bytesConstRef _block, BlockInfo const& _bi, BlockChain const& _bc); + + /// Returns back to a pristine state after having done a playback. + /// @arg _fullCommit if true flush everything out to disk. If false, this effectively only validates + /// the block since all state changes are ultimately reversed. + void cleanup(bool _fullCommit); private: /// Undo the changes to the state for committing to mine. @@ -266,13 +281,9 @@ private: /// Commit all changes waiting in the address cache to the DB. void commit(); - /// Execute the given block on our previous block. This will set up m_currentBlock first, then call the other playback(). - /// Any failure will be critical. - u256 trustedPlayback(bytesConstRef _block, bool _fullCommit); - /// Execute the given block, assuming it corresponds to m_currentBlock. If _grandParent is passed, it will be used to check the uncles. /// Throws on failure. - u256 playbackRaw(bytesConstRef _block, BlockInfo const& _grandParent, bool _fullCommit); + u256 enact(bytesConstRef _block, BlockInfo const& _grandParent = BlockInfo()); // Two priviledged entry points for transaction processing used by the VM (these don't get added to the Transaction lists): // We assume all instrinsic fees are paid up before this point. @@ -342,10 +353,10 @@ void commit(std::map const& _cache, DB& _db, TrieDB storageDB(&_db, i.second.oldRoot()); + TrieDB storageDB(&_db, i.second.baseRoot()); for (auto const& j: i.second.storage()) if (j.second) storageDB.insert(j.first, rlp(j.second));