Skip to content

Commit

Permalink
blockchaintest: Add support for revision transitions
Browse files Browse the repository at this point in the history
Add support for blockchain tests with predefined timestamp
of a revision transition (e.g. transtion from Shanghai to Cancun at
the timestamp of 15000).
  • Loading branch information
chfast committed Nov 27, 2023
1 parent b1c9637 commit 458f76a
Show file tree
Hide file tree
Showing 6 changed files with 49 additions and 14 deletions.
3 changes: 2 additions & 1 deletion test/blockchaintest/blockchaintest.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include "../state/bloom_filter.hpp"
#include "../state/state.hpp"
#include "../utils/utils.hpp"
#include <evmc/evmc.hpp>
#include <span>
#include <vector>
Expand Down Expand Up @@ -60,7 +61,7 @@ struct BlockchainTest
std::vector<TestBlock> test_blocks;
BlockHeader genesis_block_header;
state::State pre_state;
evmc_revision rev;
RevisionSchedule rev;

Expectation expectation;
};
Expand Down
4 changes: 2 additions & 2 deletions test/blockchaintest/blockchaintest_loader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,10 @@ BlockchainTest load_blockchain_test_case(const std::string& name, const json::js
bt.name = name;
bt.genesis_block_header = from_json<BlockHeader>(j.at("genesisBlockHeader"));
bt.pre_state = from_json<State>(j.at("pre"));
bt.rev = to_rev(j.at("network").get<std::string>());
bt.rev = to_rev_schedule(j.at("network").get<std::string>());

for (const auto& el : j.at("blocks"))
bt.test_blocks.emplace_back(load_test_block(el, bt.rev));
bt.test_blocks.emplace_back(load_test_block(el, bt.rev.get_revision(0)));

bt.expectation.last_block_hash = from_json<hash256>(j.at("lastblockhash"));

Expand Down
17 changes: 10 additions & 7 deletions test/blockchaintest/blockchaintest_runner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,8 @@ 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];
SCOPED_TRACE(
std::string{evmc::to_string(c.rev)} + '/' + std::to_string(case_index) + '/' + c.name);
SCOPED_TRACE(std::string{evmc::to_string(c.rev.get_revision(0))} + '/' +
std::to_string(case_index) + '/' + c.name);

auto state = c.pre_state;

Expand All @@ -147,12 +147,12 @@ void run_blockchain_tests(std::span<const BlockchainTest> tests, evmc::VM& vm)
.known_block_hashes = {},
};

const auto genesis_res = apply_block(state, vm, genesis, {}, c.rev, {});
const auto genesis_res = apply_block(state, vm, genesis, {}, c.rev.get_revision(0), {});

EXPECT_EQ(
state::mpt_hash(state.get_accounts()), state::mpt_hash(c.pre_state.get_accounts()));

if (c.rev >= EVMC_SHANGHAI)
if (c.rev.get_revision(0) >= EVMC_SHANGHAI)
{
EXPECT_EQ(state::mpt_hash(genesis.withdrawals), c.genesis_block_header.withdrawal_root);
}
Expand All @@ -169,19 +169,22 @@ void run_blockchain_tests(std::span<const BlockchainTest> tests, evmc::VM& vm)
{
auto bi = test_block.block_info;
bi.known_block_hashes = known_block_hashes;

const auto rev = c.rev.get_revision(bi.timestamp);

const auto res =
apply_block(state, vm, bi, test_block.transactions, c.rev, mining_reward(c.rev));
apply_block(state, vm, bi, test_block.transactions, rev, mining_reward(rev));

known_block_hashes[test_block.expected_block_header.block_number] =
test_block.expected_block_header.hash;

SCOPED_TRACE(std::string{evmc::to_string(c.rev)} + '/' + std::to_string(case_index) +
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(state.get_accounts()), test_block.expected_block_header.state_root);

if (c.rev >= EVMC_SHANGHAI)
if (rev >= EVMC_SHANGHAI)
{
EXPECT_EQ(state::mpt_hash(test_block.block_info.withdrawals),
test_block.expected_block_header.withdrawal_root);
Expand Down
9 changes: 5 additions & 4 deletions test/unittests/blockchaintest_loader_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ TEST(json_loader, blockchain_test)

EXPECT_EQ(btt.size(), 1);
EXPECT_EQ(btt[0].test_blocks.size(), 1);
EXPECT_EQ(btt[0].rev, evmc_revision::EVMC_SHANGHAI);
EXPECT_EQ(btt[0].rev.get_revision(0), evmc_revision::EVMC_SHANGHAI);
EXPECT_EQ(btt[0].name, "000-fork=Shanghai-fill_stack");
EXPECT_EQ(btt[0].genesis_block_header.timestamp, 0);
EXPECT_EQ(btt[0].genesis_block_header.gas_limit, 0x016345785d8a0000);
Expand Down Expand Up @@ -229,7 +229,7 @@ TEST(json_loader, blockchain_test_post_state_hash)
"hash": "0xe1bcc830589216abdc79cb3075f06f7b133f7b0cf257ecb346da33c354099700"
},
"lastblockhash": "0x01de610f00331cea813e8143d51eb44ca352cdd90c602bb4b4bcf3c6cf9d5531",
"network": "Shanghai",
"network": "ShanghaiToCancunAtTime15k",
"pre": {
"0x0000000000000000000000000000000000000100": {
"nonce": "0x00",
Expand All @@ -253,7 +253,8 @@ TEST(json_loader, blockchain_test_post_state_hash)

EXPECT_EQ(btt.size(), 1);
EXPECT_EQ(btt[0].test_blocks.size(), 1);
EXPECT_EQ(btt[0].rev, evmc_revision::EVMC_SHANGHAI);
EXPECT_EQ(btt[0].rev.get_revision(0), evmc_revision::EVMC_SHANGHAI);
EXPECT_EQ(btt[0].rev.get_revision(15'000), evmc_revision::EVMC_CANCUN);
EXPECT_EQ(btt[0].name, "000-fork=Shanghai-fill_stack");
EXPECT_EQ(btt[0].genesis_block_header.timestamp, 0);
EXPECT_EQ(btt[0].genesis_block_header.gas_limit, 0x016345785d8a0000);
Expand Down Expand Up @@ -360,7 +361,7 @@ TEST(json_loader, blockchain_test_pre_paris)

EXPECT_EQ(btt.size(), 1);
EXPECT_EQ(btt[0].test_blocks.size(), 1);
EXPECT_EQ(btt[0].rev, evmc_revision::EVMC_LONDON);
EXPECT_EQ(btt[0].rev.get_revision(0), evmc_revision::EVMC_LONDON);
EXPECT_EQ(btt[0].name, "000-fork=Shanghai-fill_stack");
EXPECT_EQ(btt[0].genesis_block_header.timestamp, 0);
EXPECT_EQ(btt[0].genesis_block_header.gas_limit, 0x016345785d8a0000);
Expand Down
9 changes: 9 additions & 0 deletions test/utils/utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,13 @@ evmc_revision to_rev(std::string_view s)
throw std::invalid_argument{"unknown revision: " + std::string{s}};
}

RevisionSchedule to_rev_schedule(std::string_view s)
{
if (s == "ShanghaiToCancunAtTime15k")
return {EVMC_SHANGHAI, EVMC_CANCUN, 15'000};

const auto single_rev = to_rev(s);
return {single_rev, single_rev, 0};
}

} // namespace evmone::test
21 changes: 21 additions & 0 deletions test/utils/utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,31 @@ using evmc::hex;

namespace evmone::test
{
/// The EVM revision schedule based on timestamps.
struct RevisionSchedule
{
/// The revision of the first block.
evmc_revision genesis_rev = EVMC_FRONTIER;

/// The final revision to transition to.
evmc_revision final_rev = genesis_rev;

/// The timestamp of the transition to the final revision.
int64_t transition_time = 0;

/// Returns the specific revision for the given timestamp.
[[nodiscard]] evmc_revision get_revision(int64_t timestamp) const noexcept
{
return timestamp >= transition_time ? final_rev : genesis_rev;
}
};

/// Translates tests fork name to EVM revision
evmc_revision to_rev(std::string_view s);

/// Translates tests fork name to the EVM revision schedule.
RevisionSchedule to_rev_schedule(std::string_view s);

} // namespace evmone::test

/// Converts a string to bytes by casting individual characters.
Expand Down

0 comments on commit 458f76a

Please sign in to comment.