Skip to content

Commit

Permalink
Support code delegation in instructions implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
gumb0 committed Aug 2, 2024
1 parent 1bab8be commit 42e7fe2
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 5 deletions.
70 changes: 67 additions & 3 deletions lib/evmone/instructions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#pragma once

#include "baseline.hpp"
#include "constants.hpp"
#include "eof.hpp"
#include "execution_state.hpp"
#include "instructions_traits.hpp"
Expand Down Expand Up @@ -128,6 +129,48 @@ inline bool check_memory(
return check_memory(gas_left, memory, offset, static_cast<uint64_t>(size));
}

constexpr bool is_code_delegated(bytes_view code) noexcept
{
return code.starts_with(DELEGATION_MAGIC);
}

inline std::optional<evmc::address> get_delegate_address(
const evmc::address& addr, const evmc::HostContext& host) noexcept
{
uint8_t prefix[std::size(DELEGATION_MAGIC)] = {};
host.copy_code(addr, 0, prefix, std::size(prefix));

if (!is_code_delegated(bytes_view{prefix, std::size(prefix)}))
return {};

assert(host.get_code_size(addr) == std::size(DELEGATION_MAGIC) + std::size(addr.bytes));

evmc::address delegate_address;
host.copy_code(
addr, std::size(prefix), delegate_address.bytes, std::size(delegate_address.bytes));
return delegate_address;
}

inline std::variant<evmc::address, Result> get_target_address(
const evmc::address& addr, int64_t gas_left, ExecutionState& state) noexcept
{
if (state.rev < EVMC_PRAGUE)
return addr;

const auto delegate_addr = get_delegate_address(addr, state.host);
if (!delegate_addr.has_value())
return addr;

const auto account_access_cost =
(state.host.access_account(addr) == EVMC_ACCESS_COLD ? instr::cold_account_access_cost :
instr::warm_storage_read_cost);

if ((gas_left -= account_access_cost) < 0)
return Result{EVMC_OUT_OF_GAS, gas_left};

return *delegate_addr;
}

namespace instr::core
{

Expand Down Expand Up @@ -515,6 +558,7 @@ inline void blobbasefee(StackTop stack, ExecutionState& state) noexcept
stack.push(intx::be::load<uint256>(state.get_tx_context().blob_base_fee));
}

// NOLINTNEXTLINE(bugprone-exception-escape)
inline Result extcodesize(StackTop stack, int64_t gas_left, ExecutionState& state) noexcept
{
auto& x = stack.top();
Expand All @@ -526,10 +570,17 @@ inline Result extcodesize(StackTop stack, int64_t gas_left, ExecutionState& stat
return {EVMC_OUT_OF_GAS, gas_left};
}

x = state.host.get_code_size(addr);
const auto target_addr_or_result = get_target_address(addr, gas_left, state);
if (const auto* result = std::get_if<Result>(&target_addr_or_result))
return *result;

const auto& target_addr = std::get<evmc::address>(target_addr_or_result);

x = state.host.get_code_size(target_addr);
return {EVMC_SUCCESS, gas_left};
}

// NOLINTNEXTLINE(bugprone-exception-escape)
inline Result extcodecopy(StackTop stack, int64_t gas_left, ExecutionState& state) noexcept
{
const auto addr = intx::be::trunc<evmc::address>(stack.pop());
Expand All @@ -550,12 +601,18 @@ inline Result extcodecopy(StackTop stack, int64_t gas_left, ExecutionState& stat
return {EVMC_OUT_OF_GAS, gas_left};
}

const auto target_addr_or_result = get_target_address(addr, gas_left, state);
if (const auto* result = std::get_if<Result>(&target_addr_or_result))
return *result;

const auto& target_addr = std::get<evmc::address>(target_addr_or_result);

if (s > 0)
{
const auto src =
(max_buffer_size < input_index) ? max_buffer_size : static_cast<size_t>(input_index);
const auto dst = static_cast<size_t>(mem_index);
const auto num_bytes_copied = state.host.copy_code(addr, src, &state.memory[dst], s);
const auto num_bytes_copied = state.host.copy_code(target_addr, src, &state.memory[dst], s);
if (const auto num_bytes_to_clear = s - num_bytes_copied; num_bytes_to_clear > 0)
std::memset(&state.memory[dst + num_bytes_copied], 0, num_bytes_to_clear);
}
Expand Down Expand Up @@ -633,6 +690,7 @@ inline Result returndatacopy(StackTop stack, int64_t gas_left, ExecutionState& s
return {EVMC_SUCCESS, gas_left};
}

// NOLINTNEXTLINE(bugprone-exception-escape)
inline Result extcodehash(StackTop stack, int64_t gas_left, ExecutionState& state) noexcept
{
auto& x = stack.top();
Expand All @@ -644,7 +702,13 @@ inline Result extcodehash(StackTop stack, int64_t gas_left, ExecutionState& stat
return {EVMC_OUT_OF_GAS, gas_left};
}

x = intx::be::load<uint256>(state.host.get_code_hash(addr));
const auto target_addr_or_result = get_target_address(addr, gas_left, state);
if (const auto* result = std::get_if<Result>(&target_addr_or_result))
return *result;

const auto& target_addr = std::get<evmc::address>(target_addr_or_result);

x = intx::be::load<uint256>(state.host.get_code_hash(target_addr));
return {EVMC_SUCCESS, gas_left};
}

Expand Down
16 changes: 14 additions & 2 deletions lib/evmone/instructions_calls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@ Result call_impl(StackTop stack, int64_t gas_left, ExecutionState& state) noexce
return {EVMC_OUT_OF_GAS, gas_left};
}

const auto target_addr_or_result = get_target_address(dst, gas_left, state);
if (const auto* result = std::get_if<Result>(&target_addr_or_result))
return *result;

const auto& code_addr = std::get<evmc::address>(target_addr_or_result);

if (!check_memory(gas_left, state.memory, input_offset_u256, input_size_u256))
return {EVMC_OUT_OF_GAS, gas_left};

Expand All @@ -82,7 +88,7 @@ Result call_impl(StackTop stack, int64_t gas_left, ExecutionState& state) noexce
msg.flags = (Op == OP_STATICCALL) ? uint32_t{EVMC_STATIC} : state.msg->flags;
msg.depth = state.msg->depth + 1;
msg.recipient = (Op == OP_CALL || Op == OP_STATICCALL) ? dst : state.msg->recipient;
msg.code_address = dst;
msg.code_address = code_addr;
msg.sender = (Op == OP_DELEGATECALL) ? state.msg->sender : state.msg->recipient;
msg.value =
(Op == OP_DELEGATECALL) ? state.msg->value : intx::be::store<evmc::uint256be>(value);
Expand Down Expand Up @@ -178,6 +184,12 @@ Result extcall_impl(StackTop stack, int64_t gas_left, ExecutionState& state) noe
return {EVMC_OUT_OF_GAS, gas_left};
}

const auto target_addr_or_result = get_target_address(dst, gas_left, state);
if (const auto* result = std::get_if<Result>(&target_addr_or_result))
return *result;

const auto& code_addr = std::get<evmc::address>(target_addr_or_result);

if (!check_memory(gas_left, state.memory, input_offset_u256, input_size_u256))
return {EVMC_OUT_OF_GAS, gas_left};

Expand All @@ -188,7 +200,7 @@ Result extcall_impl(StackTop stack, int64_t gas_left, ExecutionState& state) noe
msg.flags = (Op == OP_EXTSTATICCALL) ? uint32_t{EVMC_STATIC} : state.msg->flags;
msg.depth = state.msg->depth + 1;
msg.recipient = (Op != OP_EXTDELEGATECALL) ? dst : state.msg->recipient;
msg.code_address = dst;
msg.code_address = code_addr;
msg.sender = (Op == OP_EXTDELEGATECALL) ? state.msg->sender : state.msg->recipient;
msg.value =
(Op == OP_EXTDELEGATECALL) ? state.msg->value : intx::be::store<evmc::uint256be>(value);
Expand Down

0 comments on commit 42e7fe2

Please sign in to comment.