Skip to content

Commit

Permalink
blockchaintest: Optional partial state hash check
Browse files Browse the repository at this point in the history
This is blockchain tests execution optimization: for listed test names
only check state root hash of first 5 blocks (to detect early problems)
and last 5 blocks (to do the final check of the chain of blocks).

The current implementation of the MPT hash of the state builds
the trie from scratch (no updates to the trie of the previous block).
For the tests will a long chain of blocks the performance degrades
significantly with 99% time spent in the keccak hash function.

This improves testing of EIP-2935
implemented in #953.
  • Loading branch information
chfast committed Sep 10, 2024
1 parent a79218c commit 14ae941
Showing 1 changed file with 28 additions and 3 deletions.
31 changes: 28 additions & 3 deletions test/blockchaintest/blockchaintest_runner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,13 +116,33 @@ std::string print_state(const TestState& s)

return out.str();
}

/// How many first/last state hashes to check in the series of block for the "partial" check.
constexpr size_t PARTIAL_STATE_HASH_CHECK_MARGIN = 5;

/// List of test names for which only perform the partial state root hash checks.
/// For tests on the list, only check state hashes for first M (early problems)
/// and last M (final check of the chain) blocks,
/// where M is defined by PARTIAL_STATE_HASH_CHECK_MARGIN.
/// Otherwise, for very long blockchain test we spend a lot of time in MPT hashing
/// because the implementation of it is very simplistic: the trie is not updated
/// along the state changes but a new trie is build from scratch for every block.
constexpr std::array PARTIAL_STATE_HASH_CHECK_TESTS{
"a test name",
};


} // namespace

void run_blockchain_tests(std::span<const BlockchainTest> tests, evmc::VM& vm)
{
for (size_t case_index = 0; case_index != tests.size(); ++case_index)
{
const auto& c = tests[case_index];

const bool partial_state_hash_check = std::ranges::find(PARTIAL_STATE_HASH_CHECK_TESTS,
c.name) != PARTIAL_STATE_HASH_CHECK_TESTS.end();

SCOPED_TRACE(std::string{evmc::to_string(c.rev.get_revision(0))} + '/' +
std::to_string(case_index) + '/' + c.name);

Expand All @@ -142,8 +162,9 @@ void run_blockchain_tests(std::span<const BlockchainTest> tests, evmc::VM& vm)
std::unordered_map<int64_t, hash256> known_block_hashes{
{c.genesis_block_header.block_number, c.genesis_block_header.hash}};

for (const auto& test_block : c.test_blocks)
for (size_t block_idx = 0; block_idx != c.test_blocks.size(); ++block_idx)
{
const auto& test_block = c.test_blocks[block_idx];
auto bi = test_block.block_info;
bi.known_block_hashes = known_block_hashes;

Expand All @@ -158,8 +179,12 @@ void run_blockchain_tests(std::span<const BlockchainTest> tests, evmc::VM& vm)
SCOPED_TRACE(std::string{evmc::to_string(rev)} + '/' + std::to_string(case_index) +
'/' + c.name + '/' + std::to_string(test_block.block_info.number));

EXPECT_EQ(
state::mpt_hash(TestState{state}), test_block.expected_block_header.state_root);
if (!partial_state_hash_check || block_idx < PARTIAL_STATE_HASH_CHECK_MARGIN ||
block_idx >= c.test_blocks.size() - PARTIAL_STATE_HASH_CHECK_MARGIN)

Check warning on line 183 in test/blockchaintest/blockchaintest_runner.cpp

View check run for this annotation

Codecov / codecov/patch

test/blockchaintest/blockchaintest_runner.cpp#L183

Added line #L183 was not covered by tests
{
EXPECT_EQ(
state::mpt_hash(TestState{state}), test_block.expected_block_header.state_root);
}

if (rev >= EVMC_SHANGHAI)
{
Expand Down

0 comments on commit 14ae941

Please sign in to comment.