diff --git a/zkevm-circuits/src/evm_circuit/execution/callop.rs b/zkevm-circuits/src/evm_circuit/execution/callop.rs index abdafcc006..d4ddaeeb8a 100644 --- a/zkevm-circuits/src/evm_circuit/execution/callop.rs +++ b/zkevm-circuits/src/evm_circuit/execution/callop.rs @@ -13,7 +13,7 @@ use crate::{ math_gadget::{ ConstantDivisionGadget, IsZeroGadget, LtGadget, LtWordGadget, MinMaxGadget, }, - memory_gadget::CommonMemoryAddressGadget, + memory_gadget::{CommonMemoryAddressGadget, MemoryAddressGadget}, not, or, select, CachedRegion, Cell, }, }, @@ -46,7 +46,7 @@ pub(crate) struct CallOpGadget { current_caller_address: WordCell, is_static: Cell, depth: Cell, - call: CommonCallGadget, + call: CommonCallGadget, true>, current_value: WordCell, is_warm: Cell, is_warm_prev: Cell, @@ -93,13 +93,14 @@ impl ExecutionGadget for CallOpGadget { ) }); - let call_gadget = CommonCallGadget::construct( - cb, - is_call.expr(), - is_callcode.expr(), - is_delegatecall.expr(), - is_staticcall.expr(), - ); + let call_gadget: CommonCallGadget, true> = + CommonCallGadget::construct( + cb, + is_call.expr(), + is_callcode.expr(), + is_delegatecall.expr(), + is_staticcall.expr(), + ); cb.condition(not::expr(is_call.expr() + is_callcode.expr()), |cb| { cb.require_zero_word( "for non call/call code, value is zero", diff --git a/zkevm-circuits/src/evm_circuit/execution/error_oog_call.rs b/zkevm-circuits/src/evm_circuit/execution/error_oog_call.rs index f2f884e293..54395a4210 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_oog_call.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_oog_call.rs @@ -7,6 +7,7 @@ use crate::{ common_gadget::{CommonCallGadget, CommonErrorGadget}, constraint_builder::{ConstrainBuilderCommon, EVMConstraintBuilder}, math_gadget::{IsZeroGadget, LtGadget}, + memory_gadget::MemoryAddressGadget, CachedRegion, Cell, }, }, @@ -30,7 +31,7 @@ pub(crate) struct ErrorOOGCallGadget { is_staticcall: IsZeroGadget, tx_id: Cell, is_static: Cell, - call: CommonCallGadget, + call: CommonCallGadget, false>, is_warm: Cell, insufficient_gas: LtGadget, common_error_gadget: CommonErrorGadget, diff --git a/zkevm-circuits/src/evm_circuit/execution/error_oog_log.rs b/zkevm-circuits/src/evm_circuit/execution/error_oog_log.rs index 6f4e88922f..b8d72bdf45 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_oog_log.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_oog_log.rs @@ -8,14 +8,14 @@ use crate::{ constraint_builder::{ConstrainBuilderCommon, EVMConstraintBuilder}, math_gadget::LtGadget, memory_gadget::{ - CommonMemoryAddressGadget, MemoryAddressGadget, MemoryExpansionGadget, MemoryExpandedAddressGadget, + CommonMemoryAddressGadget, MemoryExpandedAddressGadget, MemoryExpansionGadget, }, - CachedRegion, Cell, or, + or, CachedRegion, Cell, }, witness::{Block, Call, ExecStep, Transaction}, }, table::CallContextFieldTag, - util::{word::WordExpr, Expr}, + util::Expr, }; use eth_types::{ evm_types::{GasCost, OpcodeId}, @@ -43,9 +43,9 @@ impl ExecutionGadget for ErrorOOGLogGadget { fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); - // check memory + // memory expand gadget let memory_address = MemoryExpandedAddressGadget::construct_self(cb); - + // Pop mstart_address, msize from stack cb.stack_pop(memory_address.offset_word()); cb.stack_pop(memory_address.length_word()); @@ -140,33 +140,69 @@ impl ExecutionGadget for ErrorOOGLogGadget { #[cfg(test)] mod test { use crate::test_util::CircuitTestBuilder; - use bus_mapping::evm::OpcodeId; use eth_types::{ - self, address, bytecode, bytecode::Bytecode, evm_types::GasCost, geth_types::Account, - Address, ToWord, Word, + address, bytecode, bytecode::Bytecode, evm_types::GasCost, geth_types::Account, Address, + ToWord, Transaction, Word, U256, }; - use mock::{ eth, gwei, test_ctx::helpers::account_0_code_account_1_no_code, TestContext, MOCK_ACCOUNTS, }; - fn gas(call_data: &[u8]) -> Word { - Word::from( - GasCost::TX - + 2 * OpcodeId::PUSH32.constant_gas_cost() - + call_data - .iter() - .map(|&x| if x == 0 { 4 } else { 16 }) - .sum::(), - ) + #[test] + fn test_oog_log_root_simple() { + test_root(100.into(), 0.into()); + } + + #[test] + fn test_oog_log_internal_simple() { + let bytecode = bytecode! { + PUSH32(Word::from(0)) + PUSH32(Word::from(10)) + PUSH32(Word::from(224)) + PUSH32(Word::from(1025)) + PUSH32(Word::from(5089)) + LOG2 + STOP + }; + let callee = callee(bytecode); + test_internal(caller(), callee); + } + + #[test] + fn test_oog_log_max_expanded_address() { + // 0xffffffff1 + 0xffffffff0 = 0x1fffffffe1 + // > MAX_EXPANDED_MEMORY_ADDRESS (0x1fffffffe0) + test_root(0xffffffff1_u64.into(), 0xffffffff0_u64.into()); + } + + #[test] + fn test_oog_log_max_u64_address() { + test_root(u64::MAX.into(), u64::MAX.into()); + } + + #[test] + fn test_oog_log_max_word_address() { + test_root(U256::MAX, U256::MAX); } - fn test_oog_log(tx: eth_types::Transaction) { + #[derive(Clone, Copy, Debug, Default)] + struct Stack { + gas: u64, + value: Word, + cd_offset: u64, + cd_length: u64, + rd_offset: u64, + rd_length: u64, + } + + fn test_root(offset: U256, size: U256) { + let tx = mock_tx(eth(1), gwei(2), vec![]); + let code = bytecode! { PUSH1(0) - PUSH1(0) - PUSH1(100) + PUSH32(size) + PUSH32(offset) LOG0 }; @@ -180,7 +216,7 @@ mod test { .from(tx.from) .gas_price(tx.gas_price.unwrap()) .gas(tx.gas + 5) - .input(tx.input) + .input(tx.input.clone()) .value(tx.value); }, |block, _tx| block.number(0xcafeu64), @@ -190,34 +226,35 @@ mod test { CircuitTestBuilder::new_from_test_ctx(ctx).run(); } - fn mock_tx(value: Word, gas_price: Word, calldata: Vec) -> eth_types::Transaction { - let from = MOCK_ACCOUNTS[1]; - let to = MOCK_ACCOUNTS[0]; - eth_types::Transaction { - from, - to: Some(to), - value, - gas: gas(&calldata), - gas_price: Some(gas_price), - input: calldata.into(), - ..Default::default() - } - } - - #[test] - // test oog log in root call - fn test_oog_log_root() { - test_oog_log(mock_tx(eth(1), gwei(2), vec![])); - } + fn test_internal(caller: Account, callee: Account) { + let ctx = TestContext::<3, 1>::new( + None, + |accs| { + accs[0] + .address(address!("0x000000000000000000000000000000000000cafe")) + .balance(Word::from(10u64.pow(19))); + accs[1] + .address(caller.address) + .code(caller.code) + .nonce(caller.nonce.as_u64()) + .balance(caller.balance); + accs[2] + .address(callee.address) + .code(callee.code) + .nonce(callee.nonce.as_u64()) + .balance(callee.balance); + }, + |mut txs, accs| { + txs[0] + .from(accs[0].address) + .to(accs[1].address) + .gas(24000.into()); + }, + |block, _tx| block.number(0xcafeu64), + ) + .unwrap(); - #[derive(Clone, Copy, Debug, Default)] - struct Stack { - gas: u64, - value: Word, - cd_offset: u64, - cd_length: u64, - rd_offset: u64, - rd_length: u64, + CircuitTestBuilder::new_from_test_ctx(ctx).run(); } fn caller() -> Account { @@ -251,49 +288,48 @@ mod test { .write_op(terminator) }; - Account::mock_100_ether(bytecode) + Account { + address: Address::repeat_byte(0xfe), + balance: Word::from(10).pow(20.into()), + code: bytecode.code().into(), + ..Default::default() + } } - fn oog_log_internal_call(caller: Account, callee: Account) { - let ctx = TestContext::<3, 1>::new( - None, - |accs| { - accs[0] - .address(address!("0x000000000000000000000000000000000000cafe")) - .balance(Word::from(10u64.pow(19))); - accs[1].account(&caller); - accs[2].account(&callee); - }, - |mut txs, accs| { - txs[0] - .from(accs[0].address) - .to(accs[1].address) - .gas(24000.into()); - }, - |block, _tx| block.number(0xcafeu64), - ) - .unwrap(); - - CircuitTestBuilder::new_from_test_ctx(ctx).run(); + fn callee(code: Bytecode) -> Account { + let code = code.code(); + let is_empty = code.is_empty(); + Account { + address: Address::repeat_byte(0xff), + code: code.into(), + nonce: if is_empty { 0 } else { 1 }.into(), + balance: if is_empty { 0 } else { 0xdeadbeefu64 }.into(), + ..Default::default() + } } - fn callee(code: Bytecode) -> Account { - Account::mock_code_balance(code) + fn gas(call_data: &[u8]) -> Word { + Word::from( + GasCost::TX + + 2 * OpcodeId::PUSH32.constant_gas_cost() + + call_data + .iter() + .map(|&x| if x == 0 { 4 } else { 16 }) + .sum::(), + ) } - #[test] - // test oog log in internal call - fn test_oog_log_internal() { - let bytecode = bytecode! { - PUSH32(Word::from(0)) - PUSH32(Word::from(10)) - PUSH32(Word::from(224)) - PUSH32(Word::from(1025)) - PUSH32(Word::from(5089)) - LOG2 - STOP - }; - let callee = callee(bytecode); - oog_log_internal_call(caller(), callee); + fn mock_tx(value: Word, gas_price: Word, calldata: Vec) -> Transaction { + let from = MOCK_ACCOUNTS[1]; + let to = MOCK_ACCOUNTS[0]; + Transaction { + from, + to: Some(to), + value, + gas: gas(&calldata), + gas_price: Some(gas_price), + input: calldata.into(), + ..Default::default() + } } } diff --git a/zkevm-circuits/src/evm_circuit/execution/error_oog_memory_copy.rs b/zkevm-circuits/src/evm_circuit/execution/error_oog_memory_copy.rs index 4a7d8ffba8..5bedcb318d 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_oog_memory_copy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_oog_memory_copy.rs @@ -8,10 +8,10 @@ use crate::{ constraint_builder::{ConstrainBuilderCommon, EVMConstraintBuilder}, math_gadget::{IsZeroGadget, LtGadget}, memory_gadget::{ - CommonMemoryAddressGadget, MemoryAddressGadget, MemoryCopierGasGadget, - MemoryExpansionGadget, MemoryExpandedAddressGadget, + CommonMemoryAddressGadget, MemoryCopierGasGadget, + MemoryExpandedAddressGadget, MemoryExpansionGadget, }, - select, or, AccountAddress, CachedRegion, Cell, + or, select, AccountAddress, CachedRegion, Cell, }, witness::{Block, Call, ExecStep, Transaction}, }, @@ -41,7 +41,7 @@ pub(crate) struct ErrorOOGMemoryCopyGadget { /// Source offset src_offset: WordCell, /// Destination offset and size to copy - //dst_memory_addr: MemoryAddressGadget, + // dst_memory_addr: MemoryAddressGadget, dst_memory_addr: MemoryExpandedAddressGadget, memory_expansion: MemoryExpansionGadget, memory_copier_gas: MemoryCopierGasGadget, @@ -68,9 +68,9 @@ impl ExecutionGadget for ErrorOOGMemoryCopyGadget { ], ); - //let dst_offset = cb.query_word_unchecked(); + // let dst_offset = cb.query_word_unchecked(); let src_offset = cb.query_word_unchecked(); - //let copy_size = cb.query_memory_address(); + // let copy_size = cb.query_memory_address(); let external_address = cb.query_account_address(); let is_warm = cb.query_bool(); let tx_id = cb.query_cell(); @@ -92,7 +92,7 @@ impl ExecutionGadget for ErrorOOGMemoryCopyGadget { cb.stack_pop(external_address.to_word()); }); - //let dst_memory_addr = MemoryAddressGadget::construct(cb, dst_offset, copy_size); + // let dst_memory_addr = MemoryAddressGadget::construct(cb, dst_offset, copy_size); let dst_memory_addr = MemoryExpandedAddressGadget::construct_self(cb); cb.stack_pop(dst_memory_addr.offset_word()); cb.stack_pop(src_offset.to_word()); diff --git a/zkevm-circuits/src/evm_circuit/util/common_gadget.rs b/zkevm-circuits/src/evm_circuit/util/common_gadget.rs index 4837daa489..7d7b567deb 100644 --- a/zkevm-circuits/src/evm_circuit/util/common_gadget.rs +++ b/zkevm-circuits/src/evm_circuit/util/common_gadget.rs @@ -2,7 +2,7 @@ use super::{ constraint_builder::ConstrainBuilderCommon, from_bytes, math_gadget::{IsEqualWordGadget, IsZeroGadget, IsZeroWordGadget, LtGadget}, - memory_gadget::{CommonMemoryAddressGadget, MemoryAddressGadget, MemoryExpansionGadget}, + memory_gadget::{CommonMemoryAddressGadget, MemoryExpansionGadget}, AccountAddress, CachedRegion, }; use crate::{ @@ -581,15 +581,15 @@ impl TransferGadget { } #[derive(Clone, Debug)] -pub(crate) struct CommonCallGadget { +pub(crate) struct CommonCallGadget { pub is_success: Cell, pub gas: Word32Cell, pub gas_is_u64: IsZeroGadget, pub callee_address: AccountAddress, pub value: Word32Cell, - pub cd_address: MemoryAddressGadget, - pub rd_address: MemoryAddressGadget, + pub cd_address: MemAddrGadget, + pub rd_address: MemAddrGadget, pub memory_expansion: MemoryExpansionGadget, value_is_zero: IsZeroWordGadget>, @@ -600,7 +600,9 @@ pub(crate) struct CommonCallGadget { pub callee_not_exists: IsZeroWordGadget>, } -impl CommonCallGadget { +impl, const IS_SUCCESS_CALL: bool> + CommonCallGadget +{ pub(crate) fn construct( cb: &mut EVMConstraintBuilder, is_call: Expression, @@ -624,6 +626,8 @@ impl CommonCallGadget let rd_length = cb.query_memory_address(); let is_success = cb.query_bool(); + let cd_address = MemAddrGadget::construct_self(cb); + let rd_address = MemAddrGadget::construct_self(cb); // Lookup values from stack // `callee_address` is poped from stack and used to check if it exists in // access list and get code hash. @@ -649,8 +653,8 @@ impl CommonCallGadget // Recomposition of random linear combination to integer let gas_is_u64 = IsZeroGadget::construct(cb, sum::expr(&gas_word.limbs[N_BYTES_GAS..])); - let cd_address = MemoryAddressGadget::construct(cb, cd_offset, cd_length); - let rd_address = MemoryAddressGadget::construct(cb, rd_offset, rd_length); + // let cd_address = MemoryAddressGadget::construct(cb, cd_offset, cd_length); + // let rd_address = MemoryAddressGadget::construct(cb, rd_offset, rd_length); let memory_expansion = MemoryExpansionGadget::construct(cb, [cd_address.address(), rd_address.address()]);