From 924b6b811f15f5374f4da823eab9962aa3432929 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 8 Feb 2024 14:21:47 +0100 Subject: [PATCH] test: Introduce TestState and TestAccount This decouples the `state::State` for transaction execution from the state object for test definitions and asserts. The `state::State` (also called "intra state") has some constructs and data related to transaction execution only (like "current" and "original" storage values). These should not be exposed to tests and make test definitions more complicated. This separation should also help with adding new public API for EVM with transaction-level execution granularity. --- test/blockchaintest/blockchaintest.hpp | 6 +- test/blockchaintest/blockchaintest_loader.cpp | 4 +- test/blockchaintest/blockchaintest_runner.cpp | 42 +-- test/state/CMakeLists.txt | 2 + test/state/mpt_hash.cpp | 12 +- test/state/mpt_hash.hpp | 9 +- test/state/state.hpp | 7 +- test/state/test_state.cpp | 34 ++ test/state/test_state.hpp | 67 ++++ test/statetest/statetest.hpp | 9 +- test/statetest/statetest_export.cpp | 8 +- test/statetest/statetest_loader.cpp | 21 +- test/statetest/statetest_runner.cpp | 4 +- test/t8n/t8n.cpp | 13 +- test/unittests/state_mpt_hash_test.cpp | 20 +- test/unittests/state_transition.cpp | 28 +- test/unittests/state_transition.hpp | 5 +- test/unittests/state_transition_call_test.cpp | 30 +- .../state_transition_eof_calls_test.cpp | 343 ++++++++---------- test/unittests/state_transition_tx_test.cpp | 7 +- test/unittests/statetest_loader_test.cpp | 11 +- 21 files changed, 369 insertions(+), 313 deletions(-) create mode 100644 test/state/test_state.cpp create mode 100644 test/state/test_state.hpp diff --git a/test/blockchaintest/blockchaintest.hpp b/test/blockchaintest/blockchaintest.hpp index 784013c7e2..04412d0ef8 100644 --- a/test/blockchaintest/blockchaintest.hpp +++ b/test/blockchaintest/blockchaintest.hpp @@ -5,6 +5,7 @@ #include "../state/bloom_filter.hpp" #include "../state/state.hpp" +#include "../state/test_state.hpp" #include "../utils/utils.hpp" #include #include @@ -43,7 +44,6 @@ struct BlockHeader struct TestBlock { state::BlockInfo block_info; - state::State pre_state; std::vector transactions; BlockHeader expected_block_header; @@ -54,14 +54,14 @@ struct BlockchainTest struct Expectation { hash256 last_block_hash; - std::variant post_state; + std::variant post_state; }; std::string name; std::vector test_blocks; BlockHeader genesis_block_header; - state::State pre_state; + TestState pre_state; RevisionSchedule rev; Expectation expectation; diff --git a/test/blockchaintest/blockchaintest_loader.cpp b/test/blockchaintest/blockchaintest_loader.cpp index 4141b3d6c1..b1f0cbac95 100644 --- a/test/blockchaintest/blockchaintest_loader.cpp +++ b/test/blockchaintest/blockchaintest_loader.cpp @@ -119,7 +119,7 @@ BlockchainTest load_blockchain_test_case(const std::string& name, const json::js BlockchainTest bt; bt.name = name; bt.genesis_block_header = from_json(j.at("genesisBlockHeader")); - bt.pre_state = from_json(j.at("pre")); + bt.pre_state = from_json(j.at("pre")); bt.rev = to_rev_schedule(j.at("network").get()); for (const auto& el : j.at("blocks")) @@ -128,7 +128,7 @@ BlockchainTest load_blockchain_test_case(const std::string& name, const json::js bt.expectation.last_block_hash = from_json(j.at("lastblockhash")); if (const auto it = j.find("postState"); it != j.end()) - bt.expectation.post_state = from_json(*it); + bt.expectation.post_state = from_json(*it); else if (const auto it_hash = j.find("postStateHash"); it_hash != j.end()) bt.expectation.post_state = from_json(*it_hash); diff --git a/test/blockchaintest/blockchaintest_runner.cpp b/test/blockchaintest/blockchaintest_runner.cpp index bb1fd77f73..9c1a0ffe53 100644 --- a/test/blockchaintest/blockchaintest_runner.cpp +++ b/test/blockchaintest/blockchaintest_runner.cpp @@ -66,7 +66,7 @@ TransitionResult apply_block(state::State& state, evmc::VM& vm, const state::Blo cumulative_gas_used += receipt.gas_used; receipt.cumulative_gas_used = cumulative_gas_used; if (rev < EVMC_BYZANTIUM) - receipt.post_state = state::mpt_hash(state.get_accounts()); + receipt.post_state = state::mpt_hash(TestState{state}); block_gas_left -= receipt.gas_used; blob_gas_left -= tx.blob_gas_used(); @@ -91,13 +91,11 @@ std::optional mining_reward(evmc_revision rev) noexcept return std::nullopt; } -std::string print_state(const state::State& s) +std::string print_state(const TestState& s) { std::stringstream out; - const std::map ordered( - s.get_accounts().begin(), s.get_accounts().end()); - for (const auto& [key, acc] : ordered) + for (const auto& [key, acc] : s) { out << key << " : \n"; out << "\tnonce : " << acc.nonce << "\n"; @@ -106,15 +104,11 @@ std::string print_state(const state::State& s) if (!acc.storage.empty()) { - const std::map ordered_storage( - acc.storage.begin(), acc.storage.end()); - - out << "\tstorage : " - << "\n"; - for (const auto& [s_key, val] : ordered_storage) + out << "\tstorage : \n"; + for (const auto& [s_key, val] : acc.storage) { - if (val.current) // Skip 0 values. - out << "\t\t" << s_key << " : " << hex0x(val.current) << "\n"; + if (!is_zero(val)) // Skip 0 values. + out << "\t\t" << s_key << " : " << hex0x(val) << "\n"; } } } @@ -131,7 +125,7 @@ void run_blockchain_tests(std::span tests, evmc::VM& vm) SCOPED_TRACE(std::string{evmc::to_string(c.rev.get_revision(0))} + '/' + std::to_string(case_index) + '/' + c.name); - auto state = c.pre_state; + auto state = c.pre_state.to_intra_state(); const state::BlockInfo genesis{ .number = c.genesis_block_header.block_number, @@ -151,8 +145,7 @@ void run_blockchain_tests(std::span tests, evmc::VM& vm) 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())); + EXPECT_EQ(state::mpt_hash(TestState{state}), state::mpt_hash(c.pre_state)); if (c.rev.get_revision(0) >= EVMC_SHANGHAI) { @@ -184,7 +177,7 @@ void run_blockchain_tests(std::span tests, evmc::VM& vm) '/' + 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); + state::mpt_hash(TestState{state}), test_block.expected_block_header.state_root); if (rev >= EVMC_SHANGHAI) { @@ -203,16 +196,17 @@ void run_blockchain_tests(std::span tests, evmc::VM& vm) // TODO: Add difficulty calculation verification. } - const auto post_state_hash = - std::holds_alternative(c.expectation.post_state) ? - state::mpt_hash(std::get(c.expectation.post_state).get_accounts()) : + const TestState post{state}; + const auto expected_post_hash = + std::holds_alternative(c.expectation.post_state) ? + state::mpt_hash(std::get(c.expectation.post_state)) : std::get(c.expectation.post_state); - EXPECT_TRUE(state::mpt_hash(state.get_accounts()) == post_state_hash) + EXPECT_TRUE(state::mpt_hash(post) == expected_post_hash) << "Result state:\n" - << print_state(state) - << (std::holds_alternative(c.expectation.post_state) ? + << print_state(post) + << (std::holds_alternative(c.expectation.post_state) ? "\n\nExpected state:\n" + - print_state(std::get(c.expectation.post_state)) : + print_state(std::get(c.expectation.post_state)) : ""); } } diff --git a/test/state/CMakeLists.txt b/test/state/CMakeLists.txt index c80a1532ea..db82138aa1 100644 --- a/test/state/CMakeLists.txt +++ b/test/state/CMakeLists.txt @@ -30,6 +30,8 @@ target_sources( rlp.hpp state.hpp state.cpp + test_state.hpp + test_state.cpp ) option(EVMONE_PRECOMPILES_SILKPRE "Enable precompiles support via silkpre library" OFF) diff --git a/test/state/mpt_hash.cpp b/test/state/mpt_hash.cpp index 910f768481..4f7737c9c7 100644 --- a/test/state/mpt_hash.cpp +++ b/test/state/mpt_hash.cpp @@ -3,31 +3,31 @@ // SPDX-License-Identifier: Apache-2.0 #include "mpt_hash.hpp" -#include "account.hpp" #include "mpt.hpp" #include "rlp.hpp" #include "state.hpp" +#include "test_state.hpp" namespace evmone::state { namespace { -hash256 mpt_hash(const std::unordered_map& storage) +hash256 mpt_hash(const std::map& storage) { MPT trie; for (const auto& [key, value] : storage) { - if (!is_zero(value.current)) // Skip "deleted" values. - trie.insert(keccak256(key), rlp::encode(rlp::trim(value.current))); + if (!is_zero(value)) // Skip "deleted" values. + trie.insert(keccak256(key), rlp::encode(rlp::trim(value))); } return trie.hash(); } } // namespace -hash256 mpt_hash(const std::unordered_map& accounts) +hash256 mpt_hash(const test::TestState& state) { MPT trie; - for (const auto& [addr, acc] : accounts) + for (const auto& [addr, acc] : state) { trie.insert(keccak256(addr), rlp::encode_tuple(acc.nonce, acc.balance, mpt_hash(acc.storage), keccak256(acc.code))); diff --git a/test/state/mpt_hash.hpp b/test/state/mpt_hash.hpp index 58c7301d23..f60862356a 100644 --- a/test/state/mpt_hash.hpp +++ b/test/state/mpt_hash.hpp @@ -7,12 +7,15 @@ #include #include -namespace evmone::state +namespace evmone::test { -struct Account; +class TestState; +} +namespace evmone::state +{ /// Computes Merkle Patricia Trie root hash for the given collection of state accounts. -hash256 mpt_hash(const std::unordered_map& accounts); +hash256 mpt_hash(const test::TestState& state); /// Computes Merkle Patricia Trie root hash for the given list of structures. template diff --git a/test/state/state.hpp b/test/state/state.hpp index e5b66a254a..c707fcddf0 100644 --- a/test/state/state.hpp +++ b/test/state/state.hpp @@ -16,8 +16,6 @@ namespace evmone::state { /// The Ethereum State: the collection of accounts mapped by their addresses. -/// -/// TODO: This class is copyable for testing. Consider making it non-copyable. class State { struct JournalBase @@ -71,6 +69,11 @@ class State std::vector m_journal; public: + State() = default; + State(const State&) = delete; + State(State&&) = default; + State& operator=(State&&) = default; + /// Inserts the new account at the address. /// There must not exist any account under this address before. Account& insert(const address& addr, Account account = {}); diff --git a/test/state/test_state.cpp b/test/state/test_state.cpp new file mode 100644 index 0000000000..c0073d05cb --- /dev/null +++ b/test/state/test_state.cpp @@ -0,0 +1,34 @@ +// evmone: Fast Ethereum Virtual Machine implementation +// Copyright 2024 The evmone Authors. +// SPDX-License-Identifier: Apache-2.0 +#include "test_state.hpp" +#include "state.hpp" + +namespace evmone::test +{ +TestState::TestState(const state::State& intra_state) +{ + for (const auto& [addr, acc] : intra_state.get_accounts()) + { + auto& test_acc = + (*this)[addr] = {.nonce = acc.nonce, .balance = acc.balance, .code = acc.code}; + auto& test_storage = test_acc.storage; + for (const auto& [key, value] : acc.storage) + test_storage[key] = value.current; + } +} + +state::State TestState::to_intra_state() const +{ + state::State intra_state; + for (const auto& [addr, acc] : *this) + { + auto& intra_acc = intra_state.insert( + addr, {.nonce = acc.nonce, .balance = acc.balance, .code = acc.code}); + auto& storage = intra_acc.storage; + for (const auto& [key, value] : acc.storage) + storage[key] = {.current = value, .original = value}; + } + return intra_state; +} +} // namespace evmone::test diff --git a/test/state/test_state.hpp b/test/state/test_state.hpp new file mode 100644 index 0000000000..f937712418 --- /dev/null +++ b/test/state/test_state.hpp @@ -0,0 +1,67 @@ +// evmone: Fast Ethereum Virtual Machine implementation +// Copyright 2024 The evmone Authors. +// SPDX-License-Identifier: Apache-2.0 +#pragma once + +#include +#include +#include + +namespace evmone +{ +namespace state +{ +class State; +} + +namespace test +{ +using evmc::address; +using evmc::bytes; +using evmc::bytes32; +using intx::uint256; + +/// Ethereum account representation for tests. +struct TestAccount +{ + uint64_t nonce = 0; + uint256 balance; + std::map storage; + bytes code; + + bool operator==(const TestAccount&) const noexcept = default; +}; + +/// Ethereum State representation for tests. +/// +/// This is a simplified variant of state::State: +/// it hides some details related to transaction execution (e.g. original storage values) +/// and is also easier to work with in tests. +class TestState : public std::map +{ +public: + using map::map; + + /// Inserts new account to the state. + /// + /// This method is for compatibility with state::State::insert(). + /// Don't use it in new tests, use std::map interface instead. + /// TODO: deprecate this method. + void insert(const address& addr, TestAccount&& acc) { (*this)[addr] = std::move(acc); } + + /// Gets the reference to an existing account. + /// + /// This method is for compatibility with state::State::get(). + /// Don't use it in new tests, use std::map interface instead. + /// TODO: deprecate this method. + TestAccount& get(const address& addr) { return (*this)[addr]; } + + /// Converts the intra state to TestState. + explicit TestState(const state::State& intra_state); + + /// Converts the TestState to intra state for transaction execution. + [[nodiscard]] state::State to_intra_state() const; +}; + +} // namespace test +} // namespace evmone diff --git a/test/statetest/statetest.hpp b/test/statetest/statetest.hpp index 6ca810f9e5..e4ecff114c 100644 --- a/test/statetest/statetest.hpp +++ b/test/statetest/statetest.hpp @@ -4,6 +4,7 @@ #pragma once #include "../state/state.hpp" +#include "../state/test_state.hpp" #include namespace json = nlohmann; @@ -54,7 +55,7 @@ struct StateTransitionTest }; std::string name; - state::State pre_state; + TestState pre_state; state::BlockInfo block; TestMultiTransaction multi_tx; std::vector cases; @@ -86,13 +87,13 @@ template <> state::Withdrawal from_json(const json::json& j); template <> -state::State from_json(const json::json& j); +TestState from_json(const json::json& j); template <> state::Transaction from_json(const json::json& j); /// Exports the State (accounts) to JSON format (aka pre/post/alloc state). -json::json to_json(const std::unordered_map& accounts); +json::json to_json(const TestState& state); std::vector load_state_tests(std::istream& input); @@ -100,7 +101,7 @@ std::vector load_state_tests(std::istream& input); /// - checks that there are no zero-value storage entries, /// - checks that there are no invalid EOF codes. /// Throws std::invalid_argument exception. -void validate_state(const state::State& state, evmc_revision rev); +void validate_state(const TestState& state, evmc_revision rev); /// Execute the state @p test using the @p vm. /// diff --git a/test/statetest/statetest_export.cpp b/test/statetest/statetest_export.cpp index 1a9d5c024e..7d2ed700ca 100644 --- a/test/statetest/statetest_export.cpp +++ b/test/statetest/statetest_export.cpp @@ -6,10 +6,10 @@ namespace evmone::test { -json::json to_json(const std::unordered_map& accounts) +json::json to_json(const TestState& state) { json::json j; - for (const auto& [addr, acc] : accounts) + for (const auto& [addr, acc] : state) { auto& j_acc = j[hex0x(addr)]; j_acc["nonce"] = hex0x(acc.nonce); @@ -19,8 +19,8 @@ json::json to_json(const std::unordered_map& accounts) auto& j_storage = j_acc["storage"] = json::json::object(); for (const auto& [key, val] : acc.storage) { - if (!is_zero(val.current)) - j_storage[hex0x(key)] = hex0x(val.current); + if (!is_zero(val)) + j_storage[hex0x(key)] = hex0x(val); } } return j; diff --git a/test/statetest/statetest_loader.cpp b/test/statetest/statetest_loader.cpp index d21fc34fb4..0be44e4827 100644 --- a/test/statetest/statetest_loader.cpp +++ b/test/statetest/statetest_loader.cpp @@ -270,23 +270,22 @@ state::BlockInfo from_json(const json::json& j) } template <> -state::State from_json(const json::json& j) +TestState from_json(const json::json& j) { - state::State o; + TestState o; for (const auto& [j_addr, j_acc] : j.items()) { - auto& acc = o.insert(from_json
(j_addr), - {.nonce = from_json(j_acc.at("nonce")), + auto& acc = + o[from_json
(j_addr)] = {.nonce = from_json(j_acc.at("nonce")), .balance = from_json(j_acc.at("balance")), - .code = from_json(j_acc.at("code"))}); + .code = from_json(j_acc.at("code"))}; if (const auto storage_it = j_acc.find("storage"); storage_it != j_acc.end()) { for (const auto& [j_key, j_value] : storage_it->items()) { if (const auto value = from_json(j_value); !is_zero(value)) - acc.storage.insert( - {from_json(j_key), {.current = value, .original = value}}); + acc.storage[from_json(j_key)] = value; } } } @@ -420,7 +419,7 @@ static void from_json(const json::json& j, StateTransitionTest::Case::Expectatio static void from_json(const json::json& j_t, StateTransitionTest& o) { - o.pre_state = from_json(j_t.at("pre")); + o.pre_state = from_json(j_t.at("pre")); o.multi_tx = j_t.at("transaction").get(); @@ -458,9 +457,9 @@ std::vector load_state_tests(std::istream& input) return json::json::parse(input).get>(); } -void validate_state(const state::State& state, evmc_revision rev) +void validate_state(const TestState& state, evmc_revision rev) { - for (const auto& [addr, acc] : state.get_accounts()) + for (const auto& [addr, acc] : state) { // TODO: Check for empty accounts after Paris. // https://github.com/ethereum/tests/issues/1331 @@ -484,7 +483,7 @@ void validate_state(const state::State& state, evmc_revision rev) for (const auto& [key, value] : acc.storage) { - if (is_zero(value.original)) + if (is_zero(value)) { throw std::invalid_argument{"account " + hex0x(addr) + " contains invalid zero-value storage entry " + diff --git a/test/statetest/statetest_runner.cpp b/test/statetest/statetest_runner.cpp index e1e2718db5..daac89f7c7 100644 --- a/test/statetest/statetest_runner.cpp +++ b/test/statetest/statetest_runner.cpp @@ -25,7 +25,7 @@ void run_state_test(const StateTransitionTest& test, evmc::VM& vm, bool trace_su const auto& expected = cases[case_index]; const auto tx = test.multi_tx.get(expected.indexes); - auto state = test.pre_state; + auto state = test.pre_state.to_intra_state(); const auto res = state::transition(state, test.block, tx, rev, vm, test.block.gas_limit, state::BlockInfo::MAX_BLOB_GAS_PER_BLOCK); @@ -33,7 +33,7 @@ void run_state_test(const StateTransitionTest& test, evmc::VM& vm, bool trace_su // Finalize block with reward 0. state::finalize(state, rev, test.block.coinbase, 0, {}, {}); - const auto state_root = state::mpt_hash(state.get_accounts()); + const auto state_root = state::mpt_hash(TestState{state}); if (trace_summary) { diff --git a/test/t8n/t8n.cpp b/test/t8n/t8n.cpp index 86bce75955..926245a465 100644 --- a/test/t8n/t8n.cpp +++ b/test/t8n/t8n.cpp @@ -80,7 +80,9 @@ int main(int argc, const char* argv[]) if (!alloc_file.empty()) { const auto j = json::json::parse(std::ifstream{alloc_file}, nullptr, false); - state = test::from_json(j); + const auto test_state = test::from_json(j); + validate_state(test_state, rev); + state = test_state.to_intra_state(); } if (!env_file.empty()) { @@ -115,8 +117,6 @@ int main(int argc, const char* argv[]) std::vector receipts; int64_t block_gas_left = block.gas_limit; - validate_state(state, rev); - // Parse and execute transactions if (!txs_file.empty()) { @@ -195,7 +195,7 @@ int main(int argc, const char* argv[]) cumulative_gas_used += receipt.gas_used; receipt.cumulative_gas_used = cumulative_gas_used; if (rev < EVMC_BYZANTIUM) - receipt.post_state = state::mpt_hash(state.get_accounts()); + receipt.post_state = state::mpt_hash(TestState{state}); j_receipt["cumulativeGasUsed"] = hex0x(cumulative_gas_used); j_receipt["blockHash"] = hex0x(bytes32{}); @@ -221,7 +221,7 @@ int main(int argc, const char* argv[]) state, rev, block.coinbase, block_reward, block.ommers, block.withdrawals); j_result["logsHash"] = hex0x(logs_hash(txs_logs)); - j_result["stateRoot"] = hex0x(state::mpt_hash(state.get_accounts())); + j_result["stateRoot"] = hex0x(state::mpt_hash(TestState{state})); } j_result["logsBloom"] = hex0x(compute_bloom_filter(receipts)); @@ -241,8 +241,7 @@ int main(int argc, const char* argv[]) std::ofstream{output_dir / output_result_file} << std::setw(2) << j_result; // Print out current state to outAlloc file - std::ofstream{output_dir / output_alloc_file} << std::setw(2) - << to_json(state.get_accounts()); + std::ofstream{output_dir / output_alloc_file} << std::setw(2) << to_json(TestState{state}); if (!output_body_file.empty()) std::ofstream{output_dir / output_body_file} << hex0x(rlp::encode(transactions)); diff --git a/test/unittests/state_mpt_hash_test.cpp b/test/unittests/state_mpt_hash_test.cpp index 68af2d9555..cac3807713 100644 --- a/test/unittests/state_mpt_hash_test.cpp +++ b/test/unittests/state_mpt_hash_test.cpp @@ -3,12 +3,12 @@ // SPDX-License-Identifier: Apache-2.0 #include -#include #include #include #include #include #include +#include #include #include @@ -20,7 +20,7 @@ using namespace evmone::test; TEST(state_mpt_hash, empty) { - EXPECT_EQ(mpt_hash(std::unordered_map()), emptyMPTHash); + EXPECT_EQ(mpt_hash(TestState{}), emptyMPTHash); } TEST(state_mpt_hash, single_account_v1) @@ -29,22 +29,18 @@ TEST(state_mpt_hash, single_account_v1) constexpr auto expected = 0x084f337237951e425716a04fb0aaa74111eda9d9c61767f2497697d0a201c92e_bytes32; - Account acc; - acc.balance = 1_u256; - const std::unordered_map accounts{{0x02_address, acc}}; + const TestState accounts{{0x02_address, {.balance = 1}}}; EXPECT_EQ(mpt_hash(accounts), expected); } TEST(state_mpt_hash, two_accounts) { - std::unordered_map accounts; - EXPECT_EQ(mpt_hash(accounts), emptyMPTHash); - - accounts[0x00_address] = Account{}; + TestState accounts; + accounts[0x00_address] = {}; EXPECT_EQ(mpt_hash(accounts), 0x0ce23f3c809de377b008a4a3ee94a0834aac8bec1f86e28ffe4fdb5a15b0c785_bytes32); - Account acc2; + TestAccount acc2; acc2.nonce = 1; acc2.balance = -2_u256; acc2.code = bytes{0x00}; // Note: `= {0x00}` causes GCC 12 warning at -O3. @@ -57,11 +53,11 @@ TEST(state_mpt_hash, two_accounts) TEST(state_mpt_hash, deleted_storage) { - Account acc; + TestAccount acc; acc.storage[0x01_bytes32] = {}; acc.storage[0x02_bytes32] = {0xfd_bytes32}; acc.storage[0x03_bytes32] = {}; - const std::unordered_map accounts{{0x07_address, acc}}; + const TestState accounts{{0x07_address, acc}}; EXPECT_EQ(mpt_hash(accounts), 0x4e7338c16731491e0fb5d1623f5265c17699c970c816bab71d4d717f6071414d_bytes32); } diff --git a/test/unittests/state_transition.cpp b/test/unittests/state_transition.cpp index e079b6c0eb..9d08fcecf5 100644 --- a/test/unittests/state_transition.cpp +++ b/test/unittests/state_transition.cpp @@ -56,12 +56,12 @@ void state_transition::TearDown() if (trace) trace_capture.emplace(); - auto intra_state = pre; + auto intra_state = pre.to_intra_state(); const auto res = state::transition(intra_state, block, tx, rev, selected_vm, block.gas_limit, state::BlockInfo::MAX_BLOB_GAS_PER_BLOCK); state::finalize( intra_state, rev, block.coinbase, block_reward, block.ommers, block.withdrawals); - const auto& post = intra_state; + TestState post{intra_state}; if (const auto expected_error = make_error_code(expect.tx_error)) { @@ -71,11 +71,7 @@ void state_transition::TearDown() EXPECT_EQ(tx_error, expected_error) << tx_error.message() << " vs " << expected_error.message(); - EXPECT_EQ(post.get_accounts().size(), pre.get_accounts().size()); - for (const auto& [addr, acc] : post.get_accounts()) - { - EXPECT_TRUE(pre.get_accounts().contains(addr)) << "unexpected account " << addr; - } + EXPECT_EQ(post, pre) << "failed transaction has modified the state"; } else { @@ -103,8 +99,8 @@ void state_transition::TearDown() for (const auto& [addr, expected_acc] : expect.post) { - const auto ait = post.get_accounts().find(addr); - if (ait == post.get_accounts().end()) + const auto ait = post.find(addr); + if (ait == post.end()) { EXPECT_FALSE(expected_acc.exists) << addr << ": should not exist"; continue; @@ -130,25 +126,25 @@ void state_transition::TearDown() { // Lookup storage values. Map non-existing ones to 0. const auto sit = acc.storage.find(key); - const auto& value = sit != acc.storage.end() ? sit->second.current : bytes32{}; + const auto& value = sit != acc.storage.end() ? sit->second : bytes32{}; EXPECT_EQ(value, expected_value) << addr << ": wrong storage " << key; } for (const auto& [key, value] : acc.storage) { // Find unexpected storage keys. This will also report entries with value 0. EXPECT_TRUE(expected_acc.storage.contains(key)) - << addr << ": unexpected storage " << key << "=" << value.current; + << addr << ": unexpected storage " << key << "=" << value; } } - for (const auto& [addr, _] : post.get_accounts()) + for (const auto& [addr, _] : post) { EXPECT_TRUE(expect.post.contains(addr)) << addr << ": should not exist"; } if (expect.state_hash) { - EXPECT_EQ(mpt_hash(post.get_accounts()), *expect.state_hash); + EXPECT_EQ(mpt_hash(post), *expect.state_hash); } if (!export_file_path.empty()) @@ -173,7 +169,7 @@ std::string_view to_test_fork_name(evmc_revision rev) noexcept } // namespace void state_transition::export_state_test( - const std::variant& res, const State& post) + const std::variant& res, const TestState& post) { json::json j; auto& jt = j[export_test_name]; @@ -185,7 +181,7 @@ void state_transition::export_state_test( jenv["currentCoinbase"] = hex0x(block.coinbase); jenv["currentBaseFee"] = hex0x(block.base_fee); - jt["pre"] = to_json(pre.get_accounts()); + jt["pre"] = to_json(pre); auto& jtx = jt["transaction"]; if (tx.to.has_value()) @@ -231,7 +227,7 @@ void state_transition::export_state_test( auto& jpost = jt["post"][to_test_fork_name(rev)][0]; jpost["indexes"] = {{"data", 0}, {"gas", 0}, {"value", 0}}; - jpost["hash"] = hex0x(mpt_hash(post.get_accounts())); + jpost["hash"] = hex0x(mpt_hash(post)); if (holds_alternative(res)) { diff --git a/test/unittests/state_transition.hpp b/test/unittests/state_transition.hpp index b3b20cc7c5..713460b399 100644 --- a/test/unittests/state_transition.hpp +++ b/test/unittests/state_transition.hpp @@ -7,6 +7,7 @@ #include #include #include +#include namespace evmone::test { @@ -83,7 +84,7 @@ class state_transition : public ExportableFixture .sender = Sender, .nonce = 1, }; - State pre; + TestState pre; Expectation expect; void SetUp() override; @@ -93,7 +94,7 @@ class state_transition : public ExportableFixture /// Exports the test in the JSON State Test format to ExportableFixture::export_out. void export_state_test( - const std::variant& res, const State& post); + const std::variant& res, const TestState& post); }; } // namespace evmone::test diff --git a/test/unittests/state_transition_call_test.cpp b/test/unittests/state_transition_call_test.cpp index a22be33397..2b09a9e013 100644 --- a/test/unittests/state_transition_call_test.cpp +++ b/test/unittests/state_transition_call_test.cpp @@ -26,25 +26,21 @@ TEST_F(state_transition, delegatecall_static_legacy) // Checks if DELEGATECALL forwards the "static" flag. constexpr auto callee1 = 0xca11ee01_address; constexpr auto callee2 = 0xca11ee02_address; - pre.insert(callee2, - { - .storage = {{0x01_bytes32, {.current = 0xdd_bytes32, .original = 0xdd_bytes32}}}, - .code = sstore(1, 0xcc_bytes32), - }); - pre.insert(callee1, - { - .storage = {{0x01_bytes32, {.current = 0xdd_bytes32, .original = 0xdd_bytes32}}}, - .code = ret(delegatecall(callee2).gas(100'000)), - }); + pre.insert(callee2, { + .storage = {{0x01_bytes32, 0xdd_bytes32}}, + .code = sstore(1, 0xcc_bytes32), + }); + pre.insert(callee1, { + .storage = {{0x01_bytes32, 0xdd_bytes32}}, + .code = ret(delegatecall(callee2).gas(100'000)), + }); tx.to = To; - pre.insert( - *tx.to, { - .storage = {{0x01_bytes32, {.current = 0xdd_bytes32, .original = 0xdd_bytes32}}, - {0x02_bytes32, {.current = 0xdd_bytes32, .original = 0xdd_bytes32}}}, - .code = sstore(1, staticcall(callee1).gas(200'000)) + - sstore(2, returndatacopy(0, 0, returndatasize()) + mload(0)), - }); + pre.insert(*tx.to, { + .storage = {{0x01_bytes32, 0xdd_bytes32}, {0x02_bytes32, 0xdd_bytes32}}, + .code = sstore(1, staticcall(callee1).gas(200'000)) + + sstore(2, returndatacopy(0, 0, returndatasize()) + mload(0)), + }); expect.gas_used = 131480; // Outer call - success. expect.post[*tx.to].storage[0x01_bytes32] = 0x01_bytes32; diff --git a/test/unittests/state_transition_eof_calls_test.cpp b/test/unittests/state_transition_eof_calls_test.cpp index ec5e890e52..c1000d4c86 100644 --- a/test/unittests/state_transition_eof_calls_test.cpp +++ b/test/unittests/state_transition_eof_calls_test.cpp @@ -15,17 +15,16 @@ TEST_F(state_transition, eof1_extdelegatecall_eof1) constexpr auto callee = 0xca11ee_address; pre.insert(callee, { - .storage = {{0x02_bytes32, {.current = 0xdd_bytes32, .original = 0xdd_bytes32}}}, + .storage = {{0x02_bytes32, 0xdd_bytes32}}, .code = eof_bytecode(sstore(2, 0xcc_bytes32) + mstore(0, 0x010203_bytes32) + ret(0, 32), 2), }); tx.to = To; - pre.insert(*tx.to, - { - .storage = {{0x02_bytes32, {.current = 0xdd_bytes32, .original = 0xdd_bytes32}}}, - .code = - eof_bytecode(extdelegatecall(callee) + sstore(1, returndataload(0)) + OP_STOP, 3), - }); + pre.insert(*tx.to, { + .storage = {{0x02_bytes32, 0xdd_bytes32}}, + .code = eof_bytecode( + extdelegatecall(callee) + sstore(1, returndataload(0)) + OP_STOP, 3), + }); expect.gas_used = 50742; expect.post[*tx.to].storage[0x01_bytes32] = 0x010203_bytes32; @@ -45,8 +44,7 @@ TEST_F(state_transition, eof1_extdelegatecall_legacy) tx.to = To; pre.insert(*tx.to, { - .storage = {{0x01_bytes32, {.current = 0xdd_bytes32, .original = 0xdd_bytes32}}, - {0x02_bytes32, {.current = 0xdd_bytes32, .original = 0xdd_bytes32}}}, + .storage = {{0x01_bytes32, 0xdd_bytes32}, {0x02_bytes32, 0xdd_bytes32}}, .code = eof_bytecode( sstore(1, extdelegatecall(callee)) + sstore(2, returndatasize()) + OP_STOP, 3), }); @@ -67,22 +65,19 @@ TEST_F(state_transition, extdelegatecall_static) // Checks if EXTDELEGATECALL forwards the "static" flag. constexpr auto callee1 = 0xca11ee01_address; constexpr auto callee2 = 0xca11ee02_address; - pre.insert(callee2, - { - .storage = {{0x01_bytes32, {.current = 0xdd_bytes32, .original = 0xdd_bytes32}}}, - .code = eof_bytecode(sstore(1, 0xcc_bytes32) + OP_STOP, 2), - }); - pre.insert(callee1, - { - .storage = {{0x01_bytes32, {.current = 0xdd_bytes32, .original = 0xdd_bytes32}}}, - .code = eof_bytecode(ret(extdelegatecall(callee2)), 3), - }); + pre.insert(callee2, { + .storage = {{0x01_bytes32, 0xdd_bytes32}}, + .code = eof_bytecode(sstore(1, 0xcc_bytes32) + OP_STOP, 2), + }); + pre.insert(callee1, { + .storage = {{0x01_bytes32, 0xdd_bytes32}}, + .code = eof_bytecode(ret(extdelegatecall(callee2)), 3), + }); tx.to = To; pre.insert(*tx.to, { - .storage = {{0x01_bytes32, {.current = 0xdd_bytes32, .original = 0xdd_bytes32}}, - {0x02_bytes32, {.current = 0xdd_bytes32, .original = 0xdd_bytes32}}}, + .storage = {{0x01_bytes32, 0xdd_bytes32}, {0x02_bytes32, 0xdd_bytes32}}, .code = eof_bytecode( sstore(1, extstaticcall(callee1)) + sstore(2, returndataload(0)) + OP_STOP, 3), }); @@ -107,14 +102,13 @@ TEST_F(state_transition, extcall_static_with_value) }); tx.to = To; - pre.insert( - *tx.to, { - .storage = - { - {0x01_bytes32, {.current = 0xdd_bytes32, .original = 0xdd_bytes32}}, - }, - .code = eof_bytecode(sstore(1, extstaticcall(callee1)) + OP_STOP, 3), - }); + pre.insert(*tx.to, { + .storage = + { + {0x01_bytes32, 0xdd_bytes32}, + }, + .code = eof_bytecode(sstore(1, extstaticcall(callee1)) + OP_STOP, 3), + }); expect.gas_used = 989747; // Outer call - abort in callee. expect.post[*tx.to].storage[0x01_bytes32] = 0x02_bytes32; @@ -126,19 +120,17 @@ TEST_F(state_transition, extcall_failing_with_value_balance_check) rev = EVMC_PRAGUE; constexpr auto callee = 0xca11ee_address; - pre.insert(callee, - { - .storage = {{0x01_bytes32, {.current = 0xdd_bytes32, .original = 0xdd_bytes32}}}, - .code = eof_bytecode(sstore(1, 0xcc_bytes32) + OP_STOP, 2), - }); + pre.insert(callee, { + .storage = {{0x01_bytes32, 0xdd_bytes32}}, + .code = eof_bytecode(sstore(1, 0xcc_bytes32) + OP_STOP, 2), + }); tx.to = To; - pre.insert(*tx.to, - { - .storage = {{0x01_bytes32, {.current = 0xdd_bytes32, .original = 0xdd_bytes32}}}, - .code = - eof_bytecode(sstore(1, extcall(callee).input(0x0, 0xff).value(0x1)) + OP_STOP, 4), - }); + pre.insert(*tx.to, { + .storage = {{0x01_bytes32, 0xdd_bytes32}}, + .code = eof_bytecode( + sstore(1, extcall(callee).input(0x0, 0xff).value(0x1)) + OP_STOP, 4), + }); expect.post[*tx.to].storage[0x01_bytes32] = 0x01_bytes32; expect.post[callee].storage[0x01_bytes32] = 0xdd_bytes32; @@ -149,19 +141,17 @@ TEST_F(state_transition, extcall_failing_with_value_additional_cost) rev = EVMC_PRAGUE; constexpr auto callee = 0xca11ee_address; - pre.insert(callee, - { - .storage = {{0x01_bytes32, {.current = 0xdd_bytes32, .original = 0xdd_bytes32}}}, - .code = eof_bytecode(sstore(1, 0xcc_bytes32) + OP_STOP, 2), - }); + pre.insert(callee, { + .storage = {{0x01_bytes32, 0xdd_bytes32}}, + .code = eof_bytecode(sstore(1, 0xcc_bytes32) + OP_STOP, 2), + }); tx.to = To; - pre.insert(*tx.to, - { - .storage = {{0x01_bytes32, {.current = 0xdd_bytes32, .original = 0xdd_bytes32}}}, - .code = - eof_bytecode(sstore(1, extcall(callee).input(0x0, 0xff).value(0x1)) + OP_STOP, 4), - }); + pre.insert(*tx.to, { + .storage = {{0x01_bytes32, 0xdd_bytes32}}, + .code = eof_bytecode( + sstore(1, extcall(callee).input(0x0, 0xff).value(0x1)) + OP_STOP, 4), + }); // Fails on value transfer additional cost - maximum gas limit that triggers this tx.gas_limit = 37639 - 1; @@ -176,20 +166,18 @@ TEST_F(state_transition, extcall_with_value) rev = EVMC_PRAGUE; constexpr auto callee = 0xca11ee_address; - pre.insert(callee, - { - .storage = {{0x01_bytes32, {.current = 0xdd_bytes32, .original = 0xdd_bytes32}}}, - .code = eof_bytecode(sstore(1, 0xcc_bytes32) + OP_STOP, 2), - }); + pre.insert(callee, { + .storage = {{0x01_bytes32, 0xdd_bytes32}}, + .code = eof_bytecode(sstore(1, 0xcc_bytes32) + OP_STOP, 2), + }); tx.to = To; - pre.insert(*tx.to, - { - .balance = 0x01, - .storage = {{0x01_bytes32, {.current = 0xdd_bytes32, .original = 0xdd_bytes32}}}, - .code = - eof_bytecode(sstore(1, extcall(callee).input(0x0, 0xff).value(0x1)) + OP_STOP, 4), - }); + pre.insert(*tx.to, { + .balance = 0x01, + .storage = {{0x01_bytes32, 0xdd_bytes32}}, + .code = eof_bytecode( + sstore(1, extcall(callee).input(0x0, 0xff).value(0x1)) + OP_STOP, 4), + }); expect.gas_used = 37845; expect.post[*tx.to].storage[0x01_bytes32] = 0x00_bytes32; @@ -206,11 +194,10 @@ TEST_F(state_transition, extcall_min_callee_gas_failure_mode) }); tx.to = To; - pre.insert(*tx.to, - { - .storage = {{0x01_bytes32, {.current = 0xdd_bytes32, .original = 0xdd_bytes32}}}, - .code = eof_bytecode(sstore(1, extcall(callee)) + OP_STOP, 4), - }); + pre.insert(*tx.to, { + .storage = {{0x01_bytes32, 0xdd_bytes32}}, + .code = eof_bytecode(sstore(1, extcall(callee)) + OP_STOP, 4), + }); // Just short of what the caller needs + MIN_RETAINED_GAS + MIN_CALLEE_GAS tx.gas_limit = 21000 + 4 * 3 + 2600 + 5000 + 2300 - 1; @@ -231,7 +218,7 @@ TEST_F(state_transition, extcall_output) tx.to = To; pre.insert(*tx.to, { - .storage = {{0x01_bytes32, {.current = 0xdd_bytes32, .original = 0xdd_bytes32}}}, + .storage = {{0x01_bytes32, 0xdd_bytes32}}, .code = eof_bytecode( extcall(callee) + sstore(1, returndatacopy(31, 30, 1) + mload(0)) + OP_STOP, 4), }); @@ -251,7 +238,7 @@ TEST_F(state_transition, extdelegatecall_output) tx.to = To; pre.insert(*tx.to, { - .storage = {{0x01_bytes32, {.current = 0xdd_bytes32, .original = 0xdd_bytes32}}}, + .storage = {{0x01_bytes32, 0xdd_bytes32}}, .code = eof_bytecode( extdelegatecall(callee) + sstore(1, returndatacopy(31, 30, 1) + mload(0)) + OP_STOP, 4), @@ -272,7 +259,7 @@ TEST_F(state_transition, extstaticcall_output) tx.to = To; pre.insert(*tx.to, { - .storage = {{0x01_bytes32, {.current = 0xdd_bytes32, .original = 0xdd_bytes32}}}, + .storage = {{0x01_bytes32, 0xdd_bytes32}}, .code = eof_bytecode( extstaticcall(callee) + sstore(1, returndatacopy(31, 30, 1) + mload(0)) + OP_STOP, 4), @@ -421,11 +408,10 @@ TEST_F(state_transition, extcall_value_zero_to_nonexistent_account) constexpr auto callee = 0xca11ee_address; tx.to = To; - pre.insert(*tx.to, - { - .storage = {{0x01_bytes32, {.current = 0xdd_bytes32, .original = 0xdd_bytes32}}}, - .code = eof_bytecode(sstore(1, extcall(callee).value(0x0)) + OP_STOP, 4), - }); + pre.insert(*tx.to, { + .storage = {{0x01_bytes32, 0xdd_bytes32}}, + .code = eof_bytecode(sstore(1, extcall(callee).value(0x0)) + OP_STOP, 4), + }); tx.gas_limit = 21000 + 4 * 3 + 5000 + 2300 + 2600 + 2; expect.post[*tx.to].storage[0x01_bytes32] = 0x00_bytes32; } @@ -435,18 +421,17 @@ TEST_F(state_transition, extcall_then_oog) rev = EVMC_PRAGUE; constexpr auto callee = 0xca11ee_address; - pre.insert(callee, - { - .storage = {{0x01_bytes32, {.current = 0xdd_bytes32, .original = 0xdd_bytes32}}}, - .code = eof_bytecode(sstore(1, 0xcc_bytes32) + OP_STOP, 2), - }); + pre.insert(callee, { + .storage = {{0x01_bytes32, 0xdd_bytes32}}, + .code = eof_bytecode(sstore(1, 0xcc_bytes32) + OP_STOP, 2), + }); tx.to = To; - pre.insert(*tx.to, - { - .storage = {{0x01_bytes32, {.current = 0xdd_bytes32, .original = 0xdd_bytes32}}}, - .code = eof_bytecode(sstore(1, 0xcc_bytes32) + extcall(callee) + rjump(-3), 4), - }); + pre.insert( + *tx.to, { + .storage = {{0x01_bytes32, 0xdd_bytes32}}, + .code = eof_bytecode(sstore(1, 0xcc_bytes32) + extcall(callee) + rjump(-3), 4), + }); // Enough to SSTORE and complete EXTCALL, OOG is sure to be in the infinite loop. tx.gas_limit = 1'000'000; @@ -461,16 +446,15 @@ TEST_F(state_transition, extdelegatecall_then_oog) rev = EVMC_PRAGUE; constexpr auto callee = 0xca11ee_address; - pre.insert(callee, - { - .storage = {{0x01_bytes32, {.current = 0xdd_bytes32, .original = 0xdd_bytes32}}}, - .code = eof_bytecode(sstore(1, 0xcc_bytes32) + OP_STOP, 2), - }); + pre.insert(callee, { + .storage = {{0x01_bytes32, 0xdd_bytes32}}, + .code = eof_bytecode(sstore(1, 0xcc_bytes32) + OP_STOP, 2), + }); tx.to = To; pre.insert(*tx.to, { - .storage = {{0x01_bytes32, {.current = 0xdd_bytes32, .original = 0xdd_bytes32}}}, + .storage = {{0x01_bytes32, 0xdd_bytes32}}, .code = eof_bytecode(sstore(1, 0xcc_bytes32) + extdelegatecall(callee) + rjump(-3), 3), }); // Enough to complete EXTDELEGATECALL, OOG in infinite loop. @@ -494,7 +478,7 @@ TEST_F(state_transition, extstaticcall_then_oog) tx.to = To; pre.insert(*tx.to, { - .storage = {{0x01_bytes32, {.current = 0xdd_bytes32, .original = 0xdd_bytes32}}}, + .storage = {{0x01_bytes32, 0xdd_bytes32}}, .code = eof_bytecode(sstore(1, 0xcc_bytes32) + extstaticcall(callee) + rjump(-3), 3), }); // Enough to complete EXTSTATICCALL, OOG in infinite loop. @@ -516,11 +500,10 @@ TEST_F(state_transition, extcall_callee_revert) }); tx.to = To; - pre.insert(*tx.to, - { - .storage = {{0x01_bytes32, {.current = 0xdd_bytes32, .original = 0xdd_bytes32}}}, - .code = eof_bytecode(sstore(1, extcall(callee)) + OP_STOP, 4), - }); + pre.insert(*tx.to, { + .storage = {{0x01_bytes32, 0xdd_bytes32}}, + .code = eof_bytecode(sstore(1, extcall(callee)) + OP_STOP, 4), + }); expect.post[*tx.to].storage[0x01_bytes32] = 0x01_bytes32; expect.post[callee].exists = true; expect.status = EVMC_SUCCESS; @@ -536,11 +519,10 @@ TEST_F(state_transition, extdelegatecall_callee_revert) }); tx.to = To; - pre.insert(*tx.to, - { - .storage = {{0x01_bytes32, {.current = 0xdd_bytes32, .original = 0xdd_bytes32}}}, - .code = eof_bytecode(sstore(1, extdelegatecall(callee)) + OP_STOP, 3), - }); + pre.insert(*tx.to, { + .storage = {{0x01_bytes32, 0xdd_bytes32}}, + .code = eof_bytecode(sstore(1, extdelegatecall(callee)) + OP_STOP, 3), + }); expect.post[*tx.to].storage[0x01_bytes32] = 0x01_bytes32; expect.post[callee].exists = true; expect.status = EVMC_SUCCESS; @@ -556,11 +538,10 @@ TEST_F(state_transition, extstaticcall_callee_revert) }); tx.to = To; - pre.insert(*tx.to, - { - .storage = {{0x01_bytes32, {.current = 0xdd_bytes32, .original = 0xdd_bytes32}}}, - .code = eof_bytecode(sstore(1, extstaticcall(callee)) + OP_STOP, 3), - }); + pre.insert(*tx.to, { + .storage = {{0x01_bytes32, 0xdd_bytes32}}, + .code = eof_bytecode(sstore(1, extstaticcall(callee)) + OP_STOP, 3), + }); expect.post[*tx.to].storage[0x01_bytes32] = 0x01_bytes32; expect.post[callee].exists = true; expect.status = EVMC_SUCCESS; @@ -576,11 +557,10 @@ TEST_F(state_transition, extcall_callee_abort) }); tx.to = To; - pre.insert(*tx.to, - { - .storage = {{0x01_bytes32, {.current = 0xdd_bytes32, .original = 0xdd_bytes32}}}, - .code = eof_bytecode(sstore(1, extcall(callee)) + OP_STOP, 4), - }); + pre.insert(*tx.to, { + .storage = {{0x01_bytes32, 0xdd_bytes32}}, + .code = eof_bytecode(sstore(1, extcall(callee)) + OP_STOP, 4), + }); expect.post[*tx.to].storage[0x01_bytes32] = 0x02_bytes32; expect.post[callee].exists = true; expect.status = EVMC_SUCCESS; @@ -596,11 +576,10 @@ TEST_F(state_transition, extdelegatecall_callee_abort) }); tx.to = To; - pre.insert(*tx.to, - { - .storage = {{0x01_bytes32, {.current = 0xdd_bytes32, .original = 0xdd_bytes32}}}, - .code = eof_bytecode(sstore(1, extdelegatecall(callee)) + OP_STOP, 3), - }); + pre.insert(*tx.to, { + .storage = {{0x01_bytes32, 0xdd_bytes32}}, + .code = eof_bytecode(sstore(1, extdelegatecall(callee)) + OP_STOP, 3), + }); expect.post[*tx.to].storage[0x01_bytes32] = 0x02_bytes32; expect.post[callee].exists = true; expect.status = EVMC_SUCCESS; @@ -616,11 +595,10 @@ TEST_F(state_transition, extstaticcall_callee_abort) }); tx.to = To; - pre.insert(*tx.to, - { - .storage = {{0x01_bytes32, {.current = 0xdd_bytes32, .original = 0xdd_bytes32}}}, - .code = eof_bytecode(sstore(1, extstaticcall(callee)) + OP_STOP, 3), - }); + pre.insert(*tx.to, { + .storage = {{0x01_bytes32, 0xdd_bytes32}}, + .code = eof_bytecode(sstore(1, extstaticcall(callee)) + OP_STOP, 3), + }); expect.post[*tx.to].storage[0x01_bytes32] = 0x02_bytes32; expect.post[callee].exists = true; expect.status = EVMC_SUCCESS; @@ -636,13 +614,12 @@ TEST_F(state_transition, extcall_input) }); tx.to = To; - pre.insert(*tx.to, - { - .storage = {{0x01_bytes32, {.current = 0xdd_bytes32, .original = 0xdd_bytes32}}}, - .code = eof_bytecode(mstore(0, 0x010203) + extcall(callee).input(0, 32) + - sstore(1, returndataload(0)) + OP_STOP, - 4), - }); + pre.insert(*tx.to, { + .storage = {{0x01_bytes32, 0xdd_bytes32}}, + .code = eof_bytecode(mstore(0, 0x010203) + extcall(callee).input(0, 32) + + sstore(1, returndataload(0)) + OP_STOP, + 4), + }); expect.post[*tx.to].storage[0x01_bytes32] = 0x01_bytes32; expect.post[callee].exists = true; } @@ -659,7 +636,7 @@ TEST_F(state_transition, extdelegatecall_input) tx.to = To; pre.insert(*tx.to, { - .storage = {{0x01_bytes32, {.current = 0xdd_bytes32, .original = 0xdd_bytes32}}}, + .storage = {{0x01_bytes32, 0xdd_bytes32}}, .code = eof_bytecode(mstore(0, 0x010203) + extdelegatecall(callee).input(0, 32) + sstore(1, returndataload(0)) + OP_STOP, 3), @@ -678,13 +655,13 @@ TEST_F(state_transition, extstaticcall_input) }); tx.to = To; - pre.insert(*tx.to, - { - .storage = {{0x01_bytes32, {.current = 0xdd_bytes32, .original = 0xdd_bytes32}}}, - .code = eof_bytecode(mstore(0, 0x010203) + extstaticcall(callee).input(0, 32) + - sstore(1, returndataload(0)) + OP_STOP, - 3), - }); + pre.insert( + *tx.to, { + .storage = {{0x01_bytes32, 0xdd_bytes32}}, + .code = eof_bytecode(mstore(0, 0x010203) + extstaticcall(callee).input(0, 32) + + sstore(1, returndataload(0)) + OP_STOP, + 3), + }); expect.post[*tx.to].storage[0x01_bytes32] = 0x01_bytes32; expect.post[callee].exists = true; } @@ -743,7 +720,7 @@ TEST_F(state_transition, extcall_recipient_and_code_address) tx.to = To; pre.insert(*tx.to, { - .storage = {{0x01_bytes32, {.current = 0xdd_bytes32, .original = 0xdd_bytes32}}}, + .storage = {{0x01_bytes32, 0xdd_bytes32}}, .code = eof_bytecode(extcall(callee) + sstore(1, returndataload(0)) + OP_STOP, 4), }); expect.post[*tx.to].storage[0x01_bytes32] = 0x01_bytes32; @@ -761,12 +738,11 @@ TEST_F(state_transition, extdelegatecall_recipient_and_code_address) }); tx.to = To; - pre.insert(*tx.to, - { - .storage = {{0x01_bytes32, {.current = 0xdd_bytes32, .original = 0xdd_bytes32}}}, - .code = - eof_bytecode(extdelegatecall(callee) + sstore(1, returndataload(0)) + OP_STOP, 3), - }); + pre.insert(*tx.to, { + .storage = {{0x01_bytes32, 0xdd_bytes32}}, + .code = eof_bytecode( + extdelegatecall(callee) + sstore(1, returndataload(0)) + OP_STOP, 3), + }); expect.post[*tx.to].storage[0x01_bytes32] = 0x01_bytes32; expect.post[callee].exists = true; } @@ -784,7 +760,7 @@ TEST_F(state_transition, extstaticcall_recipient_and_code_address) tx.to = To; pre.insert(*tx.to, { - .storage = {{0x01_bytes32, {.current = 0xdd_bytes32, .original = 0xdd_bytes32}}}, + .storage = {{0x01_bytes32, 0xdd_bytes32}}, .code = eof_bytecode(extstaticcall(callee) + sstore(1, returndataload(0)) + OP_STOP, 3), }); expect.post[*tx.to].storage[0x01_bytes32] = 0x01_bytes32; @@ -816,11 +792,10 @@ TEST_F(state_transition, returndatasize_before_extcall) rev = EVMC_PRAGUE; tx.to = To; - pre.insert(*tx.to, - { - .storage = {{0x01_bytes32, {.current = 0xdd_bytes32, .original = 0xdd_bytes32}}}, - .code = eof_bytecode(sstore(1, returndatasize()) + OP_STOP, 2), - }); + pre.insert(*tx.to, { + .storage = {{0x01_bytes32, 0xdd_bytes32}}, + .code = eof_bytecode(sstore(1, returndatasize()) + OP_STOP, 2), + }); expect.post[*tx.to].storage[0x01_bytes32] = 0x00_bytes32; } @@ -834,12 +809,11 @@ TEST_F(state_transition, extdelegatecall_returndatasize) }); tx.to = To; - pre.insert(*tx.to, - { - .storage = {{0x01_bytes32, {.current = 0xdd_bytes32, .original = 0xdd_bytes32}}}, - .code = - eof_bytecode(extdelegatecall(callee) + sstore(1, returndatasize()) + OP_STOP, 3), - }); + pre.insert(*tx.to, { + .storage = {{0x01_bytes32, 0xdd_bytes32}}, + .code = eof_bytecode( + extdelegatecall(callee) + sstore(1, returndatasize()) + OP_STOP, 3), + }); expect.post[*tx.to].storage[0x01_bytes32] = 0x13_bytes32; expect.post[callee].exists = true; } @@ -854,12 +828,11 @@ TEST_F(state_transition, extdelegatecall_returndatasize_abort) }); tx.to = To; - pre.insert(*tx.to, - { - .storage = {{0x01_bytes32, {.current = 0xdd_bytes32, .original = 0xdd_bytes32}}}, - .code = - eof_bytecode(extdelegatecall(callee) + sstore(1, returndatasize()) + OP_STOP, 3), - }); + pre.insert(*tx.to, { + .storage = {{0x01_bytes32, 0xdd_bytes32}}, + .code = eof_bytecode( + extdelegatecall(callee) + sstore(1, returndatasize()) + OP_STOP, 3), + }); expect.post[*tx.to].storage[0x01_bytes32] = 0x00_bytes32; expect.post[callee].exists = true; } @@ -878,7 +851,7 @@ TEST_F(state_transition, returndatacopy) tx.to = To; pre.insert(*tx.to, { - .storage = {{0x01_bytes32, {.current = 0xdd_bytes32, .original = 0xdd_bytes32}}}, + .storage = {{0x01_bytes32, 0xdd_bytes32}}, .code = eof_bytecode( extdelegatecall(callee) + sstore(1, returndatacopy(0, 0, 32) + mload(0)) + OP_STOP, 4), @@ -900,12 +873,11 @@ TEST_F(state_transition, returndataload) }); tx.to = To; - pre.insert(*tx.to, - { - .storage = {{0x01_bytes32, {.current = 0xdd_bytes32, .original = 0xdd_bytes32}}}, - .code = - eof_bytecode(extdelegatecall(callee) + sstore(1, returndataload(0)) + OP_STOP, 3), - }); + pre.insert(*tx.to, { + .storage = {{0x01_bytes32, 0xdd_bytes32}}, + .code = eof_bytecode( + extdelegatecall(callee) + sstore(1, returndataload(0)) + OP_STOP, 3), + }); expect.gas_used = 28636; expect.post[*tx.to].storage[0x01_bytes32] = call_output; expect.post[callee].exists = true; @@ -923,13 +895,12 @@ TEST_F(state_transition, extcall_clears_returndata) }); tx.to = To; - pre.insert(*tx.to, - { - .storage = {{0x01_bytes32, {.current = 0xdd_bytes32, .original = 0xdd_bytes32}}}, - .code = eof_bytecode( - extcall(callee) + extcall(callee).value(1) + sstore(1, returndatasize()) + OP_STOP, - 5), - }); + pre.insert(*tx.to, { + .storage = {{0x01_bytes32, 0xdd_bytes32}}, + .code = eof_bytecode(extcall(callee) + extcall(callee).value(1) + + sstore(1, returndatasize()) + OP_STOP, + 5), + }); expect.post[*tx.to].storage[0x01_bytes32] = 0x00_bytes32; expect.post[callee].exists = true; @@ -940,11 +911,10 @@ TEST_F(state_transition, extcall_gas_refund_propagation) rev = EVMC_PRAGUE; constexpr auto callee = 0xca11ee_address; - pre.insert(callee, - { - .storage = {{0x01_bytes32, {.current = 0xdd_bytes32, .original = 0xdd_bytes32}}}, - .code = eof_bytecode(sstore(1, 0x00) + OP_STOP, 2), - }); + pre.insert(callee, { + .storage = {{0x01_bytes32, 0xdd_bytes32}}, + .code = eof_bytecode(sstore(1, 0x00) + OP_STOP, 2), + }); tx.to = To; pre.insert(*tx.to, { @@ -965,11 +935,10 @@ TEST_F(state_transition, extdelegatecall_gas_refund_propagation) }); tx.to = To; - pre.insert(*tx.to, - { - .storage = {{0x01_bytes32, {.current = 0xdd_bytes32, .original = 0xdd_bytes32}}}, - .code = eof_bytecode(extdelegatecall(callee) + OP_STOP, 3), - }); + pre.insert(*tx.to, { + .storage = {{0x01_bytes32, 0xdd_bytes32}}, + .code = eof_bytecode(extdelegatecall(callee) + OP_STOP, 3), + }); expect.gas_used = 21000 + 2600 + 5000 + 5 * 3 - 4800; expect.post[*tx.to].storage[0x01_bytes32] = 0x00_bytes32; expect.post[callee].exists = true; diff --git a/test/unittests/state_transition_tx_test.cpp b/test/unittests/state_transition_tx_test.cpp index fa26c25557..57f26e5c58 100644 --- a/test/unittests/state_transition_tx_test.cpp +++ b/test/unittests/state_transition_tx_test.cpp @@ -25,7 +25,7 @@ TEST_F(state_transition, tx_non_existing_sender) tx.max_gas_price = 0; tx.max_priority_gas_price = 0; tx.nonce = 0; - pre.get_accounts().erase(Sender); + pre.erase(Sender); expect.status = EVMC_SUCCESS; expect.post.at(Sender).nonce = 1; @@ -40,7 +40,7 @@ TEST_F(state_transition, invalid_tx_non_existing_sender) tx.max_gas_price = 1; tx.max_priority_gas_price = 1; tx.nonce = 0; - pre.get_accounts().erase(Sender); + pre.erase(Sender); expect.tx_error = INSUFFICIENT_FUNDS; expect.post[Sender].exists = false; @@ -96,8 +96,7 @@ TEST_F(state_transition, access_list_storage) tx.to = To; tx.access_list = {{To, {0x01_bytes32}}}; - pre.insert(To, - {.storage = {{0x01_bytes32, {0x01_bytes32, 0x01_bytes32}}}, .code = sstore(2, sload(1))}); + pre.insert(To, {.storage = {{0x01_bytes32, 0x01_bytes32}}, .code = sstore(2, sload(1))}); expect.post[To].storage[0x01_bytes32] = 0x01_bytes32; expect.post[To].storage[0x02_bytes32] = 0x01_bytes32; diff --git a/test/unittests/statetest_loader_test.cpp b/test/unittests/statetest_loader_test.cpp index 8d7c164a48..ed93cc849e 100644 --- a/test/unittests/statetest_loader_test.cpp +++ b/test/unittests/statetest_loader_test.cpp @@ -128,7 +128,7 @@ TEST(statetest_loader, load_minimal_test) })"}; const auto st = std::move(load_state_tests(s).at(0)); // TODO: should add some comparison operator to State, BlockInfo, AccessList - EXPECT_EQ(st.pre_state.get_accounts().size(), 0); + EXPECT_EQ(st.pre_state.size(), 0); EXPECT_EQ(st.block.number, 0); EXPECT_EQ(st.block.timestamp, 0); EXPECT_EQ(st.block.gas_limit, 0); @@ -161,8 +161,7 @@ TEST(statetest_loader, load_minimal_test) TEST(statetest_loader, validate_state_invalid_eof) { - state::State state; - state.insert(0xadd4_address, {.code = "EF0001010000020001000103000100FEDA"_hex}); + TestState state{{0xadd4_address, {.code = "EF0001010000020001000103000100FEDA"_hex}}}; EXPECT_THAT([&] { validate_state(state, EVMC_PRAGUE); }, ThrowsMessage( "EOF container at 0x000000000000000000000000000000000000add4 is invalid: " @@ -171,8 +170,7 @@ TEST(statetest_loader, validate_state_invalid_eof) TEST(statetest_loader, validate_state_unexpected_eof) { - state::State state; - state.insert(0xadd4_address, {.code = "EF00"_hex}); + TestState state{{0xadd4_address, {.code = "EF00"_hex}}}; EXPECT_THAT([&] { validate_state(state, EVMC_CANCUN); }, ThrowsMessage( "unexpected code with EOF prefix at 0x000000000000000000000000000000000000add4")); @@ -180,8 +178,7 @@ TEST(statetest_loader, validate_state_unexpected_eof) TEST(statetest_loader, validate_state_zero_storage_slot) { - state::State state; - state.insert(0xadd4_address, {.storage = {{0x01_bytes32, {0x00_bytes32}}}}); + TestState state{{0xadd4_address, {.storage = {{0x01_bytes32, 0x00_bytes32}}}}}; EXPECT_THAT([&] { validate_state(state, EVMC_PRAGUE); }, ThrowsMessage( "account 0x000000000000000000000000000000000000add4 contains invalid zero-value "