Skip to content
This repository was archived by the owner on Jul 5, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions bus-mapping/src/circuit_input_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,16 @@ impl<'a> CircuitInputBuilder {
eth_block: &EthBlock,
geth_traces: &[eth_types::GethExecTrace],
) -> Result<(), Error> {
// accumulates gas across all txs in the block
let mut cumulative_gas_used = HashMap::new();
for (tx_index, tx) in eth_block.transactions.iter().enumerate() {
let geth_trace = &geth_traces[tx_index];
self.handle_tx(tx, geth_trace, tx_index + 1 == eth_block.transactions.len())?;
self.handle_tx(
tx,
geth_trace,
tx_index + 1 == eth_block.transactions.len(),
&mut cumulative_gas_used,
)?;
}
self.set_value_ops_call_context_rwc_eor();
Ok(())
Expand All @@ -155,6 +162,7 @@ impl<'a> CircuitInputBuilder {
eth_tx: &eth_types::Transaction,
geth_trace: &GethExecTrace,
is_last_tx: bool,
cumulative_gas_used: &mut HashMap<usize, u64>,
) -> Result<(), Error> {
let mut tx = self.new_tx(eth_tx, !geth_trace.failed)?;
let mut tx_ctx = TransactionContext::new(eth_tx, geth_trace, is_last_tx)?;
Expand All @@ -181,7 +189,10 @@ impl<'a> CircuitInputBuilder {
// - execution_state: EndTx
// - op: None
// Generate EndTx step
let end_tx_step = gen_end_tx_ops(&mut self.state_ref(&mut tx, &mut tx_ctx))?;
let end_tx_step = gen_end_tx_ops(
&mut self.state_ref(&mut tx, &mut tx_ctx),
cumulative_gas_used,
)?;
tx.steps_mut().push(end_tx_step);

self.sdb.commit_tx();
Expand Down
69 changes: 66 additions & 3 deletions bus-mapping/src/evm/opcodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,18 @@ use crate::{
evm::OpcodeId,
operation::{
AccountField, AccountOp, CallContextField, CallContextOp, TxAccessListAccountOp,
TxRefundOp, RW,
TxReceiptField, TxReceiptOp, TxRefundOp, RW,
},
Error,
};
use core::fmt::Debug;
use eth_types::{
evm_types::{GasCost, MAX_REFUND_QUOTIENT_OF_GAS_USED},
GethExecStep, ToWord,
GethExecStep, ToWord, Word,
};
use keccak256::EMPTY_HASH;
use log::warn;
use std::collections::HashMap;

mod call;
mod calldatacopy;
Expand Down Expand Up @@ -400,7 +401,10 @@ pub fn gen_begin_tx_ops(state: &mut CircuitInputStateRef) -> Result<ExecStep, Er
}
}

pub fn gen_end_tx_ops(state: &mut CircuitInputStateRef) -> Result<ExecStep, Error> {
pub fn gen_end_tx_ops(
state: &mut CircuitInputStateRef,
cumulative_gas_used: &mut HashMap<usize, u64>,
) -> Result<ExecStep, Error> {
let mut exec_step = state.new_end_tx_step();
let call = state.tx.calls()[0].clone();

Expand All @@ -413,6 +417,15 @@ pub fn gen_end_tx_ops(state: &mut CircuitInputStateRef) -> Result<ExecStep, Erro
value: state.tx_ctx.id().into(),
},
);
state.push_op(
&mut exec_step,
RW::READ,
CallContextOp {
call_id: call.call_id,
field: CallContextField::IsPersistent,
value: Word::from(call.is_persistent as u8),
},
);

let refund = state.sdb.refund();
state.push_op(
Expand Down Expand Up @@ -464,6 +477,56 @@ pub fn gen_end_tx_ops(state: &mut CircuitInputStateRef) -> Result<ExecStep, Erro
},
);

// handle tx receipt tag
state.push_op(
&mut exec_step,
RW::READ,
TxReceiptOp {
tx_id: state.tx_ctx.id(),
field: TxReceiptField::PostStateOrStatus,
value: call.is_persistent as u64,
},
);

let log_id = exec_step.log_id;
state.push_op(
&mut exec_step,
RW::READ,
TxReceiptOp {
tx_id: state.tx_ctx.id(),
field: TxReceiptField::LogLength,
value: log_id as u64,
Comment thread
DreamWuGit marked this conversation as resolved.
},
);

let gas_used = state.tx.gas - exec_step.gas_left.0;
let mut current_cumulative_gas_used: u64 = 0;
if state.tx_ctx.id() > 1 {
current_cumulative_gas_used = *cumulative_gas_used.get(&(state.tx_ctx.id() - 1)).unwrap();
// query pre tx cumulative gas
state.push_op(
&mut exec_step,
RW::READ,
TxReceiptOp {
tx_id: state.tx_ctx.id() - 1,
field: TxReceiptField::CumulativeGasUsed,
value: current_cumulative_gas_used,
},
);
}

state.push_op(
&mut exec_step,
RW::READ,
TxReceiptOp {
tx_id: state.tx_ctx.id(),
field: TxReceiptField::CumulativeGasUsed,
value: current_cumulative_gas_used + gas_used,
},
);

cumulative_gas_used.insert(state.tx_ctx.id(), current_cumulative_gas_used + gas_used);

if !state.tx_ctx.is_last_tx() {
state.push_op(
&mut exec_step,
Expand Down
1 change: 1 addition & 0 deletions bus-mapping/src/exec_trace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ impl fmt::Debug for OperationRef {
Target::Account => "Account",
Target::AccountDestructed => "AccountDestructed",
Target::CallContext => "CallContext",
Target::TxReceipt => "TxReceipt",
},
self.1
))
Expand Down
61 changes: 61 additions & 0 deletions bus-mapping/src/operation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ pub enum Target {
AccountDestructed,
/// Means the target of the operation is the CallContext.
CallContext,
/// Means the target of the operation is the TxReceipt.
TxReceipt,
}

/// Trait used for Operation Kinds.
Expand Down Expand Up @@ -760,6 +762,63 @@ impl CallContextOp {
}
}

/// Represents a field parameter of the TxReceipt that can be accessed via EVM
/// execution.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum TxReceiptField {
/// flag indicates whether a tx succeed or not
PostStateOrStatus,
/// the cumulative gas used in the block containing the transaction receipt
/// as of immediately after the transaction has happened.
CumulativeGasUsed,
/// record how many log entries in the receipt/tx , 0 if tx fails
LogLength,
}

/// Represents TxReceipt read/write operation.
#[derive(Clone, PartialEq, Eq)]
pub struct TxReceiptOp {
/// tx_id of TxReceipt
pub tx_id: usize,
/// field of TxReceipt
pub field: TxReceiptField,
/// value of TxReceipt
pub value: u64,
}

impl fmt::Debug for TxReceiptOp {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("TxReceiptOp { ")?;
f.write_fmt(format_args!(
"tx_id: {:?}, field: {:?}, value: {:?}",
self.tx_id, self.field, self.value,
))?;
f.write_str(" }")
}
}

impl PartialOrd for TxReceiptOp {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}

impl Ord for TxReceiptOp {
fn cmp(&self, other: &Self) -> Ordering {
(&self.tx_id, &self.field).cmp(&(&other.tx_id, &other.field))
}
}

impl Op for TxReceiptOp {
fn into_enum(self) -> OpEnum {
OpEnum::TxReceipt(self)
}

fn reverse(&self) -> Self {
unreachable!("TxReceiptOp can't be reverted")
Comment thread
DreamWuGit marked this conversation as resolved.
}
}

/// Generic enum that wraps over all the operation types possible.
/// In particular [`StackOp`], [`MemoryOp`] and [`StorageOp`].
#[derive(Debug, Clone)]
Expand All @@ -782,6 +841,8 @@ pub enum OpEnum {
AccountDestructed(AccountDestructedOp),
/// CallContext
CallContext(CallContextOp),
/// TxReceipt
TxReceipt(TxReceiptOp),
}

/// Operation is a Wrapper over a type that implements Op with a RWCounter.
Expand Down
11 changes: 9 additions & 2 deletions bus-mapping/src/operation/container.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use super::{
AccountDestructedOp, AccountOp, CallContextOp, MemoryOp, Op, OpEnum, Operation, RWCounter,
StackOp, StorageOp, Target, TxAccessListAccountOp, TxAccessListAccountStorageOp, TxRefundOp,
RW,
StackOp, StorageOp, Target, TxAccessListAccountOp, TxAccessListAccountStorageOp, TxReceiptOp,
TxRefundOp, RW,
};
use crate::exec_trace::OperationRef;
use itertools::Itertools;
Expand Down Expand Up @@ -40,6 +40,8 @@ pub struct OperationContainer {
pub account_destructed: Vec<Operation<AccountDestructedOp>>,
/// Operations of CallContextOp
pub call_context: Vec<Operation<CallContextOp>>,
/// Operations of TxReceiptOp
pub tx_receipt: Vec<Operation<TxReceiptOp>>,
}

impl Default for OperationContainer {
Expand All @@ -62,6 +64,7 @@ impl OperationContainer {
account: Vec::new(),
account_destructed: Vec::new(),
call_context: Vec::new(),
tx_receipt: Vec::new(),
}
}

Expand Down Expand Up @@ -154,6 +157,10 @@ impl OperationContainer {
self.call_context.push(Operation::new(rwc, rw, op));
OperationRef::from((Target::CallContext, self.call_context.len() - 1))
}
OpEnum::TxReceipt(op) => {
self.tx_receipt.push(Operation::new(rwc, rw, op));
OperationRef::from((Target::TxReceipt, self.tx_receipt.len() - 1))
}
}
}

Expand Down
1 change: 1 addition & 0 deletions zkevm-circuits/src/evm_circuit/execution/begin_tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ impl<F: Field> ExecutionGadget<F> for BeginTxGadget<F> {
code_source: To(code_hash.expr()),
gas_left: To(gas_left),
reversible_write_counter: To(2.expr()),
log_id: To(0.expr()),
Comment thread
DreamWuGit marked this conversation as resolved.
..StepStateTransition::new_context()
});

Expand Down
Loading