From 588b8b8c55bf639fc5cbf7eae575da922ea7f1fd Mon Sep 17 00:00:00 2001 From: Chih Cheng Liang Date: Sun, 10 Sep 2023 12:33:43 +0800 Subject: [PATCH 1/9] Fix callop tests and some improvements (#1585) ### Description Continuing on #1565, which was closed accidentally and Github doesn't allow me to reopen because the branch was removed. The cause of the test failure is the inconsistent read-write to the read-write table between circuit assignment and busmapping. ### Issue Link #1584 ### Type of change - [x] Bug fix (non-breaking change which fixes an issue) - [ ] 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 - Fix the account read and write in callop with non-zero values. - Enable ignored callop tests - Improve the account read-write table API. So that we don't mistakenly read the account hash when we intend to read the account balance. - Expose the lt_word gadget assignment output - Improve the debug messages - Various readability fixes ### How Has This Been Tested? ``` cargo test -p zkevm-circuits callop_simple -- --nocapture ``` ### Misc New debug message ``` > Step Op(PUSH32) 94 READ Stack { rw_counter: 94, is_write: true, call_id: 1, stack_pointer: 1018, value: 1000000000000000000 } > Step Op(PUSH32) 95 READ Stack { rw_counter: 95, is_write: true, call_id: 1, stack_pointer: 1017, value: 1461501637330902918203684832716283019655932542975 } > Step Op(PUSH32) 96 READ Stack { rw_counter: 96, is_write: true, call_id: 1, stack_pointer: 1016, value: 0 } > Step Op(CALL) 97 WRIT CallContext { rw_counter: 97, is_write: false, call_id: 1, field_tag: TxId, value: 1 } 98 WRIT CallContext { rw_counter: 98, is_write: false, call_id: 1, field_tag: RwCounterEndOfReversion, value: 0 } 99 WRIT CallContext { rw_counter: 99, is_write: false, call_id: 1, field_tag: IsPersistent, value: 1 } 100 WRIT CallContext { rw_counter: 100, is_write: false, call_id: 1, field_tag: IsStatic, value: 0 } 101 WRIT CallContext { rw_counter: 101, is_write: false, call_id: 1, field_tag: Depth, value: 1 } 102 WRIT CallContext { rw_counter: 102, is_write: false, call_id: 1, field_tag: CalleeAddress, value: 1455770258360977808720533127489944654872968101630 } 103 WRIT Stack { rw_counter: 103, is_write: false, call_id: 1, stack_pointer: 1016, value: 0 } 104 WRIT Stack { rw_counter: 104, is_write: false, call_id: 1, stack_pointer: 1017, value: 1461501637330902918203684832716283019655932542975 } 105 WRIT Stack { rw_counter: 105, is_write: false, call_id: 1, stack_pointer: 1018, value: 1000000000000000000 } 106 WRIT Stack { rw_counter: 106, is_write: false, call_id: 1, stack_pointer: 1019, value: 0 } 107 WRIT Stack { rw_counter: 107, is_write: false, call_id: 1, stack_pointer: 1020, value: 0 } ``` --- bus-mapping/src/evm/opcodes/callop.rs | 27 +++++++----- .../src/evm_circuit/execution/balance.rs | 4 +- .../src/evm_circuit/execution/begin_tx.rs | 10 ++--- .../src/evm_circuit/execution/callop.rs | 36 +++++++--------- .../src/evm_circuit/execution/create.rs | 8 ++-- .../src/evm_circuit/execution/end_tx.rs | 6 +-- .../evm_circuit/execution/error_oog_call.rs | 2 +- .../src/evm_circuit/execution/extcodecopy.rs | 2 +- .../src/evm_circuit/execution/extcodehash.rs | 2 +- .../src/evm_circuit/execution/extcodesize.rs | 2 +- .../src/evm_circuit/execution/shl_shr.rs | 3 +- .../src/evm_circuit/util/common_gadget.rs | 2 +- .../evm_circuit/util/math_gadget/lt_word.rs | 8 ++-- zkevm-circuits/src/witness/block.rs | 6 ++- zkevm-circuits/src/witness/rw.rs | 42 +++++++++++++++++-- 15 files changed, 100 insertions(+), 60 deletions(-) diff --git a/bus-mapping/src/evm/opcodes/callop.rs b/bus-mapping/src/evm/opcodes/callop.rs index 74318b419fc..7c9f25b973f 100644 --- a/bus-mapping/src/evm/opcodes/callop.rs +++ b/bus-mapping/src/evm/opcodes/callop.rs @@ -100,7 +100,8 @@ impl Opcode for CallOpcode { )?; let callee_code_hash = call.code_hash; - let callee_exists = !state.sdb.get_account(&callee_address).1.is_empty(); + let callee = state.sdb.get_account(&callee_address).1.clone(); + let callee_exists = !callee.is_empty(); let (callee_code_hash_word, is_empty_code_hash) = if callee_exists { ( @@ -145,11 +146,13 @@ impl Opcode for CallOpcode { debug_assert!(found); let caller_balance = sender_account.balance; + let is_call_or_callcode = call.kind == CallKind::Call || call.kind == CallKind::CallCode; + let is_sufficient = caller_balance >= call.value; + let is_valid_depth = geth_step.depth < 1025; // Precheck is OK when depth is in range and caller balance is sufficient - let is_precheck_ok = - geth_step.depth < 1025 && (!is_call_or_callcode || caller_balance >= call.value); + let is_precheck_ok = is_valid_depth && (is_sufficient || !is_call_or_callcode); log::debug!( "is_precheck_ok: {}, call type: {:?}, sender_account: {:?} ", @@ -173,9 +176,11 @@ impl Opcode for CallOpcode { let is_precompile = code_address .map(|ref addr| is_precompiled(addr)) .unwrap_or(false); - // TODO: What about transfer for CALLCODE? - // Transfer value only for CALL opcode, is_precheck_ok = true. - if call.kind == CallKind::Call && is_precheck_ok { + // Transfer value only when all these conditions met: + // - The opcode is CALL + // - The precheck passed + // - The value to send is not zero + if call.kind == CallKind::Call && is_precheck_ok && !call.value.is_zero() { state.transfer( &mut exec_step, call.caller_address, @@ -221,9 +226,9 @@ impl Opcode for CallOpcode { // There are 4 branches from here. // add failure case for insufficient balance or error depth in the future. - match (!is_precheck_ok, is_precompile, is_empty_code_hash) { + match (is_precheck_ok, is_precompile, is_empty_code_hash) { // 1. Call to precompiled. - (false, true, _) => { + (true, true, _) => { assert!(call.is_success, "call to precompile should not fail"); let caller_ctx = state.caller_ctx_mut()?; let code_address = code_address.unwrap(); @@ -275,7 +280,7 @@ impl Opcode for CallOpcode { Ok(vec![exec_step]) } // 2. Call to account with empty code. - (false, _, true) => { + (true, _, true) => { for (field, value) in [ (CallContextField::LastCalleeId, 0.into()), (CallContextField::LastCalleeReturnDataOffset, 0.into()), @@ -287,7 +292,7 @@ impl Opcode for CallOpcode { Ok(vec![exec_step]) } // 3. Call to account with non-empty code. - (false, _, false) => { + (true, _, false) => { for (field, value) in [ (CallContextField::ProgramCounter, (geth_step.pc + 1).into()), ( @@ -349,7 +354,7 @@ impl Opcode for CallOpcode { } // 4. insufficient balance or error depth cases. - (true, _, _) => { + (false, _, _) => { for (field, value) in [ (CallContextField::LastCalleeId, 0.into()), (CallContextField::LastCalleeReturnDataOffset, 0.into()), diff --git a/zkevm-circuits/src/evm_circuit/execution/balance.rs b/zkevm-circuits/src/evm_circuit/execution/balance.rs index 9db943ffbed..cefc1e8a784 100644 --- a/zkevm-circuits/src/evm_circuit/execution/balance.rs +++ b/zkevm-circuits/src/evm_circuit/execution/balance.rs @@ -135,7 +135,7 @@ impl ExecutionGadget for BalanceGadget { self.is_warm .assign(region, offset, Value::known(F::from(is_warm as u64)))?; - let code_hash = block.get_rws(step, 5).account_value_pair().0; + let code_hash = block.get_rws(step, 5).account_codehash_pair().0; self.code_hash .assign_u256(region, offset, code_hash.to_word())?; self.not_exists @@ -143,7 +143,7 @@ impl ExecutionGadget for BalanceGadget { let balance = if code_hash.is_zero() { eth_types::Word::zero() } else { - block.get_rws(step, 6).account_value_pair().0 + block.get_rws(step, 6).account_balance_pair().0 }; self.balance.assign_u256(region, offset, balance)?; diff --git a/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs b/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs index c22adb67a3d..4be0115c63b 100644 --- a/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs +++ b/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs @@ -514,20 +514,20 @@ impl ExecutionGadget for BeginTxGadget { let is_coinbase_warm = rws.next().tx_access_list_value_pair().1; let mut callee_code_hash = zero; if !is_precompiled(&tx.to_or_contract_addr()) && !tx.is_create() { - callee_code_hash = rws.next().account_value_pair().1; + callee_code_hash = rws.next().account_codehash_pair().1; } let callee_exists = is_precompiled(&tx.to_or_contract_addr()) || (!tx.is_create() && !callee_code_hash.is_zero()); - let caller_balance_sub_fee_pair = rws.next().account_value_pair(); + let caller_balance_sub_fee_pair = rws.next().account_balance_pair(); let must_create = tx.is_create(); if (!callee_exists && !tx.value.is_zero()) || must_create { - callee_code_hash = rws.next().account_value_pair().1; + callee_code_hash = rws.next().account_codehash_pair().1; } let mut caller_balance_sub_value_pair = (zero, zero); let mut callee_balance_pair = (zero, zero); if !tx.value.is_zero() { - caller_balance_sub_value_pair = rws.next().account_value_pair(); - callee_balance_pair = rws.next().account_value_pair(); + caller_balance_sub_value_pair = rws.next().account_balance_pair(); + callee_balance_pair = rws.next().account_balance_pair(); }; self.tx_id diff --git a/zkevm-circuits/src/evm_circuit/execution/callop.rs b/zkevm-circuits/src/evm_circuit/execution/callop.rs index f06fab13b61..be4a54316b0 100644 --- a/zkevm-circuits/src/evm_circuit/execution/callop.rs +++ b/zkevm-circuits/src/evm_circuit/execution/callop.rs @@ -253,8 +253,7 @@ impl ExecutionGadget for CallOpGadget { // caller address and value (+2). // // No extra lookups for STATICCALL opcode. - let transfer_rwc_delta = - is_call.expr() * not::expr(transfer.value_is_zero.expr()) * 2.expr(); + let transfer_rwc_delta = is_call.expr() * transfer.reversible_w_delta(); let rw_counter_delta = 21.expr() + is_call.expr() * 1.expr() + transfer_rwc_delta.clone() @@ -484,7 +483,7 @@ impl ExecutionGadget for CallOpGadget { let depth = rws.next().call_context_value(); let current_callee_address = rws.next().call_context_value(); - let is_error_depth = depth.low_u64() > 1024; + let is_valid_depth = depth.low_u64() < 1025; self.is_depth_ok .assign(region, offset, F::from(depth.low_u64()), F::from(1025))?; // This offset is used to change the index offset of `step.rw_indices`. @@ -513,7 +512,7 @@ impl ExecutionGadget for CallOpGadget { let rd_length = rws.next().stack_value(); let is_success = rws.next().stack_value(); - let callee_code_hash = rws.next().account_value_pair().0; + let callee_code_hash = rws.next().account_codehash_pair().0; let callee_exists = !callee_code_hash.is_zero(); let (is_warm, is_warm_prev) = rws.next().tx_access_list_value_pair(); @@ -523,24 +522,12 @@ impl ExecutionGadget for CallOpGadget { // check if it is insufficient balance case. // get caller balance - let caller_balance = rws.next().account_value_pair().0; + let caller_balance = rws.next().account_balance_pair().0; self.caller_balance .assign_u256(region, offset, caller_balance)?; self.is_insufficient_balance .assign(region, offset, caller_balance, value)?; - let is_insufficient = (value > caller_balance) && (is_call || is_callcode); - // only call opcode do transfer in sucessful case. - let [caller_balance_pair, callee_balance_pair] = - if is_call && !is_insufficient && !is_error_depth && !value.is_zero() { - [ - rws.next().account_value_pair(), - rws.next().account_value_pair(), - ] - } else { - [(U256::zero(), U256::zero()), (U256::zero(), U256::zero())] - }; - self.opcode .assign(region, offset, Value::known(F::from(opcode.as_u64())))?; self.is_call.assign( @@ -612,8 +599,19 @@ impl ExecutionGadget for CallOpGadget { callee_rw_counter_end_of_reversion.low_u64() as usize, callee_is_persistent.low_u64() != 0, )?; + + let is_call_or_callcode = is_call || is_callcode; + let is_sufficient = caller_balance >= value; + let is_precheck_ok = is_valid_depth && (is_sufficient || !is_call_or_callcode); + // conditionally assign - if !is_insufficient && !is_error_depth && !value.is_zero() { + if is_call && is_precheck_ok && !value.is_zero() { + if !callee_exists { + rws.next().account_codehash_pair(); // callee hash + } + + let caller_balance_pair = rws.next().account_balance_pair(); + let callee_balance_pair = rws.next().account_balance_pair(); self.transfer.assign( region, offset, @@ -695,7 +693,6 @@ mod test { } } - #[ignore] #[test] fn callop_recursive() { for opcode in TEST_CALL_OPCODES { @@ -703,7 +700,6 @@ mod test { } } - #[ignore] #[test] fn callop_simple() { let stacks = [ diff --git a/zkevm-circuits/src/evm_circuit/execution/create.rs b/zkevm-circuits/src/evm_circuit/execution/create.rs index 393537eb1c2..47898f4ac7c 100644 --- a/zkevm-circuits/src/evm_circuit/execution/create.rs +++ b/zkevm-circuits/src/evm_circuit/execution/create.rs @@ -497,8 +497,8 @@ impl ExecutionGadget< let rw_offset = if is_create2 { 8 } else { 7 }; // Pre-check: call depth, user's nonce and user's balance - let (caller_balance, _) = block.get_rws(step, rw_offset + 1).account_value_pair(); - let (caller_nonce, _) = block.get_rws(step, rw_offset + 2).account_value_pair(); + let (caller_balance, _) = block.get_rws(step, rw_offset + 1).account_balance_pair(); + let (caller_nonce, _) = block.get_rws(step, rw_offset + 2).account_nonce_pair(); let is_precheck_ok = if call.depth < 1025 && caller_balance >= value && caller_nonce.as_u64() < u64::MAX { 1 @@ -513,7 +513,7 @@ impl ExecutionGadget< .get_rws(step, rw_offset + 4) .tx_access_list_value_pair(); let (callee_prev_code_hash, _) = - block.get_rws(step, rw_offset + 5).account_value_pair(); + block.get_rws(step, rw_offset + 5).account_codehash_pair(); (callee_prev_code_hash, was_warm) } else { (U256::from(0), false) @@ -586,7 +586,7 @@ impl ExecutionGadget< rw_offset + copy_rw_increase + 14, rw_offset + copy_rw_increase + 15, ] - .map(|i| block.get_rws(step, i).account_value_pair()) + .map(|i| block.get_rws(step, i).account_balance_pair()) } else { [(0.into(), 0.into()), (0.into(), 0.into())] }; diff --git a/zkevm-circuits/src/evm_circuit/execution/end_tx.rs b/zkevm-circuits/src/evm_circuit/execution/end_tx.rs index 2575527b983..751c9d4cd3e 100644 --- a/zkevm-circuits/src/evm_circuit/execution/end_tx.rs +++ b/zkevm-circuits/src/evm_circuit/execution/end_tx.rs @@ -228,8 +228,8 @@ impl ExecutionGadget for EndTxGadget { ) -> Result<(), Error> { let gas_used = tx.gas() - step.gas_left; let (refund, _) = block.get_rws(step, 2).tx_refund_value_pair(); - let (caller_balance, caller_balance_prev) = block.get_rws(step, 3).account_value_pair(); - let (coinbase_code_hash_prev, _) = block.get_rws(step, 4).account_value_pair(); + let (caller_balance, caller_balance_prev) = block.get_rws(step, 3).account_balance_pair(); + let (coinbase_code_hash_prev, _) = block.get_rws(step, 4).account_codehash_pair(); let (coinbase_balance, coinbase_balance_prev) = block .get_rws( step, @@ -239,7 +239,7 @@ impl ExecutionGadget for EndTxGadget { 5 }, ) - .account_value_pair(); + .account_balance_pair(); self.tx_id .assign(region, offset, Value::known(F::from(tx.id)))?; 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 f31f08c310f..ccb38f0a290 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_oog_call.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_oog_call.rs @@ -129,7 +129,7 @@ impl ExecutionGadget for ErrorOOGCallGadget { let callee_code_hash = block .get_rws(step, 9 + is_call_or_callcode) - .account_value_pair() + .account_codehash_pair() .0; let callee_exists = !callee_code_hash.is_zero(); diff --git a/zkevm-circuits/src/evm_circuit/execution/extcodecopy.rs b/zkevm-circuits/src/evm_circuit/execution/extcodecopy.rs index b3e69ccd497..bb22ee27236 100644 --- a/zkevm-circuits/src/evm_circuit/execution/extcodecopy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/extcodecopy.rs @@ -203,7 +203,7 @@ impl ExecutionGadget for ExtcodecopyGadget { self.is_warm .assign(region, offset, Value::known(F::from(is_warm as u64)))?; - let code_hash = block.get_rws(step, 8).account_value_pair().0; + let code_hash = block.get_rws(step, 8).account_codehash_pair().0; self.code_hash.assign_u256(region, offset, code_hash)?; self.not_exists.assign_u256(region, offset, code_hash)?; diff --git a/zkevm-circuits/src/evm_circuit/execution/extcodehash.rs b/zkevm-circuits/src/evm_circuit/execution/extcodehash.rs index 825a84e492e..ae044ec9d7e 100644 --- a/zkevm-circuits/src/evm_circuit/execution/extcodehash.rs +++ b/zkevm-circuits/src/evm_circuit/execution/extcodehash.rs @@ -122,7 +122,7 @@ impl ExecutionGadget for ExtcodehashGadget { self.is_warm .assign(region, offset, Value::known(F::from(is_warm as u64)))?; - let code_hash = block.get_rws(step, 5).account_value_pair().0; + let code_hash = block.get_rws(step, 5).account_codehash_pair().0; self.code_hash.assign_u256(region, offset, code_hash)?; Ok(()) diff --git a/zkevm-circuits/src/evm_circuit/execution/extcodesize.rs b/zkevm-circuits/src/evm_circuit/execution/extcodesize.rs index 7c453c6a617..ee6d540722e 100644 --- a/zkevm-circuits/src/evm_circuit/execution/extcodesize.rs +++ b/zkevm-circuits/src/evm_circuit/execution/extcodesize.rs @@ -140,7 +140,7 @@ impl ExecutionGadget for ExtcodesizeGadget { self.is_warm .assign(region, offset, Value::known(F::from(is_warm as u64)))?; - let code_hash = block.get_rws(step, 5).account_value_pair().0; + let code_hash = block.get_rws(step, 5).account_codehash_pair().0; self.code_hash.assign_u256(region, offset, code_hash)?; self.not_exists .assign(region, offset, Word::from(code_hash))?; diff --git a/zkevm-circuits/src/evm_circuit/execution/shl_shr.rs b/zkevm-circuits/src/evm_circuit/execution/shl_shr.rs index a95a633101b..60bf8622c24 100644 --- a/zkevm-circuits/src/evm_circuit/execution/shl_shr.rs +++ b/zkevm-circuits/src/evm_circuit/execution/shl_shr.rs @@ -211,7 +211,8 @@ impl ExecutionGadget for ShlShrGadget { self.remainder_is_zero .assign(region, offset, Word::from(remainder))?; self.remainder_lt_divisor - .assign(region, offset, remainder, divisor) + .assign(region, offset, remainder, divisor)?; + Ok(()) } } diff --git a/zkevm-circuits/src/evm_circuit/util/common_gadget.rs b/zkevm-circuits/src/evm_circuit/util/common_gadget.rs index 71c79bf5050..3c6850e38cc 100644 --- a/zkevm-circuits/src/evm_circuit/util/common_gadget.rs +++ b/zkevm-circuits/src/evm_circuit/util/common_gadget.rs @@ -514,7 +514,7 @@ impl TransferWithGasFeeGadget { or::expr([ not::expr(self.value_is_zero.expr()) * not::expr(self.receiver.receiver_exists.expr()), 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() diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget/lt_word.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget/lt_word.rs index 95c40103537..37899253b8a 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget/lt_word.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget/lt_word.rs @@ -42,22 +42,22 @@ impl LtWordGadget { offset: usize, lhs: Word, rhs: Word, - ) -> Result<(), Error> { + ) -> Result { let (lhs_lo, lhs_hi) = split_u256(&lhs); let (rhs_lo, rhs_hi) = split_u256(&rhs); - self.comparison_hi.assign( + let (hi_lt, hi_eq) = self.comparison_hi.assign( region, offset, F::from_u128(lhs_hi.as_u128()), F::from_u128(rhs_hi.as_u128()), )?; - self.lt_lo.assign( + let (lt_lo, _) = self.lt_lo.assign( region, offset, F::from_u128(lhs_lo.as_u128()), F::from_u128(rhs_lo.as_u128()), )?; - Ok(()) + Ok(hi_lt + hi_eq * lt_lo) } } diff --git a/zkevm-circuits/src/witness/block.rs b/zkevm-circuits/src/witness/block.rs index 540f8019000..ff790740f21 100644 --- a/zkevm-circuits/src/witness/block.rs +++ b/zkevm-circuits/src/witness/block.rs @@ -60,9 +60,11 @@ impl Block { for (tx_idx, tx) in self.txs.iter().enumerate() { println!("tx {}", tx_idx); for step in tx.steps() { - println!(" step {:?} rwc: {}", step.exec_state, step.rwc.0); + println!("> Step {:?}", step.exec_state); for rw_idx in 0..step.bus_mapping_instance.len() { - println!(" - {:?}", self.get_rws(step, rw_idx)); + let rw = self.get_rws(step, rw_idx); + let rw_str = if rw.is_write() { "READ" } else { "WRIT" }; + println!(" {} {} {:?}", rw.rw_counter(), rw_str, rw); } } } diff --git a/zkevm-circuits/src/witness/rw.rs b/zkevm-circuits/src/witness/rw.rs index 859c25e9246..6b850648e54 100644 --- a/zkevm-circuits/src/witness/rw.rs +++ b/zkevm-circuits/src/witness/rw.rs @@ -357,11 +357,47 @@ impl Rw { } } - pub(crate) fn account_value_pair(&self) -> (Word, Word) { + pub(crate) fn account_balance_pair(&self) -> (Word, Word) { match self { Self::Account { - value, value_prev, .. - } => (*value, *value_prev), + value, + value_prev, + field_tag, + .. + } => { + debug_assert_eq!(field_tag, &AccountFieldTag::Balance); + (*value, *value_prev) + } + _ => unreachable!(), + } + } + + pub(crate) fn account_nonce_pair(&self) -> (Word, Word) { + match self { + Self::Account { + value, + value_prev, + field_tag, + .. + } => { + debug_assert_eq!(field_tag, &AccountFieldTag::Nonce); + (*value, *value_prev) + } + _ => unreachable!(), + } + } + + pub(crate) fn account_codehash_pair(&self) -> (Word, Word) { + match self { + Self::Account { + value, + value_prev, + field_tag, + .. + } => { + debug_assert_eq!(field_tag, &AccountFieldTag::CodeHash); + (*value, *value_prev) + } _ => unreachable!(), } } From 77c16e4ae1bfa1187a38d8d9be3d9791b389a534 Mon Sep 17 00:00:00 2001 From: Akase Cho Date: Tue, 12 Sep 2023 14:25:10 +0800 Subject: [PATCH 2/9] fix unconstrained is_warm in sload/sstore (#1596) ### Description This PR fixes the soundness problem in the implementation of SLOAD and SSTORE opcodes by adding constraints to the `is_warm` cell. The problem is detailed in issue #1049. ### Issue Link #1049 ### Type of change - [x] Bug fix (non-breaking change which fixes an issue) - [ ] 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 - Update `bus-mapping/src/evm/opcodes/sload.rs` - Update `bus-mapping/src/evm/opcodes/sstore.rs` - Update `zkevm-circuits/src/evm_circuit/execution/sload.rs` - Update `zkevm-circuits/src/evm_circuit/execution/sstore.rs` ### Rationale The current implementation of SSTORE and SLOAD didn't constrain the `is_warm` cell, which could result in any value and lead to soundness problems. This PR adds constraints to the `is_warm` cell in order to ensure correctness. ### How Has This Been Tested? - --- bus-mapping/src/evm/opcodes/sload.rs | 13 ++++++++++++- bus-mapping/src/evm/opcodes/sstore.rs | 17 ++++++++++++++--- .../src/evm_circuit/execution/sload.rs | 10 ++++++++-- .../src/evm_circuit/execution/sstore.rs | 12 +++++++++--- 4 files changed, 43 insertions(+), 9 deletions(-) diff --git a/bus-mapping/src/evm/opcodes/sload.rs b/bus-mapping/src/evm/opcodes/sload.rs index 8f891d50e0c..9bd164db46e 100644 --- a/bus-mapping/src/evm/opcodes/sload.rs +++ b/bus-mapping/src/evm/opcodes/sload.rs @@ -82,6 +82,17 @@ impl Opcode for Sload { // First stack write state.stack_write(&mut exec_step, stack_position, value)?; + state.push_op( + &mut exec_step, + RW::READ, + TxAccessListAccountStorageOp { + tx_id: state.tx_ctx.id(), + address: contract_addr, + key, + is_warm, + is_warm_prev: is_warm, + }, + ); state.push_op_reversible( &mut exec_step, TxAccessListAccountStorageOp { @@ -189,7 +200,7 @@ mod sload_tests { ); let access_list_op = &builder.block.container.tx_access_list_account_storage - [step.bus_mapping_instance[7].as_usize()]; + [step.bus_mapping_instance[8].as_usize()]; assert_eq!( (access_list_op.rw(), access_list_op.op()), ( diff --git a/bus-mapping/src/evm/opcodes/sstore.rs b/bus-mapping/src/evm/opcodes/sstore.rs index a5527aa72de..0b1eadeca5f 100644 --- a/bus-mapping/src/evm/opcodes/sstore.rs +++ b/bus-mapping/src/evm/opcodes/sstore.rs @@ -1,10 +1,9 @@ use super::Opcode; use crate::{ circuit_input_builder::{CircuitInputStateRef, ExecStep}, - operation::{CallContextField, StorageOp, TxAccessListAccountStorageOp, TxRefundOp}, + operation::{CallContextField, StorageOp, TxAccessListAccountStorageOp, TxRefundOp, RW}, Error, }; - use eth_types::{GethExecStep, ToWord, Word}; /// Placeholder structure used to implement [`Opcode`] trait over it @@ -86,6 +85,17 @@ impl Opcode for Sstore { ), )?; + state.push_op( + &mut exec_step, + RW::READ, + TxAccessListAccountStorageOp { + tx_id: state.tx_ctx.id(), + address: contract_addr, + key, + is_warm, + is_warm_prev: is_warm, + }, + ); state.push_op_reversible( &mut exec_step, TxAccessListAccountStorageOp { @@ -250,7 +260,8 @@ mod sstore_tests { ) ) ); - let refund_op = &builder.block.container.tx_refund[step.bus_mapping_instance[9].as_usize()]; + let refund_op = + &builder.block.container.tx_refund[step.bus_mapping_instance[10].as_usize()]; assert_eq!( (refund_op.rw(), refund_op.op()), ( diff --git a/zkevm-circuits/src/evm_circuit/execution/sload.rs b/zkevm-circuits/src/evm_circuit/execution/sload.rs index 3bee3fa2c95..12ee777aa65 100644 --- a/zkevm-circuits/src/evm_circuit/execution/sload.rs +++ b/zkevm-circuits/src/evm_circuit/execution/sload.rs @@ -61,6 +61,12 @@ impl ExecutionGadget for SloadGadget { cb.stack_push(value.to_word()); let is_warm = cb.query_bool(); + cb.account_storage_access_list_read( + tx_id.expr(), + callee_address.to_word(), + key.to_word(), + Word::from_lo_unchecked(is_warm.expr()), + ); cb.account_storage_access_list_write( tx_id.expr(), callee_address.to_word(), @@ -72,7 +78,7 @@ impl ExecutionGadget for SloadGadget { let gas_cost = SloadGasGadget::construct(cb, is_warm.expr()).expr(); let step_state_transition = StepStateTransition { - rw_counter: Delta(8.expr()), + rw_counter: Delta(9.expr()), program_counter: Delta(1.expr()), reversible_write_counter: Delta(1.expr()), gas_left: Delta(-gas_cost), @@ -123,7 +129,7 @@ impl ExecutionGadget for SloadGadget { self.committed_value .assign_u256(region, offset, committed_value)?; - let (_, is_warm) = block.get_rws(step, 7).tx_access_list_value_pair(); + let (_, is_warm) = block.get_rws(step, 8).tx_access_list_value_pair(); self.is_warm .assign(region, offset, Value::known(F::from(is_warm as u64)))?; diff --git a/zkevm-circuits/src/evm_circuit/execution/sstore.rs b/zkevm-circuits/src/evm_circuit/execution/sstore.rs index 46f030b0a3d..fe1fd45f0ba 100644 --- a/zkevm-circuits/src/evm_circuit/execution/sstore.rs +++ b/zkevm-circuits/src/evm_circuit/execution/sstore.rs @@ -84,6 +84,12 @@ impl ExecutionGadget for SstoreGadget { ); let is_warm = cb.query_bool(); + cb.account_storage_access_list_read( + tx_id.expr(), + callee_address.to_word(), + key.to_word(), + Word::from_lo_unchecked(is_warm.expr()), + ); cb.account_storage_access_list_write( tx_id.expr(), callee_address.to_word(), @@ -129,7 +135,7 @@ impl ExecutionGadget for SstoreGadget { ); let step_state_transition = StepStateTransition { - rw_counter: Delta(10.expr()), + rw_counter: Delta(11.expr()), program_counter: Delta(1.expr()), stack_pointer: Delta(2.expr()), reversible_write_counter: Delta(3.expr()), @@ -190,11 +196,11 @@ impl ExecutionGadget for SstoreGadget { self.original_value .assign_u256(region, offset, original_value)?; - let (_, is_warm) = block.get_rws(step, 8).tx_access_list_value_pair(); + let (_, is_warm) = block.get_rws(step, 9).tx_access_list_value_pair(); self.is_warm .assign(region, offset, Value::known(F::from(is_warm as u64)))?; - let (tx_refund, tx_refund_prev) = block.get_rws(step, 9).tx_refund_value_pair(); + let (tx_refund, tx_refund_prev) = block.get_rws(step, 10).tx_refund_value_pair(); self.tx_refund_prev .assign(region, offset, Some(tx_refund_prev.to_le_bytes()))?; From 320d31d459ad6ab994a56cecdc2dc871ae2acc32 Mon Sep 17 00:00:00 2001 From: Zhang Zhuo Date: Tue, 12 Sep 2023 22:50:39 +0800 Subject: [PATCH 3/9] fix calldatalen in calldata{copy,load} for contract deployment (#1593) ### Description The 'calldata' for a call with Kind::Create/Ceate2, should always be empty. We handled this correctly for create/create2 opcode. But for tx.to == None deployment, it was wrong. This PR fixes this problem. ### Issue Link [_link issue here_] ### Type of change - [x] Bug fix (non-breaking change which fixes an issue) - [ ] 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 --- bus-mapping/src/circuit_input_builder/transaction.rs | 2 +- .../src/evm_circuit/execution/calldatacopy.rs | 9 ++++++++- .../src/evm_circuit/execution/calldataload.rs | 12 ++++++++++-- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/bus-mapping/src/circuit_input_builder/transaction.rs b/bus-mapping/src/circuit_input_builder/transaction.rs index 7016c0a7dc7..9b86e197e11 100644 --- a/bus-mapping/src/circuit_input_builder/transaction.rs +++ b/bus-mapping/src/circuit_input_builder/transaction.rs @@ -241,7 +241,7 @@ impl Transaction { code_hash, depth: 1, value: eth_tx.value, - call_data_length: eth_tx.input.len().try_into().unwrap(), + call_data_length: 0, ..Default::default() } }; diff --git a/zkevm-circuits/src/evm_circuit/execution/calldatacopy.rs b/zkevm-circuits/src/evm_circuit/execution/calldatacopy.rs index e31047b09b9..f7d9a762400 100644 --- a/zkevm-circuits/src/evm_circuit/execution/calldatacopy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/calldatacopy.rs @@ -199,7 +199,14 @@ impl ExecutionGadget for CallDataCopyGadget { // Call data length and call data offset let (call_data_length, call_data_offset) = if call.is_root { - (tx.call_data.len() as u64, 0_u64) + ( + if tx.is_create() { + 0 + } else { + tx.call_data.len() as u64 + }, + 0_u64, + ) } else { (call.call_data_length, call.call_data_offset) }; diff --git a/zkevm-circuits/src/evm_circuit/execution/calldataload.rs b/zkevm-circuits/src/evm_circuit/execution/calldataload.rs index d7b0aba51a6..ff0890bb8fe 100644 --- a/zkevm-circuits/src/evm_circuit/execution/calldataload.rs +++ b/zkevm-circuits/src/evm_circuit/execution/calldataload.rs @@ -213,7 +213,15 @@ impl ExecutionGadget for CallDataLoadGadget { // Assign to the buffer reader gadget. let (src_id, call_data_offset, call_data_length) = if call.is_root { - (tx.id, 0, tx.call_data.len() as u64) + ( + tx.id, + 0, + if tx.is_create() { + 0 + } else { + tx.call_data.len() as u64 + }, + ) } else { ( call.caller_id as u64, @@ -249,7 +257,7 @@ impl ExecutionGadget for CallDataLoadGadget { for (i, byte) in calldata_bytes.iter_mut().enumerate() { if call.is_root { // Fetch from tx call data. - if src_addr + (i as u64) < tx.call_data.len() as u64 { + if src_addr + (i as u64) < call_data_length { *byte = tx.call_data[src_addr as usize + i]; } } else { From 7449c4f546fcfa8cb4e71c0b71043a1990c26083 Mon Sep 17 00:00:00 2001 From: Zhang Zhuo Date: Tue, 12 Sep 2023 23:43:27 +0800 Subject: [PATCH 4/9] fix(callop): fix LastCalleeId, and other fixes (#1594) ### Description 1. for callop, when there is no bytecode (empty account or non-existed account) or pre check fails, the return data should be flushed to empty, and the LastCalleeId (used in RETURNDATACOPY opcode) should be set to correct callee id instead of 0. 2. precompile can fail. (eg: out of gas) 3. "precompile account exists" is only the current status of eth mainnet. It is not part of evm spec. Following spec, precompile account can be non-existed. 4. when ErrDepth, there is no transfer 5. (not 100% sure) I also changed the 'is_static' check for only call opcode. It was a fix i made long ago during fixing each fail case of testool. I guess maybe we can construct this test case to check this behavior: delegatecall inside callcode(with non 0 value) inside staticcall. It is a valid tx, but the 'value' is not zero? ### Issue Link [_link issue here_] ### Type of change - [x] Bug fix (non-breaking change which fixes an issue) - [ ] 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 --- bus-mapping/src/evm/opcodes/callop.rs | 8 ++-- .../src/evm_circuit/execution/callop.rs | 43 +++++++++++-------- 2 files changed, 29 insertions(+), 22 deletions(-) diff --git a/bus-mapping/src/evm/opcodes/callop.rs b/bus-mapping/src/evm/opcodes/callop.rs index 7c9f25b973f..2db9fbc31da 100644 --- a/bus-mapping/src/evm/opcodes/callop.rs +++ b/bus-mapping/src/evm/opcodes/callop.rs @@ -176,6 +176,7 @@ impl Opcode for CallOpcode { let is_precompile = code_address .map(|ref addr| is_precompiled(addr)) .unwrap_or(false); + // CALLCODE does not need to do real transfer // Transfer value only when all these conditions met: // - The opcode is CALL // - The precheck passed @@ -185,7 +186,7 @@ impl Opcode for CallOpcode { &mut exec_step, call.caller_address, call.address, - callee_exists || is_precompile, + callee_exists, false, call.value, )?; @@ -229,7 +230,6 @@ impl Opcode for CallOpcode { match (is_precheck_ok, is_precompile, is_empty_code_hash) { // 1. Call to precompiled. (true, true, _) => { - assert!(call.is_success, "call to precompile should not fail"); let caller_ctx = state.caller_ctx_mut()?; let code_address = code_address.unwrap(); let (result, contract_gas_cost) = execute_precompiled( @@ -282,7 +282,7 @@ impl Opcode for CallOpcode { // 2. Call to account with empty code. (true, _, true) => { for (field, value) in [ - (CallContextField::LastCalleeId, 0.into()), + (CallContextField::LastCalleeId, call.call_id.into()), (CallContextField::LastCalleeReturnDataOffset, 0.into()), (CallContextField::LastCalleeReturnDataLength, 0.into()), ] { @@ -356,7 +356,7 @@ impl Opcode for CallOpcode { // 4. insufficient balance or error depth cases. (false, _, _) => { for (field, value) in [ - (CallContextField::LastCalleeId, 0.into()), + (CallContextField::LastCalleeId, call.call_id.into()), (CallContextField::LastCalleeReturnDataOffset, 0.into()), (CallContextField::LastCalleeReturnDataLength, 0.into()), ] { diff --git a/zkevm-circuits/src/evm_circuit/execution/callop.rs b/zkevm-circuits/src/evm_circuit/execution/callop.rs index be4a54316b0..b05aaeeb375 100644 --- a/zkevm-circuits/src/evm_circuit/execution/callop.rs +++ b/zkevm-circuits/src/evm_circuit/execution/callop.rs @@ -145,7 +145,7 @@ impl ExecutionGadget for CallOpGadget { ); }); - cb.condition(call_gadget.has_value.clone(), |cb| { + cb.condition(is_call.expr() * call_gadget.has_value.clone(), |cb| { cb.require_zero( "CALL with value must not be in static call stack", is_static.expr(), @@ -180,20 +180,17 @@ impl ExecutionGadget for CallOpGadget { // skip the transfer (this is necessary for non-existing accounts, which // will not be crated when value is 0 and so the callee balance lookup // would be invalid). - let transfer = cb.condition( - is_call.expr() * not::expr(is_insufficient_balance.expr()), - |cb| { - TransferGadget::construct( - cb, - caller_address.to_word(), - callee_address.to_word(), - not::expr(call_gadget.callee_not_exists.expr()), - 0.expr(), - call_gadget.value.clone(), - &mut callee_reversion_info, - ) - }, - ); + let transfer = cb.condition(is_call.expr() * is_precheck_ok.expr(), |cb| { + TransferGadget::construct( + cb, + caller_address.to_word(), + callee_address.to_word(), + not::expr(call_gadget.callee_not_exists.expr()), + 0.expr(), + call_gadget.value.clone(), + &mut callee_reversion_info, + ) + }); // For CALLCODE opcode, verify caller balance is greater than or equal to stack // `value` in successful case. that is `is_insufficient_balance` is false. @@ -231,12 +228,18 @@ impl ExecutionGadget for CallOpGadget { let stack_pointer_delta = select::expr(is_call.expr() + is_callcode.expr(), 6.expr(), 5.expr()); let memory_expansion = call_gadget.memory_expansion.clone(); + + // handle calls to accounts with no code. cb.condition( and::expr(&[no_callee_code.expr(), is_precheck_ok.expr()]), |cb| { // Save caller's call state - for field_tag in [ + cb.call_context_lookup_write( + None, CallContextFieldTag::LastCalleeId, + Word::from_lo_unchecked(callee_call_id.expr()), + ); + for field_tag in [ CallContextFieldTag::LastCalleeReturnDataOffset, CallContextFieldTag::LastCalleeReturnDataLength, ] { @@ -276,11 +279,15 @@ impl ExecutionGadget for CallOpGadget { }, ); - // handle is_insufficient_balance step transition + // handle is_insufficient_balance or !is_depth_ok step transition cb.condition(not::expr(is_precheck_ok.expr()), |cb| { // Save caller's call state - for field_tag in [ + cb.call_context_lookup_write( + None, CallContextFieldTag::LastCalleeId, + Word::from_lo_unchecked(callee_call_id.expr()), + ); + for field_tag in [ CallContextFieldTag::LastCalleeReturnDataOffset, CallContextFieldTag::LastCalleeReturnDataLength, ] { From 7526cbd8f62c64068b6ee20180d9a37508e3a713 Mon Sep 17 00:00:00 2001 From: Chih Cheng Liang Date: Tue, 12 Sep 2023 23:50:14 +0800 Subject: [PATCH 5/9] [MPTWG] Update CI for MPTWG (#1591) ### Description Enable the MPT witness generator CI check ### Issue Link ### Type of change Bug fix (non-breaking change which fixes an issue) ### Contents - Run Go build and Go format on MPTWG - Ignore main tests CI run if no change on zkevm-circuits - Ignore MPTWG CI run if no change on MPTWG ### Rationale We want to enable automatic checks on MPTWG --- .github/workflows/lints.yml | 2 +- .github/workflows/mpt-witness-generator.yml | 49 +++++++++++++++++++ .../.github/workflows/go.yml | 33 ------------- 3 files changed, 50 insertions(+), 34 deletions(-) create mode 100644 .github/workflows/mpt-witness-generator.yml delete mode 100644 mpt-witness-generator/.github/workflows/go.yml diff --git a/.github/workflows/lints.yml b/.github/workflows/lints.yml index 987e74d8ceb..78d8c137aa5 100644 --- a/.github/workflows/lints.yml +++ b/.github/workflows/lints.yml @@ -20,7 +20,7 @@ jobs: with: cancel_others: 'true' concurrent_skipping: 'same_content_newer' - paths_ignore: '["**/README.md"]' + paths_ignore: '["**/README.md", "mpt-witness-generator/**"]' lints: needs: [skip_check] diff --git a/.github/workflows/mpt-witness-generator.yml b/.github/workflows/mpt-witness-generator.yml new file mode 100644 index 00000000000..77da2fa9c88 --- /dev/null +++ b/.github/workflows/mpt-witness-generator.yml @@ -0,0 +1,49 @@ +name: MPT Witness Generator Checks + +on: + merge_group: + pull_request: + types: [synchronize, opened, reopened, ready_for_review] + push: + branches: + - main + +jobs: + skip_check: + runs-on: ubuntu-latest + outputs: + should_skip: ${{ steps.skip_check.outputs.should_skip }} + steps: + - id: skip_check + uses: fkirc/skip-duplicate-actions@v5 + with: + cancel_others: 'true' + concurrent_skipping: 'same_content_newer' + paths: '["mpt-witness-generator/**"]' + + + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Set up Go + uses: actions/setup-go@v4 + with: + go-version: '1.20' + + - name: Format + uses: Jerome1337/gofmt-action@v1.0.5 + with: + gofmt-path: './mpt-witness-generator' + gofmt-flags: '-l -d' + + - name: Build + working-directory: ./mpt-witness-generator + run: go build -v ./... + + - name: Test + working-directory: ./mpt-witness-generator + env: + NO_GETH: true + run: go test -v ./... diff --git a/mpt-witness-generator/.github/workflows/go.yml b/mpt-witness-generator/.github/workflows/go.yml deleted file mode 100644 index 35860814a3d..00000000000 --- a/mpt-witness-generator/.github/workflows/go.yml +++ /dev/null @@ -1,33 +0,0 @@ -# This workflow will build a golang project -# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go - -name: Go - -on: - push: - branches: [ "main" ] - pull_request: - branches: [ "main" ] - -jobs: - - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - - name: Set up Go - uses: actions/setup-go@v4 - with: - go-version: '1.20' - - - name: Format - run: go fmt ./... - - - name: Build - run: go build -v ./... - - - name: Test - env: - NO_GETH: true - run: go test -v ./... From 610acc27471a6ea8d8b493943b970b9917e92f63 Mon Sep 17 00:00:00 2001 From: naure Date: Tue, 12 Sep 2023 18:13:41 +0200 Subject: [PATCH 6/9] copy-fix-terminate: enforce secure termination of the copy circuit (#1568) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### Description This PR fixes two soundness issues in the Copy circuit. 1. There are a number of checks at the end of an event when is_last=1. However, there are no guarantees that this last row exists. The last event may not be checked fully. 2. The constraints may query cells of the "last two rows", whose content is not constrained. For example, booleans are not necessarily booleans there. ### Type of change - [x] Bug fix (non-breaking change which fixes an issue) ### Content This is a backport from Scroll, see more details here: https://github.com/scroll-tech/zkevm-circuits/pull/649. Quoting: The new constraint constrain_must_terminate guarantees that: - a "last row" is eventually reached so that final checks happen, - and every row of an event can safely query rotations 1 and 2. Now to witness generation. There must be two additional rows that are enabled so their content is verified, but not used because they touch disabled rows. See UNUSED_ROWS. Note that there was already a sanity check that no constraints query reserved rows with the error `active on an unusable row - missing selector?`. Rows can be reserved for blinding, or beyond max_rows, or simply to avoid wrap around back to the first row. This check was satisfied by adding two disabled rows (see assign_padding_row(…)). However, this alone was not sound. ### How Has This Been Tested? cargo test --release -p zkevm-circuits -p zkevm-circuits -- copy Co-authored-by: Aurélien Nicolas --- bus-mapping/src/circuit_input_builder.rs | 2 +- gadgets/src/binary_number.rs | 9 +++ zkevm-circuits/src/copy_circuit.rs | 81 +++++++++++++++++------- 3 files changed, 67 insertions(+), 25 deletions(-) diff --git a/bus-mapping/src/circuit_input_builder.rs b/bus-mapping/src/circuit_input_builder.rs index 6f83e6d13e3..1e47fa56f68 100644 --- a/bus-mapping/src/circuit_input_builder.rs +++ b/bus-mapping/src/circuit_input_builder.rs @@ -388,7 +388,7 @@ impl CircuitInputBuilder { .iter() .fold(0, |acc, c| acc + c.bytes.len()) * 2 - + 2; + + 4; // disabled and unused rows. let total_rws_before_padding: usize = >::into(self.block_ctx.rwc) - 1; // -1 since rwc start from index `1` diff --git a/gadgets/src/binary_number.rs b/gadgets/src/binary_number.rs index cb5099504b5..788074c5fdd 100644 --- a/gadgets/src/binary_number.rs +++ b/gadgets/src/binary_number.rs @@ -59,6 +59,15 @@ where } } + /// Return the constant that represents a given value. To be compared with the value expression. + pub fn constant_expr(&self, value: T) -> Expression { + let f = value.as_bits().iter().fold( + F::ZERO, + |result, bit| if *bit { F::ONE } else { F::ZERO } + result * F::from(2), + ); + Expression::Constant(f) + } + /// Returns a function that can evaluate to a binary expression, that /// evaluates to 1 if value is equal to value as bits. The returned /// expression is of degree N. diff --git a/zkevm-circuits/src/copy_circuit.rs b/zkevm-circuits/src/copy_circuit.rs index ebea1507b71..7e9cc18759b 100644 --- a/zkevm-circuits/src/copy_circuit.rs +++ b/zkevm-circuits/src/copy_circuit.rs @@ -27,18 +27,26 @@ use bus_mapping::{ }; use eth_types::Field; use gadgets::{ - binary_number::BinaryNumberChip, + binary_number::{BinaryNumberChip, BinaryNumberConfig}, less_than::{LtChip, LtConfig, LtInstruction}, util::{and, not, or, Expr}, }; use halo2_proofs::{ circuit::{Layouter, Region, Value}, - plonk::{Advice, Column, ConstraintSystem, Error, Expression, Fixed, SecondPhase, Selector}, + plonk::{ + Advice, Column, ConstraintSystem, Error, Expression, Fixed, SecondPhase, Selector, + VirtualCells, + }, poly::Rotation, }; use itertools::Itertools; use std::marker::PhantomData; +// Rows to enable but not use, that can be queried safely by the last event. +const UNUSED_ROWS: usize = 2; +// Rows to disable, so they do not query into Halo2 reserved rows. +const DISABLED_ROWS: usize = 2; + /// The rw table shared between evm circuit and state circuit #[derive(Clone, Debug)] pub struct CopyCircuitConfig { @@ -161,6 +169,8 @@ impl SubCircuitConfig for CopyCircuitConfig { ]), ); + constrain_must_terminate(&mut cb, meta, q_enable, &tag); + let not_last_two_rows = 1.expr() - meta.query_advice(is_last, Rotation::cur()) - meta.query_advice(is_last, Rotation::next()); @@ -468,6 +478,29 @@ impl SubCircuitConfig for CopyCircuitConfig { } } +/// Verify that is_last goes to 1 at some point. +pub fn constrain_must_terminate( + cb: &mut BaseConstraintBuilder, + meta: &mut VirtualCells<'_, F>, + q_enable: Column, + tag: &BinaryNumberConfig, +) { + // If an event has started (tag != Padding on reader and writer rows), require q_enable=1 at the + // next step. This prevents querying rows where constraints are disabled. + // + // The tag is then copied to the next step by "rows[0].tag == rows[2].tag". Eventually, + // q_enable=0. By that point the tag must have switched to Padding, which is only possible with + // is_last=1. This guarantees that all the final conditions are checked. + let is_event = tag.value(Rotation::cur())(meta) - tag.constant_expr::(CopyDataType::Padding); + cb.condition(is_event, |cb| { + cb.require_equal( + "the next step is enabled", + meta.query_fixed(q_enable, Rotation(2)), + 1.expr(), + ); + }); +} + impl CopyCircuitConfig { /// Assign an individual copy event to the Copy Circuit. pub fn assign_copy_event( @@ -566,11 +599,11 @@ impl CopyCircuitConfig { ) -> Result<(), Error> { let copy_rows_needed = copy_events.iter().map(|c| c.bytes.len() * 2).sum::(); - // The `+ 2` is used to take into account the two extra empty copy rows needed - // to satisfy the query at `Rotation(2)` performed inside of the - // `rows[2].value == rows[0].value * r + rows[1].value` requirement in the RLC - // Accumulation gate. - assert!(copy_rows_needed + 2 <= max_copy_rows); + assert!( + copy_rows_needed + DISABLED_ROWS + UNUSED_ROWS <= max_copy_rows, + "copy rows not enough {copy_rows_needed} + 4 vs {max_copy_rows}" + ); + let filler_rows = max_copy_rows - copy_rows_needed - DISABLED_ROWS; let tag_chip = BinaryNumberChip::construct(self.copy_table.tag); let lt_chip = LtChip::construct(self.addr_lt_addr_end); @@ -597,12 +630,14 @@ impl CopyCircuitConfig { )?; } - for _ in 0..max_copy_rows - copy_rows_needed - 2 { - self.assign_padding_row(&mut region, &mut offset, false, &tag_chip, <_chip)?; + for _ in 0..filler_rows { + self.assign_padding_row(&mut region, &mut offset, true, &tag_chip, <_chip)?; } + assert_eq!(offset % 2, 0, "enabled rows must come in pairs"); - self.assign_padding_row(&mut region, &mut offset, true, &tag_chip, <_chip)?; - self.assign_padding_row(&mut region, &mut offset, true, &tag_chip, <_chip)?; + for _ in 0..DISABLED_ROWS { + self.assign_padding_row(&mut region, &mut offset, false, &tag_chip, <_chip)?; + } Ok(()) }, @@ -613,22 +648,20 @@ impl CopyCircuitConfig { &self, region: &mut Region, offset: &mut usize, - is_last_two: bool, + enabled: bool, tag_chip: &BinaryNumberChip, lt_chip: &LtChip, ) -> Result<(), Error> { - if !is_last_two { - // q_enable - region.assign_fixed( - || "q_enable", - self.q_enable, - *offset, - || Value::known(F::ONE), - )?; - // q_step - if *offset % 2 == 0 { - self.q_step.enable(region, *offset)?; - } + // q_enable + region.assign_fixed( + || "q_enable", + self.q_enable, + *offset, + || Value::known(if enabled { F::ONE } else { F::ZERO }), + )?; + // q_step + if enabled && *offset % 2 == 0 { + self.q_step.enable(region, *offset)?; } // is_first From c67b4e80e48858cb80b1e4fa0825aefad84013de Mon Sep 17 00:00:00 2001 From: DreamWuGit Date: Wed, 13 Sep 2023 11:58:28 +0800 Subject: [PATCH 7/9] handle gas uint overflow (ErrorGasUintOverflow) (#1564) ### Description currently ErrorGasUintOverflow is handled within normal OOG cases, so distribute ErrorGasUintOverflow checking within each OOG gadgets (oog sha3, oog static/dynamic memory expansion, oog log etc.) the `MemoryExpandedAddressGadget` is responsible for overflow status. ### Issue Link [_link issue here_] ### 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 ### How Has This Been Tested? all tests pass This PR contains: - Cleanup of xxxx, yyyy - Changed xxxx to yyyy in order to bla bla - Added xxxx function to ... - Refactored .... ``` --- .../src/evm_circuit/execution/callop.rs | 19 +- .../evm_circuit/execution/error_oog_call.rs | 78 +++++-- .../evm_circuit/execution/error_oog_log.rs | 221 +++++++++--------- .../execution/error_oog_memory_copy.rs | 144 +++++++++--- .../src/evm_circuit/util/common_gadget.rs | 28 ++- 5 files changed, 316 insertions(+), 174 deletions(-) diff --git a/zkevm-circuits/src/evm_circuit/execution/callop.rs b/zkevm-circuits/src/evm_circuit/execution/callop.rs index b05aaeeb375..e8127202a75 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, StepRws, }, }, @@ -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 ccb38f0a290..38aeae1db78 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_oog_call.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_oog_call.rs @@ -7,7 +7,8 @@ use crate::{ common_gadget::{CommonCallGadget, CommonErrorGadget}, constraint_builder::{ConstrainBuilderCommon, EVMConstraintBuilder}, math_gadget::{IsZeroGadget, LtGadget}, - CachedRegion, Cell, + memory_gadget::MemoryExpandedAddressGadget, + or, CachedRegion, Cell, }, }, table::CallContextFieldTag, @@ -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, @@ -54,13 +55,14 @@ impl ExecutionGadget for ErrorOOGCallGadget { let tx_id = cb.call_context(None, CallContextFieldTag::TxId); let is_static = cb.call_context(None, CallContextFieldTag::IsStatic); - let call_gadget = CommonCallGadget::construct( - cb, - is_call.expr(), - is_callcode.expr(), - is_delegatecall.expr(), - is_staticcall.expr(), - ); + let call_gadget: CommonCallGadget, false> = + CommonCallGadget::construct( + cb, + is_call.expr(), + is_callcode.expr(), + is_delegatecall.expr(), + is_staticcall.expr(), + ); // Add callee to access list let is_warm = cb.query_bool(); @@ -78,16 +80,24 @@ impl ExecutionGadget for ErrorOOGCallGadget { // Check if the amount of gas available is less than the amount of gas required let insufficient_gas = LtGadget::construct(cb, cb.curr.state.gas_left.expr(), gas_cost); + cb.require_equal( - "gas left is less than gas required", - insufficient_gas.expr(), + "Either Memory address is overflow or gas left is less than cost", + or::expr([ + call_gadget.cd_address.overflow(), + call_gadget.rd_address.overflow(), + insufficient_gas.expr(), + ]), 1.expr(), ); // Both CALL and CALLCODE opcodes have an extra stack pop `value` relative to // DELEGATECALL and STATICCALL. - let common_error_gadget = - CommonErrorGadget::construct(cb, opcode.expr(), cb.rw_counter_offset()); + let common_error_gadget = CommonErrorGadget::construct( + cb, + opcode.expr(), + 11.expr() + is_call.expr() + is_callcode.expr(), + ); Self { opcode, @@ -364,4 +374,46 @@ mod test { }); test_oog(&caller(OpcodeId::CALL, stack), &callee, true); } + + #[test] + fn test_oog_call_max_expanded_address() { + // 0xffffffff1 + 0xffffffff0 = 0x1fffffffe1 + // > MAX_EXPANDED_MEMORY_ADDRESS (0x1fffffffe0) + let stack = Stack { + gas: Word::MAX, + cd_offset: 0xffffffff1, + cd_length: 0xffffffff0, + rd_offset: 0xffffffff1, + rd_length: 0xffffffff0, + ..Default::default() + }; + let callee = callee(bytecode! { + PUSH32(Word::from(0)) + PUSH32(Word::from(0)) + STOP + }); + for opcode in TEST_CALL_OPCODES { + test_oog(&caller(*opcode, stack), &callee, true); + } + } + + #[test] + fn test_oog_call_max_u64_address() { + let stack = Stack { + gas: Word::MAX, + cd_offset: u64::MAX, + cd_length: u64::MAX, + rd_offset: u64::MAX, + rd_length: u64::MAX, + ..Default::default() + }; + let callee = callee(bytecode! { + PUSH32(Word::from(0)) + PUSH32(Word::from(0)) + STOP + }); + for opcode in TEST_CALL_OPCODES { + test_oog(&caller(*opcode, stack), &callee, true); + } + } } 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 ae7538033e1..4dbb9f4a242 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, + CommonMemoryAddressGadget, MemoryExpandedAddressGadget, MemoryExpansionGadget, }, - CachedRegion, Cell, + or, CachedRegion, Cell, }, witness::{Block, Call, ExecStep, Transaction}, }, table::CallContextFieldTag, - util::{word::WordExpr, Expr}, + util::Expr, }; use eth_types::{ evm_types::{GasCost, OpcodeId}, @@ -27,7 +27,7 @@ use halo2_proofs::{circuit::Value, plonk::Error}; pub(crate) struct ErrorOOGLogGadget { opcode: Cell, // memory address - memory_address: MemoryAddressGadget, + memory_address: MemoryExpandedAddressGadget, is_static_call: Cell, is_opcode_logn: LtGadget, // constrain gas left is less than gas cost @@ -43,12 +43,12 @@ impl ExecutionGadget for ErrorOOGLogGadget { fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); - let mstart = cb.query_word_unchecked(); - let msize = cb.query_memory_address(); + // memory expand gadget + let memory_address = MemoryExpandedAddressGadget::construct_self(cb); // Pop mstart_address, msize from stack - cb.stack_pop(mstart.to_word()); - cb.stack_pop(msize.to_word()); + cb.stack_pop(memory_address.offset_word()); + cb.stack_pop(memory_address.length_word()); // constrain not in static call let is_static_call = cb.call_context(None, CallContextFieldTag::IsStatic); @@ -62,9 +62,6 @@ impl ExecutionGadget for ErrorOOGLogGadget { 1.expr(), ); - // check memory - let memory_address = MemoryAddressGadget::construct(cb, mstart, msize); - // Calculate the next memory size and the gas cost for this memory // access let memory_expansion = MemoryExpansionGadget::construct(cb, [memory_address.address()]); @@ -78,13 +75,12 @@ impl ExecutionGadget for ErrorOOGLogGadget { // required let insufficient_gas = LtGadget::construct(cb, cb.curr.state.gas_left.expr(), gas_cost); cb.require_equal( - "gas left is less than gas required ", - insufficient_gas.expr(), + "Memory address is overflow or gas left is less than cost", + or::expr([memory_address.overflow(), insufficient_gas.expr()]), 1.expr(), ); - let common_error_gadget = - CommonErrorGadget::construct(cb, opcode.expr(), cb.rw_counter_offset()); + let common_error_gadget = CommonErrorGadget::construct(cb, opcode.expr(), 3.expr()); Self { opcode, @@ -117,8 +113,10 @@ impl ExecutionGadget for ErrorOOGLogGadget { .assign(region, offset, memory_start, msize)?; // Memory expansion - self.memory_expansion - .assign(region, offset, step.memory_word_size(), [memory_address])?; + let memory_expansion_cost = self + .memory_expansion + .assign(region, offset, step.memory_word_size(), [memory_address])? + .1; let topic_count = opcode.postfix().expect("opcode with postfix") as u64; assert!(topic_count <= 4); @@ -128,13 +126,13 @@ impl ExecutionGadget for ErrorOOGLogGadget { self.is_opcode_logn .assign(region, offset, F::from(topic_count), F::from(5u64))?; + let gas_cost = GasCost::LOG + + GasCost::LOG * topic_count + + 8 * MemoryExpandedAddressGadget::::length_value(memory_start, msize) + + memory_expansion_cost; // Gas insufficient check - self.insufficient_gas.assign( - region, - offset, - F::from(step.gas_left), - F::from(step.gas_cost), - )?; + self.insufficient_gas + .assign(region, offset, F::from(step.gas_left), F::from(gas_cost))?; self.common_error_gadget .assign(region, offset, block, call, step, 5)?; Ok(()) @@ -144,33 +142,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()); } - fn test_oog_log(tx: eth_types::Transaction) { + #[test] + fn test_oog_log_max_word_address() { + test_root(U256::MAX, U256::MAX); + } + + #[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 }; @@ -184,7 +218,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), @@ -194,34 +228,27 @@ 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].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(); - #[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 { @@ -258,46 +285,32 @@ mod test { Account::mock_100_ether(bytecode) } - 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 { Account::mock_code_balance(code) } - #[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 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::(), + ) + } + + 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 4077d2ef994..4a3b28ac96c 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, + CommonMemoryAddressGadget, MemoryCopierGasGadget, MemoryExpandedAddressGadget, MemoryExpansionGadget, }, - select, 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: MemoryExpandedAddressGadget, memory_expansion: MemoryExpansionGadget, memory_copier_gas: MemoryCopierGasGadget, insufficient_gas: LtGadget, @@ -67,9 +67,7 @@ impl ExecutionGadget for ErrorOOGMemoryCopyGadget { ], ); - let dst_offset = cb.query_word_unchecked(); let src_offset = cb.query_word_unchecked(); - 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(); @@ -91,11 +89,11 @@ impl ExecutionGadget for ErrorOOGMemoryCopyGadget { cb.stack_pop(external_address.to_word()); }); - cb.stack_pop(dst_offset.to_word()); + let dst_memory_addr = MemoryExpandedAddressGadget::construct_self(cb); + cb.stack_pop(dst_memory_addr.offset_word()); cb.stack_pop(src_offset.to_word()); - cb.stack_pop(copy_size.to_word()); + cb.stack_pop(dst_memory_addr.length_word()); - let dst_memory_addr = MemoryAddressGadget::construct(cb, dst_offset, copy_size); let memory_expansion = MemoryExpansionGadget::construct(cb, [dst_memory_addr.address()]); let memory_copier_gas = MemoryCopierGasGadget::construct( cb, @@ -123,8 +121,8 @@ impl ExecutionGadget for ErrorOOGMemoryCopyGadget { ); cb.require_equal( - "Gas left is less than gas cost", - insufficient_gas.expr(), + "Memory address is overflow or gas left is less than cost", + or::expr([dst_memory_addr.overflow(), insufficient_gas.expr()]), 1.expr(), ); @@ -196,7 +194,7 @@ impl ExecutionGadget for ErrorOOGMemoryCopyGadget { let memory_copier_gas = self.memory_copier_gas.assign( region, offset, - copy_size.as_u64(), + MemoryExpandedAddressGadget::::length_value(dst_offset, copy_size), memory_expansion_cost, )?; let constant_gas_cost = if is_extcodecopy { @@ -241,12 +239,14 @@ mod tests { evm_circuit::test::{rand_bytes, rand_word}, test_util::CircuitTestBuilder, }; + use bus_mapping::circuit_input_builder::FixedCParams; use eth_types::{ bytecode, evm_types::gas_utils::memory_copier_gas_cost, Bytecode, ToWord, U256, }; use itertools::Itertools; use mock::{ eth, test_ctx::helpers::account_0_code_account_1_no_code, TestContext, MOCK_ACCOUNTS, + MOCK_BLOCK_GAS_LIMIT, }; const TESTING_COMMON_OPCODES: &[OpcodeId] = &[ @@ -264,7 +264,8 @@ mod tests { .iter() .cartesian_product(TESTING_DST_OFFSET_COPY_SIZE_PAIRS.iter()) { - let testing_data = TestingData::new_for_common_opcode(*opcode, *dst_offset, *copy_size); + let testing_data = + TestingData::new_for_common_opcode(*opcode, *dst_offset, *copy_size, None); test_root(&testing_data); test_internal(&testing_data); @@ -277,20 +278,38 @@ mod tests { .iter() .cartesian_product(TESTING_DST_OFFSET_COPY_SIZE_PAIRS.iter()) { - let testing_data = TestingData::new_for_extcodecopy(*is_warm, *dst_offset, *copy_size); + let testing_data = + TestingData::new_for_extcodecopy(*is_warm, *dst_offset, *copy_size, None); test_root(&testing_data); test_internal(&testing_data); } } + #[test] + fn test_oog_memory_copy_max_expanded_address() { + // 0xffffffff1 + 0xffffffff0 = 0x1fffffffe1 + // > MAX_EXPANDED_MEMORY_ADDRESS (0x1fffffffe0) + test_for_edge_memory_size(0xffffffff1, 0xffffffff0); + } + + #[test] + fn test_oog_memory_copy_max_u64_address() { + test_for_edge_memory_size(u64::MAX, u64::MAX); + } + struct TestingData { bytecode: Bytecode, gas_cost: u64, } impl TestingData { - pub fn new_for_common_opcode(opcode: OpcodeId, dst_offset: u64, copy_size: u64) -> Self { + pub fn new_for_common_opcode( + opcode: OpcodeId, + dst_offset: u64, + copy_size: u64, + gas_cost: Option, + ) -> Self { let bytecode = bytecode! { PUSH32(copy_size) PUSH32(rand_word()) @@ -298,16 +317,23 @@ mod tests { .write_op(opcode) }; - let memory_word_size = (dst_offset + copy_size + 31) / 32; + let gas_cost = gas_cost.unwrap_or_else(|| { + let memory_word_size = (dst_offset + copy_size + 31) / 32; - let gas_cost = OpcodeId::PUSH32.constant_gas_cost() * 3 - + opcode.constant_gas_cost() - + memory_copier_gas_cost(0, memory_word_size, copy_size); + OpcodeId::PUSH32.constant_gas_cost() * 3 + + opcode.constant_gas_cost() + + memory_copier_gas_cost(0, memory_word_size, copy_size) + }); Self { bytecode, gas_cost } } - pub fn new_for_extcodecopy(is_warm: bool, dst_offset: u64, copy_size: u64) -> Self { + pub fn new_for_extcodecopy( + is_warm: bool, + dst_offset: u64, + copy_size: u64, + gas_cost: Option, + ) -> Self { let external_address = MOCK_ACCOUNTS[4]; let mut bytecode = bytecode! { @@ -318,12 +344,6 @@ mod tests { EXTCODECOPY }; - let memory_word_size = (dst_offset + copy_size + 31) / 32; - - let mut gas_cost = OpcodeId::PUSH32.constant_gas_cost() * 4 - + GasCost::COLD_ACCOUNT_ACCESS - + memory_copier_gas_cost(0, memory_word_size, copy_size); - if is_warm { bytecode.append(&bytecode! { PUSH32(copy_size) @@ -332,32 +352,59 @@ mod tests { PUSH32(external_address.to_word()) EXTCODECOPY }); - - gas_cost += OpcodeId::PUSH32.constant_gas_cost() * 4 - + GasCost::WARM_ACCESS - + memory_copier_gas_cost(memory_word_size, memory_word_size, copy_size); } + let gas_cost = gas_cost.unwrap_or_else(|| { + let memory_word_size = (dst_offset + copy_size + 31) / 32; + + let gas_cost = OpcodeId::PUSH32.constant_gas_cost() * 4 + + GasCost::COLD_ACCOUNT_ACCESS + + memory_copier_gas_cost(0, memory_word_size, copy_size); + + if is_warm { + gas_cost + + OpcodeId::PUSH32.constant_gas_cost() * 4 + + GasCost::WARM_ACCESS + + memory_copier_gas_cost(memory_word_size, memory_word_size, copy_size) + } else { + gas_cost + } + }); + Self { bytecode, gas_cost } } } fn test_root(testing_data: &TestingData) { + let gas_cost = GasCost::TX + // Decrease expected gas cost (by 1) to trigger out of gas error. + .checked_add(testing_data.gas_cost - 1) + .unwrap_or(MOCK_BLOCK_GAS_LIMIT); + let gas_cost = if gas_cost > MOCK_BLOCK_GAS_LIMIT { + MOCK_BLOCK_GAS_LIMIT + } else { + gas_cost + }; + let ctx = TestContext::<2, 1>::new( None, account_0_code_account_1_no_code(testing_data.bytecode.clone()), |mut txs, accs| { - // Decrease expected gas cost (by 1) to trigger out of gas error. txs[0] .from(accs[1].address) .to(accs[0].address) - .gas((GasCost::TX + testing_data.gas_cost - 1).into()); + .gas(gas_cost.into()); }, |block, _tx| block.number(0xcafe_u64), ) .unwrap(); - CircuitTestBuilder::new_from_test_ctx(ctx).run(); + CircuitTestBuilder::new_from_test_ctx(ctx) + .params(FixedCParams { + max_copy_rows: 1750, + ..Default::default() + }) + .run(); } fn test_internal(testing_data: &TestingData) { @@ -400,6 +447,37 @@ mod tests { ) .unwrap(); - CircuitTestBuilder::new_from_test_ctx(ctx).run(); + CircuitTestBuilder::new_from_test_ctx(ctx) + .params(FixedCParams { + max_copy_rows: 1750, + ..Default::default() + }) + .run(); + } + + fn test_for_edge_memory_size(dst_offset: u64, copy_size: u64) { + TESTING_COMMON_OPCODES.iter().for_each(|opcode| { + let testing_data = TestingData::new_for_common_opcode( + *opcode, + dst_offset, + copy_size, + Some(MOCK_BLOCK_GAS_LIMIT), + ); + + test_root(&testing_data); + test_internal(&testing_data); + }); + + [false, true].into_iter().for_each(|is_warm| { + let testing_data = TestingData::new_for_extcodecopy( + is_warm, + dst_offset, + copy_size, + Some(MOCK_BLOCK_GAS_LIMIT), + ); + + test_root(&testing_data); + test_internal(&testing_data); + }); } } diff --git a/zkevm-circuits/src/evm_circuit/util/common_gadget.rs b/zkevm-circuits/src/evm_circuit/util/common_gadget.rs index 3c6850e38cc..d5052e56138 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::{ @@ -653,15 +653,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>, @@ -672,7 +672,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, @@ -690,12 +692,10 @@ impl CommonCallGadget let gas_word = cb.query_word32(); let callee_address = cb.query_account_address(); let value = cb.query_word32(); - let cd_offset = cb.query_word_unchecked(); - let cd_length = cb.query_memory_address(); - let rd_offset = cb.query_word_unchecked(); - 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. @@ -709,10 +709,10 @@ impl CommonCallGadget // `CALL` and `CALLCODE` opcodes have an additional stack pop `value`. cb.condition(is_call + is_callcode, |cb| cb.stack_pop(value.to_word())); - cb.stack_pop(cd_offset.to_word()); - cb.stack_pop(cd_length.to_word()); - cb.stack_pop(rd_offset.to_word()); - cb.stack_pop(rd_length.to_word()); + cb.stack_pop(cd_address.offset_word()); + cb.stack_pop(cd_address.length_word()); + cb.stack_pop(rd_address.offset_word()); + cb.stack_pop(rd_address.length_word()); cb.stack_push(if IS_SUCCESS_CALL { Word::from_lo_unchecked(is_success.expr()) // is_success is bool } else { @@ -721,8 +721,6 @@ 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 memory_expansion = MemoryExpansionGadget::construct(cb, [cd_address.address(), rd_address.address()]); From f36df6e1cf28601709e51dc7d2cbc2e6850dcaeb Mon Sep 17 00:00:00 2001 From: Akase Cho Date: Thu, 14 Sep 2023 01:19:02 +0800 Subject: [PATCH 8/9] [fix] skip value is zero in end_tx (#1600) --- .../circuit_input_builder/input_state_ref.rs | 37 +++++++++++++++++++ bus-mapping/src/evm/opcodes/begin_end_tx.rs | 21 +++-------- 2 files changed, 42 insertions(+), 16 deletions(-) diff --git a/bus-mapping/src/circuit_input_builder/input_state_ref.rs b/bus-mapping/src/circuit_input_builder/input_state_ref.rs index c3b7519fbaa..43ff543398d 100644 --- a/bus-mapping/src/circuit_input_builder/input_state_ref.rs +++ b/bus-mapping/src/circuit_input_builder/input_state_ref.rs @@ -611,6 +611,43 @@ impl<'a> CircuitInputStateRef<'a> { ) } + /// Transfer to an address irreversibly. + pub fn transfer_to_irreversible( + &mut self, + step: &mut ExecStep, + receiver: Address, + receiver_exists: bool, + must_create: bool, + value: Word, + ) -> Result<(), Error> { + // If receiver doesn't exist, create it + if (!receiver_exists && !value.is_zero()) || must_create { + self.account_write( + step, + receiver, + AccountField::CodeHash, + CodeDB::empty_code_hash().to_word(), + Word::zero(), + )?; + } + if value.is_zero() { + // Skip transfer if value == 0 + return Ok(()); + } + let (_found, receiver_account) = self.sdb.get_account(&receiver); + let receiver_balance_prev = receiver_account.balance; + let receiver_balance = receiver_account.balance + value; + self.account_write( + step, + receiver, + AccountField::Balance, + receiver_balance, + receiver_balance_prev, + )?; + + Ok(()) + } + /// Fetch and return code for the given code hash from the code DB. pub fn code(&self, code_hash: H256) -> Result, Error> { self.code_db diff --git a/bus-mapping/src/evm/opcodes/begin_end_tx.rs b/bus-mapping/src/evm/opcodes/begin_end_tx.rs index 9a6656443fc..ec269980809 100644 --- a/bus-mapping/src/evm/opcodes/begin_end_tx.rs +++ b/bus-mapping/src/evm/opcodes/begin_end_tx.rs @@ -277,10 +277,8 @@ fn gen_end_tx_steps(state: &mut CircuitInputStateRef) -> Result if !found { return Err(Error::AccountNotFound(state.block.coinbase)); } - let coinbase_account = coinbase_account.clone(); - let coinbase_balance_prev = coinbase_account.balance; + let coinbase_exist = !coinbase_account.is_empty(); let coinbase_transfer_value = effective_tip * (state.tx.gas() - exec_step.gas_left); - let coinbase_balance = coinbase_balance_prev + coinbase_transfer_value; state.account_read( &mut exec_step, state.block.coinbase, @@ -291,21 +289,12 @@ fn gen_end_tx_steps(state: &mut CircuitInputStateRef) -> Result coinbase_account.code_hash.to_word() }, ); - if coinbase_account.is_empty() { - state.account_write( - &mut exec_step, - state.block.coinbase, - AccountField::CodeHash, - CodeDB::empty_code_hash().to_word(), - Word::zero(), - )?; - } - state.account_write( + state.transfer_to_irreversible( &mut exec_step, state.block.coinbase, - AccountField::Balance, - coinbase_balance, - coinbase_balance_prev, + coinbase_exist, + false, + coinbase_transfer_value, )?; // handle tx receipt tag From 1bc1eef6344fba33105b018216d7af5f04550cd8 Mon Sep 17 00:00:00 2001 From: Chih Cheng Liang Date: Thu, 14 Sep 2023 08:57:45 +0800 Subject: [PATCH 9/9] [MPTWG] Deadcode round (#1590) ### Description Remove dead code in MPTWG to improve readability. ### Issue Link ### Type of change Bug fix (non-breaking change which fixes an issue) (wait CI update in #1591) --- mpt-witness-generator/go.mod | 6 +- mpt-witness-generator/go.sum | 25 +- ...gen_witness_from_infura_blockchain_test.go | 190 -------------- .../gen_witness_from_local_blockchain_test.go | 245 ------------------ .../witness/gen_witness_transactions_test.go | 21 -- mpt-witness-generator/witness/leaf.go | 5 - .../witness/modified_extension_node.go | 38 --- mpt-witness-generator/witness/util.go | 28 -- 8 files changed, 19 insertions(+), 539 deletions(-) diff --git a/mpt-witness-generator/go.mod b/mpt-witness-generator/go.mod index e7a910f8101..ce4ba3832ef 100644 --- a/mpt-witness-generator/go.mod +++ b/mpt-witness-generator/go.mod @@ -3,8 +3,6 @@ module github.com/privacy-scaling-explorations/mpt-witness-generator go 1.16 require ( - github.com/VictoriaMetrics/fastcache v1.6.0 // indirect - github.com/ethereum/go-ethereum v1.10.8 // indirect - github.com/holiman/uint256 v1.2.0 // indirect - golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 // indirect + github.com/ethereum/go-ethereum v1.10.8 + golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 ) diff --git a/mpt-witness-generator/go.sum b/mpt-witness-generator/go.sum index 5a8c30548f9..950942ce268 100644 --- a/mpt-witness-generator/go.sum +++ b/mpt-witness-generator/go.sum @@ -43,6 +43,7 @@ github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBA github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/apache/arrow/go/arrow v0.0.0-20191024131854-af6fa24be0db/go.mod h1:VTxUBvSJ3s3eHAg65PNgrsn5BtqCRPdmyXh6rAfdxN0= @@ -87,8 +88,8 @@ github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV github.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea h1:j4317fAZh7X6GqbFowYdYdI0L9bwxL07jyPZIdepyZ0= github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= github.com/deepmap/oapi-codegen v1.6.0/go.mod h1:ryDa9AgbELGeB+YEXE1dR53yAjHwFvE9iAUlWl9Al3M= github.com/deepmap/oapi-codegen v1.8.2/go.mod h1:YLgSKSDv/bZQB7N4ws6luhozi3cEdRktEqrX88CvjIw= @@ -99,7 +100,6 @@ github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55k github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/dop251/goja v0.0.0-20200721192441-a695b0cdd498/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA= github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts= -github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= @@ -109,6 +109,7 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= github.com/getkin/kin-openapi v0.53.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= @@ -119,8 +120,10 @@ github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1T github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0 h1:Wz+5lgoB0kkuqLEc6NVmwRknTKP6dTGbSqvhZtBI/j0= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-ole/go-ole v1.2.1 h1:2lOsA72HgjxAuMlKpFiCbHTvu44PIVkZ5hqm3RSdI/E= github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= @@ -176,16 +179,13 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/graph-gophers/graphql-go v0.0.0-20201113091052-beb923fada29/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs= github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= -github.com/holiman/uint256 v1.2.0 h1:gpSYcPLWGv4sG43I2mVLiDZCNDh/EpGjSk8tmtxitHM= github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huin/goupnp v1.0.2/go.mod h1:0dxJBVBHqTMjIUMkESDTNgOOx/Mw5wYIfyFmdzSamkM= @@ -214,7 +214,6 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1 github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jsternberg/zap-logfmt v1.0.0/go.mod h1:uvPs/4X51zdkcm5jXl5SYoN+4RK21K8mysFmDaM/h+o= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/julienschmidt/httprouter v1.2.0 h1:TDTW5Yz1mjftljbcKqRcrYhd4XeOoI98t+9HbQbYf7g= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/jwilder/encoding v0.0.0-20170811194829-b4e1701a28ef/go.mod h1:Ct9fl0F6iIOGgxJ5npU/IUOhOhqlVrGjyIZc8/MagT0= @@ -227,6 +226,7 @@ github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM52 github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6/go.mod h1:+ZoRqAPRLkC4NPOvfYeR5KNOrY6TD+/sAC3HXPZgDYg= github.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -235,7 +235,6 @@ github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+ github.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4FW1e6jwpg= github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= -github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -262,6 +261,7 @@ github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0= github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= +github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= @@ -269,9 +269,11 @@ github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6 github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.0.3-0.20180606204148-bd9c31933947/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= @@ -281,12 +283,12 @@ github.com/peterh/liner v1.0.1-0.20180619022028-8c1271fcf47f/go.mod h1:xIteQHvHu github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= -github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/term v0.0.0-20180730021639-bffc007b7fd5/go.mod h1:eCbImbZ95eXtAUIbLAuAVnBnwf83mjf6QIVH8SHYwqQ= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= @@ -326,6 +328,7 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954 h1:xQdMZ1WLrgkkvOZ/LDQxjVxMLdby7osSh4ZEVa5sIjs= github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954/go.mod h1:u2MKkTVTVJWe5D1rCvame8WqhBd88EuIwODJZ1VHCPM= @@ -410,6 +413,7 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -471,6 +475,7 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -506,6 +511,7 @@ golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= @@ -557,6 +563,7 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -565,7 +572,9 @@ gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/mpt-witness-generator/witness/gen_witness_from_infura_blockchain_test.go b/mpt-witness-generator/witness/gen_witness_from_infura_blockchain_test.go index 93e72ff8e37..a74695d24ce 100644 --- a/mpt-witness-generator/witness/gen_witness_from_infura_blockchain_test.go +++ b/mpt-witness-generator/witness/gen_witness_from_infura_blockchain_test.go @@ -2079,196 +2079,6 @@ func TestLeafWithMoreNibbles(t *testing.T) { oracle.PreventHashingInSecureTrie = false } -// Note: this requires MockProver with config param 11 -/* -func TestNonHashedBranchInBranch(t *testing.T) { - blockNum := 0 - blockNumberParent := big.NewInt(int64(blockNum)) - blockHeaderParent := oracle.PrefetchBlock(blockNumberParent, true, nil) - database := state.NewDatabase(blockHeaderParent) - statedb, _ := state.New(blockHeaderParent.Root, database, nil) - addr := common.HexToAddress("0x50efbf12580138bc623c95757286df4e24eb81c9") - - statedb.DisableLoadingRemoteAccounts() - - statedb.CreateAccount(addr) - - oracle.PreventHashingInSecureTrie = true // to store the unchanged key - - val1 := common.BigToHash(big.NewInt(int64(1))) - - key1Hex := "0x1000000000000000000000000000000000000000000000000000000000000000" - key2Hex := "0x2000000000000000000000000000000000000000000000000000000000000000" - key1 := common.HexToHash(key1Hex) - key2 := common.HexToHash(key2Hex) - fmt.Println(key2) - - statedb.SetState(addr, key2, val1) - - iters := 57 // making the last branch shorter than 32 bytes - for i := 0; i < iters; i++ { - fmt.Println("====") - fmt.Println(key1) - - statedb.SetState(addr, key1, val1) - - if i == iters - 1 { - break - } - - key1Hex = replaceAtIndex(key1Hex, 49, i + 3) // 49 is 1, 50 is 2, ... - key1 = common.HexToHash(key1Hex) - } - - statedb.IntermediateRoot(false) - - val := common.BigToHash(big.NewInt(int64(17))) - trieMod := TrieModification{ - Type: StorageChanged, - Key: key1, - Value: val, - Address: addr, - } - trieModifications := []TrieModification{trieMod} - - GenerateProof("NonHashedBranchInBranch", trieModifications, statedb) - - oracle.PreventHashingInSecureTrie = false -} - -func replaceAtIndex(in string, r rune, i int) string { - out := []rune(in) - out[i] = r - return string(out) -} - -// Note: this requires MockProver with config param 11 -func TestNonHashedExtensionNodeInBranch(t *testing.T) { - blockNum := 0 - blockNumberParent := big.NewInt(int64(blockNum)) - blockHeaderParent := oracle.PrefetchBlock(blockNumberParent, true, nil) - database := state.NewDatabase(blockHeaderParent) - statedb, _ := state.New(blockHeaderParent.Root, database, nil) - addr := common.HexToAddress("0x50efbf12580138bc623c95757286df4e24eb81c9") - - statedb.DisableLoadingRemoteAccounts() - - statedb.CreateAccount(addr) - - oracle.PreventHashingInSecureTrie = true // to store the unchanged key - - val1 := common.BigToHash(big.NewInt(int64(1))) - - key1Hex := "0x1000000000000000000000000000000000000000000000000000000000000000" - key2Hex := "0x2000000000000000000000000000000000000000000000000000000000000000" - key1 := common.HexToHash(key1Hex) - key2 := common.HexToHash(key2Hex) - fmt.Println(key2) - - statedb.SetState(addr, key2, val1) - - iters := 58 // make the extension node shorter than 32 - for i := 0; i < iters; i++ { - statedb.SetState(addr, key1, val1) - - if i == iters - 1 { - break - } - - makeExtension := false - if i == iters - 2 { - makeExtension = true - } - - if !makeExtension { - key1Hex = replaceAtIndex(key1Hex, 49, i + 3) - } else { - key1Hex = replaceAtIndex(key1Hex, 49, i + 1 + 3) - } - - key1 = common.HexToHash(key1Hex) - } - - statedb.IntermediateRoot(false) - - val := common.BigToHash(big.NewInt(int64(17))) - trieMod := TrieModification{ - Type: StorageChanged, - Key: key1, - Value: val, - Address: addr, - } - trieModifications := []TrieModification{trieMod} - - GenerateProof("NonHashedExtensionNodeInBranch", trieModifications, statedb) - - oracle.PreventHashingInSecureTrie = false -} - -// Note: this requires MockProver with config param 11 -func TestNonHashedExtensionNodeInBranchTwoNibbles(t *testing.T) { - blockNum := 0 - blockNumberParent := big.NewInt(int64(blockNum)) - blockHeaderParent := oracle.PrefetchBlock(blockNumberParent, true, nil) - database := state.NewDatabase(blockHeaderParent) - statedb, _ := state.New(blockHeaderParent.Root, database, nil) - addr := common.HexToAddress("0x50efbf12580138bc623c95757286df4e24eb81c9") - - statedb.DisableLoadingRemoteAccounts() - - statedb.CreateAccount(addr) - - oracle.PreventHashingInSecureTrie = true // to store the unchanged key - - val1 := common.BigToHash(big.NewInt(int64(1))) - - key1Hex := "0x1000000000000000000000000000000000000000000000000000000000000000" - key2Hex := "0x2000000000000000000000000000000000000000000000000000000000000000" - key1 := common.HexToHash(key1Hex) - key2 := common.HexToHash(key2Hex) - fmt.Println(key2) - - statedb.SetState(addr, key2, val1) - - iters := 58 // make the extension node shorter than 32 - for i := 0; i < iters; i++ { - statedb.SetState(addr, key1, val1) - - if i == iters - 1 { - break - } - - makeExtension := false - if i == iters - 2 { - makeExtension = true - } - - if !makeExtension { - key1Hex = replaceAtIndex(key1Hex, 49, i + 3) - } else { - key1Hex = replaceAtIndex(key1Hex, 49, i + 2 + 3) // +2 to have two nibbles - } - - key1 = common.HexToHash(key1Hex) - } - - statedb.IntermediateRoot(false) - - val := common.BigToHash(big.NewInt(int64(17))) - trieMod := TrieModification{ - Type: StorageChanged, - Key: key1, - Value: val, - Address: addr, - } - trieModifications := []TrieModification{trieMod} - - GenerateProof("NonHashedExtensionNodeInBranchTwoNibbles", trieModifications, statedb) - - oracle.PreventHashingInSecureTrie = false -} -*/ - func TestBranchAfterExtNode(t *testing.T) { blockNum := 0 blockNumberParent := big.NewInt(int64(blockNum)) diff --git a/mpt-witness-generator/witness/gen_witness_from_local_blockchain_test.go b/mpt-witness-generator/witness/gen_witness_from_local_blockchain_test.go index aab3b977340..8b9345b1a44 100644 --- a/mpt-witness-generator/witness/gen_witness_from_local_blockchain_test.go +++ b/mpt-witness-generator/witness/gen_witness_from_local_blockchain_test.go @@ -232,45 +232,6 @@ func TestAccountBranchPlaceholderInFirstLevel(t *testing.T) { database := state.NewDatabase(blockHeaderParent) statedb, _ := state.New(blockHeaderParent.Root, database, nil) - /* - for i := 0; i < 100000; i++ { - h := fmt.Sprintf("0xa21%d", i) - addr := common.HexToAddress(h) - - oracle.PrefetchAccount(statedb.Db.BlockNumber, addr, nil) - proof1, _, _, _, err := statedb.GetProof(addr) - check(err) - - statedb.CreateAccount(addr) - statedb.IntermediateRoot(false) - - // addrHash1 := crypto.Keccak256Hash(addr.Bytes()) - // addrHash1[31] = (addrHash1[31] + 1) % 255 // just some change - - // oracle.PrefetchAccount(statedb.Db.BlockNumber, addr1, nil) - // proof11, _, _, err := statedb.GetProofByHash(common.BytesToHash(addrHash1.Bytes())) - - statedb.CreateAccount(addr) - statedb.IntermediateRoot(false) - - proof2, _, _, _, err := statedb.GetProof(addr) - check(err) - if len(proof1) + 1 == len(proof2) && len(proof1) == 1 { - elems, _, err := rlp.SplitList(proof1[len(proof1)-1]) - if err != nil { - fmt.Println("decode error", err) - } - switch c, _ := rlp.CountValues(elems); c { - case 2: - fmt.Println("2") - case 17: - default: - fmt.Println("invalid number of list elements") - } - } - } - */ - h := fmt.Sprintf("0xab%d", 0) addr := common.HexToAddress(h) // Implicitly create account such that the account from the first level will be @@ -607,209 +568,3 @@ func TestExtNodeInsertedBefore6After1FirstLevel(t *testing.T) { ExtNodeInserted(key1, key2, key3, "ExtNodeInsertedBefore6After1FirstLevel") } - -/* -func TestExtNodeDeletedBefore6After1FirstLevel(t *testing.T) { - key1 := common.HexToHash("0x1234561000000000000000000000000000000000000000000000000000000000") - // key1 bytes: [1 * 16 + 2, 3 * 16 + 4, 5 * 16 + 6, 1 * 16, 0, ..., 0] - - key2 := common.HexToHash("0x1234563000000000000000000000000000000000000000000000000000000000") - // key2 bytes: [1 * 16 + 2, 3 * 16 + 4, 5 * 16 + 6, 3 * 16, 0, ..., 0] - // We now have an extension node with nibbles: [1, 2, 3, 4, 5, 6]. - - key3 := common.HexToHash("0x1234400000000000000000000000000000000000000000000000000000000000") - - ExtNodeDeleted(key1, key2, key3, "ExtNodeDeletedBefore6After1FirstLevel") -} - -func TestExtNodeInsertedBefore6After2FirstLevel(t *testing.T) { - key1 := common.HexToHash("0x1234561000000000000000000000000000000000000000000000000000000000") - // key1 bytes: [1 * 16 + 2, 3 * 16 + 4, 5 * 16 + 6, 1 * 16, 0, ..., 0] - - key2 := common.HexToHash("0x1234563000000000000000000000000000000000000000000000000000000000") - // key2 bytes: [1 * 16 + 2, 3 * 16 + 4, 5 * 16 + 6, 3 * 16, 0, ..., 0] - - key3 := common.HexToHash("0x1235400000000000000000000000000000000000000000000000000000000000") - // key3 bytes: [1 * 16 + 2, 3 * 16 + 5, 4 * 16 + 0, 0, ..., 0] - - ExtNodeInserted(key1, key2, key3, "ExtNodeInsertedBefore6After2FirstLevel") -} - -func TestExtNodeInsertedBefore6After4FirstLevel(t *testing.T) { - key1 := common.HexToHash("0x1234561000000000000000000000000000000000000000000000000000000000") - // key1 bytes: [1 * 16 + 2, 3 * 16 + 4, 5 * 16 + 6, 1 * 16, 0, ..., 0] - - key2 := common.HexToHash("0x1234563000000000000000000000000000000000000000000000000000000000") - // key2 bytes: [1 * 16 + 2, 3 * 16 + 4, 5 * 16 + 6, 3 * 16, 0, ..., 0] - - key3 := common.HexToHash("0x1635400000000000000000000000000000000000000000000000000000000000") - - ExtNodeInserted(key1, key2, key3, "ExtNodeInsertedBefore6After4FirstLevel") -} - -func TestExtNodeInsertedBefore5After3FirstLevel(t *testing.T) { - key1 := common.HexToHash("0x2345610000000000000000000000000000000000000000000000000000000000") - key2 := common.HexToHash("0x2345630000000000000000000000000000000000000000000000000000000000") - key3 := common.HexToHash("0x2635400000000000000000000000000000000000000000000000000000000000") - - ExtNodeInserted(key1, key2, key3, "ExtNodeInsertedBefore5After3FirstLevel") -} - -func TestExtNodeInsertedBefore5After2FirstLevel(t *testing.T) { - key1 := common.HexToHash("0x2345610000000000000000000000000000000000000000000000000000000000") - key2 := common.HexToHash("0x2345630000000000000000000000000000000000000000000000000000000000") - key3 := common.HexToHash("0x2335400000000000000000000000000000000000000000000000000000000000") - - ExtNodeInserted(key1, key2, key3, "ExtNodeInsertedBefore5After2FirstLevel") -} - -func TestExtNodeInsertedBefore5After1FirstLevel(t *testing.T) { - key1 := common.HexToHash("0x2345610000000000000000000000000000000000000000000000000000000000") - key2 := common.HexToHash("0x2345630000000000000000000000000000000000000000000000000000000000") - key3 := common.HexToHash("0x2343540000000000000000000000000000000000000000000000000000000000") - - ExtNodeInserted(key1, key2, key3, "ExtNodeInsertedBefore5After1FirstLevel") -} - -func TestExtNodeInsertedBefore4After1(t *testing.T) { - oracle.NodeUrl = oracle.LocalUrl - - blockNum := 0 - blockNumberParent := big.NewInt(int64(blockNum)) - blockHeaderParent := oracle.PrefetchBlock(blockNumberParent, true, nil) - database := state.NewDatabase(blockHeaderParent) - statedb, _ := state.New(blockHeaderParent.Root, database, nil) - addr := common.HexToAddress("0x50efbf12580138bc623c95757286df4e24eb81c9") - - statedb.DisableLoadingRemoteAccounts() - - statedb.CreateAccount(addr) - - oracle.PreventHashingInSecureTrie = true // to store the unchanged key - - val0 := common.BigToHash(big.NewInt(int64(1))) - key0 := common.HexToHash("0x1000000000000000000000000000000000000000000000000000000000000000") - statedb.SetState(addr, key0, val0) - - key00 := common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000") - statedb.SetState(addr, key00, val0) - - key1 := common.HexToHash("0x1234561000000000000000000000000000000000000000000000000000000000") - // key1 bytes: [1 * 16 + 2, 3 * 16 + 4, 5 * 16 + 6, 1 * 16, 0, ..., 0] - - // make the value long to have a hashed branch - v1 := common.FromHex("0xbbefaa12580138bc263c95757826df4e24eb81c9aaaaaaaaaaaaaaaaaaaaaaaa") - val1 := common.BytesToHash(v1) - // val1 := common.BigToHash(big.NewInt(int64(1))) - statedb.SetState(addr, key1, val1) - - key2 := common.HexToHash("0x1234563000000000000000000000000000000000000000000000000000000000") - // key2 bytes: [1 * 16 + 2, 3 * 16 + 4, 5 * 16 + 6, 3 * 16, 0, ..., 0] - - // We now have an extension node with nibbles: [3, 4, 5, 6]. - - statedb.SetState(addr, key2, val1) - statedb.IntermediateRoot(false) - - key3 := common.HexToHash("0x1234400000000000000000000000000000000000000000000000000000000000") - // After adding key3 we will have an extension node with nibbles [3, 4] - // and another one with nibbles [5, 6]. - - v1 = common.FromHex("0xbb") - val := common.BytesToHash(v1) - trieMod := TrieModification{ - Type: StorageMod, - Key: key3, - Value: val, - Address: addr, - } - trieModifications := []TrieModification{trieMod} - - prepareWitness("ExtNodeInsertedBefore4After1", trieModifications, statedb) - - oracle.PreventHashingInSecureTrie = false -} - -func TestExtNodeDeletedBefore4After1(t *testing.T) { - oracle.NodeUrl = oracle.LocalUrl - - blockNum := 0 - blockNumberParent := big.NewInt(int64(blockNum)) - blockHeaderParent := oracle.PrefetchBlock(blockNumberParent, true, nil) - database := state.NewDatabase(blockHeaderParent) - statedb, _ := state.New(blockHeaderParent.Root, database, nil) - addr := common.HexToAddress("0x50efbf12580138bc623c95757286df4e24eb81c9") - - statedb.DisableLoadingRemoteAccounts() - - statedb.CreateAccount(addr) - - oracle.PreventHashingInSecureTrie = true // to store the unchanged key - - val0 := common.BigToHash(big.NewInt(int64(1))) - key0 := common.HexToHash("0x1000000000000000000000000000000000000000000000000000000000000000") - statedb.SetState(addr, key0, val0) - - key00 := common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000") - statedb.SetState(addr, key00, val0) - - key1 := common.HexToHash("0x1234561000000000000000000000000000000000000000000000000000000000") - - // make the value long to have a hashed branch - v1 := common.FromHex("0xbbefaa12580138bc263c95757826df4e24eb81c9aaaaaaaaaaaaaaaaaaaaaaaa") - val1 := common.BytesToHash(v1) - statedb.SetState(addr, key1, val1) - - key2 := common.HexToHash("0x1234563000000000000000000000000000000000000000000000000000000000") - statedb.SetState(addr, key2, val1) - - key3 := common.HexToHash("0x1234400000000000000000000000000000000000000000000000000000000000") - statedb.SetState(addr, key3, val1) - statedb.IntermediateRoot(false) - - val := common.Hash{} // empty value deletes the key - trieMod := TrieModification{ - Type: StorageMod, - Key: key3, - Value: val, - Address: addr, - } - trieModifications := []TrieModification{trieMod} - - prepareWitness("ExtNodeDeletedBefore4After1", trieModifications, statedb) - - oracle.PreventHashingInSecureTrie = false -} - -func TestExtNodeInNewBranchFirstLevel(t *testing.T) { - key1 := common.HexToHash("0x2345610000000000000000000000000000000000000000000000000000000000") - key2 := common.HexToHash("0x2345630000000000000000000000000000000000000000000000000000000000") - key3 := common.HexToHash("0x6354000000000000000000000000000000000000000000000000000000000000") - - ExtNodeInserted(key1, key2, key3, "ExtNodeInsertedInNewBranchFirstLevel") -} - -func TestExtNodeDeletedBranchDeletedFirstLevel(t *testing.T) { - key1 := common.HexToHash("0x2345610000000000000000000000000000000000000000000000000000000000") - key2 := common.HexToHash("0x2345630000000000000000000000000000000000000000000000000000000000") - key3 := common.HexToHash("0x6354000000000000000000000000000000000000000000000000000000000000") - - ExtNodeDeleted(key1, key2, key3, "ExtNodeDeletedBranchDeletedFirstLevel") -} - -func TestExtNodeInsertedExtShortIsBranchFirstLevel(t *testing.T) { - key1 := common.HexToHash("0x2345610000000000000000000000000000000000000000000000000000000000") - key2 := common.HexToHash("0x2345630000000000000000000000000000000000000000000000000000000000") - key3 := common.HexToHash("0x2345100000000000000000000000000000000000000000000000000000000000") - - ExtNodeInserted(key1, key2, key3, "ExtNodeInsertedExtShortIsBranchFirstLevel") -} - -func TestExtNodeDeletedExtShortIsBranchFirstLevel(t *testing.T) { - key1 := common.HexToHash("0x2345610000000000000000000000000000000000000000000000000000000000") - key2 := common.HexToHash("0x2345630000000000000000000000000000000000000000000000000000000000") - key3 := common.HexToHash("0x2345100000000000000000000000000000000000000000000000000000000000") - - ExtNodeDeleted(key1, key2, key3, "ExtNodeInsertedExtShortIsBranchFirstLevel") -} -*/ diff --git a/mpt-witness-generator/witness/gen_witness_transactions_test.go b/mpt-witness-generator/witness/gen_witness_transactions_test.go index 442885246c8..51c10cd6dd0 100644 --- a/mpt-witness-generator/witness/gen_witness_transactions_test.go +++ b/mpt-witness-generator/witness/gen_witness_transactions_test.go @@ -15,22 +15,6 @@ import ( "github.com/privacy-scaling-explorations/mpt-witness-generator/types" ) -func createTransaction(ind int) *types.Transaction { - key, _ := crypto.GenerateKey() - signer := types.LatestSigner(params.TestChainConfig) - - amount := math.BigPow(2, int64(ind)) - price := big.NewInt(300000) - data := make([]byte, 100) - tx := types.NewTransaction(uint64(ind), common.Address{}, amount, 123457, price, data) - signedTx, err := types.SignTx(tx, signer, key) - if err != nil { - panic(err) - } - - return signedTx -} - func TestTransactions(t *testing.T) { t.Skip("failing test") txs := make([]*types.Transaction, 70) @@ -54,11 +38,6 @@ func TestTransactions(t *testing.T) { stackTrie.UpdateAndGetProofs(db, types.Transactions(txs)) - /* - rowsTransactions, toBeHashedAcc, _ := - convertProofToWitness(statedb, addr, accountProof, accountProof1, aExtNibbles1, aExtNibbles2, accountAddr, aNode, true, tMod.Type == NonExistingAccount, false, isShorterProofLastLeaf) - */ - fmt.Println("===") } diff --git a/mpt-witness-generator/witness/leaf.go b/mpt-witness-generator/witness/leaf.go index 39f36be95e8..b22ae4c85d6 100644 --- a/mpt-witness-generator/witness/leaf.go +++ b/mpt-witness-generator/witness/leaf.go @@ -446,11 +446,6 @@ func prepareStorageLeafInfo(row []byte, valueIsZero, isPlaceholder bool) ([]byte setValue(keyLen, offset) } else { // [196,130,32,0,1] - /* - keyLen := row[1] - 128 - copy(key, row[:keyLen+2]) - copy(value, row[keyLen+2:]) - */ keyRlpLen = 1 keyLen := row[1] - 128 keyRlp = row[:keyRlpLen] diff --git a/mpt-witness-generator/witness/modified_extension_node.go b/mpt-witness-generator/witness/modified_extension_node.go index ad4d0073de0..19b357828d3 100644 --- a/mpt-witness-generator/witness/modified_extension_node.go +++ b/mpt-witness-generator/witness/modified_extension_node.go @@ -41,11 +41,6 @@ func prepareModExtensionNode(statedb *state.StateDB, addr common.Address, rows * extNodeSelectors = append(extNodeSelectors, 24) _, extListRlpBytesS, extValuesS := prepareExtensions(extNibbles, extensionNodeInd, longExtNode, longExtNode) - /* - b := []byte{249, 1, 49, 128} // We don't really need a branch info (only extension node). - longNode := prepareBranchNode(b, b, longExtNode, longExtNode, extListRlpBytes, extValues, - key[keyIndex], key[keyIndex], branchC16, branchC1, false, false, true, false, false) - */ var extRows [][]byte // We need to prove the old extension node is in S proof (when ext. node inserted). @@ -61,7 +56,6 @@ func prepareModExtensionNode(statedb *state.StateDB, addr common.Address, rows * longNibbles := getExtensionNodeNibbles(longExtNode) ind := byte(keyIndex) + byte(numberOfNibbles) // where the old and new extension nodes start to be different - // diffNibble := oldNibbles[ind] longExtNodeKey := make([]byte, len(key)) copy(longExtNodeKey, key) // We would like to retrieve the shortened extension node from the trie via GetProof or @@ -91,13 +85,6 @@ func prepareModExtensionNode(statedb *state.StateDB, addr common.Address, rows * } var shortExtNode []byte - /* - extNodeSelectors1 := make([]byte, rowLen) - emptyExtRows := prepareEmptyExtensionRows(false, true) - extensionRowS1 := emptyExtRows[0] - extensionRowC1 := emptyExtRows[1] - */ - var extListRlpBytesC []byte var extValuesC [][]byte @@ -141,38 +128,13 @@ func prepareModExtensionNode(statedb *state.StateDB, addr common.Address, rows * // Enable `prepareExtensionRows` call: extNibbles = append(extNibbles, nibbles) - /* - var numberOfNibbles1 byte - numberOfNibbles1, extensionRowS1, extensionRowC1 = - prepareExtensionRows(extNibbles, extensionNodeInd + 1, shortExtNode, shortExtNode, false, true) - */ - _, extListRlpBytesC, extValuesC = prepareExtensions(extNibbles, extensionNodeInd+1, shortExtNode, shortExtNode) - /* - shortNode = prepareBranchNode(b, b, shortExtNode, shortExtNode, extListRlpBytes, extValues, - key[keyIndex], key[keyIndex], branchC16, branchC1, false, false, true, false, false) - - setExtNodeSelectors(extNodeSelectors1, shortExtNode, int(numberOfNibbles1), branchC16) - */ - // extNodeSelectors1 = append(extNodeSelectors1, 25) - } /* else { - if len1 > len2 { - // Needed only for len1 > len2 - (*rows)[len(*rows)-branchRows-9][driftedPos] = longNibbles[numberOfNibbles] - } - extNodeSelectors1 = append(extNodeSelectors1, 25) } - */ // The shortened extension node is needed as a witness to be able to check in a circuit // that the shortened extension node and newly added leaf (that causes newly inserted // extension node) are the only nodes in the newly inserted extension node. - /* - *rows = append(*rows, extNodeSelectors1) - *rows = append(*rows, extensionRowS1) - *rows = append(*rows, extensionRowC1) - */ listRlpBytes := [2][]byte{extListRlpBytesS, extListRlpBytesC} modExtensionNode := ModExtensionNode{ diff --git a/mpt-witness-generator/witness/util.go b/mpt-witness-generator/witness/util.go index 171a223dd77..f2adbb53d37 100644 --- a/mpt-witness-generator/witness/util.go +++ b/mpt-witness-generator/witness/util.go @@ -6,7 +6,6 @@ import ( "log" "os" "path/filepath" - "strconv" ) func check(err error) { @@ -15,33 +14,6 @@ func check(err error) { } } -func MatrixToJson(rows [][]byte) string { - // Had some problems with json.Marshal, so I just prepare json manually. - json := "[" - for i := 0; i < len(rows); i++ { - json += listToJson(rows[i]) - if i != len(rows)-1 { - json += "," - } - } - json += "]" - - return json -} - -func listToJson(row []byte) string { - json := "[" - for j := 0; j < len(row); j++ { - json += strconv.Itoa(int(row[j])) - if j != len(row)-1 { - json += "," - } - } - json += "]" - - return json -} - func StoreNodes(testName string, nodes []Node) { name := testName + ".json" path := "../generated_witnesses/" + name