Skip to content
This repository has been archived by the owner on Jul 5, 2024. It is now read-only.

Commit

Permalink
merge transfer gadgets ugly
Browse files Browse the repository at this point in the history
  • Loading branch information
ChihChengLiang committed Feb 22, 2024
1 parent 39b2ead commit 8d4d596
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 132 deletions.
24 changes: 15 additions & 9 deletions zkevm-circuits/src/evm_circuit/execution/begin_tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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},
Expand All @@ -14,7 +14,7 @@ use crate::{
math_gadget::{
ContractCreateGadget, IsEqualWordGadget, IsZeroWordGadget, RangeCheckGadget,
},
not, or,
not,
tx::{BeginTxHelperGadget, TxDataGadget},
AccountAddress, CachedRegion, Cell, StepRws,
},
Expand All @@ -41,7 +41,7 @@ pub(crate) struct BeginTxGadget<F> {
call_callee_address: AccountAddress<F>,
reversion_info: ReversionInfo<F>,
sufficient_gas_left: RangeCheckGadget<F, N_BYTES_GAS>,
transfer_with_gas_fee: TransferWithGasFeeGadget<F>,
transfer_with_gas_fee: TransferGadget<F, true>,
code_hash: WordLoHiCell<F>,
is_empty_code_hash: IsEqualWordGadget<F, WordLoHi<Expression<F>>, WordLoHi<Expression<F>>>,
caller_nonce_hash_bytes: Word32Cell<F>,
Expand Down Expand Up @@ -170,17 +170,20 @@ impl<F: Field> ExecutionGadget<F> for BeginTxGadget<F> {
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();
Expand Down Expand Up @@ -505,11 +508,14 @@ impl<F: Field> ExecutionGadget<F> for BeginTxGadget<F> {
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)?;
Expand Down
6 changes: 4 additions & 2 deletions zkevm-circuits/src/evm_circuit/execution/callop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ pub(crate) struct CallOpGadget<F> {
is_warm: Cell<F>,
is_warm_prev: Cell<F>,
callee_reversion_info: ReversionInfo<F>,
transfer: TransferGadget<F>,
transfer: TransferGadget<F, false>,
// current handling Call* opcode's caller balance
caller_balance: WordLoHi<Cell<F>>,
// check if insufficient balance case
Expand Down Expand Up @@ -242,9 +242,9 @@ impl<F: Field> ExecutionGadget<F> for CallOpGadget<F> {
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() +
Expand Down Expand Up @@ -876,9 +876,11 @@ impl<F: Field> ExecutionGadget<F> for CallOpGadget<F> {
self.transfer.assign(
region,
offset,
(None, None),
caller_balance_pair,
callee_balance_pair,
value,
None,
)?;
}

Expand Down
6 changes: 4 additions & 2 deletions zkevm-circuits/src/evm_circuit/execution/create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ pub(crate) struct CreateGadget<F, const IS_CREATE2: bool, const S: ExecutionStat
callee_nonce: Cell<F>,
prev_code_hash: WordLoHiCell<F>,
prev_code_hash_is_zero: IsZeroWordGadget<F, WordLoHi<Expression<F>>>,
transfer: TransferGadget<F>,
transfer: TransferGadget<F, false>,
create: ContractCreateGadget<F, IS_CREATE2>,

init_code: MemoryAddressGadget<F>,
Expand Down Expand Up @@ -334,9 +334,9 @@ impl<F: Field, const IS_CREATE2: bool, const S: ExecutionState> 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
Expand Down Expand Up @@ -650,9 +650,11 @@ impl<F: Field, const IS_CREATE2: bool, const S: ExecutionState> ExecutionGadget<
self.transfer.assign(
region,
offset,
(None, None),
caller_balance_pair,
callee_balance_pair,
value,
None,
)?;
}

Expand Down
1 change: 0 additions & 1 deletion zkevm-circuits/src/evm_circuit/execution/end_tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,6 @@ impl<F: Field> ExecutionGadget<F> for EndTxGadget<F> {
cb,
coinbase.to_word(),
1.expr() - coinbase_code_hash_is_zero.expr(),
false.expr(),
mul_effective_tip_by_gas_used.product().clone(),
None,
);
Expand Down
146 changes: 28 additions & 118 deletions zkevm-circuits/src/evm_circuit/util/common_gadget.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use crate::{
Transition::{Delta, Same, To},
},
math_gadget::{AddWordsGadget, RangeCheckGadget},
not, or, Cell,
not, Cell,
},
},
table::{AccountFieldTag, CallContextFieldTag},
Expand Down Expand Up @@ -370,7 +370,6 @@ impl<F: Field, const N_ADDENDS: usize, const INCREASE: bool>
pub(crate) struct TransferToGadget<F> {
receiver: UpdateBalanceGadget<F, 2, true>,
receiver_exists: Expression<F>,
must_create: Expression<F>,
value_is_zero: IsZeroWordGadget<F, Word32Cell<F>>,
}

Expand All @@ -380,16 +379,16 @@ impl<F: Field> TransferToGadget<F> {
cb: &mut EVMConstraintBuilder<F>,
receiver_address: WordLoHi<Expression<F>>,
receiver_exists: Expression<F>,
must_create: Expression<F>,
value: Word32Cell<F>,
mut reversion_info: Option<&mut ReversionInfo<F>>,
) -> 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(
Expand All @@ -409,7 +408,6 @@ impl<F: Field> TransferToGadget<F> {
Self {
receiver,
receiver_exists,
must_create,
value_is_zero,
}
}
Expand All @@ -436,8 +434,7 @@ impl<F: Field> TransferToGadget<F> {
pub(crate) fn rw_delta(&self) -> Expression<F> {
// +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())
Expand All @@ -452,26 +449,29 @@ impl<F: Field> TransferToGadget<F> {
/// 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<F> {
sender_sub_fee: UpdateBalanceGadget<F, 2, false>,
pub(crate) struct TransferGadget<F, const WITH_FEE: bool> {
sender_sub_fee: Option<UpdateBalanceGadget<F, 2, false>>,
sender_sub_value: UpdateBalanceGadget<F, 2, false>,
receiver: TransferToGadget<F>,
value_is_zero: IsZeroWordGadget<F, Word32Cell<F>>,
pub(crate) value_is_zero: IsZeroWordGadget<F, Word32Cell<F>>,
}

impl<F: Field> TransferWithGasFeeGadget<F> {
impl<F: Field, const WITH_FEE: bool> TransferGadget<F, WITH_FEE> {
#[allow(clippy::too_many_arguments)]
pub(crate) fn construct(
cb: &mut EVMConstraintBuilder<F>,
sender_address: WordLoHi<Expression<F>>,
receiver_address: WordLoHi<Expression<F>>,
receiver_exists: Expression<F>,
must_create: Expression<F>,
value: Word32Cell<F>,
gas_fee: Word32Cell<F>,
reversion_info: &mut ReversionInfo<F>,
gas_fee: Option<Word32Cell<F>>,
) -> 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| {
Expand All @@ -481,7 +481,6 @@ impl<F: Field> TransferWithGasFeeGadget<F> {
cb,
receiver_address,
receiver_exists,
must_create,
value,
Some(reversion_info),
);
Expand All @@ -496,12 +495,9 @@ impl<F: Field> TransferWithGasFeeGadget<F> {

pub(crate) fn rw_delta(&self) -> Expression<F> {
// +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()
Expand All @@ -510,10 +506,7 @@ impl<F: Field> TransferWithGasFeeGadget<F> {
pub(crate) fn reversible_w_delta(&self) -> Expression<F> {
// 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()
Expand All @@ -524,19 +517,21 @@ impl<F: Field> TransferWithGasFeeGadget<F> {
&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<U256>, Option<U256>),
(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<U256>,
) -> 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,
Expand All @@ -556,91 +551,6 @@ impl<F: Field> TransferWithGasFeeGadget<F> {
}
}

/// 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<F> {
sender: UpdateBalanceGadget<F, 2, false>,
receiver: TransferToGadget<F>,
pub(crate) value_is_zero: IsZeroWordGadget<F, Word32Cell<F>>,
}

impl<F: Field> TransferGadget<F> {
pub(crate) fn construct(
cb: &mut EVMConstraintBuilder<F>,
sender_address: WordLoHi<Expression<F>>,
receiver_address: WordLoHi<Expression<F>>,
receiver_exists: Expression<F>,
must_create: bool,
value: Word32Cell<F>,
reversion_info: &mut ReversionInfo<F>,
) -> 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<F> {
// +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<F> {
// +1 Write Account (sender) Balance
not::expr(self.value_is_zero.expr()) + self.receiver.rw_delta()
}
}

#[derive(Clone, Debug)]
pub(crate) struct CommonCallGadget<F, MemAddrGadget, const IS_SUCCESS_CALL: bool> {
pub is_success: Cell<F>,
Expand Down

0 comments on commit 8d4d596

Please sign in to comment.