diff --git a/test/state/errors.hpp b/test/state/errors.hpp index 8c4afd64c2..5c71081019 100644 --- a/test/state/errors.hpp +++ b/test/state/errors.hpp @@ -32,6 +32,7 @@ enum ErrorCode : int // NOLINT(*-use-enum-class) EMPTY_AUTHORIZATION_LIST, MAX_GAS_LIMIT_EXCEEDED, INVALID_CHAIN_ID, + INVALID_ENCODING, UNKNOWN_ERROR, // Block-level validation. @@ -103,6 +104,8 @@ inline const std::error_category& evmone_category() noexcept return "max gas limit exceeded"; case INVALID_CHAIN_ID: return "invalid transaction chain id"; + case INVALID_ENCODING: + return "invalid transaction encoding"; case UNKNOWN_ERROR: return "Unknown error"; case INCORRECT_BLOCK_FORMAT: diff --git a/test/statetest/statetest_runner.cpp b/test/statetest/statetest_runner.cpp index 6c607c19f1..cb6765461e 100644 --- a/test/statetest/statetest_runner.cpp +++ b/test/statetest/statetest_runner.cpp @@ -24,12 +24,24 @@ void run_state_test(const StateTransitionTest& test, evmc::VM& vm, bool trace_su // continue; const auto& expected = cases[case_index]; - const auto tx = test.multi_tx.get(expected.indexes); auto state = test.pre_state; const auto blob_params = get_blob_params(rev, test.blob_schedule); - const auto res = transition(state, block, test.block_hashes, tx, rev, vm, - block.gas_limit, static_cast(state::max_blob_gas_per_block(blob_params))); + // Decode transaction from txbytes if available. + const auto template_tx = test.multi_tx.get(expected.indexes); + auto tx = std::optional{template_tx}; + if (expected.txbytes.has_value()) + { + tx = state::decode_transaction(*expected.txbytes); + if (tx.has_value()) + tx->sender = template_tx.sender; // No recovery yet, take sender from JSON. + } + + const auto res = + tx.has_value() ? + transition(state, block, test.block_hashes, *tx, rev, vm, block.gas_limit, + static_cast(state::max_blob_gas_per_block(blob_params))) : + make_error_code(state::INVALID_ENCODING); if (holds_alternative(res)) { diff --git a/test/utils/statetest.hpp b/test/utils/statetest.hpp index ea42821c7a..55c096832d 100644 --- a/test/utils/statetest.hpp +++ b/test/utils/statetest.hpp @@ -51,6 +51,9 @@ struct StateTransitionTest hash256 state_hash; hash256 logs_hash = EmptyListHash; bool exception = false; + + /// The full encoded transaction for this case. Not always available. + std::optional txbytes; }; evmc_revision rev; diff --git a/test/utils/statetest_loader.cpp b/test/utils/statetest_loader.cpp index 9b0a74879b..c17f1bf15f 100644 --- a/test/utils/statetest_loader.cpp +++ b/test/utils/statetest_loader.cpp @@ -494,6 +494,9 @@ static void from_json(const json::json& j, StateTransitionTest::Case::Expectatio o.state_hash = from_json(j.at("hash")); o.logs_hash = from_json(j.at("logs")); o.exception = j.contains("expectException"); + // Not load_if_exists(): it maps an absent key to bytes{}, which engages the optional. + if (const auto it = j.find("txbytes"); it != j.end()) + o.txbytes = from_json(*it); } static void from_json(const json::json& j_t, StateTransitionTest& o)