diff --git a/bus-mapping/src/evm/opcodes/begin_end_tx.rs b/bus-mapping/src/evm/opcodes/begin_end_tx.rs index 8393060278..e8baf7f88f 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 { 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 { @@ -127,13 +136,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; @@ -158,6 +179,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 = @@ -262,8 +295,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 @@ -279,7 +313,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()), @@ -318,11 +352,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() }); @@ -362,8 +397,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 @@ -379,7 +415,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()), @@ -406,6 +442,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, @@ -415,6 +452,8 @@ impl ExecutionGadget for BeginTxGadget { create, callee_not_exists, is_caller_callee_equal, + coinbase, + is_coinbase_warm, } } @@ -432,6 +471,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; @@ -504,6 +545,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, @@ -557,6 +600,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(()) } }