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

Commit

Permalink
Feat/CREATE Part C - bus-mapping and gadget implementation (#1430)
Browse files Browse the repository at this point in the history
### Description

NOTE: This is an updated version of
#1358

This PR is actually based on top of
#1425

### Issue Link

#1130 

### Type of change

- [ ] Bug fix (non-breaking change which fixes an issue)
- [x] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to not work as expected)
- [ ] This change requires a documentation update

### Contents

Bus mapping implementation for CREATE/CREATE2
EVM circuit's gadget for CREATE/CREATE2

### How Has This Been Tested?
Tests can be found here:
https://github.com/scroll-tech/zkevm-circuits/blob/2d2bfc6ccf179ade1a8d063f9586b93e5283a557/zkevm-circuits/src/evm_circuit/execution/create.rs#L678

---------

Co-authored-by: Rohit Narurkar <[email protected]>
  • Loading branch information
KimiWu123 and roynalnaruto authored Jun 9, 2023
1 parent 9620822 commit 9ab662b
Show file tree
Hide file tree
Showing 13 changed files with 1,432 additions and 157 deletions.
7 changes: 7 additions & 0 deletions bus-mapping/src/circuit_input_builder/call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,13 @@ pub struct CallContext {
pub return_data: Vec<u8>,
}

impl CallContext {
/// Memory size in words, rounded up
pub fn memory_word_size(&self) -> u64 {
u64::try_from(self.memory.len()).expect("failed to convert usize to u64") / 32
}
}

/// A reversion group is the collection of calls and the operations which are
/// [`Operation::reversible`](crate::operation::Operation::reversible) that
/// happened in them, that will be reverted at once when the call that initiated
Expand Down
61 changes: 60 additions & 1 deletion bus-mapping/src/circuit_input_builder/input_state_ref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,22 @@ impl<'a> CircuitInputStateRef<'a> {
ExecStep {
exec_state: ExecState::EndTx,
gas_left: if prev_step.error.is_none() {
prev_step.gas_left - prev_step.gas_cost
let mut gas_left = prev_step.gas_left - prev_step.gas_cost;

// for contract creation
let call = self.tx.calls()[0].clone();
if call.is_create() {
let code_hash = self.sdb.get_account(&call.address).1.code_hash;
let bytecode_len = self.code(code_hash).unwrap().len() as u64;
let deposit_cost = bytecode_len * GasCost::CODE_DEPOSIT_BYTE_COST;
assert!(
gas_left >= deposit_cost,
"gas left {gas_left} is not enough for deposit cost {deposit_cost}"
);
gas_left -= deposit_cost;
}

gas_left
} else {
// consume all remaining gas when non revert err happens
0
Expand Down Expand Up @@ -461,6 +476,24 @@ impl<'a> CircuitInputStateRef<'a> {
Ok(())
}

/// Add address to access list for the current transaction.
pub fn tx_access_list_write(
&mut self,
step: &mut ExecStep,
address: Address,
) -> Result<(), Error> {
let is_warm = self.sdb.check_account_in_access_list(&address);
self.push_op_reversible(
step,
TxAccessListAccountOp {
tx_id: self.tx_ctx.id(),
address,
is_warm: true,
is_warm_prev: is_warm,
},
)
}

/// Push 2 reversible [`AccountOp`] to update `sender` and `receiver`'s
/// balance by `value`. If `fee` is existing (not None), also need to push 1
/// non-reversible [`AccountOp`] to update `sender` balance by `fee`.
Expand Down Expand Up @@ -688,6 +721,32 @@ impl<'a> CircuitInputStateRef<'a> {
))
}

/// read reversion info
pub(crate) fn reversion_info_read(&mut self, step: &mut ExecStep, call: &Call) {
for (field, value) in [
(
CallContextField::RwCounterEndOfReversion,
call.rw_counter_end_of_reversion.to_word(),
),
(CallContextField::IsPersistent, call.is_persistent.to_word()),
] {
self.call_context_read(step, call.call_id, field, value);
}
}

/// write reversion info
pub(crate) fn reversion_info_write(&mut self, step: &mut ExecStep, call: &Call) {
for (field, value) in [
(
CallContextField::RwCounterEndOfReversion,
call.rw_counter_end_of_reversion.to_word(),
),
(CallContextField::IsPersistent, call.is_persistent.to_word()),
] {
self.call_context_write(step, call.call_id, field, value);
}
}

/// Check if address is a precompiled or not.
pub fn is_precompiled(&self, address: &Address) -> bool {
address.0[0..19] == [0u8; 19] && (1..=9).contains(&address.0[19])
Expand Down
28 changes: 11 additions & 17 deletions bus-mapping/src/evm/opcodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ use callop::CallOpcode;
use callvalue::Callvalue;
use codecopy::Codecopy;
use codesize::Codesize;
use create::DummyCreate;
use create::Create;
use dup::Dup;
use error_invalid_jump::InvalidJump;
use error_oog_call::OOGCall;
Expand Down Expand Up @@ -251,19 +251,13 @@ fn fn_gen_associated_ops(opcode_id: &OpcodeId) -> FnGenAssociatedOps {
OpcodeId::LOG4 => Log::gen_associated_ops,
OpcodeId::CALL | OpcodeId::CALLCODE => CallOpcode::<7>::gen_associated_ops,
OpcodeId::DELEGATECALL | OpcodeId::STATICCALL => CallOpcode::<6>::gen_associated_ops,
OpcodeId::CREATE => Create::<false>::gen_associated_ops,
OpcodeId::CREATE2 => Create::<true>::gen_associated_ops,
OpcodeId::RETURN | OpcodeId::REVERT => ReturnRevert::gen_associated_ops,
OpcodeId::SELFDESTRUCT => {
evm_unimplemented!("Using dummy gen_selfdestruct_ops for opcode SELFDESTRUCT");
DummySelfDestruct::gen_associated_ops
}
OpcodeId::CREATE => {
evm_unimplemented!("Using dummy gen_create_ops for opcode {:?}", opcode_id);
DummyCreate::<false>::gen_associated_ops
}
OpcodeId::CREATE2 => {
evm_unimplemented!("Using dummy gen_create_ops for opcode {:?}", opcode_id);
DummyCreate::<true>::gen_associated_ops
}
_ => {
evm_unimplemented!("Using dummy gen_associated_ops for opcode {:?}", opcode_id);
Dummy::gen_associated_ops
Expand All @@ -289,26 +283,26 @@ fn fn_gen_error_state_associated_ops(error: &ExecError) -> Option<FnGenAssociate
}
// create & create2 can encounter insufficient balance.
ExecError::InsufficientBalance(InsufficientBalanceError::Create) => {
Some(DummyCreate::<false>::gen_associated_ops)
Some(Create::<false>::gen_associated_ops)
}
ExecError::InsufficientBalance(InsufficientBalanceError::Create2) => {
Some(DummyCreate::<true>::gen_associated_ops)
Some(Create::<true>::gen_associated_ops)
}
// only create2 may cause ContractAddressCollision error, so use DummyCreate::<true>.
ExecError::ContractAddressCollision => Some(DummyCreate::<true>::gen_associated_ops),
// only create2 may cause ContractAddressCollision error, so use Create::<true>.
ExecError::ContractAddressCollision => Some(Create::<true>::gen_associated_ops),
// create & create2 can encounter nonce uint overflow.
ExecError::NonceUintOverflow(NonceUintOverflowError::Create) => {
Some(DummyCreate::<false>::gen_associated_ops)
Some(Create::<false>::gen_associated_ops)
}
ExecError::NonceUintOverflow(NonceUintOverflowError::Create2) => {
Some(DummyCreate::<true>::gen_associated_ops)
Some(Create::<true>::gen_associated_ops)
}
ExecError::WriteProtection => Some(ErrorWriteProtection::gen_associated_ops),
ExecError::ReturnDataOutOfBounds => Some(ErrorReturnDataOutOfBound::gen_associated_ops),
// call, callcode, create & create2 can encounter DepthError error,
ExecError::Depth(DepthError::Call) => Some(CallOpcode::<7>::gen_associated_ops),
ExecError::Depth(DepthError::Create) => Some(DummyCreate::<false>::gen_associated_ops),
ExecError::Depth(DepthError::Create2) => Some(DummyCreate::<true>::gen_associated_ops),
ExecError::Depth(DepthError::Create) => Some(Create::<false>::gen_associated_ops),
ExecError::Depth(DepthError::Create2) => Some(Create::<true>::gen_associated_ops),
// more future errors place here
_ => {
evm_unimplemented!("TODO: error state {:?} not implemented", error);
Expand Down
Loading

0 comments on commit 9ab662b

Please sign in to comment.