Skip to content

Commit

Permalink
Implement circuit for ErrorOutOfGasMemoryCopy state (privacy-scalin…
Browse files Browse the repository at this point in the history
…g-explorations#1288)

### Description

Spec Markdown PR
privacy-scaling-explorations/zkevm-specs#397

#### Summary

1. Merge OOG error `ExtCodeCopy` into `MemoryCopy`.

2. Implement bus-mapping and circuit for this OOG error of
`CALLDATACOPY`, `CODECOPY`, `EXTCODECOPY` and `RETURNDATACOPY` opcodes.

3. OOG error executions of `CALLDATACOPY`, `CODECOPY` and
`RETURNDATACOPY` are same.

4. `EXTCODECOPY` has extra `1` stack pop, and constant gas costs are
different for cold (2600) and warm (100) accounts according to EIP-2929
(could reference [go-etherum gasExtCodeCopyEIP2929
function](https://github.com/ethereum/go-ethereum/blob/master/core/vm/operations_acl.go#L116)).

5. Fix `memory_copier_gas_cost` function to not calculate memory
expansion for zero copy size in gas utils of `eth-types`.

### Issue Link

Close
privacy-scaling-explorations#1266

### Type of change

- [X] New feature (non-breaking change which adds functionality)

### How Has This Been Tested?

Add new unit-test cases for this error state.
  • Loading branch information
silathdiir authored Apr 20, 2023
1 parent 3429f83 commit e55ba06
Show file tree
Hide file tree
Showing 7 changed files with 499 additions and 12 deletions.
14 changes: 6 additions & 8 deletions bus-mapping/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,8 @@ pub enum OogError {
/// Out of Gas for CREATE, RETURN, REVERT, which have dynamic memory
/// expansion gas cost
DynamicMemoryExpansion,
/// Out of Gas for CALLDATACOPY, CODECOPY, RETURNDATACOPY, which copy a
/// specified chunk of memory
/// Out of Gas for CALLDATACOPY, CODECOPY, EXTCODECOPY, RETURNDATACOPY,
/// which copy a specified chunk of memory
MemoryCopy,
/// Out of Gas for BALANCE, EXTCODESIZE, EXTCODEHASH, which possibly touch
/// an extra account
Expand All @@ -88,8 +88,6 @@ pub enum OogError {
Exp,
/// Out of Gas for SHA3
Sha3,
/// Out of Gas for EXTCODECOPY
ExtCodeCopy,
/// Out of Gas for SLOAD and SSTORE
SloadSstore,
/// Out of Gas for CALL, CALLCODE, DELEGATECALL and STATICCALL
Expand Down Expand Up @@ -144,9 +142,10 @@ pub(crate) fn get_step_reported_error(op: &OpcodeId, error: &str) -> ExecError {
OpcodeId::CREATE | OpcodeId::RETURN | OpcodeId::REVERT => {
OogError::DynamicMemoryExpansion
}
OpcodeId::CALLDATACOPY | OpcodeId::CODECOPY | OpcodeId::RETURNDATACOPY => {
OogError::MemoryCopy
}
OpcodeId::CALLDATACOPY
| OpcodeId::CODECOPY
| OpcodeId::EXTCODECOPY
| OpcodeId::RETURNDATACOPY => OogError::MemoryCopy,
OpcodeId::BALANCE | OpcodeId::EXTCODESIZE | OpcodeId::EXTCODEHASH => {
OogError::AccountAccess
}
Expand All @@ -155,7 +154,6 @@ pub(crate) fn get_step_reported_error(op: &OpcodeId, error: &str) -> ExecError {
}
OpcodeId::EXP => OogError::Exp,
OpcodeId::SHA3 => OogError::Sha3,
OpcodeId::EXTCODECOPY => OogError::ExtCodeCopy,
OpcodeId::CALL | OpcodeId::CALLCODE | OpcodeId::DELEGATECALL | OpcodeId::STATICCALL => {
OogError::Call
}
Expand Down
3 changes: 3 additions & 0 deletions bus-mapping/src/evm/opcodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ mod error_invalid_jump;
mod error_oog_call;
mod error_oog_exp;
mod error_oog_log;
mod error_oog_memory_copy;
mod error_oog_sload_sstore;
mod error_return_data_outofbound;
mod error_simple;
Expand All @@ -83,6 +84,7 @@ use error_invalid_jump::InvalidJump;
use error_oog_call::OOGCall;
use error_oog_exp::OOGExp;
use error_oog_log::ErrorOOGLog;
use error_oog_memory_copy::OOGMemoryCopy;
use error_oog_sload_sstore::OOGSloadSstore;
use error_return_data_outofbound::ErrorReturnDataOutOfBound;
use error_simple::ErrorSimple;
Expand Down Expand Up @@ -275,6 +277,7 @@ fn fn_gen_error_state_associated_ops(error: &ExecError) -> Option<FnGenAssociate
ExecError::OutOfGas(OogError::Constant) => Some(ErrorSimple::gen_associated_ops),
ExecError::OutOfGas(OogError::Exp) => Some(OOGExp::gen_associated_ops),
ExecError::OutOfGas(OogError::Log) => Some(ErrorOOGLog::gen_associated_ops),
ExecError::OutOfGas(OogError::MemoryCopy) => Some(OOGMemoryCopy::gen_associated_ops),
ExecError::OutOfGas(OogError::SloadSstore) => Some(OOGSloadSstore::gen_associated_ops),
ExecError::StackOverflow => Some(ErrorSimple::gen_associated_ops),
ExecError::StackUnderflow => Some(ErrorSimple::gen_associated_ops),
Expand Down
73 changes: 73 additions & 0 deletions bus-mapping/src/evm/opcodes/error_oog_memory_copy.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
use crate::{
circuit_input_builder::{CircuitInputStateRef, ExecStep},
error::{ExecError, OogError},
evm::Opcode,
operation::{CallContextField, TxAccessListAccountOp, RW},
Error,
};
use eth_types::{evm_types::OpcodeId, GethExecStep, ToAddress};

/// Placeholder structure used to implement [`Opcode`] trait over it
/// corresponding to the
/// [`OogError::MemoryCopy`](crate::error::OogError::MemoryCopy).
#[derive(Clone, Copy, Debug)]
pub(crate) struct OOGMemoryCopy;

impl Opcode for OOGMemoryCopy {
fn gen_associated_ops(
state: &mut CircuitInputStateRef,
geth_steps: &[GethExecStep],
) -> Result<Vec<ExecStep>, Error> {
let geth_step = &geth_steps[0];
debug_assert!([
OpcodeId::CALLDATACOPY,
OpcodeId::CODECOPY,
OpcodeId::EXTCODECOPY,
OpcodeId::RETURNDATACOPY
]
.contains(&geth_step.op));

let mut exec_step = state.new_step(geth_step)?;
exec_step.error = Some(ExecError::OutOfGas(OogError::MemoryCopy));

let is_extcodecopy = geth_step.op == OpcodeId::EXTCODECOPY;

// According to EIP-2929, EXTCODECOPY constant gas cost is different for cold
// and warm accounts.
if is_extcodecopy {
state.call_context_read(
&mut exec_step,
state.call()?.call_id,
CallContextField::TxId,
state.tx_ctx.id().into(),
);

let external_address = geth_step.stack.last()?.to_address();
let is_warm = state.sdb.check_account_in_access_list(&external_address);
state.push_op(
&mut exec_step,
RW::READ,
TxAccessListAccountOp {
tx_id: state.tx_ctx.id(),
address: external_address,
is_warm,
is_warm_prev: is_warm,
},
);
}

// Each of CALLDATACOPY, CODECOPY and RETURNDATACOPY has 3 stack read values.
// But EXTCODECOPY has 4. It has an extra stack pop for external address.
let stack_read_num = if is_extcodecopy { 4 } else { 3 };
for i in 0..stack_read_num {
state.stack_read(
&mut exec_step,
geth_step.stack.nth_last_filled(i),
geth_step.stack.nth_last(i)?,
)?;
}

state.handle_return(&mut exec_step, geth_steps, true)?;
Ok(vec![exec_step])
}
}
10 changes: 8 additions & 2 deletions eth-types/src/evm_types/gas_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,14 @@ pub fn memory_copier_gas_cost(
num_copy_bytes: u64,
) -> u64 {
let num_words = (num_copy_bytes + 31) / 32;
num_words * GasCost::COPY.as_u64()
+ memory_expansion_gas_cost(curr_memory_word_size, next_memory_word_size)
num_words * GasCost::COPY.as_u64() +
// Note that opcodes with a byte size parameter of 0 will not trigger
// memory expansion, regardless of their offset parameters.
if num_words > 0 {
memory_expansion_gas_cost(curr_memory_word_size, next_memory_word_size)
} else {
0
}
}

/// Calculate EIP 150 gas passed to callee.
Expand Down
4 changes: 3 additions & 1 deletion zkevm-circuits/src/evm_circuit/execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ mod error_oog_call;
mod error_oog_constant;
mod error_oog_exp;
mod error_oog_log;
mod error_oog_memory_copy;
mod error_oog_sload_sstore;
mod error_oog_static_memory;
mod error_return_data_oo_bound;
Expand Down Expand Up @@ -137,6 +138,7 @@ use error_oog_call::ErrorOOGCallGadget;
use error_oog_constant::ErrorOOGConstantGadget;
use error_oog_exp::ErrorOOGExpGadget;
use error_oog_log::ErrorOOGLogGadget;
use error_oog_memory_copy::ErrorOOGMemoryCopyGadget;
use error_oog_sload_sstore::ErrorOOGSloadSstoreGadget;
use error_return_data_oo_bound::ErrorReturnDataOutOfBoundGadget;
use error_stack::ErrorStackGadget;
Expand Down Expand Up @@ -282,6 +284,7 @@ pub(crate) struct ExecutionConfig<F> {
error_oog_call: Box<ErrorOOGCallGadget<F>>,
error_oog_constant: Box<ErrorOOGConstantGadget<F>>,
error_oog_exp: Box<ErrorOOGExpGadget<F>>,
error_oog_memory_copy: Box<ErrorOOGMemoryCopyGadget<F>>,
error_oog_sload_sstore: Box<ErrorOOGSloadSstoreGadget<F>>,
error_oog_static_memory_gadget:
Box<DummyGadget<F, 0, 0, { ExecutionState::ErrorOutOfGasStaticMemoryExpansion }>>,
Expand All @@ -290,7 +293,6 @@ pub(crate) struct ExecutionConfig<F> {
error_oog_dynamic_memory_gadget:
Box<DummyGadget<F, 0, 0, { ExecutionState::ErrorOutOfGasDynamicMemoryExpansion }>>,
error_oog_log: Box<ErrorOOGLogGadget<F>>,
error_oog_memory_copy: Box<DummyGadget<F, 0, 0, { ExecutionState::ErrorOutOfGasMemoryCopy }>>,
error_oog_account_access:
Box<DummyGadget<F, 0, 0, { ExecutionState::ErrorOutOfGasAccountAccess }>>,
error_oog_sha3: Box<DummyGadget<F, 0, 0, { ExecutionState::ErrorOutOfGasSHA3 }>>,
Expand Down
Loading

0 comments on commit e55ba06

Please sign in to comment.