Skip to content
This repository was archived by the owner on Apr 18, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion bus-mapping/src/evm/opcodes/create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ impl<const IS_CREATE2: bool> Opcode for Create<IS_CREATE2> {

let callee_account = &state.sdb.get_account(&address).1.clone();
let callee_exists = !callee_account.is_empty();
let is_address_collision = callee_account.code_hash != CodeDB::empty_code_hash();
let is_address_collision = callee_account.code_hash != CodeDB::empty_code_hash()
|| callee_account.nonce > Word::zero();
if !callee_exists && callee.value.is_zero() {
state.sdb.get_account_mut(&address).1.storage.clear();
}
Expand Down Expand Up @@ -199,6 +200,16 @@ impl<const IS_CREATE2: bool> Opcode for Create<IS_CREATE2> {
code_hash_previous.to_word(),
);

// read callee nonce for address collision checking
if !code_hash_previous.is_zero() {
state.account_read(
&mut exec_step,
address,
AccountField::Nonce,
callee_account.nonce,
);
}

if is_precheck_ok && !is_address_collision {
state.transfer(
&mut exec_step,
Expand Down Expand Up @@ -242,6 +253,7 @@ impl<const IS_CREATE2: bool> Opcode for Create<IS_CREATE2> {
state.call_context_write(&mut exec_step, caller.call_id, field, value);
}

// precheck failed
if !is_precheck_ok {
for (field, value) in [
(CallContextField::LastCalleeId, callee.call_id.into()),
Expand Down
41 changes: 37 additions & 4 deletions zkevm-circuits/src/evm_circuit/execution/create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ pub(crate) struct CreateGadget<F, const IS_CREATE2: bool, const S: ExecutionStat
is_depth_in_range: LtGadget<F, N_BYTES_U64>,
is_insufficient_balance: LtWordGadget<F>,
is_nonce_in_range: LtGadget<F, N_BYTES_U64>,
// check address collision use
callee_nonce: Cell<F>,
callee_nonce_is_zero: IsZeroGadget<F>,
keccak_code_hash: Cell<F>,
keccak_output: Word<F>,
// prevous code hash befor creating
Expand All @@ -85,6 +88,8 @@ impl<F: Field, const IS_CREATE2: bool, const S: ExecutionState> ExecutionGadget<
// Use rw_counter of the step which triggers next call as its call_id.
let callee_call_id = cb.curr.state.rw_counter.clone();
let code_hash_previous = cb.query_cell();
let callee_nonce = cb.query_cell();

#[cfg(feature = "scroll")]
let keccak_code_hash_previous = cb.query_cell_phase2();
let opcode = cb.query_cell();
Expand Down Expand Up @@ -217,6 +222,7 @@ impl<F: Field, const IS_CREATE2: bool, const S: ExecutionState> ExecutionGadget<
AccountFieldTag::Nonce,
caller_nonce.expr(),
);

let is_nonce_in_range = LtGadget::construct(cb, caller_nonce.expr(), u64::MAX.expr());

cb.condition(is_insufficient_balance.expr(), |cb| {
Expand Down Expand Up @@ -285,11 +291,23 @@ impl<F: Field, const IS_CREATE2: bool, const S: ExecutionState> ExecutionGadget<
AccountFieldTag::CodeHash,
code_hash_previous.expr(),
);

// callee address's nonce
let code_hash_is_zero = IsZeroGadget::construct(cb, code_hash_previous.expr());
cb.condition(not::expr(code_hash_is_zero.expr()), |cb| {
cb.account_read(
new_address.clone(),
AccountFieldTag::Nonce,
callee_nonce.expr(),
);
});

let code_hash_is_empty =
IsEqualGadget::construct(cb, code_hash_previous.expr(), cb.empty_code_hash_rlc());
let not_address_collision = code_hash_is_zero.expr() + code_hash_is_empty.expr();
let callee_nonce_is_zero = IsZeroGadget::construct(cb, callee_nonce.expr());
let not_address_collision = and::expr([
code_hash_is_zero.expr() + code_hash_is_empty.expr(),
callee_nonce_is_zero.expr(),
]);
/*
// CREATE2 may cause address collision error. And for a tricky
// case of CREATE, it could also cause this error. e.g. the `to`
Expand Down Expand Up @@ -527,6 +545,8 @@ impl<F: Field, const IS_CREATE2: bool, const S: ExecutionState> ExecutionGadget<
is_depth_in_range,
is_insufficient_balance,
is_nonce_in_range,
callee_nonce,
callee_nonce_is_zero,
keccak_code_hash,
keccak_output,
code_hash_previous,
Expand Down Expand Up @@ -648,6 +668,12 @@ impl<F: Field, const IS_CREATE2: bool, const S: ExecutionState> ExecutionGadget<

// retrieve code_hash for creating address
let code_hash_previous = rws.next().account_codehash_pair();
let callee_nonce = if !code_hash_previous.0.is_zero() {
rws.next().account_nonce_pair().1.low_u64()
} else {
0
};

let code_hash_previous_rlc = region.code_hash(code_hash_previous.0);
self.code_hash_previous
.assign(region, offset, code_hash_previous_rlc)?;
Expand All @@ -659,9 +685,16 @@ impl<F: Field, const IS_CREATE2: bool, const S: ExecutionState> ExecutionGadget<
code_hash_previous_rlc,
region.empty_code_hash_rlc(),
)?;
let is_address_collision = !code_hash_previous.0.is_zero()
&& code_hash_previous.0 != CodeDB::empty_code_hash().to_word();

self.callee_nonce
.assign(region, offset, Value::known(F::from(callee_nonce)))?;
self.callee_nonce_is_zero
.assign(region, offset, F::from(callee_nonce))?;

let callee_nonce_is_zero = callee_nonce == 0;
let codehash_non_empty = !code_hash_previous.0.is_zero()
&& code_hash_previous.0 != CodeDB::empty_code_hash().to_word();
let is_address_collision = !callee_nonce_is_zero || codehash_non_empty;
if is_precheck_ok && !is_address_collision {
/*
rws:
Expand Down