Skip to content

Commit

Permalink
Circuit for opcode DELEGATECALL (privacy-scaling-explorations#847)
Browse files Browse the repository at this point in the history
* Implement `DELEGATECALL` circuit.

* Add `IsZeroGadget` for `is_staticcall`, and check if `is_call + is_delegatecall + is_staticcall == 1`.

* Rename `current_address` to `current_callee_address`, `parent_address` to `current_caller_address`, and `parent_value` to `current_value`.

* Delete function `is_opcode`.
  • Loading branch information
silathdiir authored Nov 24, 2022
1 parent cb5bfe2 commit bfb1d1f
Show file tree
Hide file tree
Showing 6 changed files with 226 additions and 115 deletions.
6 changes: 2 additions & 4 deletions bus-mapping/src/evm/opcodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@ fn fn_gen_associated_ops(opcode_id: &OpcodeId) -> FnGenAssociatedOps {
OpcodeId::LOG3 => Log::gen_associated_ops,
OpcodeId::LOG4 => Log::gen_associated_ops,
OpcodeId::CALL => CallOpcode::<7>::gen_associated_ops,
OpcodeId::DELEGATECALL => CallOpcode::<6>::gen_associated_ops,
OpcodeId::STATICCALL => CallOpcode::<6>::gen_associated_ops,
OpcodeId::RETURN => Return::gen_associated_ops,
// REVERT is almost the same as RETURN
Expand All @@ -239,7 +240,7 @@ fn fn_gen_associated_ops(opcode_id: &OpcodeId) -> FnGenAssociatedOps {
warn!("Using dummy gen_selfdestruct_ops for opcode SELFDESTRUCT");
DummySelfDestruct::gen_associated_ops
}
OpcodeId::CALLCODE | OpcodeId::DELEGATECALL => {
OpcodeId::CALLCODE => {
warn!("Using dummy gen_call_ops for opcode {:?}", opcode_id);
DummyCall::gen_associated_ops
}
Expand Down Expand Up @@ -620,11 +621,8 @@ fn dummy_gen_call_ops(

let (args_offset, args_length, ret_offset, ret_length) = {
// CALLCODE (gas, addr, value, argsOffset, argsLength, retOffset, retLength)
// DELEGATECALL(gas, addr, argsOffset, argsLength, retOffset, retLength)
// STATICCALL (gas, addr, argsOffset, argsLength, retOffset, retLength)
let pos = match geth_step.op {
OpcodeId::CALLCODE => (3, 4, 5, 6),
OpcodeId::DELEGATECALL | OpcodeId::STATICCALL => (2, 3, 4, 5),
_ => unreachable!("opcode is not of call type"),
};
(
Expand Down
72 changes: 49 additions & 23 deletions bus-mapping/src/evm/opcodes/callop.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::Opcode;
use crate::circuit_input_builder::{CircuitInputStateRef, ExecStep};
use crate::circuit_input_builder::{CallKind, CircuitInputStateRef, CodeSource, ExecStep};
use crate::operation::{AccountField, CallContextField, TxAccessListAccountOp, RW};
use crate::Error;
use eth_types::evm_types::gas_utils::{eip150_gas, memory_expansion_gas_cost};
Expand All @@ -9,11 +9,11 @@ use keccak256::EMPTY_HASH;
use log::warn;

/// Placeholder structure used to implement [`Opcode`] trait over it
/// corresponding to the `OpcodeId::CALL` and `OpcodeId::STATICCALL`.
/// corresponding to the `OpcodeId::CALL`, `OpcodeId::DELEGATECALL` and
/// `OpcodeId::STATICCALL`.
/// - CALL: N_ARGS = 7
/// - STATICCALL: N_ARGS = 6
/// TODO: Suppose to add bus-mapping of `OpcodeId::CALLCODE` and
/// `OpcodeId::DELEGATECALL` here.
/// - DELEGATECALL and STATICCALL: N_ARGS = 6
/// TODO: Suppose to also add bus-mapping of `OpcodeId::CALLCODE` here.
#[derive(Debug, Copy, Clone)]
pub(crate) struct CallOpcode<const N_ARGS: usize>;

Expand All @@ -37,26 +37,43 @@ impl<const N_ARGS: usize> Opcode for CallOpcode<N_ARGS> {
let call = state.parse_call(geth_step)?;
let current_call = state.call()?.clone();

// NOTE: For `RwCounterEndOfReversion` we use the `0` value as a placeholder,
// and later set the proper value in
// `CircuitInputBuilder::set_value_ops_call_context_rwc_eor`
for (field, value) in [
// For opcode `DELEGATECALL`, `call.address` is caller address which is
// different with callee address (code address).
let callee_address = match call.code_source {
CodeSource::Address(address) => address,
_ => call.address,
};

let mut field_values = vec![
(CallContextField::TxId, tx_id.into()),
// NOTE: For `RwCounterEndOfReversion` we use the `0` value as a
// placeholder, and later set the proper value in
// `CircuitInputBuilder::set_value_ops_call_context_rwc_eor`
(CallContextField::RwCounterEndOfReversion, 0.into()),
(
CallContextField::IsPersistent,
(current_call.is_persistent as u64).into(),
),
(
CallContextField::CalleeAddress,
current_call.address.to_word(),
),
(
CallContextField::IsStatic,
(current_call.is_static as u64).into(),
),
(CallContextField::Depth, current_call.depth.into()),
] {
(
CallContextField::CalleeAddress,
current_call.address.to_word(),
),
];
if call.kind == CallKind::DelegateCall {
field_values.extend([
(
CallContextField::CallerAddress,
current_call.caller_address.to_word(),
),
(CallContextField::Value, current_call.value),
]);
}
for (field, value) in field_values {
state.call_context_read(&mut exec_step, current_call.call_id, field, value);
}

Expand All @@ -74,13 +91,13 @@ impl<const N_ARGS: usize> Opcode for CallOpcode<N_ARGS> {
(call.is_success as u64).into(),
)?;

let is_warm = state.sdb.check_account_in_access_list(&call.address);
let is_warm = state.sdb.check_account_in_access_list(&callee_address);
state.push_op_reversible(
&mut exec_step,
RW::WRITE,
TxAccessListAccountOp {
tx_id,
address: call.address,
address: callee_address,
is_warm: true,
is_warm_prev: is_warm,
},
Expand Down Expand Up @@ -109,13 +126,22 @@ impl<const N_ARGS: usize> Opcode for CallOpcode<N_ARGS> {
let (_, callee_account) = state.sdb.get_account(&call.address);
let is_empty_account = callee_account.is_empty();
let callee_nonce = callee_account.nonce;
let callee_code_hash = callee_account.code_hash;
for (field, value) in [
(AccountField::Nonce, callee_nonce),
(AccountField::CodeHash, callee_code_hash.to_word()),
] {
state.account_read(&mut exec_step, call.address, field, value, value)?;
}
state.account_read(
&mut exec_step,
call.address,
AccountField::Nonce,
callee_nonce,
callee_nonce,
)?;
let callee_code_hash = call.code_hash;
let callee_code_hash_word = callee_code_hash.to_word();
state.account_read(
&mut exec_step,
callee_address,
AccountField::CodeHash,
callee_code_hash_word,
callee_code_hash_word,
)?;

// Calculate next_memory_word_size and callee_gas_left manually in case
// there isn't next geth_step (e.g. callee doesn't have code).
Expand Down
5 changes: 1 addition & 4 deletions zkevm-circuits/src/evm_circuit/execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,6 @@ pub(crate) struct ExecutionConfig<F> {
returndatacopy_gadget: ReturnDataCopyGadget<F>,
create_gadget: DummyGadget<F, 3, 1, { ExecutionState::CREATE }>,
callcode_gadget: DummyGadget<F, 7, 1, { ExecutionState::CALLCODE }>,
delegatecall_gadget: DummyGadget<F, 6, 1, { ExecutionState::DELEGATECALL }>,
create2_gadget: DummyGadget<F, 4, 1, { ExecutionState::CREATE2 }>,
selfdestruct_gadget: DummyGadget<F, 1, 0, { ExecutionState::SELFDESTRUCT }>,
signed_comparator_gadget: SignedComparatorGadget<F>,
Expand Down Expand Up @@ -472,7 +471,6 @@ impl<F: Field> ExecutionConfig<F> {
returndatacopy_gadget: configure_gadget!(),
create_gadget: configure_gadget!(),
callcode_gadget: configure_gadget!(),
delegatecall_gadget: configure_gadget!(),
create2_gadget: configure_gadget!(),
selfdestruct_gadget: configure_gadget!(),
shl_shr_gadget: configure_gadget!(),
Expand Down Expand Up @@ -968,7 +966,7 @@ impl<F: Field> ExecutionConfig<F> {
ExecutionState::ADDRESS => assign_exec_step!(self.address_gadget),
ExecutionState::BITWISE => assign_exec_step!(self.bitwise_gadget),
ExecutionState::BYTE => assign_exec_step!(self.byte_gadget),
ExecutionState::CALL_STATICCALL => assign_exec_step!(self.call_op_gadget),
ExecutionState::CALL_DELEGATECALL_STATICCALL => assign_exec_step!(self.call_op_gadget),
ExecutionState::CALLDATACOPY => assign_exec_step!(self.calldatacopy_gadget),
ExecutionState::CALLDATALOAD => assign_exec_step!(self.calldataload_gadget),
ExecutionState::CALLDATASIZE => assign_exec_step!(self.calldatasize_gadget),
Expand Down Expand Up @@ -1014,7 +1012,6 @@ impl<F: Field> ExecutionConfig<F> {
ExecutionState::EXTCODECOPY => assign_exec_step!(self.extcodecopy_gadget),
ExecutionState::CREATE => assign_exec_step!(self.create_gadget),
ExecutionState::CALLCODE => assign_exec_step!(self.callcode_gadget),
ExecutionState::DELEGATECALL => assign_exec_step!(self.delegatecall_gadget),
ExecutionState::CREATE2 => assign_exec_step!(self.create2_gadget),
ExecutionState::SELFDESTRUCT => assign_exec_step!(self.selfdestruct_gadget),
// end of dummy gadgets
Expand Down
Loading

0 comments on commit bfb1d1f

Please sign in to comment.