diff --git a/Cargo.toml b/Cargo.toml index 8781d1ee6..914c0450a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,8 +57,8 @@ keywords = ["blockchain", "zksync", "zk", "risc-v"] categories = ["cryptography"] [workspace.dependencies] -zksync_os_evm_errors = { version = "0.0.10", default-features = false } -zksync_os_interface = { version = "0.0.10"} +zksync_os_evm_errors = { git = "https://github.com/matter-labs/zksync-os-interface", branch = "alocascio-prover-input-gen", default-features = false } +zksync_os_interface = { git = "https://github.com/matter-labs/zksync-os-interface", branch = "alocascio-prover-input-gen", version = "0.0.10"} risc_v_simulator = { git = "https://github.com/matter-labs/zksync-airbender", tag = "v0.4.3"} blake2s_u32 = { git = "https://github.com/matter-labs/zksync-airbender", tag = "v0.4.3"} diff --git a/api/src/lib.rs b/api/src/lib.rs index 913ebd84c..13aecf3ae 100644 --- a/api/src/lib.rs +++ b/api/src/lib.rs @@ -1,54 +1,5 @@ #![feature(allocator_api)] -use std::{path::PathBuf, str::FromStr}; - -use forward_system::run::{ - test_impl::{InMemoryPreimageSource, InMemoryTree}, - BlockContext, StorageCommitment, -}; -use oracle_provider::ReadWitnessSource; -use zksync_os_interface::traits::TxListSource; -pub mod helpers; - /// Runs the batch, and returns the output (that contains gas usage, transaction status etc.). -pub use forward_system::run::run_block; -use zk_ee::common_structs::da_commitment_scheme::DACommitmentScheme; -use zk_ee::common_structs::ProofData; - -/// Runs a block in RISC-V - using zksync_os binary - and returns the -/// witness that can be passed to the prover subsystem. -pub fn run_block_generate_witness( - block_context: BlockContext, - tree: InMemoryTree, - preimage_source: InMemoryPreimageSource, - tx_source: TxListSource, - proof_data: ProofData, - da_commitment_scheme: DACommitmentScheme, - zksync_os_bin_path: &str, -) -> Vec { - use forward_system::run::*; - - let oracle = make_oracle_for_proofs_and_dumps_for_init_data( - block_context, - tree, - preimage_source, - tx_source, - Some(proof_data), - Some(da_commitment_scheme), - false, - ); - - // We'll wrap the source, to collect all the reads. - let copy_source = ReadWitnessSource::new(oracle); - - let items = copy_source.get_read_items(); - // By default - enable diagnostics is false (which makes the test run faster). - let path = PathBuf::from_str(zksync_os_bin_path).unwrap(); - let output = zksync_os_runner::run(path, None, 1 << 36, copy_source); - - // We return 0s in case of failure. - assert_ne!(output, [0u32; 8]); - - let result = items.borrow().clone(); - result -} +pub use forward_system::run::{generate_proof_input, run_block}; +pub mod helpers; diff --git a/basic_system/src/system_functions/mod.rs b/basic_system/src/system_functions/mod.rs index eb5d6574e..fded162dc 100644 --- a/basic_system/src/system_functions/mod.rs +++ b/basic_system/src/system_functions/mod.rs @@ -29,9 +29,9 @@ fn bytereverse(input: &mut [u8]) { /// No std system functions implementations. /// All of them are following EVM specs(for precompiles and keccak opcode). /// -pub struct NoStdSystemFunctions; +pub struct NoStdSystemFunctions; -impl SystemFunctions for NoStdSystemFunctions { +impl SystemFunctions for NoStdSystemFunctions { type Keccak256 = keccak256::Keccak256Impl; type Sha256 = sha256::Sha256Impl; type Secp256k1ECRecover = ecrecover::EcRecoverImpl; @@ -47,6 +47,8 @@ impl SystemFunctions for NoStdSystemFunctions { type PointEvaluation = point_evaluation::PointEvaluationImpl; } -impl SystemFunctionsExt for NoStdSystemFunctions { - type ModExp = modexp::ModExpImpl; +impl SystemFunctionsExt + for NoStdSystemFunctions +{ + type ModExp = modexp::ModExpImpl; } diff --git a/basic_system/src/system_functions/modexp/delegation/bigint.rs b/basic_system/src/system_functions/modexp/advice/bigint.rs similarity index 90% rename from basic_system/src/system_functions/modexp/delegation/bigint.rs rename to basic_system/src/system_functions/modexp/advice/bigint.rs index 4b2b9b33d..af39d7f3c 100644 --- a/basic_system/src/system_functions/modexp/delegation/bigint.rs +++ b/basic_system/src/system_functions/modexp/advice/bigint.rs @@ -1,15 +1,15 @@ // Representation of big integers using primitives that are friendly for our delegations extern crate alloc; -#[cfg(any(all(target_arch = "riscv32", feature = "proving"), test))] -use super::super::{ModExpAdviceParams, MODEXP_ADVICE_QUERY_ID}; +use super::super::MODEXP_ADVICE_QUERY_ID; use super::u256::*; +use crate::system_functions::modexp::ModExpAdviceParams64; use alloc::vec::Vec; use core::alloc::Allocator; use core::fmt::Debug; use core::mem::MaybeUninit; use crypto::{bigint_op_delegation_raw, bigint_op_delegation_with_carry_bit_raw, BigIntOps}; -#[cfg(any(all(target_arch = "riscv32", feature = "proving"), test))] +use ruint::aliases::U256; use zk_ee::oracle::IOOracle; // There is a small choice to make - either we do exponentiation walking as via LE or BE exponent. @@ -812,32 +812,32 @@ pub(crate) mod naive_advisor { } } -#[cfg(any(all(target_arch = "riscv32", feature = "proving"), test))] pub(crate) struct OracleAdvisor<'a, O: IOOracle> { pub(crate) inner: &'a mut O, } -#[cfg(any(all(target_arch = "riscv32", feature = "proving"), test))] fn write_bigint( it: &mut impl ExactSizeIterator, mut to_consume: usize, dst: &mut BigintRepr, ) { - const { - assert!(core::mem::size_of::() == core::mem::size_of::()); - } // NOTE: even if oracle overstates the number of digits (so - iterator length), it is not important // as long as caller checks that number of digits is within bounds of soundness unsafe { - let num_digits = to_consume.next_multiple_of(8) / 8; + const BIGINT_DIGIT_USIZE_SIZE: usize = U256::BYTES / core::mem::size_of::(); + let num_digits = + to_consume.next_multiple_of(BIGINT_DIGIT_USIZE_SIZE) / BIGINT_DIGIT_USIZE_SIZE; let dst_capacity = dst.clear_as_capacity_mut(); for dst in dst_capacity[..num_digits].iter_mut() { - let dst: *mut u32 = dst.as_mut_ptr().cast::<[u32; 8]>().cast(); - for i in 0..8 { + let dst: *mut usize = dst + .as_mut_ptr() + .cast::<[usize; BIGINT_DIGIT_USIZE_SIZE]>() + .cast(); + for i in 0..BIGINT_DIGIT_USIZE_SIZE { if to_consume > 0 { to_consume -= 1; let digit = it.next().unwrap(); - dst.add(i).write(digit as u32); + dst.add(i).write(digit); } else { dst.add(i).write(0); } @@ -848,7 +848,6 @@ fn write_bigint( } } -#[cfg(any(all(target_arch = "riscv32", feature = "proving"), test))] impl<'a, O: IOOracle> ModexpAdvisor for OracleAdvisor<'a, O> { fn get_reduction_op_advice( &mut self, @@ -857,37 +856,79 @@ impl<'a, O: IOOracle> ModexpAdvisor for OracleAdvisor<'a, O> { quotient_dst: &mut BigintRepr, remainder_dst: &mut BigintRepr, ) { - let arg: ModExpAdviceParams = { - let a_len = a.digits; - let a_ptr = a.backing.as_ptr(); - - let modulus_len = m.digits; - let modulus_ptr = m.backing.as_ptr(); - - assert!(modulus_len > 0); - - ModExpAdviceParams { - op: 0, - a_ptr: a_ptr.addr() as u32, - a_len: a_len as u32, - b_ptr: 0, - b_len: 0, - modulus_ptr: modulus_ptr.addr() as u32, - modulus_len: modulus_len as u32, - } + // We use different advice params depending on architecture + // Both are mostly the same, main difference is the width of pointers + #[cfg(target_arch = "riscv32")] + let (mut it, q_len, r_len) = { + use crate::system_functions::modexp::ModExpAdviceParams; + let arg: ModExpAdviceParams = { + let a_len = a.digits; + let a_ptr = a.backing.as_ptr(); + + let modulus_len = m.digits; + let modulus_ptr = m.backing.as_ptr(); + + assert!(modulus_len > 0); + + ModExpAdviceParams { + op: 0, + a_ptr: a_ptr.addr() as u32, + a_len: a_len as u32, + b_ptr: 0, + b_len: 0, + modulus_ptr: modulus_ptr.addr() as u32, + modulus_len: modulus_len as u32, + } + }; + // We assume that oracle's response is well-formed lengths-wise, and we will check value-wise separately + let mut it = self + .inner + .raw_query( + MODEXP_ADVICE_QUERY_ID, + &((&arg as *const ModExpAdviceParams).addr() as u32), + ) + .unwrap(); + let q_len = it.next().expect("quotient length"); + let r_len = it.next().expect("remainder length"); + (it, q_len, r_len) }; - // We assume that oracle's response is well-formed lengths-wise, and we will check value-wise separately - let mut it = self - .inner - .raw_query( - MODEXP_ADVICE_QUERY_ID, - &((&arg as *const ModExpAdviceParams).addr() as u32), - ) - .unwrap(); - - let q_len = it.next().expect("quotient length"); - let r_len = it.next().expect("remainder length"); + #[cfg(not(target_arch = "riscv32"))] + let (mut it, q_len, r_len) = { + let arg: ModExpAdviceParams64 = { + let a_len = a.digits; + let a_ptr = a.backing.as_ptr(); + + let modulus_len = m.digits; + let modulus_ptr = m.backing.as_ptr(); + + assert!(modulus_len > 0); + + ModExpAdviceParams64 { + op: 0, + a_ptr: a_ptr.addr() as u64, + a_len: a_len as u64, + b_ptr: 0, + b_len: 0, + modulus_ptr: modulus_ptr.addr() as u64, + modulus_len: modulus_len as u64, + } + }; + // We assume that oracle's response is well-formed lengths-wise, and we will check value-wise separately + let mut it = self + .inner + .raw_query( + MODEXP_ADVICE_QUERY_ID, + &((&arg as *const ModExpAdviceParams64).addr() as u64), + ) + .unwrap(); + // Oracle provides lengths as u32, so in this case they are + // packed into a single usize + let packed_lens = it.next().expect("packed lengths"); + let q_len = (packed_lens & 0xFFFF_FFFF) as usize; + let r_len = (packed_lens >> 32) as usize; + (it, q_len / 2, r_len / 2) + }; let max_quotient_digits = if a.digits < m.digits { 0 @@ -899,10 +940,6 @@ impl<'a, O: IOOracle> ModexpAdvisor for OracleAdvisor<'a, O> { let max_remainder_digits = m.digits; - const { - assert!(core::mem::size_of::() == core::mem::size_of::()); - } - // check that hint is "sane" in upper bound assert!(q_len.next_multiple_of(8) / 8 <= max_quotient_digits); diff --git a/basic_system/src/system_functions/modexp/delegation/mod.rs b/basic_system/src/system_functions/modexp/advice/mod.rs similarity index 99% rename from basic_system/src/system_functions/modexp/delegation/mod.rs rename to basic_system/src/system_functions/modexp/advice/mod.rs index aa13cffcb..34cf985f2 100644 --- a/basic_system/src/system_functions/modexp/delegation/mod.rs +++ b/basic_system/src/system_functions/modexp/advice/mod.rs @@ -11,7 +11,6 @@ use zk_ee::system::logger::Logger; #[cfg(feature = "testing")] use zk_ee::system::logger::NullLogger; -#[cfg(any(all(target_arch = "riscv32", feature = "proving"), test))] pub(super) fn modexp( base: &[u8], exp: &[u8], diff --git a/basic_system/src/system_functions/modexp/delegation/u256.rs b/basic_system/src/system_functions/modexp/advice/u256.rs similarity index 100% rename from basic_system/src/system_functions/modexp/delegation/u256.rs rename to basic_system/src/system_functions/modexp/advice/u256.rs diff --git a/basic_system/src/system_functions/modexp/mod.rs b/basic_system/src/system_functions/modexp/mod.rs index 32a9caabe..298cf617b 100644 --- a/basic_system/src/system_functions/modexp/mod.rs +++ b/basic_system/src/system_functions/modexp/mod.rs @@ -25,29 +25,32 @@ pub const MODEXP_ADVICE_QUERY_ID: u32 = ADVICE_SUBSPACE_MASK | 0x10; /// Used to request division advice for big integer operations during modexp #[repr(C)] #[derive(Debug, Default)] -pub struct ModExpAdviceParams { - pub op: u32, // Operation type (0 = division) - pub a_ptr: u32, // Pointer to dividend - pub a_len: u32, // Length of dividend in words - pub b_ptr: u32, // Pointer to divisor - pub b_len: u32, // Length of divisor in words - pub modulus_ptr: u32, // Pointer to modulus - pub modulus_len: u32, // Length of modulus in words +pub struct ModExpAdviceParamsGeneric { + pub op: W, // Operation type (0 = division) + pub a_ptr: W, // Pointer to dividend + pub a_len: W, // Length of dividend in words + pub b_ptr: W, // Pointer to divisor + pub b_len: W, // Length of divisor in words + pub modulus_ptr: W, // Pointer to modulus + pub modulus_len: W, // Length of modulus in words } -#[cfg(any( - all(target_arch = "riscv32", feature = "proving"), - test, - feature = "testing" -))] -pub mod delegation; +/// Used for proving (RISC-V 32-bit) +pub type ModExpAdviceParams = ModExpAdviceParamsGeneric; + +/// Used for native execution (64-bit) +pub type ModExpAdviceParams64 = ModExpAdviceParamsGeneric; + +pub mod advice; /// /// modexp system function implementation. /// -pub struct ModExpImpl; +pub struct ModExpImpl; -impl SystemFunctionExt for ModExpImpl { +impl SystemFunctionExt + for ModExpImpl +{ /// If the input size is less than expected - it will be padded with zeroes. /// If the input size is greater - redundant bytes will be ignored. /// @@ -71,7 +74,9 @@ impl SystemFunctionExt for ModExpImpl { allocator: A, ) -> Result<(), SubsystemError> { cycle_marker::wrap_with_resources!("modexp", resources, { - modexp_as_system_function_inner(input, output, resources, oracle, logger, allocator) + modexp_as_system_function_inner::<_, _, _, _, _, USE_ADVICE>( + input, output, resources, oracle, logger, allocator, + ) }) } } @@ -106,6 +111,9 @@ fn modexp_as_system_function_inner< D: ?Sized + TryExtend, A: Allocator + Clone, R: Resources, + // Toggle delegation-based implementation for forward run, to be able + // to capture oracle queries. + const USE_ADVICE: bool, >( input: &[u8], dst: &mut D, @@ -211,7 +219,7 @@ fn modexp_as_system_function_inner< // Call the modexp. #[cfg(any(all(target_arch = "riscv32", feature = "proving"), test))] - let output = self::delegation::modexp( + let output = self::advice::modexp( base.as_slice(), exponent.as_slice(), modulus.as_slice(), @@ -221,12 +229,23 @@ fn modexp_as_system_function_inner< ); #[cfg(not(any(all(target_arch = "riscv32", feature = "proving"), test)))] - let output = ::modexp::modexp( - base.as_slice(), - exponent.as_slice(), - modulus.as_slice(), - allocator, - ); + let output = if USE_ADVICE { + self::advice::modexp( + base.as_slice(), + exponent.as_slice(), + modulus.as_slice(), + oracle, + logger, + allocator, + ) + } else { + ::modexp::modexp( + base.as_slice(), + exponent.as_slice(), + modulus.as_slice(), + allocator, + ) + }; if output.len() >= mod_len { // truncate diff --git a/basic_system/src/system_implementation/system/da_commitment_generator/blob_commitment_generator/commitment_and_proof_advice.rs b/basic_system/src/system_implementation/system/da_commitment_generator/blob_commitment_generator/commitment_and_proof_advice.rs index 2d1c57d88..f7b44830f 100644 --- a/basic_system/src/system_implementation/system/da_commitment_generator/blob_commitment_generator/commitment_and_proof_advice.rs +++ b/basic_system/src/system_implementation/system/da_commitment_generator/blob_commitment_generator/commitment_and_proof_advice.rs @@ -70,7 +70,6 @@ pub struct OracleBasedBlobCommitmentAndProofAdvisor<'a, O: zk_ee::oracle::IOOrac pub oracle: &'a mut O, } -// Right now, we run it only on RISC-V, but in theory, it should be possible to make it runnable on native arch as well impl<'a, O: zk_ee::oracle::IOOracle> BlobCommitmentAndProofAdvisor for OracleBasedBlobCommitmentAndProofAdvisor<'a, O> { diff --git a/basic_system/src/system_implementation/system/io_subsystem.rs b/basic_system/src/system_implementation/system/io_subsystem.rs index f333ccfc8..bbce685d5 100644 --- a/basic_system/src/system_implementation/system/io_subsystem.rs +++ b/basic_system/src/system_implementation/system/io_subsystem.rs @@ -28,6 +28,7 @@ use zk_ee::common_structs::ProofData; use zk_ee::common_structs::L2_TO_L1_LOG_SERIALIZE_SIZE; use zk_ee::interface_error; use zk_ee::oracle::basic_queries::ZKProofDataQuery; +use zk_ee::oracle::query_ids::DISCONNECT_ORACLE_QUERY_ID; use zk_ee::oracle::simple_oracle_query::SimpleOracleQuery; use zk_ee::out_of_ergs_error; use zk_ee::system::metadata::zk_metadata::BlockMetadataFromOracle; @@ -531,6 +532,9 @@ impl< // finishing IO, applying changes let mut da_commitment_generator = crate::system_implementation::system::da_commitment_generator::Blake2sCommitmentGenerator::new(); // Write version byte first to enable future pubdata format upgrades + result_keeper.pubdata(&[PUBDATA_ENCODING_VERSION]); + result_keeper.pubdata(current_block_hash.as_u8_ref()); + result_keeper.pubdata(&block_metadata.timestamp.to_be_bytes()); da_commitment_generator.write(&[PUBDATA_ENCODING_VERSION]); da_commitment_generator.write(current_block_hash.as_u8_ref()); da_commitment_generator.write(&block_metadata.timestamp.to_be_bytes()); @@ -588,6 +592,11 @@ impl< blocks_output: block_output.hash().into(), }; + #[allow(unused_must_use)] + self.oracle + .raw_query_with_empty_input(DISCONNECT_ORACLE_QUERY_ID) + .expect("must disconnect an oracle before performing arbitrary CSR access"); + (self.oracle, public_input.hash().into()) } } @@ -607,7 +616,7 @@ impl< O: IOOracle, > FinishIO for FullIO { - type FinalData = (O, Bytes32); + type FinalData = (O, Bytes32, public_input::BatchOutput); fn finish( mut self, block_metadata: BlockMetadataFromOracle, @@ -647,6 +656,9 @@ impl< .unwrap(); // Write version byte first to enable future pubdata format upgrades + result_keeper.pubdata(&[PUBDATA_ENCODING_VERSION]); + result_keeper.pubdata(current_block_hash.as_u8_ref()); + result_keeper.pubdata(&block_metadata.timestamp.to_be_bytes()); da_commitment_generator.write(&[PUBDATA_ENCODING_VERSION]); da_commitment_generator.write(current_block_hash.as_u8_ref()); da_commitment_generator.write(&block_metadata.timestamp.to_be_bytes()); @@ -733,10 +745,15 @@ impl< "PI calculation: final batch public input hash {public_input_hash:?}\n", )); + #[allow(unused_must_use)] + self.oracle + .raw_query_with_empty_input(DISCONNECT_ORACLE_QUERY_ID) + .expect("must disconnect an oracle before performing arbitrary CSR access"); + if cfg!(feature = "state-diffs-pi") { - (self.oracle, state_diffs_hash) + (self.oracle, state_diffs_hash, batch_output) } else { - (self.oracle, public_input_hash) + (self.oracle, public_input_hash, batch_output) } } } @@ -892,6 +909,11 @@ where upgrade_tx_hash, ); + #[allow(unused_must_use)] + self.oracle + .raw_query_with_empty_input(DISCONNECT_ORACLE_QUERY_ID) + .expect("must disconnect an oracle before performing arbitrary CSR access"); + self.oracle } } diff --git a/callable_oracles/src/arithmetic/mod.rs b/callable_oracles/src/arithmetic/mod.rs index c5be8b62a..e1faa7a0e 100644 --- a/callable_oracles/src/arithmetic/mod.rs +++ b/callable_oracles/src/arithmetic/mod.rs @@ -1,12 +1,57 @@ -use basic_system::system_functions::modexp::{ModExpAdviceParams, MODEXP_ADVICE_QUERY_ID}; +use basic_system::system_functions::modexp::{ + ModExpAdviceParams, ModExpAdviceParams64, MODEXP_ADVICE_QUERY_ID, +}; use oracle_provider::OracleQueryProcessor; use risc_v_simulator::abstractions::memory::MemorySource; +use crate::read_u64_words; use crate::utils::{ evaluate::{read_memory_as_u64, read_struct}, usize_slice_iterator::UsizeSliceIteratorOwned, }; +struct ArithmeticQueryOutput { + quotient: Vec, + remainder: Vec, +} + +impl ArithmeticQueryOutput { + fn into_usize_iterator(self) -> Box + 'static> { + // Trim zeros + fn strip_leading_zeroes(input: &[u64]) -> &[u64] { + let mut digits = input.len(); + for el in input.iter().rev() { + if *el == 0 { + digits -= 1; + } else { + break; + } + } + &input[..digits] + } + let quotient = strip_leading_zeroes(&self.quotient); + let remainder = strip_leading_zeroes(&self.remainder); + + // account for usize being u64 here + let q_len_in_u32_words = quotient.len() * 2; + let r_len_in_u32_words = remainder.len() * 2; + // account for LE, and we will ask quotient first, then remainder + let header = [(q_len_in_u32_words as u64) | ((r_len_in_u32_words as u64) << 32)]; + + let r = header + .iter() + .chain(quotient.iter()) + .chain(remainder.iter()) + .map(|x| *x as usize) + .collect::>(); + let r = Vec::into_boxed_slice(r); + + let n = UsizeSliceIteratorOwned::new(r); + + Box::new(n) + } +} + pub struct ArithmeticQuery { _marker: std::marker::PhantomData, } @@ -58,37 +103,75 @@ impl OracleQueryProcessor for ArithmeticQuery { ruint::algorithms::div(&mut n, &mut d); - // Trim zeros - fn strip_leading_zeroes(input: &[u64]) -> &[u64] { - let mut digits = input.len(); - for el in input.iter().rev() { - if *el == 0 { - digits -= 1; - } else { - break; - } - } - &input[..digits] + ArithmeticQueryOutput { + quotient: n, + remainder: d, + } + .into_usize_iterator() + } +} + +/// Query processor to be used for prover input native run +/// Works in a similar way as the ArithmeticQuery, but with +/// 64 bit pointers. Importantly, the query response is the +/// same. +/// +/// This processor explicitly reads the process memory +/// using a raw pointer to get the input. +pub struct NativeArithmeticQuery { + _marker: std::marker::PhantomData, +} + +impl Default for NativeArithmeticQuery { + fn default() -> Self { + Self { + _marker: std::marker::PhantomData, } - let quotient = strip_leading_zeroes(&n); - let remainder = strip_leading_zeroes(&d); + } +} - // account for usize being u64 here - let q_len_in_u32_words = quotient.len() * 2; - let r_len_in_u32_words = remainder.len() * 2; - // account for LE, and we will ask quotient first, then remainder - let header = [(q_len_in_u32_words as u64) | ((r_len_in_u32_words as u64) << 32)]; +impl OracleQueryProcessor for NativeArithmeticQuery { + fn supported_query_ids(&self) -> Vec { + vec![MODEXP_ADVICE_QUERY_ID] + } - let r = header - .iter() - .chain(quotient.iter()) - .chain(remainder.iter()) - .map(|x| *x as usize) - .collect::>(); - let r = Vec::into_boxed_slice(r); + fn process_buffered_query( + &mut self, + query_id: u32, + query: Vec, + _memory: &M, + ) -> Box + 'static> { + debug_assert!(self.supports_query_id(query_id)); - let n = UsizeSliceIteratorOwned::new(r); + let mut it = query.into_iter(); - Box::new(n) + let arg_ptr = it.next().expect("A u64 should've been passed in."); + + assert!(it.next().is_none(), "A single ptr should've been passed."); + + let arg = unsafe { + let p = arg_ptr as *const ModExpAdviceParams64; + core::ptr::read_unaligned(p) + }; + + assert!(arg.a_ptr > 0); + assert!(arg.a_len > 0); + + assert_eq!(arg.b_ptr, 0); + assert_eq!(arg.b_len, 0); + + assert!(arg.modulus_ptr > 0); + assert!(arg.modulus_len > 0); + + let mut n: Vec = unsafe { read_u64_words(arg.a_ptr, arg.a_len * 4) }; + let mut d: Vec = unsafe { read_u64_words(arg.modulus_ptr, arg.modulus_len * 4) }; + + ruint::algorithms::div(&mut n, &mut d); + + ArithmeticQueryOutput { + quotient: n, + remainder: d, + } + .into_usize_iterator() } } diff --git a/callable_oracles/src/blob_kzg_commitment/mod.rs b/callable_oracles/src/blob_kzg_commitment/mod.rs index 412e61545..6d329d58e 100644 --- a/callable_oracles/src/blob_kzg_commitment/mod.rs +++ b/callable_oracles/src/blob_kzg_commitment/mod.rs @@ -63,6 +63,58 @@ impl OracleQueryProcessor for BlobCommitmentAndProofQuery } } +/// Query processor to be used for prover input native run +/// Works in a similar way as the NativeBlobCommitmentAndProof, but with +/// 64 bit pointers. Importantly, the query response is the +/// same. +/// +/// This processor explicitly reads the process memory +/// using a raw pointer to get the input. +pub struct NativeBlobCommitmentAndProofQuery { + _marker: std::marker::PhantomData, +} + +impl Default for NativeBlobCommitmentAndProofQuery { + fn default() -> Self { + Self { + _marker: std::marker::PhantomData, + } + } +} + +impl OracleQueryProcessor for NativeBlobCommitmentAndProofQuery { + fn supported_query_ids(&self) -> Vec { + vec![BLOB_COMMITMENT_AND_PROOF_QUERY_ID] + } + + fn process_buffered_query( + &mut self, + query_id: u32, + query: Vec, + _memory: &M, + ) -> Box + 'static> { + debug_assert!(self.supports_query_id(query_id)); + + // this query processor supposed to work only on "host" architecture, which is always 64 bit + const { assert!(8 == core::mem::size_of::()) }; + let mut it = query.into_iter(); + + let data_ptr = it.next().unwrap(); + let data_len = it.next().unwrap(); + assert!( + it.next().is_none(), + "A single RISC-V ptr should've been passed." + ); + let data = unsafe { crate::read_u8_words(data_ptr as u64, data_len as u64) }; + let result = blob_kzg_commitment_and_proof(&data); + + let r = result.iter().collect::>(); + let r = Vec::into_boxed_slice(r); + let n = UsizeSliceIteratorOwned::new(r); + Box::new(n) + } +} + /// /// Calculate kzg commitment and proof at the point `blake2s(versioned_hash & data)` for blob created from passed data. /// diff --git a/callable_oracles/src/lib.rs b/callable_oracles/src/lib.rs index bd63748d2..8c834c0bd 100644 --- a/callable_oracles/src/lib.rs +++ b/callable_oracles/src/lib.rs @@ -59,3 +59,23 @@ impl UsizeDeserializable for MemoryRegionDescriptionParams { Ok(new) } } + +#[inline(always)] +unsafe fn read_u64_words(ptr_u64: u64, len_words_u64: u64) -> Vec { + if ptr_u64 == 0 || len_words_u64 == 0 { + return vec![]; + } + let addr = ptr_u64 as usize; + let len_words = len_words_u64 as usize; + core::slice::from_raw_parts(addr as *const u64, len_words).to_vec() +} + +#[inline(always)] +unsafe fn read_u8_words(ptr_u64: u64, len_words_u8: u64) -> Vec { + if ptr_u64 == 0 || len_words_u8 == 0 { + return vec![]; + } + let addr = ptr_u64 as usize; + let len_words = len_words_u8 as usize; + core::slice::from_raw_parts(addr as *const u8, len_words).to_vec() +} diff --git a/cycle_marker/src/lib.rs b/cycle_marker/src/lib.rs index a08909f01..13f8b9df9 100644 --- a/cycle_marker/src/lib.rs +++ b/cycle_marker/src/lib.rs @@ -158,6 +158,74 @@ macro_rules! wrap_with_resources { }}; } +// Snapshotting mechanism, used for tests +// We run multiple native runs of the program, so labels can be duplicated. +// This is a way to ignore some of those side effects. +#[cfg(not(target_arch = "riscv32"))] +pub struct Snapshot { + labels_len: usize, + #[cfg(feature = "log_to_file")] + file_len: u64, +} + +#[cfg(target_arch = "riscv32")] +pub struct Snapshot; + +#[cfg(not(target_arch = "riscv32"))] +pub fn snapshot() -> Snapshot { + let labels_len = LABELS.with(|l| l.borrow().len()); + + #[cfg(feature = "log_to_file")] + let file_len = MARKER_FILE.with(|f| { + use std::io::Seek; + use std::io::SeekFrom; + + let mut file = f.borrow_mut(); + // Get current position; writing always appends, so this is effectively the "index" + file.seek(SeekFrom::Current(0)) + .expect("Failed to seek marker file") + }); + + Snapshot { + labels_len, + #[cfg(feature = "log_to_file")] + file_len, + } +} + +#[cfg(target_arch = "riscv32")] +pub fn snapshot() -> Snapshot { + Snapshot +} + +#[cfg(not(target_arch = "riscv32"))] +pub fn revert(snap: Snapshot) { + // Restore LABELS length + LABELS.with(|l| { + let mut v = l.borrow_mut(); + if v.len() > snap.labels_len { + v.truncate(snap.labels_len); + } + }); + + // Restore file length/position if logging to file + #[cfg(feature = "log_to_file")] + { + use std::io::{Seek, SeekFrom}; + + MARKER_FILE.with(|f| { + let mut file = f.borrow_mut(); + file.set_len(snap.file_len) + .expect("Failed to truncate marker file"); + file.seek(SeekFrom::Start(snap.file_len)) + .expect("Failed to seek marker file"); + }); + } +} + +#[cfg(target_arch = "riscv32")] +pub fn revert(_: Snapshot) {} + #[cfg(all(feature = "use_risc_v_simulator", not(target_arch = "riscv32")))] pub fn print_cycle_markers() -> Option { const BLAKE_DELEGATION_ID: u32 = 1991; diff --git a/forward_system/src/run/mod.rs b/forward_system/src/run/mod.rs index 26339875a..8664ffe25 100644 --- a/forward_system/src/run/mod.rs +++ b/forward_system/src/run/mod.rs @@ -21,17 +21,21 @@ use crate::run::query_processors::ZKProofDataResponder; use crate::run::query_processors::{BlockMetadataResponder, DACommitmentSchemeResponder}; use crate::run::result_keeper::ForwardRunningResultKeeper; use crate::system::bootloader::run_forward; +use crate::system::bootloader::run_prover_input_no_panic; use crate::system::system::CallSimulationBootloader; use crate::system::system::CallSimulationSystem; use crate::system::system::ForwardRunningSystem; use basic_bootloader::bootloader::config::{ BasicBootloaderCallSimulationConfig, BasicBootloaderForwardSimulationConfig, + BasicBootloaderProvingExecutionConfig, }; use errors::ForwardSubsystemError; use oracle_provider::MemorySource; use oracle_provider::ReadWitnessSource; use oracle_provider::ZkEENonDeterminismSource; +use result_keeper::ProverInputResultKeeper; use zk_ee::common_structs::ProofData; +use zk_ee::system::tracer::NopTracer; use zk_ee::system::tracer::Tracer; use zk_ee::utils::Bytes32; @@ -45,7 +49,6 @@ pub use preimage_source::PreimageSource; use zk_ee::wrap_error; use zksync_os_interface::traits::EncodedTx; -use std::path::PathBuf; pub use tx_result_callback::TxResultCallback; pub use tx_source::NextTxResponse; pub use tx_source::TxSource; @@ -94,16 +97,21 @@ pub fn run_block( - zk_os_program_path: PathBuf, +// Returns (prover_input, block_output, pubdata) +pub fn generate_proof_input< + T: ReadStorageTree, + PS: PreimageSource, + TS: TxSource, + TR: TxResultCallback, +>( block_context: BlockContext, proof_data: ProofData, da_commitment_scheme: DACommitmentScheme, tree: T, preimage_source: PS, tx_source: TS, -) -> Result, ForwardSubsystemError> { + tx_result_callback: TR, +) -> Result<(Vec, BlockOutput, Vec), ForwardSubsystemError> { let block_metadata_responder = BlockMetadataResponder { block_metadata: block_context, }; @@ -129,19 +137,25 @@ pub fn generate_proof_input( + copy_source, + &mut result_keeper, + &mut tracer, + ) + .map_err(|e| wrap_error!(e))?; + // Take pubdata, as it's not part of BlockOutput + let pubdata = std::mem::take(&mut result_keeper.pubdata); + + Ok((prover_input, result_keeper.into(), pubdata)) } // TODO(EVM-1184): in future we should generate input per batch @@ -220,6 +234,7 @@ pub fn make_oracle_for_proofs_and_dumps< proof_data: Option>, da_commitment_scheme: Option, add_uart: bool, + use_native_callable_oracles: bool, ) -> ZkEENonDeterminismSource { make_oracle_for_proofs_and_dumps_for_init_data( block_context, @@ -229,6 +244,7 @@ pub fn make_oracle_for_proofs_and_dumps< proof_data, da_commitment_scheme, add_uart, + use_native_callable_oracles, ) } @@ -245,6 +261,7 @@ pub fn make_oracle_for_proofs_and_dumps_for_init_data< proof_data: Option>, da_commitment_scheme: Option, add_uart: bool, + use_native_callable_oracles: bool, ) -> ZkEENonDeterminismSource { let block_metadata_responder = BlockMetadataResponder { block_metadata: block_context, @@ -269,10 +286,18 @@ pub fn make_oracle_for_proofs_and_dumps_for_init_data< oracle.add_external_processor(tree_responder); oracle.add_external_processor(zk_proof_data_responder); oracle.add_external_processor(da_commitment_scheme_responder); - oracle.add_external_processor(callable_oracles::arithmetic::ArithmeticQuery::default()); - oracle.add_external_processor( - callable_oracles::blob_kzg_commitment::BlobCommitmentAndProofQuery::default(), - ); + if use_native_callable_oracles { + oracle + .add_external_processor(callable_oracles::arithmetic::NativeArithmeticQuery::default()); + oracle.add_external_processor( + callable_oracles::blob_kzg_commitment::NativeBlobCommitmentAndProofQuery::default(), + ); + } else { + oracle.add_external_processor(callable_oracles::arithmetic::ArithmeticQuery::default()); + oracle.add_external_processor( + callable_oracles::blob_kzg_commitment::BlobCommitmentAndProofQuery::default(), + ); + } if add_uart { let uart_responder = UARTPrintResponder; diff --git a/forward_system/src/run/output.rs b/forward_system/src/run/output.rs index b483a9dcd..617ad68e6 100644 --- a/forward_system/src/run/output.rs +++ b/forward_system/src/run/output.rs @@ -24,6 +24,8 @@ use zk_ee::types_config::EthereumIOTypesConfig; pub use zksync_os_interface::types::BlockOutput; use zksync_os_interface::types::L2ToL1LogWithPreimage; +use super::result_keeper::ProverInputResultKeeper; + pub type TxResult = Result; /// Extension trait to create `StorageWrite` from components. @@ -53,7 +55,6 @@ impl From> for BlockOutput storage_writes, tx_results, new_preimages, - pubdata, .. } = value; @@ -134,12 +135,17 @@ impl From> for BlockOutput storage_writes, account_diffs, published_preimages, - pubdata, computaional_native_used: block_computaional_native_used, } } } +impl From> for BlockOutput { + fn from(value: ProverInputResultKeeper) -> Self { + BlockOutput::from(value.forward_running_rk) + } +} + /// Extract account diffs from a BlockOutput. /// /// This method processes the published preimages and storage writes to extract diff --git a/forward_system/src/run/result_keeper.rs b/forward_system/src/run/result_keeper.rs index 00dbe314e..8e81d6e46 100644 --- a/forward_system/src/run/result_keeper.rs +++ b/forward_system/src/run/result_keeper.rs @@ -24,8 +24,6 @@ pub struct ForwardRunningResultKeeper { Result, >, pub new_preimages: Vec<(Bytes32, Vec, PreimageType)>, - pub pubdata: Vec, - pub tx_result_callback: TR, } @@ -38,7 +36,6 @@ impl ForwardRunningResultKeeper { storage_writes: vec![], tx_results: vec![], new_preimages: vec![], - pubdata: vec![], tx_result_callback, } } @@ -50,7 +47,7 @@ impl IOResultKeeper fn events<'a>( &mut self, iter: impl Iterator< - Item = GenericEventContentWithTxRef<'a, { MAX_EVENT_TOPICS }, EthereumIOTypesConfig>, + Item = GenericEventContentWithTxRef<'a, MAX_EVENT_TOPICS, EthereumIOTypesConfig>, >, ) { self.events = iter @@ -84,10 +81,6 @@ impl IOResultKeeper .map(|(hash, preimage, preimage_type)| (*hash, preimage.to_vec(), preimage_type)) .collect(); } - - fn pubdata(&mut self, value: &[u8]) { - self.pubdata.extend_from_slice(value); - } } impl ResultKeeperExt for ForwardRunningResultKeeper { @@ -123,3 +116,84 @@ impl ResultKeeperExt for ForwardRunningResultKeeper { .sum() } } + +/// +/// Result keeper for prover input run. +/// Adds pubdata to ForwardRunningResultKeeper +/// +pub struct ProverInputResultKeeper { + pub forward_running_rk: ForwardRunningResultKeeper, + pub pubdata: Vec, +} + +impl ProverInputResultKeeper { + pub fn new(tx_result_callback: TR) -> Self { + Self { + forward_running_rk: ForwardRunningResultKeeper::new(tx_result_callback), + pubdata: vec![], + } + } +} + +// Delegate to ForwardRunningResultKeeper, except for pubdata +impl IOResultKeeper for ProverInputResultKeeper { + fn events<'a>( + &mut self, + iter: impl Iterator< + Item = GenericEventContentWithTxRef<'a, MAX_EVENT_TOPICS, EthereumIOTypesConfig>, + >, + ) { + // Have to reimplement, as delegating it causes an ICE... + self.forward_running_rk.events = iter + .map(|e| GenericEventContent { + tx_number: e.tx_number, + address: *e.address, + topics: e.topics.clone(), + data: UsizeAlignedByteBox::from_slice_in(e.data, Global), + }) + .collect(); + } + + fn logs<'a>( + &mut self, + iter: impl Iterator>, + ) { + self.forward_running_rk.logs(iter) + } + + fn storage_diffs(&mut self, iter: impl Iterator) { + self.forward_running_rk.storage_diffs(iter) + } + + fn new_preimages<'a>( + &mut self, + iter: impl Iterator, + ) { + self.forward_running_rk.new_preimages(iter) + } + + fn pubdata(&mut self, value: &[u8]) { + self.pubdata.extend_from_slice(value); + } +} + +// Delegate to ForwardRunningResultKeeper +impl ResultKeeperExt for ProverInputResultKeeper { + fn tx_processed( + &mut self, + tx_result: Result< + TxProcessingOutput, + basic_bootloader::bootloader::errors::InvalidTransaction, + >, + ) { + self.forward_running_rk.tx_processed(tx_result) + } + + fn block_sealed(&mut self, block_header: BlockHeader) { + self.forward_running_rk.block_sealed(block_header) + } + + fn get_gas_used(&self) -> u64 { + self.forward_running_rk.get_gas_used() + } +} diff --git a/forward_system/src/system/bootloader.rs b/forward_system/src/system/bootloader.rs index c13bd7fb6..2aaab25c8 100644 --- a/forward_system/src/system/bootloader.rs +++ b/forward_system/src/system/bootloader.rs @@ -3,6 +3,7 @@ use basic_bootloader::bootloader::config::BasicBootloaderExecutionConfig; use basic_bootloader::bootloader::errors::BootloaderSubsystemError; use basic_bootloader::bootloader::result_keeper::ResultKeeperExt; use oracle_provider::DummyMemorySource; +use oracle_provider::ReadWitnessSource; use oracle_provider::ZkEENonDeterminismSource; use zk_ee::system::tracer::Tracer; @@ -27,3 +28,12 @@ pub fn run_forward_no_panic( ) -> Result<(), BootloaderSubsystemError> { ForwardBootloader::run_prepared::(oracle, result_keeper, tracer).map(|_| ()) } + +pub fn run_prover_input_no_panic( + oracle: ReadWitnessSource, + result_keeper: &mut impl ResultKeeperExt, + tracer: &mut impl Tracer, +) -> Result, BootloaderSubsystemError> { + ProverInputBootloader::run_prepared::(oracle, result_keeper, tracer) + .map(|o| o.0.get_read_items().borrow().clone()) +} diff --git a/forward_system/src/system/system.rs b/forward_system/src/system/system.rs index 428c478f2..df90a5c12 100644 --- a/forward_system/src/system/system.rs +++ b/forward_system/src/system/system.rs @@ -19,11 +19,11 @@ type Logger = crate::system::logger::StdIOLogger; #[cfg(feature = "no_print")] type Logger = zk_ee::system::NullLogger; -pub struct ForwardSystemTypes(O); +pub struct ForwardSystemTypes(O); type Native = zk_ee::reference_implementations::DecreasingNative; -impl SystemTypes for ForwardSystemTypes { +impl SystemTypes for ForwardSystemTypes { type IOTypes = EthereumIOTypesConfig; type Resources = BaseResources; type IO = FullIO< @@ -33,21 +33,29 @@ impl SystemTypes for ForwardSystemTypes { VecStackFactory, 0, O, - false, + PROOF_ENV, >; - type SystemFunctions = NoStdSystemFunctions; - type SystemFunctionsExt = NoStdSystemFunctions; + // For PROOF_ENV=true, we can enable delegation-based modexp to capture prover input. + type SystemFunctions = NoStdSystemFunctions; + type SystemFunctionsExt = NoStdSystemFunctions; type Allocator = Global; type Logger = Logger; type Metadata = zk_ee::system::metadata::zk_metadata::ZkMetadata; } -impl EthereumLikeTypes for ForwardSystemTypes {} +impl EthereumLikeTypes for ForwardSystemTypes {} -pub type ForwardRunningSystem = ForwardSystemTypes>; +pub type ForwardRunningSystem = + ForwardSystemTypes, false>; -pub type CallSimulationSystem = ForwardSystemTypes>; +pub type CallSimulationSystem = + ForwardSystemTypes, false>; + +pub type ProverInputSystem = + ForwardSystemTypes, true>; pub type ForwardBootloader = BasicBootloader; pub type CallSimulationBootloader = BasicBootloader; + +pub type ProverInputBootloader = BasicBootloader; diff --git a/oracle_provider/src/lib.rs b/oracle_provider/src/lib.rs index 5d3308baf..17af59550 100644 --- a/oracle_provider/src/lib.rs +++ b/oracle_provider/src/lib.rs @@ -322,3 +322,42 @@ impl NonDeterminismCSRSource for ReadWitnessSource { self.original_source.write_with_memory_access(memory, value); } } + +impl IOOracle for ReadWitnessSource { + type RawIterator<'a> = + as IOOracle>::RawIterator<'a>; + + fn raw_query<'a, I>( + &'a mut self, + query_type: u32, + input: &I, + ) -> Result, InternalError> + where + I: UsizeSerializable + UsizeDeserializable, + { + let inner = self.original_source.raw_query(query_type, input)?; + // First add the length of the iterator. + let len = inner.len(); + { + let mut read_items = self.read_items.borrow_mut(); + // Len is multiplied by 2 to account for 32/64-bit mismatch + let len_u32 = u32::try_from(len * 2).expect("iterator length does not fit into u32"); + read_items.push(len_u32); + } + let read_items = Rc::clone(&self.read_items); + let wrapped: Self::RawIterator<'a> = Box::new(inner.inspect(move |v| { + record_usize_as_u32_words(&mut read_items.borrow_mut(), *v); + })); + + Ok(wrapped) + } +} + +fn record_usize_as_u32_words(dst: &mut Vec, value: usize) { + { + let v = value as u64; + // LE + dst.push((v & 0xFFFF_FFFF) as u32); + dst.push((v >> 32) as u32); + } +} diff --git a/proof_running_system/src/system/bootloader.rs b/proof_running_system/src/system/bootloader.rs index 07698a0f5..df8300802 100644 --- a/proof_running_system/src/system/bootloader.rs +++ b/proof_running_system/src/system/bootloader.rs @@ -5,7 +5,6 @@ use basic_bootloader::bootloader::config::BasicBootloaderProvingExecutionConfig; use core::alloc::Allocator; use core::mem::MaybeUninit; use zk_ee::memory::ZSTAllocator; -use zk_ee::oracle::query_ids::DISCONNECT_ORACLE_QUERY_ID; use zk_ee::oracle::IOOracle; use zk_ee::system::tracer::NopTracer; use zk_ee::system::{logger::Logger, NopResultKeeper}; @@ -179,17 +178,13 @@ pub fn run_proving_inner< let _ = L::default().write_fmt(format_args!("IO implementer init is complete")); // Load all transactions from oracle and apply them. - let (mut oracle, public_input) = ProvingBootloader::::run_prepared::< - BasicBootloaderProvingExecutionConfig, - >(oracle, &mut NopResultKeeper, &mut NopTracer::default()) - .expect("Tried to prove a failing batch"); - - // disconnect oracle before returning, if some other post-logic is needed that doesn't use Oracle trait - // TODO: check this is the intended behaviour (ignoring the result) - #[allow(unused_must_use)] - oracle - .raw_query_with_empty_input(DISCONNECT_ORACLE_QUERY_ID) - .expect("must disconnect an oracle before performing arbitrary CSR access"); + let (_oracle, public_input, _batch_output) = + ProvingBootloader::::run_prepared::( + oracle, + &mut NopResultKeeper, + &mut NopTracer::default(), + ) + .expect("Tried to prove a failing batch"); unsafe { core::mem::transmute(public_input) } } @@ -224,12 +219,6 @@ pub fn run_proving_inner< upgrade_tx_hash, &mut batch_pi_builder, ); - // we do this query for consistency with block based input generation(there is empty iterator as response to this query) - // but during proving this request shouldn't have the effect with "u32 array based" oracle - #[allow(unused_must_use)] - oracle - .raw_query_with_empty_input(DISCONNECT_ORACLE_QUERY_ID) - .expect("must disconnect an oracle before performing arbitrary CSR access"); } unsafe { diff --git a/proof_running_system/src/system/mod.rs b/proof_running_system/src/system/mod.rs index c2aa4d8f4..9c845e2a8 100644 --- a/proof_running_system/src/system/mod.rs +++ b/proof_running_system/src/system/mod.rs @@ -42,8 +42,8 @@ impl SystemTypes for ProofRunningSystemTypes; - type SystemFunctions = NoStdSystemFunctions; - type SystemFunctionsExt = NoStdSystemFunctions; + type SystemFunctions = NoStdSystemFunctions; + type SystemFunctionsExt = NoStdSystemFunctions; type Allocator = BootloaderAllocator; type Logger = L; type Metadata = zk_ee::system::metadata::zk_metadata::ZkMetadata; diff --git a/tests/evm_tester/Cargo.lock b/tests/evm_tester/Cargo.lock index ed066f6f1..6c842fdeb 100644 --- a/tests/evm_tester/Cargo.lock +++ b/tests/evm_tester/Cargo.lock @@ -8798,14 +8798,12 @@ dependencies = [ [[package]] name = "zksync_os_evm_errors" version = "0.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b3ad55a8aa3498e304565de55b61dc930bac227c8c5e81284b623c69f2143d2" +source = "git+https://github.com/matter-labs/zksync-os-interface?branch=alocascio-prover-input-gen#16f2306bb4c3b6cb7465f6809637661ff4f2f86f" [[package]] name = "zksync_os_interface" version = "0.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3476c481db1ea2db28ed8cbdfef391576288cb9e13241f7944274b72cf1e251e" +source = "git+https://github.com/matter-labs/zksync-os-interface?branch=alocascio-prover-input-gen#16f2306bb4c3b6cb7465f6809637661ff4f2f86f" dependencies = [ "alloy-consensus", "alloy-primitives", diff --git a/tests/fuzzer/fuzz/fuzz_targets/bootloader/common/mod.rs b/tests/fuzzer/fuzz/fuzz_targets/bootloader/common/mod.rs index 800cd1ccc..71788387e 100644 --- a/tests/fuzzer/fuzz/fuzz_targets/bootloader/common/mod.rs +++ b/tests/fuzzer/fuzz/fuzz_targets/bootloader/common/mod.rs @@ -214,6 +214,7 @@ pub fn mock_oracle() -> ( init_data, None, true, + false, ), ) } @@ -275,6 +276,7 @@ pub fn mock_oracle_balance( init_data, None, true, + false, ), ) } diff --git a/tests/fuzzer/fuzz/fuzz_targets/precompiles_diff/modexp.rs b/tests/fuzzer/fuzz/fuzz_targets/precompiles_diff/modexp.rs index 4c2727cc4..b8981df1a 100644 --- a/tests/fuzzer/fuzz/fuzz_targets/precompiles_diff/modexp.rs +++ b/tests/fuzzer/fuzz/fuzz_targets/precompiles_diff/modexp.rs @@ -1,18 +1,18 @@ #![no_main] #![feature(allocator_api)] +use arbitrary::{Arbitrary, Unstructured}; +use basic_system::system_functions::modexp::ModExpImpl; +use basic_system_proving::system_functions::modexp::advice::delegated_modexp_with_naive_advisor; use libfuzzer_sys::fuzz_target; use revm::primitives::U256; use revm_precompile::modexp::berlin_run; -use arbitrary::{Arbitrary, Unstructured}; -use zk_ee::system::Resource; -use basic_system_proving::system_functions::modexp::delegation::delegated_modexp_with_naive_advisor; -use zk_ee::system::base_system_functions::ModExpErrors; -use zk_ee::system::errors::subsystem::SubsystemError; -use basic_system::system_functions::modexp::ModExpImpl; use zk_ee::reference_implementations::BaseResources; -use zk_ee::system::{SystemFunction,SystemFunctionExt}; use zk_ee::reference_implementations::DecreasingNative; +use zk_ee::system::base_system_functions::ModExpErrors; +use zk_ee::system::errors::subsystem::SubsystemError; +use zk_ee::system::Resource; +use zk_ee::system::{SystemFunction, SystemFunctionExt}; #[derive(Arbitrary, Debug, Clone, Copy)] enum LenMode { @@ -63,8 +63,8 @@ struct Input { // Raw entropy to fill buffers base_seed: Vec, - exp_seed: Vec, - mod_seed: Vec, + exp_seed: Vec, + mod_seed: Vec, // Random lengths used when LenMode::Random bl_rand: u32, @@ -95,13 +95,17 @@ fn shape_exponent(mut exp: Vec, ek: ExpKind) -> Vec { ExpKind::Random => exp, ExpKind::Zero => vec![0u8; exp.len()], ExpKind::One => { - if exp.is_empty() { return exp; } + if exp.is_empty() { + return exp; + } let mut v = vec![0u8; exp.len()]; *v.last_mut().unwrap() = 1; v } ExpKind::Two => { - if exp.is_empty() { return exp; } + if exp.is_empty() { + return exp; + } let mut v = vec![0u8; exp.len()]; *v.last_mut().unwrap() = 2; v @@ -112,8 +116,8 @@ fn shape_exponent(mut exp: Vec, ek: ExpKind) -> Vec { } let mut v = vec![0u8; exp.len()]; let n = v.len(); - v[n-3] = 0x01; - v[n-1] = 0x01; + v[n - 3] = 0x01; + v[n - 1] = 0x01; v } } @@ -124,20 +128,26 @@ fn shape_modulus(mut m: Vec, mk: ModKind) -> Vec { ModKind::Random => m, ModKind::Zero => vec![0u8; m.len()], ModKind::One => { - if m.is_empty() { return m; } + if m.is_empty() { + return m; + } let mut v = vec![0u8; m.len()]; *v.last_mut().unwrap() = 1; v } ModKind::PowerOfTwo => { - if m.is_empty() { return m; } + if m.is_empty() { + return m; + } let mut v = vec![0u8; m.len()]; let bit = 1u8 << (v.len() as u8 % 8); *v.last_mut().unwrap() = bit.max(1); v } ModKind::Odd => { - if m.is_empty() { return m; } + if m.is_empty() { + return m; + } let mut v = m; *v.last_mut().unwrap() |= 1; v @@ -157,12 +167,12 @@ fn fill_len(u: &mut Unstructured<'_>, len: usize, seed: &[u8]) -> Vec { fn mutate_len(chosen: u32, mode: LenMode, rnd: u32) -> u32 { match mode { - LenMode::Exact => chosen, + LenMode::Exact => chosen, LenMode::OffByOneShort => chosen.saturating_sub(1), - LenMode::OffByOneLong => chosen.saturating_add(1).min(MAX_COMPONENT_LEN), - LenMode::MuchShorter => chosen / 2, - LenMode::MuchLonger => chosen.saturating_mul(2).min(MAX_COMPONENT_LEN), - LenMode::Random => rnd.min(MAX_DECL_LEN), + LenMode::OffByOneLong => chosen.saturating_add(1).min(MAX_COMPONENT_LEN), + LenMode::MuchShorter => chosen / 2, + LenMode::MuchLonger => chosen.saturating_mul(2).min(MAX_COMPONENT_LEN), + LenMode::Random => rnd.min(MAX_DECL_LEN), } } @@ -179,21 +189,21 @@ fn normalize_be(s: &[u8]) -> &[u8] { fn build_input_bytes( mut u: &mut Unstructured<'_>, - i: &Input + i: &Input, ) -> (Vec, Vec, Vec, Vec) { let bl = i.bl as usize; let el = i.el as usize; let ml = i.ml as usize; let base = fill_len(&mut u, bl, &i.base_seed); - let exp_raw = fill_len(&mut u, el, &i.exp_seed); - let mod_raw = fill_len(&mut u, ml, &i.mod_seed); + let exp_raw = fill_len(&mut u, el, &i.exp_seed); + let mod_raw = fill_len(&mut u, ml, &i.mod_seed); let mbl = mutate_len(bl as u32, i.bl_lm, i.bl_rand); let mel = mutate_len(el as u32, i.el_lm, i.el_rand); let mml = mutate_len(ml as u32, i.ml_lm, i.ml_rand); - let exp = shape_exponent(exp_raw.clone(), i.ek); + let exp = shape_exponent(exp_raw.clone(), i.ek); let modu = shape_modulus(mod_raw.clone(), i.mk); let mut out = Vec::with_capacity(96 + bl + el + ml); @@ -206,7 +216,9 @@ fn build_input_bytes( if let Some(t) = i.max_len { let t = t as usize; - if t < out.len() { out.truncate(t); } + if t < out.len() { + out.truncate(t); + } } (out, base, exp_raw, mod_raw) } @@ -244,7 +256,7 @@ fn fuzz(data: &[u8]) { pub fn modexp_forward(src: &[u8], dst: &mut Vec) -> Result<(), SubsystemError> { let allocator = std::alloc::Global; let mut resource = as Resource>::FORMAL_INFINITE; - ModExpImpl::execute( + ModExpImpl::::execute( &src, dst, &mut resource, @@ -264,11 +276,15 @@ struct DummyOracle {} impl zk_ee::oracle::IOOracle for DummyOracle { type RawIterator<'a> = Box + 'static>; - fn raw_query<'a, I: zk_ee::oracle::usize_serialization::UsizeSerializable + zk_ee::oracle::usize_serialization::UsizeDeserializable>( + fn raw_query< + 'a, + I: zk_ee::oracle::usize_serialization::UsizeSerializable + + zk_ee::oracle::usize_serialization::UsizeDeserializable, + >( &'a mut self, _query_type: u32, _input: &I, ) -> Result, zk_ee::system::errors::internal::InternalError> { unreachable!("oracle should not be consulted on native targets"); } -} \ No newline at end of file +} diff --git a/tests/fuzzer/fuzz/fuzz_targets/system_functions/modexp.rs b/tests/fuzzer/fuzz/fuzz_targets/system_functions/modexp.rs index 8bc59ec25..da934d203 100644 --- a/tests/fuzzer/fuzz/fuzz_targets/system_functions/modexp.rs +++ b/tests/fuzzer/fuzz/fuzz_targets/system_functions/modexp.rs @@ -97,7 +97,7 @@ fn fuzz(data: &[u8]) { let mut dst = dst.clone(); - let _ = ModExpImpl::execute( + let _ = ModExpImpl::::execute( &src.to_bytes().as_slice()[0..src.n], &mut dst, &mut resource, @@ -113,7 +113,11 @@ struct DummyOracle {} impl zk_ee::oracle::IOOracle for DummyOracle { type RawIterator<'a> = Box + 'static>; - fn raw_query<'a, I: zk_ee::oracle::usize_serialization::UsizeSerializable + zk_ee::oracle::usize_serialization::UsizeDeserializable>( + fn raw_query< + 'a, + I: zk_ee::oracle::usize_serialization::UsizeSerializable + + zk_ee::oracle::usize_serialization::UsizeDeserializable, + >( &'a mut self, _query_type: u32, _input: &I, @@ -125,4 +129,4 @@ impl zk_ee::oracle::IOOracle for DummyOracle { fuzz_target!(|data: &[u8]| { // call fuzzing in a separate function, so we can see its coverage fuzz(data); -}); \ No newline at end of file +}); diff --git a/tests/fuzzer/fuzz/fuzz_targets/system_functions/modexp_delegation.rs b/tests/fuzzer/fuzz/fuzz_targets/system_functions/modexp_delegation.rs index e8eac8008..e5f5f3033 100644 --- a/tests/fuzzer/fuzz/fuzz_targets/system_functions/modexp_delegation.rs +++ b/tests/fuzzer/fuzz/fuzz_targets/system_functions/modexp_delegation.rs @@ -2,7 +2,7 @@ #![feature(allocator_api)] use arbitrary::{Arbitrary, Unstructured}; -use basic_system::system_functions::modexp::delegation::delegated_modexp_with_naive_advisor; +use basic_system::system_functions::modexp::advice::delegated_modexp_with_naive_advisor; use libfuzzer_sys::fuzz_target; use ruint::aliases::U256; use std::alloc::Global; diff --git a/tests/instances/eth_runner/Cargo.lock b/tests/instances/eth_runner/Cargo.lock index 616ee269e..bc47e96a0 100644 --- a/tests/instances/eth_runner/Cargo.lock +++ b/tests/instances/eth_runner/Cargo.lock @@ -8670,14 +8670,12 @@ dependencies = [ [[package]] name = "zksync_os_evm_errors" version = "0.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b3ad55a8aa3498e304565de55b61dc930bac227c8c5e81284b623c69f2143d2" +source = "git+https://github.com/matter-labs/zksync-os-interface?branch=alocascio-prover-input-gen#16f2306bb4c3b6cb7465f6809637661ff4f2f86f" [[package]] name = "zksync_os_interface" version = "0.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3476c481db1ea2db28ed8cbdfef391576288cb9e13241f7944274b72cf1e251e" +source = "git+https://github.com/matter-labs/zksync-os-interface?branch=alocascio-prover-input-gen#16f2306bb4c3b6cb7465f6809637661ff4f2f86f" dependencies = [ "alloy-consensus", "alloy-primitives", diff --git a/tests/instances/eth_runner/src/live_run/mod.rs b/tests/instances/eth_runner/src/live_run/mod.rs index de485ec79..c350f581b 100644 --- a/tests/instances/eth_runner/src/live_run/mod.rs +++ b/tests/instances/eth_runner/src/live_run/mod.rs @@ -173,7 +173,7 @@ fn run_block( check_storage_diff_hashes: true, ..Default::default() }; - let (output, stats, _) = chain + let (output, stats, _, _) = chain .run_block_with_extra_stats( transactions, Some(block_context), diff --git a/tests/instances/eth_runner/src/single_run.rs b/tests/instances/eth_runner/src/single_run.rs index cc9f7313f..b281b41c5 100644 --- a/tests/instances/eth_runner/src/single_run.rs +++ b/tests/instances/eth_runner/src/single_run.rs @@ -46,11 +46,11 @@ fn run( check_storage_diff_hashes: true, ..Default::default() }; - let (output, stats, _) = chain + let (output, stats, _, _) = chain .run_block_with_extra_stats( transactions, Some(block_context), - None, + Some(zk_ee::common_structs::da_commitment_scheme::DACommitmentScheme::BlobsZKsyncOS), Some(run_config), &mut NopTracer::default(), ) diff --git a/tests/instances/header/src/lib.rs b/tests/instances/header/src/lib.rs index 0034bab80..aa4207480 100644 --- a/tests/instances/header/src/lib.rs +++ b/tests/instances/header/src/lib.rs @@ -25,7 +25,7 @@ fn test_block_header_invariants() { // TODO: enable when this is implemented // assert_ne!(header.transactions_root, Bytes32::ZERO); // assert_ne!(header.receipts_root, Bytes32::ZERO); - assert_eq!(header.number, 0); + assert_eq!(header.number, 1); assert_eq!(header.gas_limit, MAX_BLOCK_GAS_LIMIT); assert!( header.gas_used @@ -63,7 +63,7 @@ fn test_block_header_invariants() { // TODO: enable when this is implemented // assert_ne!(header.transactions_root, Bytes32::ZERO); // assert_ne!(header.receipts_root, Bytes32::ZERO); - assert_eq!(header.number, 1); + assert_eq!(header.number, 2); assert_eq!(header.gas_limit, gas_limit); assert!( header.gas_used diff --git a/tests/instances/multiblock_batch/src/lib.rs b/tests/instances/multiblock_batch/src/lib.rs index cc697336e..94b9a4833 100644 --- a/tests/instances/multiblock_batch/src/lib.rs +++ b/tests/instances/multiblock_batch/src/lib.rs @@ -88,10 +88,7 @@ fn run_multiblock_batch_proof_run(da_commitment_scheme: DACommitmentScheme) { let batch_input = generate_batch_proof_input( vec![block1_result.2.as_slice(), block2_result.2.as_slice()], da_commitment_scheme, - vec![ - block1_result.0.pubdata.as_slice(), - block2_result.0.pubdata.as_slice(), - ], + vec![block1_result.3.as_slice(), block2_result.3.as_slice()], ); let multinblock_program_path = PathBuf::from(std::env::var("CARGO_WORKSPACE_DIR").unwrap()) diff --git a/tests/instances/transactions/src/lib.rs b/tests/instances/transactions/src/lib.rs index a68e01de2..7ae666f7f 100644 --- a/tests/instances/transactions/src/lib.rs +++ b/tests/instances/transactions/src/lib.rs @@ -8,7 +8,7 @@ use alloy::signers::local::PrivateKeySigner; use rig::alloy::consensus::TxEip7702; use rig::alloy::primitives::{address, b256}; use rig::alloy::rpc::types::{AccessList, AccessListItem, TransactionRequest}; -use rig::basic_system::system_implementation::system::pubdata::PUBDATA_ENCODING_VERSION; +use rig::basic_system::system_implementation::system::pubdata::{self, PUBDATA_ENCODING_VERSION}; use rig::ruint::aliases::{B160, U256}; use rig::zksync_os_interface::error::InvalidTransaction; use rig::{alloy, zksync_web3_rs, Chain}; @@ -1319,11 +1319,12 @@ fn test_check_pubdata_encoding_version() { ..Default::default() }; // Check tx succeeds - let result = chain.run_block(vec![tx], Some(block_context), None, run_config()); + let (result, pubdata) = + chain.run_block_get_pubdata(vec![tx], Some(block_context), None, run_config()); let res0 = result.tx_results.first().expect("Must have a tx result"); assert!(res0.as_ref().is_ok(), "Tx should succeed"); - assert_eq!(result.pubdata[0], PUBDATA_ENCODING_VERSION); + assert_eq!(pubdata[0], PUBDATA_ENCODING_VERSION); } #[test] @@ -1363,12 +1364,13 @@ fn test_check_pubdata_has_timestamp() { ..Default::default() }; // Check tx succeeds - let result = chain.run_block(vec![tx], Some(block_context), None, run_config()); + let (result, pubdata) = + chain.run_block_get_pubdata(vec![tx], Some(block_context), None, run_config()); let res0 = result.tx_results.first().expect("Must have a tx result"); assert!(res0.as_ref().is_ok(), "Tx should succeed"); // Pubdata format is [VERSION(1)][BLOCK_HASH(32)][TIMESTAMP(8)][DIFFS...] - let pubdata_timestamp_bytes = &result.pubdata.as_slice()[33..41]; + let pubdata_timestamp_bytes = &pubdata.as_slice()[33..41]; let pubdata_timestamp = u64::from_be_bytes( pubdata_timestamp_bytes .try_into() diff --git a/tests/instances/unit/src/initial_slot_regression.rs b/tests/instances/unit/src/initial_slot_regression.rs index 642825c4a..e6cf66d14 100644 --- a/tests/instances/unit/src/initial_slot_regression.rs +++ b/tests/instances/unit/src/initial_slot_regression.rs @@ -133,6 +133,7 @@ impl TestingOracleFactory for InvalidInitialValueOracleFactory { proof_data: Option>>, da_commitment_scheme: Option, _add_uart: bool, + _use_native_callable_oracles: bool, ) -> ZkEENonDeterminismSource { // Create a malicious oracle manually instead of using the default factory let block_metadata_responder = BlockMetadataResponder { block_metadata }; diff --git a/tests/instances/unit/src/tracer/evm_opcodes_logger.rs b/tests/instances/unit/src/tracer/evm_opcodes_logger.rs index 61070a046..67e1d4338 100644 --- a/tests/instances/unit/src/tracer/evm_opcodes_logger.rs +++ b/tests/instances/unit/src/tracer/evm_opcodes_logger.rs @@ -47,7 +47,7 @@ fn run_chain_with_tracer( let result = chain.run_block_with_extra_stats(vec![encoded_tx], None, None, None, tracer); assert!(result.is_ok(), "Block execution should succeed"); - let (block_output, _, _) = result.unwrap(); + let (block_output, _, _, _) = result.unwrap(); assert!( block_output.tx_results[0].is_ok(), "Transaction should succeed. Result: {:?}", diff --git a/tests/instances/unit/src/tracer/mod.rs b/tests/instances/unit/src/tracer/mod.rs index f062ff0b5..6dff7a115 100644 --- a/tests/instances/unit/src/tracer/mod.rs +++ b/tests/instances/unit/src/tracer/mod.rs @@ -46,7 +46,7 @@ pub(crate) fn run_chain_with_tracer( let result = chain.run_block_with_extra_stats(vec![encoded_tx], None, None, None, tracer); assert!(result.is_ok(), "Block execution should succeed"); - let (block_output, _, _) = result.unwrap(); + let (block_output, _, _, _) = result.unwrap(); assert!( block_output.tx_results[0].is_ok(), "Transaction should succeed. Result: {:?}", diff --git a/tests/instances/unit/src/tracer/tracer_event_hook.rs b/tests/instances/unit/src/tracer/tracer_event_hook.rs index ff11dba25..a2de3a4f0 100644 --- a/tests/instances/unit/src/tracer/tracer_event_hook.rs +++ b/tests/instances/unit/src/tracer/tracer_event_hook.rs @@ -152,7 +152,7 @@ fn test_event_hook() { let result = chain.run_block_with_extra_stats(vec![encoded_tx], None, None, None, &mut tracer); assert!(result.is_ok(), "Block execution should succeed"); - let (block_output, _, _) = result.unwrap(); + let (block_output, _, _, _) = result.unwrap(); assert!( block_output.tx_results[0].is_ok(), "Transaction should succeed with correct tracer calls. Result: {:?}", diff --git a/tests/instances/unit/src/tracer/tracer_storage_hooks.rs b/tests/instances/unit/src/tracer/tracer_storage_hooks.rs index e66e205f2..b77d1ba08 100644 --- a/tests/instances/unit/src/tracer/tracer_storage_hooks.rs +++ b/tests/instances/unit/src/tracer/tracer_storage_hooks.rs @@ -159,7 +159,7 @@ fn test_storage_hooks() { let result = chain.run_block_with_extra_stats(vec![encoded_tx], None, None, None, &mut tracer); assert!(result.is_ok(), "Block execution should succeed"); - let (block_output, _, _) = result.unwrap(); + let (block_output, _, _, _) = result.unwrap(); assert!( block_output.tx_results[0].is_ok(), "Transaction should succeed with correct tracer calls. Result: {:?}", diff --git a/tests/rig/src/chain.rs b/tests/rig/src/chain.rs index 30e5428e9..a6593dbb4 100644 --- a/tests/rig/src/chain.rs +++ b/tests/rig/src/chain.rs @@ -11,13 +11,14 @@ use basic_system::system_implementation::flat_storage_model::{ }; use ethers::signers::LocalWallet; use forward_system::run::result_keeper::ForwardRunningResultKeeper; +use forward_system::run::result_keeper::ProverInputResultKeeper; use forward_system::run::test_impl::{InMemoryPreimageSource, InMemoryTree, NoopTxCallback}; use forward_system::system::bootloader::run_forward_no_panic; +use forward_system::system::bootloader::run_prover_input_no_panic; use forward_system::system::system::ForwardRunningSystem; use log::{debug, info, trace}; use oracle_provider::MemorySource; use oracle_provider::{ReadWitnessSource, ZkEENonDeterminismSource}; -use risc_v_simulator::abstractions::memory::VectorMemoryImpl; use risc_v_simulator::sim::{DiagnosticsConfig, ProfilerConfig}; use ruint::aliases::{B160, B256, U256}; use std::collections::HashMap; @@ -47,6 +48,7 @@ pub trait TestingOracleFactory { proof_data: Option>>, da_commitment_scheme: Option, add_uart: bool, + use_native_callable_oracles: bool, ) -> ZkEENonDeterminismSource; } @@ -65,6 +67,7 @@ impl TestingOracleFactory proof_data: Option>>, da_commitment_scheme: Option, add_uart: bool, + use_native_callable_oracles: bool, ) -> ZkEENonDeterminismSource { forward_system::run::make_oracle_for_proofs_and_dumps( block_metadata, @@ -74,6 +77,7 @@ impl TestingOracleFactory proof_data, da_commitment_scheme, add_uart, + use_native_callable_oracles, ) } } @@ -85,7 +89,7 @@ pub struct Chain { state_tree: InMemoryTree, pub preimage_source: InMemoryPreimageSource, chain_id: u64, - previous_block_number: Option, + previous_block_number: u64, block_hashes: [U256; 256], block_timestamp: u64, } @@ -148,7 +152,7 @@ impl Chain { inner: HashMap::new(), }, chain_id: chain_id.unwrap_or(37), - previous_block_number: None, + previous_block_number: 0, block_hashes: [U256::ZERO; 256], block_timestamp: 0, } @@ -171,7 +175,7 @@ impl Chain { inner: HashMap::new(), }, chain_id: chain_id.unwrap_or(37), - previous_block_number: None, + previous_block_number: 0, block_hashes: [U256::ZERO; 256], block_timestamp: 0, } @@ -186,52 +190,17 @@ pub struct BlockExtraStats { impl Chain { pub fn set_last_block_number(&mut self, prev: u64) { - self.previous_block_number = Some(prev) + self.previous_block_number = prev } pub fn next_block_number(&self) -> u64 { - self.previous_block_number.map(|n| n + 1).unwrap_or(0) + self.previous_block_number + 1 } pub fn set_block_hashes(&mut self, block_hashes: [U256; 256]) { self.block_hashes = block_hashes } - /// TODO: duplicated from API, unify. - /// Runs a block in riscV - using zksync_os binary - and returns the - /// witness that can be passed to the prover subsystem. - pub fn run_block_generate_witness( - oracle: ZkEENonDeterminismSource, - app: &Option, - ) -> Vec { - // We'll wrap the source, to collect all the reads. - let copy_source = ReadWitnessSource::new(oracle); - let items = copy_source.get_read_items(); - // By default - enable diagnostics is false (which makes the test run faster). - let path = get_zksync_os_img_path(app); - - let diagnostics_config = if FLAMEGRAPH { - let mut profiler_config = ProfilerConfig::new("flamegraph.svg".into()); - profiler_config.frequency_recip = 10; - - Some(profiler_config).map(|cfg| { - let mut diagnostics_cfg = DiagnosticsConfig::new(get_zksync_os_sym_path(app)); - diagnostics_cfg.profiler_config = Some(cfg); - diagnostics_cfg - }) - } else { - None - }; - - let output = zksync_os_runner::run(path, diagnostics_config, 1 << 36, copy_source); - - // We return 0s in case of failure. - assert_ne!(output, [0u32; 8]); - - let result = items.borrow().clone(); - result - } - /// /// Simulate block, do not validate transactions /// @@ -311,6 +280,25 @@ impl Chain { .0 } + pub fn run_block_get_pubdata( + &mut self, + transactions: Vec, + block_context: Option, + da_commitment_scheme: Option, + run_config: Option, + ) -> (BlockOutput, Vec) { + let (r, _, _, pubdata) = self + .run_block_with_extra_stats( + transactions, + block_context, + da_commitment_scheme, + run_config, + &mut NopTracer::default(), + ) + .unwrap(); + (r, pubdata) + } + /// /// Run block with given transactions, block context, and custom oracle factory. /// If block context is `None` default testing values will be used. @@ -365,7 +353,7 @@ impl Chain { da_commitment_scheme: Option, run_config: Option, tracer: &mut impl Tracer, - ) -> Result<(BlockOutput, BlockExtraStats, Vec), BootloaderSubsystemError> { + ) -> Result<(BlockOutput, BlockExtraStats, Vec, Vec), BootloaderSubsystemError> { let factory = DefaultOracleFactory::; self.run_inner( transactions, @@ -388,7 +376,7 @@ impl Chain { run_config: Option, tracer: &mut impl Tracer, oracle_factory: &OF, - ) -> Result<(BlockOutput, BlockExtraStats, Vec), BootloaderSubsystemError> { + ) -> Result<(BlockOutput, BlockExtraStats, Vec, Vec), BootloaderSubsystemError> { self.run_inner( transactions, block_context, @@ -408,7 +396,7 @@ impl Chain { run_config: RunConfig, oracle_factory: &OF, tracer: &mut impl Tracer, - ) -> Result<(BlockOutput, BlockExtraStats, Vec), BootloaderSubsystemError> { + ) -> Result<(BlockOutput, BlockExtraStats, Vec, Vec), BootloaderSubsystemError> { let RunConfig { profiler_config, witness_output_file, @@ -452,6 +440,7 @@ impl Chain { Some(proof_data), Some(da_commitment_scheme), true, + false, ); let forward_oracle = oracle_factory.create_oracle( @@ -462,6 +451,18 @@ impl Chain { Some(proof_data), Some(da_commitment_scheme), true, + false, + ); + + let prover_input_oracle = oracle_factory.create_oracle( + block_metadata, + self.state_tree.clone(), + self.preimage_source.clone(), + tx_source.clone(), + Some(proof_data), + Some(da_commitment_scheme), + false, + true, ); #[cfg(feature = "simulate_witness_gen")] @@ -480,6 +481,9 @@ impl Chain { // forward run let mut result_keeper = ForwardRunningResultKeeper::new(NoopTxCallback); + // Avoid capturing markers from second round, it duplicate them + #[cfg(feature = "cycle_marker")] + let snapshot = cycle_marker::snapshot(); // we use proving config here for benchmarking, // although sequencer can have extra optimizations run_forward_no_panic::( @@ -487,8 +491,32 @@ impl Chain { &mut result_keeper, tracer, )?; + #[cfg(feature = "cycle_marker")] + cycle_marker::revert(snapshot); + + let mut result_keeper_prover_input = ProverInputResultKeeper::new(NoopTxCallback); + + let copy_source = ReadWitnessSource::new(prover_input_oracle); + let mut tracer = NopTracer::default(); + let prover_input_forward = run_prover_input_no_panic::< + BasicBootloaderProvingExecutionConfig, + >( + copy_source, &mut result_keeper_prover_input, &mut tracer + )?; + + if let Some(path) = witness_output_file { + let mut file = File::create(&path).expect("should create file"); + let witness: Vec = prover_input_forward + .iter() + .flat_map(|x| x.to_be_bytes()) + .collect(); + let hex = hex::encode(witness); + file.write_all(hex.as_bytes()) + .expect("should write to file"); + } let block_output: BlockOutput = result_keeper.into(); + let pubdata = result_keeper_prover_input.pubdata; trace!( "{}Block output:{} \n{:#?}", @@ -516,7 +544,7 @@ impl Chain { } // update state - self.previous_block_number = Some(self.next_block_number()); + self.previous_block_number = self.next_block_number(); self.block_timestamp = block_context.timestamp; for i in 0..255 { self.block_hashes[i] = self.block_hashes[i + 1]; @@ -539,105 +567,95 @@ impl Chain { } let proof_input = if !only_forward { - if let Some(path) = witness_output_file { - let result = Self::run_block_generate_witness::(oracle, &app); - let mut file = File::create(&path).expect("should create file"); - let witness: Vec = result.iter().flat_map(|x| x.to_be_bytes()).collect(); - let hex = hex::encode(witness); - file.write_all(hex.as_bytes()) - .expect("should write to file"); - result - } else { - // We'll wrap the source, to collect all the reads. - let copy_source = ReadWitnessSource::new(oracle); - let items = copy_source.get_read_items(); - - let diagnostics_config = profiler_config.map(|cfg| { - let mut diagnostics_cfg = DiagnosticsConfig::new(get_zksync_os_sym_path(&app)); - diagnostics_cfg.profiler_config = Some(cfg); - diagnostics_cfg - }); - - let now = std::time::Instant::now(); - let (proof_output, block_effective) = { - zksync_os_runner::run_and_get_effective_cycles( - get_zksync_os_img_path(&app), - diagnostics_config, - 1 << 36, - copy_source, - ) - }; + // We'll wrap the source, to collect all the reads. + let copy_source = ReadWitnessSource::new(oracle); + let items = copy_source.get_read_items(); - info!( - "Simulator without witness tracing executed over {:?}", - now.elapsed() - ); - stats.effective_used = block_effective; - - #[cfg(feature = "simulate_witness_gen")] - { - zksync_os_runner::simulate_witness_tracing( - get_zksync_os_img_path(), - source_for_witness_bench, - ) - } + let diagnostics_config = profiler_config.map(|cfg| { + let mut diagnostics_cfg = DiagnosticsConfig::new(get_zksync_os_sym_path(&app)); + diagnostics_cfg.profiler_config = Some(cfg); + diagnostics_cfg + }); + + let now = std::time::Instant::now(); + let (proof_output, block_effective) = { + zksync_os_runner::run_and_get_effective_cycles( + get_zksync_os_img_path(&app), + diagnostics_config, + 1 << 36, + copy_source, + ) + }; + + info!( + "Simulator without witness tracing executed over {:?}", + now.elapsed() + ); + stats.effective_used = block_effective; + + #[cfg(feature = "simulate_witness_gen")] + { + zksync_os_runner::simulate_witness_tracing( + get_zksync_os_img_path(), + source_for_witness_bench, + ) + } - // dump csr reads if env var set - if let Ok(output_csr) = std::env::var("CSR_READS_DUMP") { - // Save the read elements into a file - that can be later read with the tools/cli from zksync-airbender. - let mut file = - File::create(&output_csr).expect("Failed to create csr reads file"); - // Write each u32 as an 8-character hexadecimal string without newlines - for num in items.borrow().iter() { - write!(file, "{num:08X}").expect("Failed to write to file"); - } - debug!( - "Successfully wrote {} u32 csr reads elements to file: {}", - items.borrow().len(), - output_csr - ); + // dump csr reads if env var set + if let Ok(output_csr) = std::env::var("CSR_READS_DUMP") { + // Save the read elements into a file - that can be later read with the tools/cli from zksync-airbender. + let mut file = File::create(&output_csr).expect("Failed to create csr reads file"); + // Write each u32 as an 8-character hexadecimal string without newlines + for num in items.borrow().iter() { + write!(file, "{num:08X}").expect("Failed to write to file"); } - - let proof_input = items.borrow().iter().copied().collect::>(); - debug!( - "{}Proof running output{} = 0x", - colors::GREEN, - colors::RESET + "Successfully wrote {} u32 csr reads elements to file: {}", + items.borrow().len(), + output_csr ); - for word in proof_output.into_iter() { - debug!("{word:08x}"); - } + } - // Ensure that proof running didn't fail: check that output is not zero - assert!(proof_output.into_iter().any(|word| word != 0)); - let proof_output_u8: [u8; 32] = unsafe { core::mem::transmute(proof_output) }; - - if check_storage_diff_hashes { - // Also ensure that storage diff hash matches - use crypto::MiniDigest; - let mut hasher = crypto::blake2s::Blake2s256::new(); - for StorageWrite { key, value, .. } in block_output.storage_writes.iter() { - hasher.update(key.0.as_ref()); - hasher.update(value.0.as_ref()); - } - let forward_storage_diff_hash = hasher.finalize(); - info!( - "Forward storage diff hash: 0x{}", - hex::encode(forward_storage_diff_hash.as_ref()) - ); - assert_eq!(proof_output_u8, forward_storage_diff_hash); - - #[cfg(feature = "e2e_proving")] - run_prover(items.borrow().as_slice()); + let proof_input = items.borrow().iter().copied().collect::>(); + + debug!( + "{}Proof running output{} = 0x", + colors::GREEN, + colors::RESET + ); + for word in proof_output.into_iter() { + debug!("{word:08x}"); + } + + // Ensure that proof running didn't fail: check that output is not zero + assert!(proof_output.into_iter().any(|word| word != 0)); + let proof_output_u8: [u8; 32] = unsafe { core::mem::transmute(proof_output) }; + + if check_storage_diff_hashes { + // Also ensure that storage diff hash matches + use crypto::MiniDigest; + let mut hasher = crypto::blake2s::Blake2s256::new(); + for StorageWrite { key, value, .. } in block_output.storage_writes.iter() { + hasher.update(key.0.as_ref()); + hasher.update(value.0.as_ref()); } + let forward_storage_diff_hash = hasher.finalize(); + info!( + "Forward storage diff hash: 0x{}", + hex::encode(forward_storage_diff_hash.as_ref()) + ); + assert_eq!(proof_output_u8, forward_storage_diff_hash); - proof_input + #[cfg(feature = "e2e_proving")] + run_prover(items.borrow().as_slice()); } + + assert_eq!(prover_input_forward, proof_input); + proof_input } else { vec![] }; - Ok((block_output, stats, proof_input)) + Ok((block_output, stats, proof_input, pubdata)) } pub fn get_account_properties(&mut self, address: &B160) -> AccountProperties { diff --git a/tests/rig/src/testing_utils.rs b/tests/rig/src/testing_utils.rs index 4f04ff631..84f776c03 100644 --- a/tests/rig/src/testing_utils.rs +++ b/tests/rig/src/testing_utils.rs @@ -81,7 +81,7 @@ pub fn call_address_and_measure_gas_cost( let mut tracer = CallTracer::default(); - let (output, _, _) = chain + let (output, _, _, _) = chain .run_block_with_extra_stats(transactions, None, None, None, &mut tracer) .expect("Should succeed");