Skip to content

Commit

Permalink
Merge pull request #327 from ethereum/state_types
Browse files Browse the repository at this point in the history
State types extensions for tracing
  • Loading branch information
chfast authored May 20, 2021
2 parents e912538 + 59182d1 commit 2c1f473
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 39 deletions.
2 changes: 1 addition & 1 deletion lib/evmone/baseline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ inline evmc_status_code check_requirements(const char* const* instruction_names,
const auto stack_size = state.stack.size();
if (stack_size < metrics.stack_height_required)
return EVMC_STACK_UNDERFLOW;
if (stack_size + metrics.stack_height_change > evm_stack::limit)
if (stack_size + metrics.stack_height_change > Stack::limit)
return EVMC_STACK_OVERFLOW;

return EVMC_SUCCESS;
Expand Down
23 changes: 15 additions & 8 deletions lib/evmone/execution_state.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ using bytes_view = std::basic_string_view<uint8_t>;
///
/// This implementation reserves memory inplace for all possible stack items (1024),
/// so this type is big. Make sure it is allocated on heap.
struct evm_stack
struct Stack
{
/// The maximum number of stack items.
static constexpr auto limit = 1024;
Expand All @@ -33,7 +33,7 @@ struct evm_stack
alignas(sizeof(intx::uint256)) intx::uint256 storage[limit];

/// Default constructor. Sets the top_item pointer to below the stack bottom.
evm_stack() noexcept { clear(); }
Stack() noexcept { clear(); }

/// The current number of items on the stack.
[[nodiscard]] int size() const noexcept { return static_cast<int>(top_item + 1 - storage); }
Expand All @@ -44,6 +44,12 @@ struct evm_stack
/// Returns the reference to the stack item on given position from the stack top.
[[nodiscard]] intx::uint256& operator[](int index) noexcept { return *(top_item - index); }

/// Returns the const reference to the stack item on given position from the stack top.
[[nodiscard]] const intx::uint256& operator[](int index) const noexcept
{
return *(top_item - index);
}

/// Pushes an item on the stack. The stack limit is not checked.
void push(const intx::uint256& item) noexcept { *++top_item = item; }

Expand All @@ -62,21 +68,22 @@ struct evm_stack
/// Also std::basic_string<uint8_t> has been tried but not faster and we don't want SSO
/// if initial_capacity is used.
/// In future, transition to std::realloc() + std::free() planned.
class evm_memory
class Memory
{
/// The initial memory allocation.
static constexpr size_t initial_capacity = 4 * 1024;

std::vector<uint8_t> m_memory;

public:
evm_memory() noexcept { m_memory.reserve(initial_capacity); }
Memory() noexcept { m_memory.reserve(initial_capacity); }

evm_memory(const evm_memory&) = delete;
evm_memory& operator=(const evm_memory&) = delete;
Memory(const Memory&) = delete;
Memory& operator=(const Memory&) = delete;

uint8_t& operator[](size_t index) noexcept { return m_memory[index]; }

[[nodiscard]] const uint8_t* data() const noexcept { return m_memory.data(); }
[[nodiscard]] size_t size() const noexcept { return m_memory.size(); }

void resize(size_t new_size) { m_memory.resize(new_size); }
Expand All @@ -88,8 +95,8 @@ class evm_memory
struct ExecutionState
{
int64_t gas_left = 0;
evm_stack stack;
evm_memory memory;
Stack stack;
Memory memory;
const evmc_message* msg = nullptr;
evmc::HostContext host;
evmc_revision rev = {};
Expand Down
4 changes: 2 additions & 2 deletions lib/evmone/instructions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace evmone
{
namespace
{
template <void InstrFn(evm_stack&)>
template <void InstrFn(Stack&)>
const instruction* op(const instruction* instr, AdvancedExecutionState& state) noexcept
{
InstrFn(state.stack);
Expand Down Expand Up @@ -189,7 +189,7 @@ const instruction* opx_beginblock(const instruction* instr, AdvancedExecutionSta
if (static_cast<int>(state.stack.size()) < block.stack_req)
return state.exit(EVMC_STACK_UNDERFLOW);

if (static_cast<int>(state.stack.size()) + block.stack_max_growth > evm_stack::limit)
if (static_cast<int>(state.stack.size()) + block.stack_max_growth > Stack::limit)
return state.exit(EVMC_STACK_OVERFLOW);

state.current_block_cost = block.gas_cost;
Expand Down
54 changes: 27 additions & 27 deletions lib/evmone/instructions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,59 +56,59 @@ inline bool check_memory(ExecutionState& state, const uint256& offset, const uin
return check_memory(state, offset, static_cast<uint64_t>(size));
}

inline void add(evm_stack& stack) noexcept
inline void add(Stack& stack) noexcept
{
stack.top() += stack.pop();
}

inline void mul(evm_stack& stack) noexcept
inline void mul(Stack& stack) noexcept
{
stack.top() *= stack.pop();
}

inline void sub(evm_stack& stack) noexcept
inline void sub(Stack& stack) noexcept
{
stack[1] = stack[0] - stack[1];
stack.pop();
}

inline void div(evm_stack& stack) noexcept
inline void div(Stack& stack) noexcept
{
auto& v = stack[1];
v = v != 0 ? stack[0] / v : 0;
stack.pop();
}

inline void sdiv(evm_stack& stack) noexcept
inline void sdiv(Stack& stack) noexcept
{
auto& v = stack[1];
v = v != 0 ? intx::sdivrem(stack[0], v).quot : 0;
stack.pop();
}

inline void mod(evm_stack& stack) noexcept
inline void mod(Stack& stack) noexcept
{
auto& v = stack[1];
v = v != 0 ? stack[0] % v : 0;
stack.pop();
}

inline void smod(evm_stack& stack) noexcept
inline void smod(Stack& stack) noexcept
{
auto& v = stack[1];
v = v != 0 ? intx::sdivrem(stack[0], v).rem : 0;
stack.pop();
}

inline void addmod(evm_stack& stack) noexcept
inline void addmod(Stack& stack) noexcept
{
const auto x = stack.pop();
const auto y = stack.pop();
auto& m = stack.top();
m = m != 0 ? intx::addmod(x, y, m) : 0;
}

inline void mulmod(evm_stack& stack) noexcept
inline void mulmod(Stack& stack) noexcept
{
const auto x = stack.pop();
const auto y = stack.pop();
Expand All @@ -132,7 +132,7 @@ inline evmc_status_code exp(ExecutionState& state) noexcept
return EVMC_SUCCESS;
}

inline void signextend(evm_stack& stack) noexcept
inline void signextend(Stack& stack) noexcept
{
const auto ext = stack.pop();
auto& x = stack.top();
Expand All @@ -147,19 +147,19 @@ inline void signextend(evm_stack& stack) noexcept
}
}

inline void lt(evm_stack& stack) noexcept
inline void lt(Stack& stack) noexcept
{
const auto x = stack.pop();
stack[0] = x < stack[0];
}

inline void gt(evm_stack& stack) noexcept
inline void gt(Stack& stack) noexcept
{
const auto x = stack.pop();
stack[0] = stack[0] < x; // TODO: Using < is faster than >.
}

inline void slt(evm_stack& stack) noexcept
inline void slt(Stack& stack) noexcept
{
// TODO: Move this to intx.
const auto x = stack.pop();
Expand All @@ -169,7 +169,7 @@ inline void slt(evm_stack& stack) noexcept
y = ((x_neg ^ y_neg) != 0) ? x_neg : x < y;
}

inline void sgt(evm_stack& stack) noexcept
inline void sgt(Stack& stack) noexcept
{
const auto x = stack.pop();
auto& y = stack[0];
Expand All @@ -178,38 +178,38 @@ inline void sgt(evm_stack& stack) noexcept
y = ((x_neg ^ y_neg) != 0) ? y_neg : y < x;
}

inline void eq(evm_stack& stack) noexcept
inline void eq(Stack& stack) noexcept
{
stack[1] = stack[0] == stack[1];
stack.pop();
}

inline void iszero(evm_stack& stack) noexcept
inline void iszero(Stack& stack) noexcept
{
stack.top() = stack.top() == 0;
}

inline void and_(evm_stack& stack) noexcept
inline void and_(Stack& stack) noexcept
{
stack.top() &= stack.pop();
}

inline void or_(evm_stack& stack) noexcept
inline void or_(Stack& stack) noexcept
{
stack.top() |= stack.pop();
}

inline void xor_(evm_stack& stack) noexcept
inline void xor_(Stack& stack) noexcept
{
stack.top() ^= stack.pop();
}

inline void not_(evm_stack& stack) noexcept
inline void not_(Stack& stack) noexcept
{
stack.top() = ~stack.top();
}

inline void byte(evm_stack& stack) noexcept
inline void byte(Stack& stack) noexcept
{
const auto n = stack.pop();
auto& x = stack.top();
Expand All @@ -224,17 +224,17 @@ inline void byte(evm_stack& stack) noexcept
}
}

inline void shl(evm_stack& stack) noexcept
inline void shl(Stack& stack) noexcept
{
stack.top() <<= stack.pop();
}

inline void shr(evm_stack& stack) noexcept
inline void shr(Stack& stack) noexcept
{
stack.top() >>= stack.pop();
}

inline void sar(evm_stack& stack) noexcept
inline void sar(Stack& stack) noexcept
{
if ((stack[1] & (uint256{1} << 255)) == 0)
return shr(stack);
Expand Down Expand Up @@ -554,7 +554,7 @@ inline void selfbalance(ExecutionState& state) noexcept
}


inline void pop(evm_stack& stack) noexcept
inline void pop(Stack& stack) noexcept
{
stack.pop();
}
Expand Down Expand Up @@ -671,7 +671,7 @@ inline void msize(ExecutionState& state) noexcept
/// DUP instruction implementation.
/// @tparam N The number as in the instruction definition, e.g. DUP3 is dup<3>.
template <size_t N>
inline void dup(evm_stack& stack) noexcept
inline void dup(Stack& stack) noexcept
{
static_assert(N >= 1 && N <= 16);
stack.push(stack[N - 1]);
Expand All @@ -680,7 +680,7 @@ inline void dup(evm_stack& stack) noexcept
/// SWAP instruction implementation.
/// @tparam N The number as in the instruction definition, e.g. SWAP3 is swap<3>.
template <size_t N>
inline void swap(evm_stack& stack) noexcept
inline void swap(Stack& stack) noexcept
{
static_assert(N >= 1 && N <= 16);
std::swap(stack.top(), stack[N]);
Expand Down
33 changes: 32 additions & 1 deletion test/unittests/execution_state_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ TEST(execution_state, reset_advanced)

TEST(execution_state, stack_clear)
{
evmone::evm_stack stack;
evmone::Stack stack;

stack.clear();
EXPECT_EQ(stack.size(), 0);
Expand All @@ -158,3 +158,34 @@ TEST(execution_state, stack_clear)
EXPECT_EQ(stack.size(), 0);
EXPECT_EQ(stack.top_item + 1, stack.storage);
}

TEST(execution_state, const_stack)
{
evmone::Stack stack;
stack.push(1);
stack.push(2);

const auto& cstack = stack;

EXPECT_EQ(cstack[0], 2);
EXPECT_EQ(cstack[1], 1);
}

TEST(execution_state, memory_view)
{
evmone::Memory memory;
memory.resize(3);

evmone::bytes_view view{memory.data(), memory.size()};
ASSERT_EQ(view.size(), 3);
EXPECT_EQ(view[0], 0x00);
EXPECT_EQ(view[1], 0x00);
EXPECT_EQ(view[2], 0x00);

memory[0] = 0xc0;
memory[2] = 0xc2;
ASSERT_EQ(view.size(), 3);
EXPECT_EQ(view[0], 0xc0);
EXPECT_EQ(view[1], 0x00);
EXPECT_EQ(view[2], 0xc2);
}

0 comments on commit 2c1f473

Please sign in to comment.