Skip to content
This repository was archived by the owner on Apr 18, 2025. It is now read-only.

feat: Add TxEip2930Gadget to handle EIP-2930 (for evm-circuit part) #1045

Merged
merged 10 commits into from
Nov 30, 2023
10 changes: 10 additions & 0 deletions bus-mapping/src/circuit_input_builder/execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,12 @@ pub enum CopyDataType {
/// scenario where we wish to accumulate the value (RLC) over all rows.
/// This is used for Copy Lookup from SHA3 opcode verification.
RlcAcc,
/// When copy event is access-list addresses (EIP-2930), source is tx-table
/// and destination is rw-table.
AccessListAddresses,
/// When copy event is access-list storage keys (EIP-2930), source is
/// tx-table and destination is rw-table.
AccessListStorageKeys,
}
impl CopyDataType {
/// How many bits are necessary to represent a copy data type.
Expand Down Expand Up @@ -307,6 +313,8 @@ impl From<CopyDataType> for usize {
CopyDataType::TxCalldata => 3,
CopyDataType::TxLog => 4,
CopyDataType::RlcAcc => 5,
CopyDataType::AccessListAddresses => 6,
CopyDataType::AccessListStorageKeys => 7,
}
}
}
Expand All @@ -320,6 +328,8 @@ impl From<&CopyDataType> for u64 {
CopyDataType::TxCalldata => 3,
CopyDataType::TxLog => 4,
CopyDataType::RlcAcc => 5,
CopyDataType::AccessListAddresses => 6,
CopyDataType::AccessListStorageKeys => 7,
}
}
}
Expand Down
60 changes: 58 additions & 2 deletions bus-mapping/src/evm/opcodes/begin_end_tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use eth_types::{
gas_utils::{tx_access_list_gas_cost, tx_data_gas_cost},
GasCost, MAX_REFUND_QUOTIENT_OF_GAS_USED,
},
geth_types::access_list_size,
Bytecode, ToWord, Word,
};
use ethers_core::utils::get_contract_address;
Expand All @@ -42,10 +43,12 @@ impl TxExecSteps for BeginEndTx {

pub fn gen_begin_tx_steps(state: &mut CircuitInputStateRef) -> Result<ExecStep, Error> {
let mut exec_step = state.new_begin_tx_step();
let call = state.call()?.clone();

let caller_address = call.caller_address;
// Add two copy-events for tx access-list addresses and storage keys if EIP-2930.
gen_tx_eip2930_ops(state, &mut exec_step)?;

let call = state.call()?.clone();
let caller_address = call.caller_address;
if state.tx.tx_type.is_l1_msg() {
// for l1 message, no need to add rw op, but we must check
// caller for its existent status
Expand Down Expand Up @@ -615,3 +618,56 @@ fn gen_tx_l1_fee_ops(
)?;
Ok(())
}

// Add two copy-events for tx access-list addresses and storage keys if EIP-2930.
fn gen_tx_eip2930_ops(
state: &mut CircuitInputStateRef,
exec_step: &mut ExecStep,
) -> Result<(), Error> {
if !state.tx.tx_type.is_eip2930_tx() {
return Ok(());
}

let tx_id = NumberOrHash::Number(state.tx_ctx.id());
let (address_size, storage_key_size) = access_list_size(&state.tx.access_list);

// Add copy event for access-list addresses.
let rw_counter_start = state.block_ctx.rwc;
state.push_copy(
exec_step,
CopyEvent {
src_addr: 0,
src_addr_end: address_size,
src_type: CopyDataType::AccessListAddresses,
src_id: tx_id.clone(),
dst_addr: 0,
dst_type: CopyDataType::AccessListAddresses,
dst_id: tx_id.clone(),
log_id: None,
rw_counter_start,
// TODO
copy_bytes: CopyBytes::new(vec![], None, None),
},
);

// Add copy event for access-list storage keys.
let rw_counter_start = state.block_ctx.rwc;
state.push_copy(
exec_step,
CopyEvent {
src_addr: 0,
src_addr_end: storage_key_size,
src_type: CopyDataType::AccessListStorageKeys,
src_id: tx_id.clone(),
dst_addr: 0,
dst_type: CopyDataType::AccessListStorageKeys,
dst_id: tx_id,
log_id: None,
rw_counter_start,
// TODO
copy_bytes: CopyBytes::new(vec![], None, None),
},
);

Ok(())
}
27 changes: 24 additions & 3 deletions eth-types/src/geth_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,17 @@ impl From<TxType> for u64 {
impl TxType {
/// If this type is L1Msg or not
pub fn is_l1_msg(&self) -> bool {
matches!(*self, TxType::L1Msg)
matches!(*self, Self::L1Msg)
}

/// If this type is Eip155 or not
/// If this type is EIP-155 or not
pub fn is_eip155_tx(&self) -> bool {
matches!(*self, TxType::Eip155)
matches!(*self, Self::Eip155)
}

/// If this type is EIP-2930 or not
pub fn is_eip2930_tx(&self) -> bool {
matches!(*self, Self::Eip2930)
}

/// Get the type of transaction
Expand Down Expand Up @@ -402,3 +407,19 @@ impl GethData {
}
}
*/

/// Returns the number of addresses and the cumulative number of storage keys in
/// the entire access list.
pub fn access_list_size(access_list: &Option<AccessList>) -> (u64, u64) {
access_list.as_ref().map_or_else(
|| (0, 0),
|list| {
(
list.0.len() as u64,
list.0
.iter()
.fold(0, |acc, item| acc + item.storage_keys.len()) as u64,
)
},
)
}
39 changes: 21 additions & 18 deletions zkevm-circuits/src/evm_circuit/execution/begin_tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ use crate::{
util::{
and,
common_gadget::{
TransferGadgetInfo, TransferWithGasFeeGadget, TxL1FeeGadget, TxL1MsgGadget,
TransferGadgetInfo, TransferWithGasFeeGadget, TxEip2930Gadget, TxL1FeeGadget,
TxL1MsgGadget,
},
constraint_builder::{
ConstrainBuilderCommon, EVMConstraintBuilder, ReversionInfo, StepStateTransition,
Expand Down Expand Up @@ -43,6 +44,7 @@ const PRECOMPILE_COUNT: usize = 9;
#[derive(Clone, Debug)]
pub(crate) struct BeginTxGadget<F> {
tx_id: Cell<F>,
tx_type: Cell<F>,
sender_nonce: Cell<F>,
tx_nonce: Cell<F>,
tx_gas: Cell<F>,
Expand All @@ -60,8 +62,6 @@ pub(crate) struct BeginTxGadget<F> {
is_call_data_empty: IsZeroGadget<F>,
tx_call_data_word_length: ConstantDivisionGadget<F, N_BYTES_U64>,
tx_call_data_gas_cost: Cell<F>,
// The gas cost for access list (EIP 2930)
access_list_gas_cost: Cell<F>,
// The gas cost for rlp-encoded bytes of unsigned tx
tx_data_gas_cost: Cell<F>,
reversion_info: ReversionInfo<F>,
Expand Down Expand Up @@ -92,6 +92,7 @@ pub(crate) struct BeginTxGadget<F> {
is_coinbase_warm: Cell<F>,
tx_l1_fee: TxL1FeeGadget<F>,
tx_l1_msg: TxL1MsgGadget<F>,
tx_eip2930: TxEip2930Gadget<F>,
}

impl<F: Field> ExecutionGadget<F> for BeginTxGadget<F> {
Expand All @@ -104,25 +105,26 @@ impl<F: Field> ExecutionGadget<F> for BeginTxGadget<F> {
let call_id = cb.curr.state.rw_counter.clone();

let tx_id = cb.query_cell();

let sender_nonce = cb.query_cell();
let [tx_nonce, tx_gas, tx_caller_address, tx_callee_address, tx_is_create, tx_call_data_length, tx_call_data_gas_cost, access_list_gas_cost, tx_data_gas_cost] =

let [tx_type, tx_nonce, tx_gas, tx_caller_address, tx_callee_address, tx_is_create, tx_call_data_length, tx_call_data_gas_cost, tx_data_gas_cost] =
[
TxContextFieldTag::TxType,
TxContextFieldTag::Nonce,
TxContextFieldTag::Gas,
TxContextFieldTag::CallerAddress,
TxContextFieldTag::CalleeAddress,
TxContextFieldTag::IsCreate,
TxContextFieldTag::CallDataLength,
TxContextFieldTag::CallDataGasCost,
TxContextFieldTag::AccessListGasCost,
TxContextFieldTag::TxDataGasCost,
]
.map(|field_tag| cb.tx_context(tx_id.expr(), field_tag, None));

let tx_eip2930 = TxEip2930Gadget::construct(cb, tx_id.expr(), tx_type.expr());
let is_call_data_empty = IsZeroGadget::construct(cb, tx_call_data_length.expr());

let tx_l1_msg = TxL1MsgGadget::construct(cb, tx_id.expr(), tx_caller_address.expr());
let tx_l1_msg = TxL1MsgGadget::construct(cb, tx_type.expr(), tx_caller_address.expr());
let tx_l1_fee = cb.condition(not::expr(tx_l1_msg.is_l1_msg()), |cb| {
cb.require_equal(
"tx.nonce == sender.nonce",
Expand Down Expand Up @@ -258,7 +260,7 @@ impl<F: Field> ExecutionGadget<F> for BeginTxGadget<F> {
eth_types::evm_types::GasCost::CREATION_TX.expr(),
eth_types::evm_types::GasCost::TX.expr(),
) + tx_call_data_gas_cost.expr()
+ access_list_gas_cost.expr()
+ tx_eip2930.gas_cost()
+ init_code_gas_cost,
)
});
Expand Down Expand Up @@ -676,6 +678,7 @@ impl<F: Field> ExecutionGadget<F> for BeginTxGadget<F> {

Self {
tx_id,
tx_type,
tx_nonce,
sender_nonce,
tx_gas,
Expand All @@ -693,7 +696,6 @@ impl<F: Field> ExecutionGadget<F> for BeginTxGadget<F> {
is_call_data_empty,
tx_call_data_word_length,
tx_call_data_gas_cost,
access_list_gas_cost,
tx_data_gas_cost,
reversion_info,
sufficient_gas_left,
Expand All @@ -717,6 +719,7 @@ impl<F: Field> ExecutionGadget<F> for BeginTxGadget<F> {
is_coinbase_warm,
tx_l1_fee,
tx_l1_msg,
tx_eip2930,
}
}

Expand All @@ -737,7 +740,8 @@ impl<F: Field> ExecutionGadget<F> for BeginTxGadget<F> {

let mut rws = StepRws::new(block, step);

let caller_code_hash = if tx.tx_type.is_l1_msg() {
let tx_type = tx.tx_type;
let caller_code_hash = if tx_type.is_l1_msg() {
let caller_code_hash_pair = rws.next().account_codehash_pair();
assert_eq!(
caller_code_hash_pair.0, caller_code_hash_pair.1,
Expand All @@ -748,7 +752,7 @@ impl<F: Field> ExecutionGadget<F> for BeginTxGadget<F> {
U256::zero()
};
self.tx_l1_msg
.assign(region, offset, tx.tx_type, caller_code_hash)?;
.assign(region, offset, tx_type, caller_code_hash)?;

////////////// RWS ////////////////
// if L1:
Expand All @@ -768,7 +772,7 @@ impl<F: Field> ExecutionGadget<F> for BeginTxGadget<F> {
// caller addr
// callee addr
// coinbase
rws.offset_add(if tx.tx_type.is_l1_msg() {
rws.offset_add(if tx_type.is_l1_msg() {
if caller_code_hash.is_zero() {
assert_eq!(
tx.nonce, 0,
Expand Down Expand Up @@ -851,6 +855,8 @@ impl<F: Field> ExecutionGadget<F> for BeginTxGadget<F> {

self.tx_id
.assign(region, offset, Value::known(F::from(tx.id as u64)))?;
self.tx_type
.assign(region, offset, Value::known(F::from(tx_type as u64)))?;
self.tx_nonce
.assign(region, offset, Value::known(F::from(tx.nonce)))?;
self.sender_nonce
Expand Down Expand Up @@ -921,11 +927,6 @@ impl<F: Field> ExecutionGadget<F> for BeginTxGadget<F> {
offset,
Value::known(F::from(tx.call_data_gas_cost)),
)?;
self.access_list_gas_cost.assign(
region,
offset,
Value::known(F::from(tx.access_list_gas_cost)),
)?;
self.tx_data_gas_cost
.assign(region, offset, Value::known(F::from(tx.tx_data_gas_cost)))?;
self.reversion_info.assign(
Expand Down Expand Up @@ -1054,7 +1055,9 @@ impl<F: Field> ExecutionGadget<F> for BeginTxGadget<F> {
tx.l1_fee,
tx.l1_fee_committed,
tx.tx_data_gas_cost,
)
)?;

self.tx_eip2930.assign(region, offset, tx)
}
}

Expand Down
2 changes: 2 additions & 0 deletions zkevm-circuits/src/evm_circuit/util/common_gadget.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,11 @@ use halo2_proofs::{
plonk::{Error, Expression},
};

mod tx_eip2930;
mod tx_l1_fee;
mod tx_l1_msg;

pub(crate) use tx_eip2930::TxEip2930Gadget;
pub(crate) use tx_l1_fee::TxL1FeeGadget;
pub(crate) use tx_l1_msg::TxL1MsgGadget;

Expand Down
Loading