From 14ae9412071bf33a6e5c74fccd484876b2cf4c3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 19 Aug 2024 17:31:13 +0200 Subject: [PATCH] blockchaintest: Optional partial state hash check 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 https://github.com/ethereum/evmone/pull/953. --- test/blockchaintest/blockchaintest_runner.cpp | 31 +++++++++++++++++-- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/test/blockchaintest/blockchaintest_runner.cpp b/test/blockchaintest/blockchaintest_runner.cpp index b80f83e3b4..6f2e2529e6 100644 --- a/test/blockchaintest/blockchaintest_runner.cpp +++ b/test/blockchaintest/blockchaintest_runner.cpp @@ -116,6 +116,22 @@ 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 tests, evmc::VM& vm) @@ -123,6 +139,10 @@ void run_blockchain_tests(std::span 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); @@ -142,8 +162,9 @@ void run_blockchain_tests(std::span tests, evmc::VM& vm) std::unordered_map 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; @@ -158,8 +179,12 @@ void run_blockchain_tests(std::span 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) + { + EXPECT_EQ( + state::mpt_hash(TestState{state}), test_block.expected_block_header.state_root); + } if (rev >= EVMC_SHANGHAI) {