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

Commit 3733326

Browse files
circuit for invalid creation code (#1292)
### Description circuit for invalid creation code error in create, markdown spec privacy-scaling-explorations/zkevm-specs#400 ### Issue Link issue #1291 ### Type of change - [x] New feature (non-breaking change which adds functionality) ### Rationale Get first byte of code to store , check it is 0xef This PR contains: - buss mapping: at the return opcode in create, get the first byte . - add circuit & test - add tx deploy trace test . --------- Co-authored-by: Steven Gu <[email protected]>
1 parent a884ae0 commit 3733326

File tree

11 files changed

+446
-53
lines changed

11 files changed

+446
-53
lines changed

bus-mapping/src/circuit_input_builder/input_state_ref.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1064,9 +1064,10 @@ impl<'a> CircuitInputStateRef<'a> {
10641064
let geth_step = steps
10651065
.get(0)
10661066
.ok_or(Error::InternalError("invalid index 0"))?;
1067-
let is_return_revert = geth_step.op == OpcodeId::REVERT || geth_step.op == OpcodeId::RETURN;
1067+
let is_revert_or_return_call_success = geth_step.op == OpcodeId::REVERT
1068+
|| geth_step.op == OpcodeId::RETURN && exec_step.error.is_none();
10681069

1069-
if !is_return_revert && !call.is_success {
1070+
if !is_revert_or_return_call_success && !call.is_success {
10701071
// add call failure ops for exception cases
10711072
self.call_context_read(
10721073
exec_step,
@@ -1138,7 +1139,7 @@ impl<'a> CircuitInputStateRef<'a> {
11381139
};
11391140
let gas_refund = geth_step.gas - memory_expansion_gas_cost - code_deposit_cost;
11401141

1141-
let caller_gas_left = if is_return_revert || call.is_success {
1142+
let caller_gas_left = if is_revert_or_return_call_success || call.is_success {
11421143
geth_step_next.gas - gas_refund
11431144
} else {
11441145
geth_step_next.gas

bus-mapping/src/circuit_input_builder/tracer_tests.rs

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use crate::{
1010
};
1111
use eth_types::{
1212
address, bytecode,
13-
evm_types::{stack::Stack, OpcodeId},
13+
evm_types::{stack::Stack, OpcodeId, INVALID_INIT_CODE_FIRST_BYTE},
1414
geth_types::GethData,
1515
word, Bytecode, Hash, ToAddress, ToWord, Word,
1616
};
@@ -742,11 +742,11 @@ fn check_err_invalid_code(step: &GethExecStep, next_step: Option<&GethExecStep>)
742742
&& result(next_step).is_zero()
743743
&& length > Word::zero()
744744
&& !step.memory.is_empty()
745-
&& step.memory.0.get(offset.low_u64() as usize) == Some(&0xef)
745+
&& step.memory.0.get(offset.low_u64() as usize) == Some(&INVALID_INIT_CODE_FIRST_BYTE)
746746
}
747747

748748
#[test]
749-
fn tracer_err_invalid_code() {
749+
fn tracer_err_invalid_code_for_create_opcode() {
750750
// code_creator outputs byte array that starts with 0xef, which is
751751
// invalid code.
752752
let code_creator = bytecode! {
@@ -833,6 +833,61 @@ fn tracer_err_invalid_code() {
833833
);
834834
}
835835

836+
// Test ErrInvalidCode in transaction deployment (`tx.to == null`).
837+
#[test]
838+
fn tracer_err_invalid_code_for_tx_deployment() {
839+
// Code creator outputs a byte array that starts with 0xef, which is the
840+
// invalid code.
841+
let code_creator = bytecode! {
842+
PUSH32(word!("0xef00000000000000000000000000000000000000000000000000000000000000")) // value
843+
PUSH1(0x00) // offset
844+
MSTORE
845+
PUSH1(0x01) // length
846+
PUSH1(0x00) // offset
847+
RETURN
848+
};
849+
850+
// Get the execution steps from external tracer.
851+
let block: GethData = TestContext::<2, 1>::new_with_logger_config(
852+
None,
853+
|accs| {
854+
accs[0].address(address!("0x0000000000000000000000000000000000000000"));
855+
accs[1].address(*ADDR_B).balance(Word::from(1u64 << 30));
856+
},
857+
|mut txs, accs| {
858+
txs[0]
859+
.from(accs[1].address)
860+
.gas(60000u64.into())
861+
.input(code_creator.into());
862+
},
863+
|block, _tx| block.number(0x0264),
864+
LoggerConfig::enable_memory(),
865+
)
866+
.unwrap()
867+
.into();
868+
869+
// Get last RETURN.
870+
let (index, step) = block.geth_traces[0]
871+
.struct_logs
872+
.iter()
873+
.enumerate()
874+
.rev()
875+
.find(|(_, s)| s.op == OpcodeId::RETURN)
876+
.unwrap();
877+
let next_step = block.geth_traces[0].struct_logs.get(index + 1);
878+
assert!(check_err_invalid_code(step, next_step));
879+
880+
// Setup call context at RETURN.
881+
let mut builder = CircuitInputBuilderTx::new(&block, step);
882+
builder.tx_ctx.call_is_success.push(false);
883+
builder.state_ref().push_call(mock_root_create());
884+
builder.state_ref().call_ctx_mut().unwrap().memory = step.memory.clone();
885+
assert_eq!(
886+
builder.state_ref().get_step_err(step, next_step).unwrap(),
887+
Some(ExecError::InvalidCreationCode)
888+
);
889+
}
890+
836891
fn check_err_max_code_size_exceeded(step: &GethExecStep, next_step: Option<&GethExecStep>) -> bool {
837892
let length = step.stack.nth_last(1).unwrap();
838893
step.op == OpcodeId::RETURN

bus-mapping/src/evm/opcodes.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ mod stackonlyop;
4444
mod stop;
4545
mod swap;
4646

47+
mod error_invalid_creation_code;
4748
mod error_invalid_jump;
4849
mod error_oog_call;
4950
mod error_oog_exp;
@@ -71,6 +72,7 @@ use codecopy::Codecopy;
7172
use codesize::Codesize;
7273
use create::Create;
7374
use dup::Dup;
75+
use error_invalid_creation_code::ErrorCreationCode;
7476
use error_invalid_jump::InvalidJump;
7577
use error_oog_call::OOGCall;
7678
use error_oog_exp::OOGExp;
@@ -297,6 +299,7 @@ fn fn_gen_error_state_associated_ops(error: &ExecError) -> Option<FnGenAssociate
297299
}
298300
ExecError::WriteProtection => Some(ErrorWriteProtection::gen_associated_ops),
299301
ExecError::ReturnDataOutOfBounds => Some(ErrorReturnDataOutOfBound::gen_associated_ops),
302+
ExecError::InvalidCreationCode => Some(ErrorCreationCode::gen_associated_ops),
300303
// call, callcode, create & create2 can encounter DepthError error,
301304
ExecError::Depth(DepthError::Call) => Some(CallOpcode::<7>::gen_associated_ops),
302305
ExecError::Depth(DepthError::Create) => Some(Create::<false>::gen_associated_ops),
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
use crate::{
2+
circuit_input_builder::{CircuitInputStateRef, ExecStep},
3+
error::ExecError,
4+
evm::Opcode,
5+
Error,
6+
};
7+
use eth_types::{evm_types::INVALID_INIT_CODE_FIRST_BYTE, GethExecStep};
8+
9+
#[derive(Clone, Copy, Debug)]
10+
pub struct ErrorCreationCode;
11+
12+
impl Opcode for ErrorCreationCode {
13+
fn gen_associated_ops(
14+
state: &mut CircuitInputStateRef,
15+
geth_steps: &[GethExecStep],
16+
) -> Result<Vec<ExecStep>, Error> {
17+
let geth_step = &geth_steps[0];
18+
let mut exec_step = state.new_step(geth_step)?;
19+
exec_step.error = Some(ExecError::InvalidCreationCode);
20+
21+
let offset = geth_step.stack.nth_last(0)?;
22+
let length = geth_step.stack.nth_last(1)?;
23+
state.stack_read(&mut exec_step, geth_step.stack.nth_last_filled(0), offset)?;
24+
state.stack_read(&mut exec_step, geth_step.stack.nth_last_filled(1), length)?;
25+
26+
let call = state.call()?;
27+
assert!(call.is_create() && !length.is_zero());
28+
29+
// Read the first byte of init code and check it must be 0xef for this error.
30+
let init_code_first_byte = state.call_ctx()?.memory.0[offset.as_usize()];
31+
state.memory_read(&mut exec_step, offset.try_into()?, init_code_first_byte)?;
32+
assert_eq!(init_code_first_byte, INVALID_INIT_CODE_FIRST_BYTE);
33+
34+
state.handle_return(&mut exec_step, geth_steps, true)?;
35+
Ok(vec![exec_step])
36+
}
37+
}

bus-mapping/src/evm/opcodes/return_revert.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::{
66
state_db::CodeDB,
77
Error,
88
};
9-
use eth_types::{Bytecode, GethExecStep, ToWord, H256};
9+
use eth_types::{evm_types::INVALID_INIT_CODE_FIRST_BYTE, Bytecode, GethExecStep, ToWord, H256};
1010

1111
#[derive(Debug, Copy, Clone)]
1212
pub(crate) struct ReturnRevert;
@@ -47,6 +47,11 @@ impl Opcode for ReturnRevert {
4747

4848
// Case A in the spec.
4949
if call.is_create() && call.is_success && length > 0 {
50+
// Read the first byte of init code and check it must not be 0xef (EIP-3541).
51+
let init_code_first_byte = state.call_ctx()?.memory.0[offset];
52+
state.memory_read(&mut exec_step, offset.into(), init_code_first_byte)?;
53+
assert_ne!(init_code_first_byte, INVALID_INIT_CODE_FIRST_BYTE);
54+
5055
// Note: handle_return updates state.code_db. All we need to do here is push the
5156
// copy event.
5257
let code_hash = handle_create(

eth-types/src/evm_types.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ pub use opcode_ids::OpcodeId;
1414
pub use stack::{Stack, StackAddress};
1515
pub use storage::Storage;
1616

17+
/// According to EIP-3541, disallow new code starting with 0xEF to be deployed.
18+
pub const INVALID_INIT_CODE_FIRST_BYTE: u8 = 0xef;
1719
/// Once per word of the init code when creating a contract.
1820
pub const INIT_CODE_WORD_GAS: u64 = 2;
1921
/// Quotient for max refund of gas used

zkevm-circuits/src/evm_circuit/execution.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ mod dummy;
6767
mod dup;
6868
mod end_block;
6969
mod end_tx;
70+
mod error_invalid_creation_code;
7071
mod error_invalid_jump;
7172
mod error_invalid_opcode;
7273
mod error_oog_call;
@@ -139,6 +140,7 @@ use dummy::DummyGadget;
139140
use dup::DupGadget;
140141
use end_block::EndBlockGadget;
141142
use end_tx::EndTxGadget;
143+
use error_invalid_creation_code::ErrorInvalidCreationCodeGadget;
142144
use error_invalid_jump::ErrorInvalidJumpGadget;
143145
use error_invalid_opcode::ErrorInvalidOpcodeGadget;
144146
use error_oog_call::ErrorOOGCallGadget;
@@ -311,8 +313,7 @@ pub struct ExecutionConfig<F> {
311313
error_depth: Box<DummyGadget<F, 0, 0, { ExecutionState::ErrorDepth }>>,
312314
error_contract_address_collision:
313315
Box<DummyGadget<F, 0, 0, { ExecutionState::ErrorContractAddressCollision }>>,
314-
error_invalid_creation_code:
315-
Box<DummyGadget<F, 0, 0, { ExecutionState::ErrorInvalidCreationCode }>>,
316+
error_invalid_creation_code: Box<ErrorInvalidCreationCodeGadget<F>>,
316317
error_return_data_out_of_bound: Box<ErrorReturnDataOutOfBoundGadget<F>>,
317318
}
318319

0 commit comments

Comments
 (0)