Skip to content

Commit

Permalink
state: Implement system call (EIP-4788)
Browse files Browse the repository at this point in the history
Implement the system call from the "Block processing" of the EIP-4788.
https://eips.ethereum.org/EIPS/eip-4788#block-processing

At the beginning of each block a gas-free call is invoked from
the _system_ account (0xff..fe) to the specific _system_ contract.
  • Loading branch information
chfast committed Nov 24, 2023
1 parent a10d9ac commit 9447d28
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 2 deletions.
3 changes: 2 additions & 1 deletion test/state/host.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,8 @@ evmc::Result Host::call(const evmc_message& orig_msg) noexcept
evmc_tx_context Host::get_tx_context() const noexcept
{
// TODO: The effective gas price is already computed in transaction validation.
assert(m_tx.max_gas_price >= m_block.base_fee);
// TODO: The effective gas price calculation is broken for system calls (gas price 0).
assert(m_tx.max_gas_price >= m_block.base_fee || m_tx.max_gas_price == 0);
const auto priority_gas_price =
std::min(m_tx.max_priority_gas_price, m_tx.max_gas_price - m_block.base_fee);
const auto effective_gas_price = m_block.base_fee + priority_gas_price;
Expand Down
38 changes: 38 additions & 0 deletions test/state/state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,44 @@ void delete_empty_accounts(State& state)
}
} // namespace

void system_call(State& state, const BlockInfo& block, evmc_revision rev, evmc::VM& vm)
{
static constexpr auto SystemAddress = 0xfffffffffffffffffffffffffffffffffffffffe_address;
static constexpr auto BeaconRootsAddress = 0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02_address;

if (rev >= EVMC_CANCUN)
{
// TODO: Check if the system account should be touched.
// state.touch(SystemAddress);

if (const auto acc = state.find(BeaconRootsAddress); acc != nullptr)
{
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
const evmc_message msg{
.kind = EVMC_CALL,
.gas = 30'000'000,
.recipient = BeaconRootsAddress,
.sender = SystemAddress,
.input_data = block.parent_beacon_block_root.bytes,
.input_size = sizeof(block.parent_beacon_block_root),
};

Host host{rev, vm, state, block, {}};
const auto& code = acc->code;
[[maybe_unused]] const auto res = vm.execute(host, rev, msg, code.data(), code.size());
assert(res.status_code == EVMC_SUCCESS);
assert(acc->access_status == EVMC_ACCESS_COLD);

// Reset storage status.
for (auto& [_, val] : acc->storage)
{
val.access_status = EVMC_ACCESS_COLD;
val.original = val.current;
}
}
}
}

void finalize(State& state, evmc_revision rev, const address& coinbase,
std::optional<uint64_t> block_reward, std::span<const Ommer> ommers,
std::span<const Withdrawal> withdrawals)
Expand Down
8 changes: 7 additions & 1 deletion test/state/state.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ struct BlockInfo
std::vector<Ommer> ommers = {};
std::vector<Withdrawal> withdrawals;
std::unordered_map<int64_t, hash256> known_block_hashes = {};
hash256 parent_beacon_block_root;
hash256 parent_beacon_block_root = {};
};

using AccessList = std::vector<std::pair<address, std::vector<bytes32>>>;
Expand Down Expand Up @@ -191,6 +191,12 @@ std::variant<int64_t, std::error_code> validate_transaction(const Account& sende
const BlockInfo& block, const Transaction& tx, evmc_revision rev,
int64_t block_gas_left) noexcept;

/// Performs the system call.
///
/// Executes code at pre-defined accounts from the system sender (0xff...fe).
/// The sender's nonce is not increased.
void system_call(State& state, const BlockInfo& block, evmc_revision rev, evmc::VM& vm);

/// Defines how to RLP-encode a Transaction.
[[nodiscard]] bytes rlp_encode(const Transaction& tx);

Expand Down

0 comments on commit 9447d28

Please sign in to comment.