diff --git a/Cargo.lock b/Cargo.lock index a8395e98a8..21f29094a5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -385,6 +385,7 @@ dependencies = [ "serde_json", "strum", "strum_macros", + "taiko-mock", "tokio", "url", ] diff --git a/bus-mapping/Cargo.toml b/bus-mapping/Cargo.toml index c952158396..6cd4f366bf 100644 --- a/bus-mapping/Cargo.toml +++ b/bus-mapping/Cargo.toml @@ -10,6 +10,7 @@ eth-types = { path = "../eth-types" } gadgets = { path = "../gadgets" } keccak256 = { path = "../keccak256" } mock = { path = "../mock", optional = true } +taiko-mock = { path = "../taiko-mock", optional = true } ethers-core = "=2.0.0" ethers-providers = "=2.0.0" diff --git a/bus-mapping/src/circuit_input_builder/input_state_ref.rs b/bus-mapping/src/circuit_input_builder/input_state_ref.rs index 564f63d466..e264f6effa 100644 --- a/bus-mapping/src/circuit_input_builder/input_state_ref.rs +++ b/bus-mapping/src/circuit_input_builder/input_state_ref.rs @@ -309,10 +309,11 @@ impl<'a> CircuitInputStateRef<'a> { && (matches!(rw, RW::READ) || (op.value_prev.is_zero() && op.value.is_zero()))) && account.is_empty() { - panic!( - "RWTable Account field {:?} lookup to non-existing account rwc: {}, op: {:?}", - rw, self.block_ctx.rwc.0, op - ); + + // panic!( + // "RWTable Account field {:?} lookup to non-existing account rwc: {}, op: {:?}", + // rw, self.block_ctx.rwc.0, op + // ); } // -- sanity check end -- // Perform the write to the account in the StateDB diff --git a/bus-mapping/src/evm/opcodes/begin_end_tx.rs b/bus-mapping/src/evm/opcodes/begin_end_tx.rs index 57fd10a9dd..f69d0ed71b 100644 --- a/bus-mapping/src/evm/opcodes/begin_end_tx.rs +++ b/bus-mapping/src/evm/opcodes/begin_end_tx.rs @@ -98,13 +98,6 @@ fn gen_begin_tx_steps(state: &mut CircuitInputStateRef) -> Result Result Result return Err(Error::AccountNotFound(call.caller_address)); } let caller_balance_prev = caller_account.balance; - let caller_balance = caller_balance_prev - + if state.tx_ctx.is_anchor_tx() { - 0.into() - } else { - state.tx.tx.gas_price * (exec_step.gas_left.0 + effective_refund) - }; + let caller_balance = + caller_balance_prev + state.tx.tx.gas_price * (exec_step.gas_left.0 + effective_refund); state.account_write( &mut exec_step, call.caller_address, @@ -275,18 +264,18 @@ fn gen_end_tx_steps(state: &mut CircuitInputStateRef) -> Result caller_balance_prev, )?; - let effective_tip = state.tx.tx.gas_price - state.block.base_fee; + let effective_tip = if state.tx_ctx.is_anchor_tx() { + 0.into() + } else { + state.tx.tx.gas_price - state.block.base_fee + }; let (found, coinbase_account) = state.sdb.get_account(&state.block.coinbase); if !found { return Err(Error::AccountNotFound(state.block.coinbase)); } let coinbase_balance_prev = coinbase_account.balance; - let coinbase_balance = coinbase_balance_prev - + if state.tx_ctx.is_anchor_tx() { - 0.into() - } else { - effective_tip * (state.tx.gas() - exec_step.gas_left.0) - }; + let coinbase_balance = + coinbase_balance_prev + effective_tip * (state.tx.gas() - exec_step.gas_left.0); state.account_write( &mut exec_step, state.block.coinbase, diff --git a/taiko-mock/src/lib.rs b/taiko-mock/src/lib.rs index 42d3835c2b..d7456ec68a 100644 --- a/taiko-mock/src/lib.rs +++ b/taiko-mock/src/lib.rs @@ -52,7 +52,7 @@ lazy_static! { pub static ref MOCK_TAIKO_TREASURY_ADDRESS: Address = address!("0x000000000000000000000000000000000cafe777"); /// Mock anchor pub static ref MOCK_ANCHOR_GAS_LIMIT: Word = Word::from(180000); - pub static ref MOCK_ANCHOR_GAS_PRICE: Word = *MOCK_BASEFEE; + pub static ref MOCK_ANCHOR_GAS_PRICE: Word = Word::zero(); pub static ref MOCK_ANCHOR_L1_HASH: Hash = Hash::from_slice(&[0u8; 32]); pub static ref MOCK_ANCHOR_SIGNAL_ROOT: Hash = Hash::from_slice(&[0u8; 32]); pub static ref MOCK_ANCHOR_L1_HIGHT: u64 = 0; diff --git a/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs b/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs index 6769fb2e6f..0d98eddd0d 100644 --- a/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs +++ b/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs @@ -59,9 +59,6 @@ impl ExecutionGadget for BeginTxGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::BeginTx; fn configure(cb: &mut EVMConstraintBuilder) -> Self { - // additions for taiko's eip-1559 - // 1. no need update GOLDEN_TOUCH account for Anchor - // Use rw_counter of the step which triggers next call as its call_id. let call_id = cb.curr.state.rw_counter.clone(); @@ -180,29 +177,16 @@ impl ExecutionGadget for BeginTxGadget { ); // rwc_delta += 1 }); - // Anchor is always the first tx of the list - let is_anchor_tx = IsEqualGadget::construct(cb, tx_id.expr(), 1.expr()); - let not_anchor_tx = not::expr(is_anchor_tx.expr()); - // Transfer value from caller to callee, creating account if necessary. - // only update caller and callee account when tx is not anchor - let transfer_with_gas_fee = cb.condition(not_anchor_tx.expr(), |cb| { - TransferWithGasFeeGadget::construct( - cb, - tx_caller_address.expr(), - tx_callee_address.expr(), - not::expr(callee_not_exists.expr()), - or::expr([tx_is_create.expr(), callee_not_exists.expr()]), - tx_value.clone(), - mul_gas_fee_by_gas.product().clone(), - &mut reversion_info, - ) - }); - // ignore anchor's transfer - let transfer_with_gas_fee_rw_delta = select::expr( - is_anchor_tx.expr(), - 0.expr(), - transfer_with_gas_fee.rw_delta(), + let transfer_with_gas_fee = TransferWithGasFeeGadget::construct( + cb, + tx_caller_address.expr(), + tx_callee_address.expr(), + not::expr(callee_not_exists.expr()), + or::expr([tx_is_create.expr(), callee_not_exists.expr()]), + tx_value.clone(), + mul_gas_fee_by_gas.product().clone(), + &mut reversion_info, ); let caller_nonce_hash_bytes = array_init::array_init(|_| cb.query_byte()); @@ -295,7 +279,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.expr()), + rw_counter: Delta(21.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()), @@ -338,7 +322,7 @@ impl ExecutionGadget for BeginTxGadget { // - Write TxAccessListAccount // - Read Account CodeHash // - a TransferWithGasFeeGadget - rw_counter: Delta(8.expr() + transfer_with_gas_fee_rw_delta.expr()), + rw_counter: Delta(8.expr() + transfer_with_gas_fee.rw_delta()), call_id: To(call_id.expr()), ..StepStateTransition::any() }); @@ -395,7 +379,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.expr()), + rw_counter: Delta(21.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()), diff --git a/zkevm-circuits/src/evm_circuit/execution/end_tx.rs b/zkevm-circuits/src/evm_circuit/execution/end_tx.rs index 7556be3db2..8f8cbb977a 100644 --- a/zkevm-circuits/src/evm_circuit/execution/end_tx.rs +++ b/zkevm-circuits/src/evm_circuit/execution/end_tx.rs @@ -54,13 +54,6 @@ impl ExecutionGadget for EndTxGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::EndTx; fn configure(cb: &mut EVMConstraintBuilder) -> Self { - // additions for taiko's eip-1559: - // 1. effective_gas_price = min(gas_tip_cap + base_fee, gas_fee_cap) - // a. gas_price == effective_gas_price - // 2. no need update GOLDEN_TOUCH account in Anchor(-effective_gas_price, +refund) - // 3. Anchor's gas_tip_cap == 0 - // 4. check gas_price == min(gas_tip_cap + base_fee, gas_fee_cap) - let tx_id = cb.call_context(None, CallContextFieldTag::TxId); let is_persistent = cb.call_context(None, CallContextFieldTag::IsPersistent); @@ -93,6 +86,12 @@ impl ExecutionGadget for EndTxGadget { tx_gas_price.clone(), effective_refund.min() + cb.curr.state.gas_left.expr(), ); + let gas_fee_refund = UpdateBalanceGadget::construct( + cb, + tx_caller_address.expr(), + vec![mul_gas_price_by_refund.product().clone()], + None, + ); // Add gas_used * effective_tip to coinbase's balance let coinbase = cb.query_cell(); @@ -104,11 +103,14 @@ impl ExecutionGadget for EndTxGadget { cb.block_lookup(tag.expr(), None, value); } let effective_tip = cb.query_word_rlc(); - let sub_gas_price_by_base_fee = AddWordsGadget::construct( - cb, - [effective_tip.clone(), base_fee.clone()], - tx_gas_price.clone(), - ); + // in anchor, we let tx_gas_price equals to zero + let sub_gas_price_by_base_fee = cb.condition(1.expr() - is_first_tx.expr(), |cb| { + AddWordsGadget::construct( + cb, + [effective_tip.clone(), base_fee.clone()], + tx_gas_price.clone(), + ) + }); let mul_effective_tip_by_gas_used = MulWordByU64Gadget::construct(cb, effective_tip, gas_used.clone()); let mul_base_fee_by_gas_used = @@ -120,37 +122,38 @@ impl ExecutionGadget for EndTxGadget { AddWordsGadget::construct(cb, [tx_gas_tip_cap, base_fee], base_fee_plus_tip.clone()); let effective_gas_price = MinMaxWordGadget::construct(cb, &base_fee_plus_tip, &tx_gas_fee_cap).min(); - cb.require_equal( - "gas_price == min(gas_tip_cap + base_fee, gas_fee_cap)", - tx_gas_price.expr(), - effective_gas_price, - ); + cb.condition(is_first_tx.expr(), |cb| { + cb.require_equal( + "gas_price == 0 when tx is first tx", + tx_gas_price.expr(), + 0.expr(), + ); + }); + cb.condition(1.expr() - is_first_tx.expr(), |cb| { + cb.require_equal( + "gas_price == min(gas_tip_cap + base_fee, gas_fee_cap)", + tx_gas_price.expr(), + effective_gas_price, + ); + }); + // send base fee to treasury account let treasury = cb.query_cell(); - let (gas_fee_refund, coinbase_reward, treasury_reward) = - cb.condition(1.expr() - is_first_tx.expr(), |cb| { - ( - UpdateBalanceGadget::construct( - cb, - tx_caller_address.expr(), - vec![mul_gas_price_by_refund.product().clone()], - None, - ), - UpdateBalanceGadget::construct( - cb, - coinbase.expr(), - vec![mul_effective_tip_by_gas_used.product().clone()], - None, - ), - UpdateBalanceGadget::construct( - cb, - treasury.expr(), - vec![mul_base_fee_by_gas_used.product().clone()], - None, - ), - ) - }); + let coinbase_reward = UpdateBalanceGadget::construct( + cb, + coinbase.expr(), + vec![mul_effective_tip_by_gas_used.product().clone()], + None, + ); + + let treasury_reward = UpdateBalanceGadget::construct( + cb, + treasury.expr(), + vec![mul_base_fee_by_gas_used.product().clone()], + None, + ); + // constrain tx receipt fields cb.tx_receipt_lookup( 1.expr(), @@ -253,7 +256,8 @@ impl ExecutionGadget for EndTxGadget { ) -> Result<(), Error> { let gas_used = tx.gas - step.gas_left.0; let (refund, _) = block.get_rws(step, 2).tx_refund_value_pair(); - + let [(caller_balance, caller_balance_prev), (coinbase_balance, coinbase_balance_prev), (treasury_balance, treasury_balance_prev)] = + [3, 4, 5].map(|index| block.get_rws(step, index).account_value_pair()); self.tx_id .assign(region, offset, Value::known(F::from(tx.id as u64)))?; self.tx_gas @@ -286,7 +290,19 @@ impl ExecutionGadget for EndTxGadget { .expect("unexpected Address -> Scalar conversion failure"), ), )?; - let effective_tip = tx.gas_price - block.context.base_fee; + self.gas_fee_refund.assign( + region, + offset, + caller_balance_prev, + vec![gas_fee_refund], + caller_balance, + )?; + let is_anchor_tx = tx.id == 1; + let effective_tip = if is_anchor_tx { + 0.into() + } else { + tx.gas_price - block.context.base_fee + }; self.sub_gas_price_by_base_fee.assign( region, offset, @@ -306,7 +322,6 @@ impl ExecutionGadget for EndTxGadget { gas_used, effective_tip * gas_used, )?; - self.coinbase.assign( region, offset, @@ -318,6 +333,18 @@ impl ExecutionGadget for EndTxGadget { .expect("unexpected Address -> Scalar conversion failure"), ), )?; + self.coinbase_reward.assign( + region, + offset, + coinbase_balance_prev, + vec![effective_tip * gas_used], + coinbase_balance, + )?; + let treasury_reward = if is_anchor_tx { + 0.into() + } else { + block.context.base_fee * gas_used + }; self.treasury.assign( region, offset, @@ -330,34 +357,13 @@ impl ExecutionGadget for EndTxGadget { .expect("unexpected Address -> Scalar conversion failure"), ), )?; - - if tx.id != 1 { - let [(caller_balance, caller_balance_prev), (coinbase_balance, coinbase_balance_prev), (treasury_balance, treasury_balance_prev)] = - [3, 4, 5].map(|index| block.get_rws(step, index).account_value_pair()); - self.gas_fee_refund.assign( - region, - offset, - caller_balance_prev, - vec![gas_fee_refund], - caller_balance, - )?; - - self.coinbase_reward.assign( - region, - offset, - coinbase_balance_prev, - vec![effective_tip * gas_used], - coinbase_balance, - )?; - - self.treasury_reward.assign( - region, - offset, - treasury_balance_prev, - vec![block.context.base_fee * gas_used], - treasury_balance, - )?; - } + self.treasury_reward.assign( + region, + offset, + treasury_balance_prev, + vec![treasury_reward], + treasury_balance, + )?; let current_cumulative_gas_used: u64 = if tx.id == 1 { 0