Skip to content

Commit

Permalink
Support withdrawals in t8n
Browse files Browse the repository at this point in the history
  • Loading branch information
rodiazet committed Apr 20, 2023
1 parent 31fd534 commit cc6431c
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 9 deletions.
8 changes: 6 additions & 2 deletions test/state/state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,8 @@ evmc_message build_message(const Transaction& tx, int64_t execution_gas_limit) n
}
} // namespace

void finalize(
State& state, evmc_revision rev, const address& coinbase, std::optional<uint64_t> block_reward)
void finalize(State& state, evmc_revision rev, const address& coinbase,
std::optional<uint64_t> block_reward, std::span<Withdrawal> withdrawals)
{
if (block_reward.has_value())
state.touch(coinbase).balance += *block_reward;
Expand All @@ -131,6 +131,10 @@ void finalize(
return acc.erasable && acc.is_empty();
});
}

// Apply withdrawals. Amount value is in gwei.
for (const auto& withdraw : withdrawals)
state.touch(withdraw.first).balance += intx::uint256{withdraw.second} * 1e9;
}

std::variant<TransactionReceipt, std::error_code> transition(
Expand Down
12 changes: 9 additions & 3 deletions test/state/state.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ class State
[[nodiscard]] const auto& get_accounts() const noexcept { return m_accounts; }
};

/// Vector of withdrawals in a block. Contains `to` address and ETH `amount` in gwei.
using Withdrawal = std::pair<address, uint64_t>;
using Withdrawals = std::vector<Withdrawal>;

struct BlockInfo
{
int64_t number = 0;
Expand All @@ -74,6 +78,7 @@ struct BlockInfo
address coinbase;
bytes32 prev_randao;
uint64_t base_fee = 0;
Withdrawals withdrawals;
};

using AccessList = std::vector<std::pair<address, std::vector<bytes32>>>;
Expand Down Expand Up @@ -121,9 +126,10 @@ struct TransactionReceipt

/// Finalize state after applying a "block" of transactions.
///
/// Applies block reward to coinbase and deletes empty touched accounts (post Spurious Dragon).
void finalize(
State& state, evmc_revision rev, const address& coinbase, std::optional<uint64_t> block_reward);
/// Applies block reward to coinbase, withdrawals (post Shanghai) and deletes empty touched accounts
/// (post Spurious Dragon).
void finalize(State& state, evmc_revision rev, const address& coinbase,
std::optional<uint64_t> block_reward, std::span<Withdrawal> withdrawals);

[[nodiscard]] std::variant<TransactionReceipt, std::error_code> transition(
State& state, const BlockInfo& block, const Transaction& tx, evmc_revision rev, evmc::VM& vm);
Expand Down
14 changes: 13 additions & 1 deletion test/statetest/statetest_loader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -170,9 +170,21 @@ state::BlockInfo from_json<state::BlockInfo>(const json::json& j)
from_json<uint64_t>(j.at("parentGasLimit")),
from_json<uint64_t>(j.at("parentBaseFee")));
}

state::Withdrawals withdrawals;
if (const auto withdrawals_it = j.find("withdrawals"); withdrawals_it != j.end())
{
for (const auto& withdraw : *withdrawals_it)
{
withdrawals.push_back({from_json<evmc::address>(withdraw.at("address")),
from_json<uint64_t>(withdraw.at("amount"))});
}
}

return {from_json<int64_t>(j.at("currentNumber")), from_json<int64_t>(j.at("currentTimestamp")),
from_json<int64_t>(j.at("currentGasLimit")),
from_json<evmc::address>(j.at("currentCoinbase")), difficulty, base_fee};
from_json<evmc::address>(j.at("currentCoinbase")), difficulty, base_fee,
std::move(withdrawals)};
}

template <>
Expand Down
2 changes: 1 addition & 1 deletion test/statetest/statetest_runner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ void run_state_test(const StateTransitionTest& test, evmc::VM& vm)
const auto res = state::transition(state, test.block, tx, rev, vm);

// Finalize block with reward 0.
state::finalize(state, rev, test.block.coinbase, 0);
state::finalize(state, rev, test.block.coinbase, 0, {});

if (holds_alternative<state::TransactionReceipt>(res))
EXPECT_EQ(logs_hash(get<state::TransactionReceipt>(res).logs), expected.logs_hash);
Expand Down
2 changes: 1 addition & 1 deletion test/t8n/t8n.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ int main(int argc, const char* argv[])
}
}

state::finalize(state, rev, block.coinbase, block_reward);
state::finalize(state, rev, block.coinbase, block_reward, block.withdrawals);

j_result["logsHash"] = hex0x(logs_hash(txs_logs));
j_result["stateRoot"] = hex0x(state::mpt_hash(state.get_accounts()));
Expand Down
2 changes: 1 addition & 1 deletion test/unittests/state_transition.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ void state_transition::TearDown()
ASSERT_TRUE(holds_alternative<TransactionReceipt>(res))
<< std::get<std::error_code>(res).message();
const auto& receipt = std::get<TransactionReceipt>(res);
evmone::state::finalize(state, rev, block.coinbase, 0);
evmone::state::finalize(state, rev, block.coinbase, 0, {});

EXPECT_EQ(receipt.status, expect.status);
if (expect.gas_used.has_value())
Expand Down
40 changes: 40 additions & 0 deletions test/unittests/statetest_loader_block_info_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -170,3 +170,43 @@ TEST(statetest_loader, block_info_0_random)
EXPECT_EQ(bi.timestamp, 0);
EXPECT_EQ(bi.number, 0);
}

TEST(statetest_loader, block_info_withdrawals)
{
constexpr std::string_view input = R"({
"currentCoinbase": "0x1111111111111111111111111111111111111111",
"currentDifficulty": "0x0",
"currentGasLimit": "0x0",
"currentNumber": "0",
"currentTimestamp": "0",
"currentBaseFee": "7",
"currentRandom": "0x00",
"withdrawals": [
{
"index": "0x0",
"validatorIndex": "0x0",
"address": "0x0000000000000000000000000000000000000100",
"amount": "0x800000000"
},
{
"index": "0x1",
"validatorIndex": "0x1",
"address": "0x0000000000000000000000000000000000000200",
"amount": "0xffffffffffffffff"
}
]
})";

const auto bi = test::from_json<state::BlockInfo>(json::json::parse(input));
EXPECT_EQ(bi.coinbase, 0x1111111111111111111111111111111111111111_address);
EXPECT_EQ(bi.prev_randao, 0x00_bytes32);
EXPECT_EQ(bi.gas_limit, 0x0);
EXPECT_EQ(bi.base_fee, 7);
EXPECT_EQ(bi.timestamp, 0);
EXPECT_EQ(bi.number, 0);
EXPECT_EQ(bi.withdrawals.size(), 2);
EXPECT_EQ(bi.withdrawals[0].first, 0x0000000000000000000000000000000000000100_address);
EXPECT_EQ(bi.withdrawals[0].second, 0x800000000);
EXPECT_EQ(bi.withdrawals[1].first, 0x0000000000000000000000000000000000000200_address);
EXPECT_EQ(bi.withdrawals[1].second, 0xffffffffffffffff);
}

0 comments on commit cc6431c

Please sign in to comment.