Skip to content

Commit

Permalink
g
Browse files Browse the repository at this point in the history
  • Loading branch information
rodiazet committed Dec 5, 2023
1 parent 82d9055 commit 2461de9
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 43 deletions.
3 changes: 2 additions & 1 deletion include/evmmax/evmmax.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ struct EXMMAXModState

[[nodiscard]] virtual size_t value_size_multiplier() const noexcept = 0;
[[nodiscard]] virtual size_t num_values() const noexcept = 0;
[[nodiscard]] virtual size_t mod_size() const noexcept = 0;

virtual ~EXMMAXModState() {}
};
Expand Down Expand Up @@ -55,6 +54,8 @@ class EVMMAXState
[[nodiscard]] bool mulmodx(
int64_t& gas_left, size_t dst_idx, size_t x_idx, size_t y_idx) noexcept;

[[nodiscard]] bool exists(const uint256& mod_id) const noexcept;

[[nodiscard]] size_t active_mod_value_size_multiplier() const noexcept;
[[nodiscard]] size_t active_mod_size() const noexcept;
};
Expand Down
48 changes: 16 additions & 32 deletions lib/evmmax/evmmax.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,10 @@ struct EXMMAXModStateTyped : public EXMMAXModState
{
std::vector<UintT> values;
ModArith<UintT> arith;
const size_t value_size; /// Size of the values passed from EVM. // TODO: Add better naming
const size_t value_size_mult;

explicit EXMMAXModStateTyped(const UintT& mod, size_t mod_size, size_t vals_used) noexcept
: arith(mod), value_size(mod_size)
: arith(mod), value_size_mult((mod_size + 7) / 8)
{
values.resize(vals_used);
}
Expand All @@ -51,7 +51,8 @@ struct EXMMAXModStateTyped : public EXMMAXModState
return false;

for (unsigned i = 0; i < num_vals; ++i)
store(out_ptr + i * value_size, arith.from_mont(values[val_idx]), value_size);
store(out_ptr + i * value_size_mult * 8, arith.from_mont(values[val_idx]),
value_size_mult * 8);

return true;
}
Expand All @@ -65,7 +66,7 @@ struct EXMMAXModStateTyped : public EXMMAXModState
for (unsigned i = 0; i < num_vals; ++i)
{
values[dst_val_idx + i] =
arith.to_mont(load<UintT>(in_ptr + value_size * i, value_size));
arith.to_mont(load<UintT>(in_ptr + value_size_mult * 8 * i, value_size_mult * 8));
}

return true;
Expand Down Expand Up @@ -105,12 +106,7 @@ struct EXMMAXModStateTyped : public EXMMAXModState
}

[[nodiscard]] size_t num_values() const noexcept override { return values.size(); }
[[nodiscard]] size_t value_size_multiplier() const noexcept override
{
return (value_size + 7) / 8;
}

[[nodiscard]] size_t mod_size() const noexcept override { return value_size; }
[[nodiscard]] size_t value_size_multiplier() const noexcept override { return value_size_mult; }
};

[[nodiscard]] std::unique_ptr<EXMMAXModState> create_mod_state(
Expand Down Expand Up @@ -232,29 +228,31 @@ struct EXMMAXModStateTyped : public EXMMAXModState
return gas_left >= 0;
}

[[nodiscard]] bool EVMMAXState::exists(const intx::uint256& mod_id) const noexcept
{
// TODO: Add support for uint256 to be a key in std::unordered_map
const auto mod_id_bytes = intx::be::store<evmc::bytes32>(mod_id);

return mods.contains(mod_id_bytes);
}

[[nodiscard]] bool EVMMAXState::setupx(int64_t& gas_left, const uint256& mod_id,
const uint8_t* mod_ptr, size_t mod_size, size_t vals_used) noexcept
{
static constexpr int64_t SETUPX_BASE_GAS = 3;

// TODO: Add support for uint256 to be a key in std::unordered_map
const auto mod_id_bytes = intx::be::store<evmc::bytes32>(mod_id);

gas_left -= SETUPX_BASE_GAS;
if (gas_left < 0)
return false;

if (active_mod != mods.end() && active_mod->first == mod_id_bytes)
return true;

active_mod = mods.find(mod_id_bytes);
if (active_mod != mods.end())
return true;

if (!charge_gas_precompute_mont(gas_left, mod_size))
if (!validate_memory_usage(mod_size, vals_used))
return false;

if (!validate_memory_usage(mod_size, vals_used))
if (!charge_gas_precompute_mont(gas_left, mod_size))
return false;

// TODO: Handle `create_mod_state` returns nullptr case
Expand All @@ -265,9 +263,6 @@ struct EXMMAXModStateTyped : public EXMMAXModState
[[nodiscard]] bool EVMMAXState::loadx(
int64_t& gas_left, uint8_t* out_ptr, size_t val_idx, size_t num_vals) noexcept
{
static constexpr int64_t LOADX_BASE_GAS = 3;
gas_left -= LOADX_BASE_GAS;

if (active_mod == mods.end())
return false;

Expand All @@ -280,9 +275,6 @@ struct EXMMAXModStateTyped : public EXMMAXModState
[[nodiscard]] bool EVMMAXState::storex(
int64_t& gas_left, const uint8_t* in_ptr, size_t dst_val_idx, size_t num_vals) noexcept
{
static constexpr int64_t STOREX_BASE_GAS = 3;
gas_left -= STOREX_BASE_GAS;

if (active_mod == mods.end())
return false;

Expand Down Expand Up @@ -336,14 +328,6 @@ struct EXMMAXModStateTyped : public EXMMAXModState
return active_mod->second->value_size_multiplier();
}

[[nodiscard]] size_t EVMMAXState::active_mod_size() const noexcept
{
if (active_mod == mods.end())
return 0;

return active_mod->second->mod_size();
}

[[nodiscard]] bool EVMMAXState::validate_memory_usage(size_t val_size, size_t num_val) noexcept
{
static constexpr auto EVMMAX_MAX_MEM_SIZE = 65536;
Expand Down
58 changes: 48 additions & 10 deletions lib/evmone/instructions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1160,14 +1160,33 @@ inline TermResult selfdestruct(StackTop stack, int64_t gas_left, ExecutionState&
}

/// 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<int64_t>(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;
static constexpr int64_t SETUPX_BASE_GAS = 3;

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

const auto mod_id = stack.pop();
const auto mod_offset_256 = stack.pop();
const auto mod_size_256 = stack.pop();
const auto vals_used = 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};
Expand All @@ -1179,15 +1198,24 @@ inline Result setupx(StackTop stack, int64_t gas_left, ExecutionState& state) no
const auto mod_ptr = &state.memory[static_cast<size_t>(mod_offset_256)];
const auto mod_size = static_cast<size_t>(mod_size_256);

// Modulus must be odd and max used value slots is 256
if (mod_ptr[mod_size - 1] % 2 == 0 || vals_used > 256)
// Modulus must be odd
if (mod_ptr[mod_size - 1] % 2 == 0)
return {EVMC_OUT_OF_GAS, gas_left};

if (state.evmmax_state.setupx(
gas_left, mod_id, mod_ptr, mod_size, static_cast<size_t>(vals_used)))
const auto vals_used = static_cast<size_t>(vals_used_256);
// max number of value slots is 256
if (vals_used_256 > 256)
return {EVMC_OUT_OF_GAS, gas_left};

if (!state.evmmax_state.exists(mod_id))
{
return {EVMC_SUCCESS, gas_left};
const auto value_size_multiplier = (mod_size + 7) / 8;
gas_left -= evm_memory_expansion_cost(
state.memory, (vals_used * value_size_multiplier * 8 + 31) / 32);
}

if (state.evmmax_state.setupx(gas_left, mod_id, mod_ptr, mod_size, vals_used))
return {EVMC_SUCCESS, gas_left};
else
return {EVMC_OUT_OF_GAS, gas_left};
}
Expand All @@ -1198,8 +1226,13 @@ inline Result loadx(StackTop stack, int64_t gas_left, ExecutionState& state) noe
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_size()))
static constexpr int64_t LOADX_BASE_GAS = 3;
gas_left -= LOADX_BASE_GAS;
if (gas_left < 0)
return {EVMC_OUT_OF_GAS, gas_left};

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};

if (state.evmmax_state.loadx(gas_left, &state.memory[static_cast<size_t>(dst_offset)],
Expand All @@ -1217,8 +1250,13 @@ inline Result storex(StackTop stack, int64_t gas_left, ExecutionState& state) no
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_size()))
static constexpr int64_t STOREX_BASE_GAS = 3;
gas_left -= STOREX_BASE_GAS;
if (gas_left < 0)
return {EVMC_OUT_OF_GAS, gas_left};

if (!check_memory(gas_left, state.memory, offset,
num_vals * state.evmmax_state.active_mod_value_size_multiplier()))
return {EVMC_OUT_OF_GAS, gas_left};

if (state.evmmax_state.storex(gas_left, &state.memory[static_cast<size_t>(offset)],
Expand Down

0 comments on commit 2461de9

Please sign in to comment.