diff --git a/bus-mapping/src/evm/opcodes/begin_end_tx.rs b/bus-mapping/src/evm/opcodes/begin_end_tx.rs index fb8784442ec..a65e2561be2 100644 --- a/bus-mapping/src/evm/opcodes/begin_end_tx.rs +++ b/bus-mapping/src/evm/opcodes/begin_end_tx.rs @@ -59,8 +59,8 @@ fn gen_begin_tx_steps(state: &mut CircuitInputStateRef) -> Result Result for u64 { } } +/// Once per word of the init code when creating a contract. +pub const INIT_CODE_WORD_GAS: u64 = 2; /// Quotient for max refund of gas used pub const MAX_REFUND_QUOTIENT_OF_GAS_USED: usize = 5; /// Gas stipend when CALL or CALLCODE is attached with value. diff --git a/external-tracer/src/lib.rs b/external-tracer/src/lib.rs index 28f8cd35d9b..539777bda34 100644 --- a/external-tracer/src/lib.rs +++ b/external-tracer/src/lib.rs @@ -29,18 +29,15 @@ pub struct TraceConfig { /// Configuration structure for `logger.Config` #[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "PascalCase")] pub struct LoggerConfig { /// enable memory capture - #[serde(rename = "EnableMemory")] pub enable_memory: bool, /// disable stack capture - #[serde(rename = "DisableStack")] pub disable_stack: bool, /// disable storage capture - #[serde(rename = "DisableStorage")] pub disable_storage: bool, /// enable return data capture - #[serde(rename = "EnableReturnData")] pub enable_return_data: bool, } diff --git a/geth-utils/gethutil/trace.go b/geth-utils/gethutil/trace.go index 13f4182d429..39cd78b8942 100644 --- a/geth-utils/gethutil/trace.go +++ b/geth-utils/gethutil/trace.go @@ -130,22 +130,21 @@ func newUint64(val uint64) *uint64 { return &val } func Trace(config TraceConfig) ([]*ExecutionResult, error) { chainConfig := params.ChainConfig{ - ChainID: toBigInt(config.ChainID), - HomesteadBlock: big.NewInt(0), - DAOForkBlock: big.NewInt(0), - DAOForkSupport: true, - EIP150Block: big.NewInt(0), - EIP155Block: big.NewInt(0), - EIP158Block: big.NewInt(0), - ByzantiumBlock: big.NewInt(0), - ConstantinopleBlock: big.NewInt(0), - PetersburgBlock: big.NewInt(0), - IstanbulBlock: big.NewInt(0), - MuirGlacierBlock: big.NewInt(0), - BerlinBlock: big.NewInt(0), - LondonBlock: big.NewInt(0), - // FIXME: EIP-3860 - // ShanghaiTime: newUint64(0), + ChainID: toBigInt(config.ChainID), + HomesteadBlock: big.NewInt(0), + DAOForkBlock: big.NewInt(0), + DAOForkSupport: true, + EIP150Block: big.NewInt(0), + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + ByzantiumBlock: big.NewInt(0), + ConstantinopleBlock: big.NewInt(0), + PetersburgBlock: big.NewInt(0), + IstanbulBlock: big.NewInt(0), + MuirGlacierBlock: big.NewInt(0), + BerlinBlock: big.NewInt(0), + LondonBlock: big.NewInt(0), + ShanghaiTime: newUint64(0), MergeNetsplitBlock: nil, TerminalTotalDifficulty: common.Big0, TerminalTotalDifficultyPassed: true, diff --git a/geth-utils/src/lib.rs b/geth-utils/src/lib.rs index 07716e927ff..66f15393060 100644 --- a/geth-utils/src/lib.rs +++ b/geth-utils/src/lib.rs @@ -152,8 +152,7 @@ mod test { ] }"#, ] { - let _trace = trace(config); - assert!(_trace.is_err()) + assert!(trace(config).is_err()) } } } diff --git a/mock/src/test_ctx.rs b/mock/src/test_ctx.rs index 6b7e982197f..a985aa903c1 100644 --- a/mock/src/test_ctx.rs +++ b/mock/src/test_ctx.rs @@ -286,7 +286,7 @@ impl TestContext { /// account_0_code_account_1_no_code`]. Extra accounts, txs and/or block /// configs are set as [`Default`]. pub fn simple_ctx_with_bytecode(bytecode: Bytecode) -> Result, Error> { - TestContext::<2, 1>::new( + TestContext::new( None, account_0_code_account_1_no_code(bytecode), tx_from_1_to_0, diff --git a/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs b/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs index 985b67570f0..dc1a2f7fca5 100644 --- a/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs +++ b/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs @@ -1,7 +1,7 @@ use crate::{ evm_circuit::{ execution::ExecutionGadget, - param::{N_BYTES_ACCOUNT_ADDRESS, N_BYTES_GAS, N_BYTES_WORD}, + param::{N_BYTES_ACCOUNT_ADDRESS, N_BYTES_GAS, N_BYTES_U64, N_BYTES_WORD}, step::ExecutionState, util::{ and, @@ -12,14 +12,16 @@ use crate::{ }, is_precompiled, math_gadget::{ - ContractCreateGadget, IsEqualGadget, IsZeroGadget, MulWordByU64Gadget, - RangeCheckGadget, + ConstantDivisionGadget, ContractCreateGadget, IsEqualGadget, IsZeroGadget, + MulWordByU64Gadget, RangeCheckGadget, }, not, or, select, CachedRegion, Cell, StepRws, Word, }, witness::{Block, Call, ExecStep, Transaction}, }, - table::{AccountFieldTag, CallContextFieldTag, TxFieldTag as TxContextFieldTag}, + table::{ + AccountFieldTag, BlockContextFieldTag, CallContextFieldTag, TxFieldTag as TxContextFieldTag, + }, util::Expr, }; use eth_types::{evm_types::GasCost, Field, ToLittleEndian, ToScalar}; @@ -42,6 +44,7 @@ pub(crate) struct BeginTxGadget { tx_value: Word, tx_call_data_length: Cell, tx_call_data_gas_cost: Cell, + tx_call_data_word_length: ConstantDivisionGadget, reversion_info: ReversionInfo, sufficient_gas_left: RangeCheckGadget, transfer_with_gas_fee: TransferWithGasFeeGadget, @@ -51,6 +54,12 @@ pub(crate) struct BeginTxGadget { create: ContractCreateGadget, callee_not_exists: IsZeroGadget, is_caller_callee_equal: Cell, + // EIP-3651 (Warm COINBASE) + coinbase: Cell, + // Caller, callee and a list addresses are added to the access list before + // coinbase, and may be duplicate. + // + is_coinbase_warm: Cell, } impl ExecutionGadget for BeginTxGadget { @@ -126,13 +135,25 @@ impl ExecutionGadget for BeginTxGadget { let mul_gas_fee_by_gas = MulWordByU64Gadget::construct(cb, tx_gas_price.clone(), tx_gas.expr()); + let tx_call_data_word_length = + ConstantDivisionGadget::construct(cb, tx_call_data_length.expr() + 31.expr(), 32); + + // Calculate gas cost of init code for EIP-3860. + let init_code_gas_cost = select::expr( + tx_is_create.expr(), + tx_call_data_word_length.quotient().expr() + * eth_types::evm_types::INIT_CODE_WORD_GAS.expr(), + 0.expr(), + ); + // TODO: Take gas cost of access list (EIP 2930) into consideration. // Use intrinsic gas let intrinsic_gas_cost = select::expr( tx_is_create.expr(), GasCost::CREATION_TX.expr(), GasCost::TX.expr(), - ) + tx_call_data_gas_cost.expr(); + ) + tx_call_data_gas_cost.expr() + + init_code_gas_cost; // Check gas_left is sufficient let gas_left = tx_gas.expr() - intrinsic_gas_cost; @@ -157,6 +178,18 @@ impl ExecutionGadget for BeginTxGadget { None, ); // rwc_delta += 1 + // Query coinbase address. + let coinbase = cb.query_cell(); + let is_coinbase_warm = cb.query_bool(); + cb.block_lookup(BlockContextFieldTag::Coinbase.expr(), None, coinbase.expr()); + cb.account_access_list_write( + tx_id.expr(), + coinbase.expr(), + 1.expr(), + is_coinbase_warm.expr(), + None, + ); // rwc_delta += 1 + // Read code_hash of callee let phase2_code_hash = cb.query_cell_phase2(); let is_empty_code_hash = @@ -261,8 +294,9 @@ impl ExecutionGadget for BeginTxGadget { // - Write CallContext IsPersistent // - Write CallContext IsSuccess // - Write Account (Caller) Nonce - // - Write TxAccessListAccount - // - Write TxAccessListAccount + // - Write TxAccessListAccount (Caller) + // - Write TxAccessListAccount (Callee) + // - Write TxAccessListAccount (Coinbase) for EIP-3651 // - a TransferWithGasFeeGadget // - Write Account (Callee) Nonce (Reversible) // - Write CallContext Depth @@ -278,7 +312,7 @@ impl ExecutionGadget for BeginTxGadget { // - Write CallContext IsRoot // - Write CallContext IsCreate // - Write CallContext CodeHash - rw_counter: Delta(21.expr() + transfer_with_gas_fee.rw_delta()), + rw_counter: Delta(22.expr() + transfer_with_gas_fee.rw_delta()), call_id: To(call_id.expr()), is_root: To(true.expr()), is_create: To(tx_is_create.expr()), @@ -317,11 +351,12 @@ impl ExecutionGadget for BeginTxGadget { // - Write CallContext IsPersistent // - Write CallContext IsSuccess // - Write Account Nonce - // - Write TxAccessListAccount - // - Write TxAccessListAccount + // - Write TxAccessListAccount (Caller) + // - Write TxAccessListAccount (Callee) + // - Write TxAccessListAccount (Coinbase) for EIP-3651 // - Read Account CodeHash // - a TransferWithGasFeeGadget - rw_counter: Delta(8.expr() + transfer_with_gas_fee.rw_delta()), + rw_counter: Delta(9.expr() + transfer_with_gas_fee.rw_delta()), call_id: To(call_id.expr()), ..StepStateTransition::any() }); @@ -361,8 +396,9 @@ impl ExecutionGadget for BeginTxGadget { // - Write CallContext IsPersistent // - Write CallContext IsSuccess // - Write Account Nonce - // - Write TxAccessListAccount - // - Write TxAccessListAccount + // - Write TxAccessListAccount (Caller) + // - Write TxAccessListAccount (Callee) + // - Write TxAccessListAccount (Coinbase) for EIP-3651 // - Read Account CodeHash // - a TransferWithGasFeeGadget // - Write CallContext Depth @@ -378,7 +414,7 @@ impl ExecutionGadget for BeginTxGadget { // - Write CallContext IsRoot // - Write CallContext IsCreate // - Write CallContext CodeHash - rw_counter: Delta(21.expr() + transfer_with_gas_fee.rw_delta()), + rw_counter: Delta(22.expr() + transfer_with_gas_fee.rw_delta()), call_id: To(call_id.expr()), is_root: To(true.expr()), is_create: To(tx_is_create.expr()), @@ -405,6 +441,7 @@ impl ExecutionGadget for BeginTxGadget { tx_value, tx_call_data_length, tx_call_data_gas_cost, + tx_call_data_word_length, reversion_info, sufficient_gas_left, transfer_with_gas_fee, @@ -414,6 +451,8 @@ impl ExecutionGadget for BeginTxGadget { create, callee_not_exists, is_caller_callee_equal, + coinbase, + is_coinbase_warm, } } @@ -431,6 +470,8 @@ impl ExecutionGadget for BeginTxGadget { let mut rws = StepRws::new(block, step); rws.offset_add(7); + + let is_coinbase_warm = rws.next().tx_access_list_value_pair().1; let mut callee_code_hash = zero; if !is_precompiled(&tx.callee_address) && !tx.is_create { callee_code_hash = rws.next().account_value_pair().1; @@ -503,6 +544,8 @@ impl ExecutionGadget for BeginTxGadget { offset, Value::known(F::from(tx.call_data_gas_cost)), )?; + self.tx_call_data_word_length + .assign(region, offset, tx.call_data_length as u128 + 31)?; self.reversion_info.assign( region, offset, @@ -556,6 +599,23 @@ impl ExecutionGadget for BeginTxGadget { None, )?; + self.coinbase.assign( + region, + offset, + Value::known( + block + .context + .coinbase + .to_scalar() + .expect("unexpected Address -> Scalar conversion failure"), + ), + )?; + self.is_coinbase_warm.assign( + region, + offset, + Value::known(F::from(is_coinbase_warm as u64)), + )?; + Ok(()) } }