Skip to content
This repository has been archived by the owner on Oct 28, 2021. It is now read-only.

Commit

Permalink
Make sure debug_traceBlock, debug_traceTransaction, debug_storageRang…
Browse files Browse the repository at this point in the history
…eAt, admin_eth_vmTrace RPC methods work even when intermediate state root hash is not available in receipts

(this going to be the case after Metropolis). In this case execute all previous transactions in the block to get the intermediate state.
  • Loading branch information
gumb0 committed Apr 20, 2017
1 parent 7394901 commit 29df14f
Show file tree
Hide file tree
Showing 8 changed files with 54 additions and 16 deletions.
9 changes: 2 additions & 7 deletions libethereum/Block.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -829,15 +829,10 @@ bool Block::sealBlock(bytesConstRef _header)
return true;
}

State Block::fromPending(unsigned _i) const
h256 Block::stateRootBeforeTx(unsigned _i) const
{
State ret = m_state;
_i = min<unsigned>(_i, m_transactions.size());
if (!_i)
ret.setRoot(m_previousBlock.stateRoot());
else
ret.setRoot(m_receipts[_i - 1].stateRoot());
return ret;
return (_i > 0 ? m_receipts[_i - 1].stateRoot() : m_previousBlock.stateRoot());
}

LogBloom Block::logBloom() const
Expand Down
4 changes: 2 additions & 2 deletions libethereum/Block.h
Original file line number Diff line number Diff line change
Expand Up @@ -202,10 +202,10 @@ class Block
/// Get the bloom filter of a particular transaction that happened in the block.
LogBloom const& logBloom(unsigned _i) const { return m_receipts[_i].bloom(); }

/// Get the State immediately after the given number of pending transactions have been applied.
/// Get the State root hash immediately after the given number of pending transactions have been applied.
/// If (_i == 0) returns the initial state of the block.
/// If (_i == pending().size()) returns the final state of the block, prior to rewards.
State fromPending(unsigned _i) const;
h256 stateRootBeforeTx(unsigned _i) const;

// State-change operations

Expand Down
10 changes: 9 additions & 1 deletion libethereum/Executive.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,11 +158,19 @@ Executive::Executive(Block& _s, LastHashes const& _lh, unsigned _level):
}

Executive::Executive(State& _s, Block const& _block, unsigned _txIndex, BlockChain const& _bc, unsigned _level):
m_s(_s = _block.fromPending(_txIndex)),
m_s(_s = _block.state()),
m_envInfo(_block.info(), _bc.lastHashes(_block.info().parentHash()), _txIndex ? _block.receipt(_txIndex - 1).gasUsed() : 0),
m_depth(_level),
m_sealEngine(*_bc.sealEngine())
{
u256 const rootHash = _block.stateRootBeforeTx(_txIndex);
if (rootHash)
m_s.setRoot(rootHash);
else
{
m_s.setRoot(_block.stateRootBeforeTx(0));
m_s.executeBlockTransactions(_block, _txIndex, _bc.lastHashes(_block.info().parentHash()), *_bc.sealEngine());
}
}

u256 Executive::gasUsed() const
Expand Down
18 changes: 18 additions & 0 deletions libethereum/State.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include <libethcore/Exceptions.h>
#include <libevm/VMFactory.h>
#include "BlockChain.h"
#include "Block.h"
#include "CodeSizeCache.h"
#include "Defaults.h"
#include "ExtVM.h"
Expand Down Expand Up @@ -543,6 +544,23 @@ std::pair<ExecutionResult, TransactionReceipt> State::execute(EnvInfo const& _en
return make_pair(res, TransactionReceipt(rootState, startGasUsed + e.gasUsed(), e.logs()));
}

void State::executeBlockTransactions(Block const& _block, unsigned _txCount, LastHashes const& _lastHashes, SealEngineFace const& _sealEngine)
{
u256 gasUsed = 0;
for (unsigned i = 0; i < _txCount; ++i)
{
EnvInfo envInfo(_block.info(), _lastHashes, gasUsed);

Executive e(*this, envInfo, _sealEngine);
e.initialize(_block.pending()[i]);
if (!e.execute())
e.go();
e.finalize();

gasUsed += e.gasUsed();
}
}

std::ostream& dev::eth::operator<<(std::ostream& _out, State const& _s)
{
_out << "--- " << _s.rootHash() << std::endl;
Expand Down
2 changes: 2 additions & 0 deletions libethereum/State.h
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,8 @@ class State
/// This will change the state accordingly.
std::pair<ExecutionResult, TransactionReceipt> execute(EnvInfo const& _envInfo, SealEngineFace const& _sealEngine, Transaction const& _t, Permanence _p = Permanence::Committed, OnOpFunc const& _onOp = OnOpFunc());

void executeBlockTransactions(Block const& _block, unsigned _txCount, LastHashes const& _lastHashes, SealEngineFace const& _sealEngine);

/// Check if the address is in use.
bool addressInUse(Address const& _address) const;

Expand Down
20 changes: 17 additions & 3 deletions libweb3jsonrpc/Debug.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,19 @@ Json::Value Debug::traceTransaction(Executive& _e, Transaction const& _t, Json::

Json::Value Debug::traceBlock(Block const& _block, Json::Value const& _json)
{
State s(_block.state());
s.setRoot(_block.stateRootBeforeTx(0));

Json::Value traces(Json::arrayValue);
for (unsigned k = 0; k < _block.pending().size(); k++)
{
Transaction t = _block.pending()[k];
State s(State::Null);

u256 const gasUsed = k ? _block.receipt(k - 1).gasUsed() : 0;
EnvInfo envInfo(_block.info(), m_eth.blockChain().lastHashes(_block.info().parentHash()), gasUsed);
Executive e(s, envInfo, *m_eth.blockChain().sealEngine());

eth::ExecutionResult er;
Executive e(s, _block, k, m_eth.blockChain());
e.setResultRecipient(er);
traces.append(traceTransaction(e, t, _json));
}
Expand Down Expand Up @@ -136,7 +142,15 @@ Json::Value Debug::debug_storageRangeAt(string const& _blockHashOrNumber, int _t
Block block = m_eth.block(blockHash(_blockHashOrNumber));

unsigned const i = ((unsigned)_txIndex < block.pending().size()) ? (unsigned)_txIndex : block.pending().size();
State state = block.fromPending(i);
State state(block.state());
u256 const rootHash = block.stateRootBeforeTx(_txIndex);
if (rootHash)
state.setRoot(rootHash);
else
{
state.setRoot(block.stateRootBeforeTx(0));
state.executeBlockTransactions(block, i, m_eth.blockChain().lastHashes(block.info().parentHash()), *m_eth.blockChain().sealEngine());
}

map<h256, pair<u256, u256>> const storage(state.storage(Address(_address)));

Expand Down
2 changes: 1 addition & 1 deletion test/tools/libtesteth/BlockChainHelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,7 @@ bool TestBlockChain::addBlock(TestBlock const& _block)
block.sync(*m_blockChain.get());

//BOOST_REQUIRE(m_lastBlock.blockHeader().hash() == BlockHeader(block.blockData()).hash());
m_lastBlock.setState(block.fromPending(10000));
// m_lastBlock.setState(block.fromPending(10000));
return true;
}

Expand Down
5 changes: 3 additions & 2 deletions test/unittests/libethereum/Block.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,16 +76,17 @@ BOOST_AUTO_TEST_CASE(bStates)

Block block2 = blockchain.genesisBlock(genesisDB);
block2.populateFromChain(blockchain, testBlock.blockHeader().hash());
State stateAfterInsert = block2.fromPending(0); //get the state of blockchain on previous block
/* State stateAfterInsert = block2.fromPending(0); //get the state of blockchain on previous block
BOOST_REQUIRE(ImportTest::compareStates(stateBofore, stateAfterInsert) == 0);
// TODO remove this
State stateAfterInsert1 = block2.fromPending(1); //get the state of blockchain on current block executed
BOOST_REQUIRE(ImportTest::compareStates(stateAfterInsert, stateAfterInsert1, eth::AccountMaskMap(), WhenError::DontThrow) == 1);
State stateAfterInsert2 = block2.fromPending(2); //get the state of blockchain on current block executed
BOOST_REQUIRE(ImportTest::compareStates(stateBofore, stateAfterInsert2, eth::AccountMaskMap(), WhenError::DontThrow) == 1);
BOOST_REQUIRE(ImportTest::compareStates(stateAfterInsert1, stateAfterInsert2, eth::AccountMaskMap(), WhenError::DontThrow) == 1);

*/
//Block2 will start a new block on top of blockchain
BOOST_REQUIRE(block1.info() == block2.info());
block2.sync(blockchain);
Expand Down

0 comments on commit 29df14f

Please sign in to comment.