diff --git a/lib/evmone/advanced_instructions.cpp b/lib/evmone/advanced_instructions.cpp index 7102fd854b..791562c85f 100644 --- a/lib/evmone/advanced_instructions.cpp +++ b/lib/evmone/advanced_instructions.cpp @@ -70,6 +70,15 @@ inline code_iterator impl(AdvancedExecutionState& state, code_iterator pos) noex state.stack.top_item += instr::traits[Op].stack_height_change; return new_pos; } + +template > +inline code_iterator impl(AdvancedExecutionState& state, code_iterator pos) noexcept +{ + const auto new_pos = CoreFn(state.stack.top_item, state, pos, state.gas_left); + state.stack.top_item += instr::traits[Op].stack_height_change; + return new_pos; +} /// @} } // namespace instr diff --git a/lib/evmone/baseline.cpp b/lib/evmone/baseline.cpp index 56ab443c89..dcaae5528a 100644 --- a/lib/evmone/baseline.cpp +++ b/lib/evmone/baseline.cpp @@ -194,6 +194,13 @@ struct Position return instr_fn(pos.stack_top, state, pos.code_it); } +[[release_inline]] inline code_iterator invoke( + code_iterator (*instr_fn)(StackTop, ExecutionState&, code_iterator, int64_t&) noexcept, + Position pos, int64_t& gas, ExecutionState& state) noexcept +{ + return instr_fn(pos.stack_top, state, pos.code_it, gas); +} + [[release_inline]] inline code_iterator invoke( TermResult (*instr_fn)(StackTop, int64_t, ExecutionState&) noexcept, Position pos, int64_t& gas, ExecutionState& state) noexcept diff --git a/lib/evmone/instructions.hpp b/lib/evmone/instructions.hpp index 03d9a813d4..28aeb26dd0 100644 --- a/lib/evmone/instructions.hpp +++ b/lib/evmone/instructions.hpp @@ -1167,6 +1167,138 @@ inline TermResult selfdestruct(StackTop stack, int64_t gas_left, ExecutionState& return {EVMC_SUCCESS, gas_left}; } +/// EVMMAX instructions +namespace +{ +// TODO: Use it in `grom_memory` function +[[nodiscard]] inline int64_t evm_memory_expansion_cost( + const Memory& memory, uint64_t new_size) noexcept +{ + const auto new_words = num_words(new_size); + const auto current_words = static_cast(memory.size() / word_size); + const auto new_cost = 3 * new_words + new_words * new_words / 512; + const auto current_cost = 3 * current_words + current_words * current_words / 512; + return new_cost - current_cost; +} +} // namespace + +inline Result setupx(StackTop stack, int64_t gas_left, ExecutionState& state) noexcept +{ + static constexpr auto MAX_MOD_SIZE = 4096; + + const auto mod_id = stack.pop(); + const auto mod_offset_256 = stack.pop(); + const auto mod_size_256 = stack.pop(); + const auto vals_used_256 = stack.pop(); + + if (!check_memory(gas_left, state.memory, mod_offset_256, mod_size_256)) + return {EVMC_OUT_OF_GAS, gas_left}; + + // Maximum allowed modulus size + if (mod_size_256 > MAX_MOD_SIZE / 8) + return {EVMC_FAILURE, gas_left}; + + const auto mod_ptr = &state.memory[static_cast(mod_offset_256)]; + const auto mod_size = static_cast(mod_size_256); + + // Modulus must be odd + if (mod_ptr[mod_size - 1] % 2 == 0) + return {EVMC_FAILURE, gas_left}; + + const auto vals_used = static_cast(vals_used_256); + // max number of value slots is 256 + if (vals_used_256 > 256) + return {EVMC_FAILURE, gas_left}; + + if (!state.evmmax_state.exists(mod_id)) + { + const auto value_size_multiplier = (mod_size + 7) / 8; + if ((gas_left -= evm_memory_expansion_cost( + state.memory, (vals_used * value_size_multiplier * 8 + 31) / 32)) < 0) + { + return {EVMC_OUT_OF_GAS, gas_left}; + } + } + + const auto status = state.evmmax_state.setupx(gas_left, mod_id, mod_ptr, mod_size, vals_used); + return {status, gas_left}; +} + +inline Result loadx(StackTop stack, int64_t gas_left, ExecutionState& state) noexcept +{ + const auto dst_offset = stack.pop(); + const auto val_idx = stack.pop(); + const auto num_vals = stack.pop(); + + if (!check_memory(gas_left, state.memory, dst_offset, + num_vals * state.evmmax_state.active_mod_value_size_multiplier() * 8)) + return {EVMC_OUT_OF_GAS, gas_left}; + + const auto status = + state.evmmax_state.loadx(gas_left, &state.memory[static_cast(dst_offset)], + static_cast(val_idx), static_cast(num_vals)); + + return {status, gas_left}; +} + +inline Result storex(StackTop stack, int64_t gas_left, ExecutionState& state) noexcept +{ + const auto dst_val = stack.pop(); + const auto offset = stack.pop(); + const auto num_vals = stack.pop(); + + if (!check_memory(gas_left, state.memory, offset, + num_vals * state.evmmax_state.active_mod_value_size_multiplier() * 8)) + return {EVMC_OUT_OF_GAS, gas_left}; + + const auto status = + state.evmmax_state.storex(gas_left, &state.memory[static_cast(offset)], + static_cast(dst_val), static_cast(num_vals)); + + return {status, gas_left}; +} + +inline code_iterator addmodx( + StackTop /*stack*/, ExecutionState& state, code_iterator pos, int64_t& gas_left) noexcept +{ + const auto dst_idx = pos[1]; + const auto x_idx = pos[2]; + const auto y_idx = pos[3]; + + state.status = state.evmmax_state.addmodx(gas_left, dst_idx, x_idx, y_idx); + if (state.status == EVMC_SUCCESS) + return pos + 4; + else + return nullptr; +} + +inline code_iterator submodx( + StackTop /*stack*/, ExecutionState& state, code_iterator pos, int64_t& gas_left) noexcept +{ + const auto dst_idx = pos[1]; + const auto x_idx = pos[2]; + const auto y_idx = pos[3]; + + state.status = state.evmmax_state.submodx(gas_left, dst_idx, x_idx, y_idx); + if (state.status == EVMC_SUCCESS) + return pos + 4; + else + return nullptr; +} + +inline code_iterator mulmodx( + StackTop /*stack*/, ExecutionState& state, code_iterator pos, int64_t& gas_left) noexcept +{ + const auto dst_idx = pos[1]; + const auto x_idx = pos[2]; + const auto y_idx = pos[3]; + + state.status = state.evmmax_state.mulmodx(gas_left, dst_idx, x_idx, y_idx); + if (state.status == EVMC_SUCCESS) + return pos + 4; + else + return nullptr; +} /// Maps an opcode to the instruction implementation. /// diff --git a/lib/evmone/instructions_traits.hpp b/lib/evmone/instructions_traits.hpp index 076fe04d2d..66179e726a 100644 --- a/lib/evmone/instructions_traits.hpp +++ b/lib/evmone/instructions_traits.hpp @@ -185,9 +185,9 @@ constexpr inline GasCostTable gas_costs = []() noexcept { table[EVMC_PRAGUE][OP_DATASIZE] = 2; table[EVMC_PRAGUE][OP_DATACOPY] = 3; table[EVMC_EVMMAX][OP_SETUPX] = 3; - table[EVMC_EVMMAX][OP_ADDMODX] = 1; - table[EVMC_EVMMAX][OP_SUBMODX] = 1; - table[EVMC_EVMMAX][OP_MULMODX] = 1; + table[EVMC_EVMMAX][OP_ADDMODX] = 0; + table[EVMC_EVMMAX][OP_SUBMODX] = 0; + table[EVMC_EVMMAX][OP_MULMODX] = 0; table[EVMC_EVMMAX][OP_LOADX] = 3; table[EVMC_EVMMAX][OP_STOREX] = 3; diff --git a/lib/evmone/instructions_xmacro.hpp b/lib/evmone/instructions_xmacro.hpp index 17984355db..77ac0b795a 100644 --- a/lib/evmone/instructions_xmacro.hpp +++ b/lib/evmone/instructions_xmacro.hpp @@ -67,12 +67,12 @@ ON_OPCODE_UNDEFINED(0x1f) \ \ ON_OPCODE_IDENTIFIER(OP_KECCAK256, keccak256) \ - ON_OPCODE_UNDEFINED(0x21) \ - ON_OPCODE_UNDEFINED(0x22) \ - ON_OPCODE_UNDEFINED(0x23) \ - ON_OPCODE_UNDEFINED(0x24) \ - ON_OPCODE_UNDEFINED(0x25) \ - ON_OPCODE_UNDEFINED(0x26) \ + ON_OPCODE_IDENTIFIER(OP_SETUPX, setupx) \ + ON_OPCODE_IDENTIFIER(OP_ADDMODX, addmodx) \ + ON_OPCODE_IDENTIFIER(OP_SUBMODX, submodx) \ + ON_OPCODE_IDENTIFIER(OP_MULMODX, mulmodx) \ + ON_OPCODE_IDENTIFIER(OP_LOADX, loadx) \ + ON_OPCODE_IDENTIFIER(OP_STOREX, storex) \ ON_OPCODE_UNDEFINED(0x27) \ ON_OPCODE_UNDEFINED(0x28) \ ON_OPCODE_UNDEFINED(0x29) \