diff --git a/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs b/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs index 80de4c1973f..f0554c5b1f6 100644 --- a/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs +++ b/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs @@ -5,7 +5,7 @@ use crate::{ step::ExecutionState, util::{ and, - common_gadget::TransferWithGasFeeGadget, + common_gadget::TransferGadget, constraint_builder::{ ConstrainBuilderCommon, EVMConstraintBuilder, ReversionInfo, StepStateTransition, Transition::{Delta, To}, @@ -14,7 +14,7 @@ use crate::{ math_gadget::{ ContractCreateGadget, IsEqualWordGadget, IsZeroWordGadget, RangeCheckGadget, }, - not, or, + not, tx::{BeginTxHelperGadget, TxDataGadget}, AccountAddress, CachedRegion, Cell, StepRws, }, @@ -41,7 +41,7 @@ pub(crate) struct BeginTxGadget { call_callee_address: AccountAddress, reversion_info: ReversionInfo, sufficient_gas_left: RangeCheckGadget, - transfer_with_gas_fee: TransferWithGasFeeGadget, + transfer_with_gas_fee: TransferGadget, code_hash: WordLoHiCell, is_empty_code_hash: IsEqualWordGadget>, WordLoHi>>, caller_nonce_hash_bytes: Word32Cell, @@ -170,17 +170,20 @@ impl ExecutionGadget for BeginTxGadget { AccountFieldTag::CodeHash, code_hash.to_word(), ); - + cb.require_equal( + "is create: callee_not_exists", + tx.is_create.expr(), + callee_not_exists.expr(), + ); // Transfer value from caller to callee, creating account if necessary. - let transfer_with_gas_fee = TransferWithGasFeeGadget::construct( + let transfer_with_gas_fee = TransferGadget::construct( cb, tx.caller_address.to_word(), tx.callee_address.to_word(), not::expr(callee_not_exists.expr()), - or::expr([tx.is_create.expr(), callee_not_exists.expr()]), tx.value.clone(), - tx.mul_gas_fee_by_gas.product().clone(), &mut reversion_info, + Some(tx.mul_gas_fee_by_gas.product().clone()), ); let caller_nonce_hash_bytes = cb.query_word32(); @@ -505,11 +508,14 @@ impl ExecutionGadget for BeginTxGadget { self.transfer_with_gas_fee.assign( region, offset, - caller_balance_sub_fee_pair, + ( + Some(caller_balance_sub_fee_pair.0), + Some(caller_balance_sub_fee_pair.1), + ), caller_balance_sub_value_pair, callee_balance_pair, tx.value, - gas_fee, + Some(gas_fee), )?; self.code_hash .assign_u256(region, offset, callee_code_hash)?; diff --git a/zkevm-circuits/src/evm_circuit/execution/callop.rs b/zkevm-circuits/src/evm_circuit/execution/callop.rs index 8f71f965e48..0a35387ecca 100644 --- a/zkevm-circuits/src/evm_circuit/execution/callop.rs +++ b/zkevm-circuits/src/evm_circuit/execution/callop.rs @@ -60,7 +60,7 @@ pub(crate) struct CallOpGadget { is_warm: Cell, is_warm_prev: Cell, callee_reversion_info: ReversionInfo, - transfer: TransferGadget, + transfer: TransferGadget, // current handling Call* opcode's caller balance caller_balance: WordLoHi>, // check if insufficient balance case @@ -242,9 +242,9 @@ impl ExecutionGadget for CallOpGadget { caller_address.to_word(), callee_address.to_word(), not::expr(call_gadget.callee_not_exists.expr()), - false, call_gadget.value.clone(), &mut callee_reversion_info, + None, ) }); // rwc_delta = 8 + is_delegatecall * 2 + call_gadget.rw_delta() + @@ -876,9 +876,11 @@ impl ExecutionGadget for CallOpGadget { self.transfer.assign( region, offset, + (None, None), caller_balance_pair, callee_balance_pair, value, + None, )?; } diff --git a/zkevm-circuits/src/evm_circuit/execution/create.rs b/zkevm-circuits/src/evm_circuit/execution/create.rs index b7df77aaa88..b351f4bfee0 100644 --- a/zkevm-circuits/src/evm_circuit/execution/create.rs +++ b/zkevm-circuits/src/evm_circuit/execution/create.rs @@ -63,7 +63,7 @@ pub(crate) struct CreateGadget, prev_code_hash: WordLoHiCell, prev_code_hash_is_zero: IsZeroWordGadget>>, - transfer: TransferGadget, + transfer: TransferGadget, create: ContractCreateGadget, init_code: MemoryAddressGadget, @@ -334,9 +334,9 @@ impl ExecutionGadget< create.caller_address(), contract_addr.to_word(), 0.expr(), - true, value.clone(), &mut callee_reversion_info, + None, ); // EIP 161, the nonce of a newly created contract is 1 @@ -650,9 +650,11 @@ impl ExecutionGadget< self.transfer.assign( region, offset, + (None, None), caller_balance_pair, callee_balance_pair, value, + None, )?; } diff --git a/zkevm-circuits/src/evm_circuit/execution/end_tx.rs b/zkevm-circuits/src/evm_circuit/execution/end_tx.rs index 4ebe758a314..5996da5758a 100644 --- a/zkevm-circuits/src/evm_circuit/execution/end_tx.rs +++ b/zkevm-circuits/src/evm_circuit/execution/end_tx.rs @@ -107,7 +107,6 @@ impl ExecutionGadget for EndTxGadget { cb, coinbase.to_word(), 1.expr() - coinbase_code_hash_is_zero.expr(), - false.expr(), mul_effective_tip_by_gas_used.product().clone(), None, ); diff --git a/zkevm-circuits/src/evm_circuit/util/common_gadget.rs b/zkevm-circuits/src/evm_circuit/util/common_gadget.rs index f8e11ef9e86..c1450424350 100644 --- a/zkevm-circuits/src/evm_circuit/util/common_gadget.rs +++ b/zkevm-circuits/src/evm_circuit/util/common_gadget.rs @@ -17,7 +17,7 @@ use crate::{ Transition::{Delta, Same, To}, }, math_gadget::{AddWordsGadget, RangeCheckGadget}, - not, or, Cell, + not, Cell, }, }, table::{AccountFieldTag, CallContextFieldTag}, @@ -370,7 +370,6 @@ impl pub(crate) struct TransferToGadget { receiver: UpdateBalanceGadget, receiver_exists: Expression, - must_create: Expression, value_is_zero: IsZeroWordGadget>, } @@ -380,16 +379,16 @@ impl TransferToGadget { cb: &mut EVMConstraintBuilder, receiver_address: WordLoHi>, receiver_exists: Expression, - must_create: Expression, value: Word32Cell, mut reversion_info: Option<&mut ReversionInfo>, ) -> Self { let value_is_zero = cb.is_zero_word(&value); + // Create account cb.condition( and::expr([ not::expr(receiver_exists.expr()), - or::expr([not::expr(value_is_zero.expr()), must_create.clone()]), + not::expr(value_is_zero.expr()), ]), |cb| { cb.account_write( @@ -409,7 +408,6 @@ impl TransferToGadget { Self { receiver, receiver_exists, - must_create, value_is_zero, } } @@ -436,8 +434,7 @@ impl TransferToGadget { pub(crate) fn rw_delta(&self) -> Expression { // +1 Write Account (receiver) CodeHash (account creation via code_hash update) and::expr([ - not::expr(self.receiver_exists.expr()), - or::expr([not::expr(self.value_is_zero.expr()), self.must_create.clone()]), + not::expr(self.receiver_exists.expr()),not::expr(self.value_is_zero.expr()) ]) + // +1 Write Account (receiver) Balance not::expr(self.value_is_zero.expr()) @@ -452,26 +449,29 @@ impl TransferToGadget { /// setting it's code_hash = EMPTY_HASH. The receiver account is also created /// unconditionally if must_create is true. This gadget is used in BeginTx. #[derive(Clone, Debug)] -pub(crate) struct TransferWithGasFeeGadget { - sender_sub_fee: UpdateBalanceGadget, +pub(crate) struct TransferGadget { + sender_sub_fee: Option>, sender_sub_value: UpdateBalanceGadget, receiver: TransferToGadget, - value_is_zero: IsZeroWordGadget>, + pub(crate) value_is_zero: IsZeroWordGadget>, } -impl TransferWithGasFeeGadget { +impl TransferGadget { #[allow(clippy::too_many_arguments)] pub(crate) fn construct( cb: &mut EVMConstraintBuilder, sender_address: WordLoHi>, receiver_address: WordLoHi>, receiver_exists: Expression, - must_create: Expression, value: Word32Cell, - gas_fee: Word32Cell, reversion_info: &mut ReversionInfo, + gas_fee: Option>, ) -> Self { - let sender_sub_fee = cb.decrease_balance(sender_address.to_word(), gas_fee, None); + let sender_sub_fee = if WITH_FEE { + Some(cb.decrease_balance(sender_address.to_word(), gas_fee.expect("fee exists"), None)) + } else { + None + }; let value_is_zero = cb.is_zero_word(&value); // Skip transfer if value == 0 let sender_sub_value = cb.condition(not::expr(value_is_zero.expr()), |cb| { @@ -481,7 +481,6 @@ impl TransferWithGasFeeGadget { cb, receiver_address, receiver_exists, - must_create, value, Some(reversion_info), ); @@ -496,12 +495,9 @@ impl TransferWithGasFeeGadget { pub(crate) fn rw_delta(&self) -> Expression { // +1 Write Account (sender) Balance (Not Reversible tx fee) - 1.expr() + + WITH_FEE.expr() + // +1 Write Account (receiver) CodeHash (account creation via code_hash update) - and::expr([not::expr(self.receiver.receiver_exists.expr()), or::expr([ - not::expr(self.value_is_zero.expr()), - self.receiver.must_create.clone()] - )]) * 1.expr() + + self.receiver.rw_delta()+ // +1 Write Account (sender) Balance // +1 Write Account (receiver) Balance not::expr(self.value_is_zero.expr()) * 2.expr() @@ -510,10 +506,7 @@ impl TransferWithGasFeeGadget { pub(crate) fn reversible_w_delta(&self) -> Expression { // NOTE: Write Account (sender) Balance (Not Reversible tx fee) // +1 Write Account (receiver) CodeHash (account creation via code_hash update) - and::expr([not::expr(self.receiver.receiver_exists.expr()), or::expr([ - not::expr(self.value_is_zero.expr()), - self.receiver.must_create.clone()] - )]) + + self.receiver.rw_delta()+ // +1 Write Account (sender) Balance // +1 Write Account (receiver) Balance not::expr(self.value_is_zero.expr()) * 2.expr() @@ -524,19 +517,21 @@ impl TransferWithGasFeeGadget { &self, region: &mut CachedRegion<'_, '_, F>, offset: usize, - (sender_balance_sub_fee, prev_sender_balance_sub_fee): (U256, U256), + (sender_balance_sub_fee, prev_sender_balance_sub_fee): (Option, Option), (sender_balance_sub_value, prev_sender_balance_sub_value): (U256, U256), (receiver_balance, prev_receiver_balance): (U256, U256), value: U256, - gas_fee: U256, + gas_fee: Option, ) -> Result<(), Error> { - self.sender_sub_fee.assign( - region, - offset, - prev_sender_balance_sub_fee, - vec![gas_fee], - sender_balance_sub_fee, - )?; + if WITH_FEE { + self.sender_sub_fee.as_ref().expect("Exists").assign( + region, + offset, + prev_sender_balance_sub_fee.expect("exists"), + vec![gas_fee.expect("exists")], + sender_balance_sub_fee.expect("exists"), + )?; + } self.sender_sub_value.assign( region, offset, @@ -556,91 +551,6 @@ impl TransferWithGasFeeGadget { } } -/// The TransferGadget handles a transfer of value from sender to receiver. The -/// transfer is only performed if the value is not zero. If the transfer is -/// performed and the receiver account doesn't exist, it will be created by -/// setting it's code_hash = EMPTY_HASH. This gadget is used in callop. -#[derive(Clone, Debug)] -pub(crate) struct TransferGadget { - sender: UpdateBalanceGadget, - receiver: TransferToGadget, - pub(crate) value_is_zero: IsZeroWordGadget>, -} - -impl TransferGadget { - pub(crate) fn construct( - cb: &mut EVMConstraintBuilder, - sender_address: WordLoHi>, - receiver_address: WordLoHi>, - receiver_exists: Expression, - must_create: bool, - value: Word32Cell, - reversion_info: &mut ReversionInfo, - ) -> Self { - let value_is_zero = cb.is_zero_word(&value); - // Skip transfer if value == 0 - let sender = cb.condition(not::expr(value_is_zero.expr()), |cb| { - cb.decrease_balance(sender_address, value.clone(), Some(reversion_info)) - }); - let receiver = TransferToGadget::construct( - cb, - receiver_address, - receiver_exists, - must_create.expr(), - value, - Some(reversion_info), - ); - - Self { - sender, - receiver, - value_is_zero, - } - } - - pub(crate) fn reversible_w_delta(&self) -> Expression { - // +1 Write Account (receiver) CodeHash (account creation via code_hash update) - or::expr([ - not::expr(self.value_is_zero.expr()) * not::expr(self.receiver.receiver_exists.clone()), - self.receiver.must_create.clone()] - ) * 1.expr() + - // +1 Write Account (sender) Balance - // +1 Write Account (receiver) Balance - not::expr(self.value_is_zero.expr()) * 2.expr() - } - - pub(crate) fn assign( - &self, - region: &mut CachedRegion<'_, '_, F>, - offset: usize, - (sender_balance, sender_balance_prev): (U256, U256), - (receiver_balance, receiver_balance_prev): (U256, U256), - value: U256, - ) -> Result<(), Error> { - self.sender.assign( - region, - offset, - sender_balance_prev, - vec![value], - sender_balance, - )?; - self.receiver.assign( - region, - offset, - (receiver_balance, receiver_balance_prev), - value, - )?; - self.value_is_zero - .assign_value(region, offset, Value::known(WordLoHi::from(value)))?; - Ok(()) - } - - pub(crate) fn rw_delta(&self) -> Expression { - // +1 Write Account (sender) Balance - not::expr(self.value_is_zero.expr()) + self.receiver.rw_delta() - } -} - #[derive(Clone, Debug)] pub(crate) struct CommonCallGadget { pub is_success: Cell,