From 9ba11ded6bd1fe21760c758a1324548b7a2bba68 Mon Sep 17 00:00:00 2001 From: Daniel Kuehr Date: Wed, 4 Dec 2024 09:05:36 -0500 Subject: [PATCH 1/2] tx fuzzer: diff accounts between OCaml and Rust sides on bug detection --- tools/fuzzing/src/context.rs | 1354 ---------- tools/fuzzing/src/generator.rs | 2299 ----------------- tools/fuzzing/src/invariants.rs | 353 --- tools/fuzzing/src/main.rs | 96 +- .../fuzzing/src/transaction_fuzzer/context.rs | 109 +- .../src/transaction_fuzzer/coverage/cov.rs | 22 +- .../src/transaction_fuzzer/coverage/names.rs | 11 +- .../coverage/profile_data.rs | 11 +- .../transaction_fuzzer/coverage/reports.rs | 68 +- .../src/transaction_fuzzer/coverage/stats.rs | 10 +- .../src/transaction_fuzzer/coverage/util.rs | 2 +- .../src/transaction_fuzzer/generator.rs | 215 +- .../src/transaction_fuzzer/invariants.rs | 1 + .../fuzzing/src/transaction_fuzzer/mutator.rs | 4 +- tools/fuzzing/src/util.rs | 95 - 15 files changed, 286 insertions(+), 4364 deletions(-) delete mode 100644 tools/fuzzing/src/context.rs delete mode 100644 tools/fuzzing/src/generator.rs delete mode 100644 tools/fuzzing/src/invariants.rs delete mode 100644 tools/fuzzing/src/util.rs diff --git a/tools/fuzzing/src/context.rs b/tools/fuzzing/src/context.rs deleted file mode 100644 index 96710d111b..0000000000 --- a/tools/fuzzing/src/context.rs +++ /dev/null @@ -1,1354 +0,0 @@ -use crate::generator::{Generator, GeneratorRange32, GeneratorRange64}; -use crate::mutator::Mutator; -use crate::{deserialize, serialize}; -use ark_ff::Zero; -//use binprot::macros::BinProtWrite; -use ledger::scan_state::currency::{Amount, Fee, Length, Magnitude, Nonce, Signed, Slot}; -use ledger::scan_state::transaction_logic::protocol_state::{ - protocol_state_view, EpochData, EpochLedger, ProtocolStateView, -}; -use ledger::scan_state::transaction_logic::transaction_applied::{ - signed_command_applied, CommandApplied, TransactionApplied, Varying, -}; -use ledger::scan_state::transaction_logic::{ - apply_transactions, Transaction, TransactionStatus, UserCommand, -}; -use ledger::sparse_ledger::LedgerIntf; -use ledger::staged_ledger::staged_ledger::StagedLedger; -use ledger::{dummy, Account, AccountId, Database, Mask, Timing, TokenId}; -use mina_hasher::Fp; -use mina_p2p_messages::binprot::SmallString1k; -use mina_p2p_messages::{ - bigint, binprot, - v2::{ - MinaTransactionLogicTransactionAppliedStableV2, - TransactionSnarkScanStateLedgerProofWithSokMessageStableV2, - }, -}; -use mina_signer::{CompressedPubKey, Keypair}; -use openmina_core::constants::ConstraintConstants; -use rand::{rngs::SmallRng, seq::SliceRandom, Rng, SeedableRng}; -use ring_buffer::RingBuffer; -use std::collections::HashMap; -use std::fmt::Debug; -use std::{fs, str::FromStr}; - -/// Same values when we run `dune runtest src/lib/staged_ledger -f` -pub const CONSTRAINT_CONSTANTS: ConstraintConstants = ConstraintConstants { - sub_windows_per_window: 11, - ledger_depth: 35, - work_delay: 2, - block_window_duration_ms: 180000, - transaction_capacity_log_2: 7, - pending_coinbase_depth: 5, - coinbase_amount: 720000000000, - supercharged_coinbase_factor: 2, - account_creation_fee: 1000000000, - fork: None, -}; - -// Taken from ocaml_tests -/// Same values when we run `dune runtest src/lib/staged_ledger -f` -#[coverage(off)] -fn dummy_state_view(global_slot_since_genesis: Option) -> ProtocolStateView { - // TODO: Use OCaml implementation, not hardcoded value - let f = #[coverage(off)] - |s: &str| Fp::from_str(s).unwrap(); - - ProtocolStateView { - snarked_ledger_hash: f( - "19095410909873291354237217869735884756874834695933531743203428046904386166496", - ), - blockchain_length: Length::from_u32(1), - min_window_density: Length::from_u32(77), - total_currency: Amount::from_u64(10016100000000000), - global_slot_since_genesis: global_slot_since_genesis.unwrap_or_else(Slot::zero), - staking_epoch_data: EpochData { - ledger: EpochLedger { - hash: f( - "19095410909873291354237217869735884756874834695933531743203428046904386166496", - ), - total_currency: Amount::from_u64(10016100000000000), - }, - seed: Fp::zero(), - start_checkpoint: Fp::zero(), - lock_checkpoint: Fp::zero(), - epoch_length: Length::from_u32(1), - }, - next_epoch_data: EpochData { - ledger: EpochLedger { - hash: f( - "19095410909873291354237217869735884756874834695933531743203428046904386166496", - ), - total_currency: Amount::from_u64(10016100000000000), - }, - seed: f( - "18512313064034685696641580142878809378857342939026666126913761777372978255172", - ), - start_checkpoint: Fp::zero(), - lock_checkpoint: f( - "9196091926153144288494889289330016873963015481670968646275122329689722912273", - ), - epoch_length: Length::from_u32(2), - }, - } -} - -#[coverage(off)] -pub fn dummy_state_and_view( - global_slot: Option, -) -> ( - mina_p2p_messages::v2::MinaStateProtocolStateValueStableV2, - ProtocolStateView, -) { - let mut state = dummy::for_tests::dummy_protocol_state(); - - if let Some(global_slot) = global_slot { - let new_global_slot = global_slot; - - let global_slot_since_genesis = { - let since_genesis = &state.body.consensus_state.global_slot_since_genesis; - let curr = &state - .body - .consensus_state - .curr_global_slot_since_hard_fork - .slot_number; - - let since_genesis = Slot::from_u32(since_genesis.as_u32()); - let curr = Slot::from_u32(curr.as_u32()); - - (since_genesis.checked_sub(&curr).unwrap()) - .checked_add(&new_global_slot) - .unwrap() - }; - - let cs = &mut state.body.consensus_state; - cs.curr_global_slot_since_hard_fork.slot_number = (&new_global_slot).into(); - cs.global_slot_since_genesis = (&global_slot_since_genesis).into(); - }; - - let view = protocol_state_view(&state); - - (state, view) -} - -pub enum PermissionModel { - Any, // Allow any (random) combination of permissions - Empty, // Permissions are always set to None - Initial, // Permissions are always set to "user_default" set (signature only). - Default, // "default" permissions as set by SnarkyJS when deploying a zkApp. - TokenOwner, // permission set usually set in Token owner zkApps -} - -impl Clone for PermissionModel { - #[coverage(off)] - fn clone(&self) -> Self { - match self { - PermissionModel::Any => PermissionModel::Any, - PermissionModel::Empty => PermissionModel::Empty, - PermissionModel::Initial => PermissionModel::Initial, - PermissionModel::Default => PermissionModel::Default, - PermissionModel::TokenOwner => PermissionModel::TokenOwner, - } - } -} - -// #[derive(BinProtWrite, Debug)] -// pub struct TxProofCreateInputs { -// pub sok_message: MinaBaseSokMessageStableV1, -// pub snarked_ledger_state: MinaStateSnarkedLedgerStateStableV2, -// pub witness: TxWitness, -// } - -// #[derive(BinProtWrite, Debug)] -// pub struct TxWitness { -// pub transaction: Tx, -// pub first_pass_ledger: MinaBaseSparseLedgerBaseStableV2, -// pub second_pass_ledger: MinaBaseSparseLedgerBaseStableV2, -// pub protocol_state_body: MinaStateProtocolStateBodyValueStableV2, -// pub init_stack: MinaBasePendingCoinbaseStackVersionedStableV1, -// pub status: MinaBaseTransactionStatusStableV2, -// pub block_global_slot: UnsignedExtendedUInt32StableV1, -// } - -#[derive(Debug)] -pub struct ApplyTxResult { - root_hash: Fp, - apply_result: Vec, - error: String, -} - -impl binprot::BinProtRead for ApplyTxResult { - #[coverage(off)] - fn binprot_read(r: &mut R) -> Result - where - Self: Sized, - { - let root_hash: Fp = bigint::BigInt::binprot_read(r)?.into(); - // Start of Selection - let apply_result = Vec::::binprot_read(r)? - .into_iter() - .map( - #[coverage(off)] - |MinaTransactionLogicTransactionAppliedStableV2 { - previous_hash, - varying, - }| TransactionApplied { - previous_hash: (&previous_hash.0).into(), - varying: (&varying).into(), - }, - ) - .collect(); - let error: String = SmallString1k::binprot_read(r)?.0; - - Ok(ApplyTxResult { - root_hash, - apply_result, - error, - }) - } -} - -// // TODO: remove this type once `Transaction` implements `BinProtWrite`. -// #[derive(BinProtWrite, Debug, Clone)] -// pub enum Tx { -// UserCommand(UserCommand), -// } - -// impl From for Transaction { -// fn from(value: Tx) -> Self { -// match value { -// Tx::UserCommand(v) => Self::Command(v), -// } -// } -// } - -// impl From for Tx { -// fn from(value: Transaction) -> Self { -// match value { -// Transaction::Command(v) => Tx::UserCommand(v), -// _ => unimplemented!(), -// } -// } -// } - -pub enum LedgerKind { - Mask(Mask), - Staged(StagedLedger, Mask), -} - -impl Clone for LedgerKind { - #[coverage(off)] - fn clone(&self) -> Self { - match self { - Self::Mask(ledger) => Self::Mask(ledger.copy()), - Self::Staged(ledger, snarked_ledger) => { - Self::Staged(ledger.clone(), snarked_ledger.clone()) - } - } - } -} - -pub struct FuzzerState { - pub ledger: LedgerKind, - pub potential_senders: Vec<(Keypair, PermissionModel)>, - pub potential_new_accounts: Vec<(Keypair, PermissionModel)>, - pub cache_pool: RingBuffer, - pub cache_apply: RingBuffer, -} - -impl Clone for FuzzerState { - #[coverage(off)] - fn clone(&self) -> Self { - Self { - ledger: self.ledger.clone(), - potential_senders: self.potential_senders.clone(), - potential_new_accounts: self.potential_new_accounts.clone(), - cache_pool: self.cache_pool.clone(), - cache_apply: self.cache_apply.clone(), - } - } -} - -pub struct GeneratorCtx { - pub rng: SmallRng, - pub max_account_balance: u64, - pub minimum_fee: u64, - pub excess_fee: Signed, - pub token_id: TokenId, - pub tx_proof: Option, - pub nonces: HashMap, // TODO: implement hash trait for CompressedPubKey - /// Attempt to produce a valid zkapp - pub attempt_valid_zkapp: bool, -} - -pub struct FuzzerCtx { - pub constraint_constants: ConstraintConstants, - pub txn_state_view: ProtocolStateView, - pub fuzzcases_path: String, - pub gen: GeneratorCtx, - pub state: FuzzerState, - pub snapshots: RingBuffer, -} - -impl FuzzerCtx { - #[coverage(off)] - fn get_ledger_inner(&self) -> &Mask { - match &self.state.ledger { - LedgerKind::Mask(ledger) => ledger, - LedgerKind::Staged(ledger, _) => ledger.ledger_ref(), - } - } - - #[coverage(off)] - fn get_ledger_inner_mut(&mut self) -> &mut Mask { - match &mut self.state.ledger { - LedgerKind::Mask(ledger) => ledger, - LedgerKind::Staged(ledger, _) => ledger.ledger_mut(), - } - } - - #[coverage(off)] - fn get_snarked_ledger_inner_mut(&mut self) -> Option<&mut Mask> { - match &mut self.state.ledger { - LedgerKind::Mask(_) => None, - LedgerKind::Staged(_, snarked_ledger) => Some(snarked_ledger), - } - } - - // #[coverage(off)] - // fn set_snarked_ledger(&mut self, snarked_ledger: Mask) { - // match &mut self.state.ledger { - // LedgerKind::Mask(_) => panic!(), - // LedgerKind::Staged(_, old_snarked_ledger) => *old_snarked_ledger = snarked_ledger, - // } - // } - - // #[coverage(off)] - // fn get_staged_ledger(&mut self) -> &mut StagedLedger { - // match &mut self.state.ledger { - // LedgerKind::Staged(ledger, _) => ledger, - // _ => panic!(), - // } - // } - - #[coverage(off)] - pub fn get_snarked_ledger(&mut self) -> &mut Mask { - match &mut self.state.ledger { - LedgerKind::Staged(_, ledger) => ledger, - _ => panic!(), - } - } - - #[coverage(off)] - pub fn create_inital_accounts(&mut self, n: usize) { - for _ in 0..n { - loop { - let keypair: Keypair = self.gen(); - - if !self.state.potential_senders.iter().any( - #[coverage(off)] - |(kp, _)| kp.public == keypair.public, - ) { - let pk_compressed = keypair.public.into_compressed(); - let account_id = AccountId::new(pk_compressed, TokenId::default()); - let mut account = Account::initialize(&account_id); - - account.balance = GeneratorRange64::gen_range( - self, - 1_000_000_000_000..=self.gen.max_account_balance, - ); - account.nonce = GeneratorRange32::gen_range(self, 0..=u32::MAX); - account.timing = Timing::Untimed; - - let permission_model = self.gen(); - self.state - .potential_senders - .push((keypair, permission_model)); - - if let Some(snarked_ledger) = self.get_snarked_ledger_inner_mut() { - snarked_ledger - .create_new_account(account_id.clone(), account.clone()) - .unwrap(); - }; - - self.get_ledger_inner_mut() - .create_new_account(account_id, account) - .unwrap(); - - break; - } - } - } - } - - #[coverage(off)] - pub fn get_account(&mut self, pkey: &CompressedPubKey) -> Option { - let account_location = LedgerIntf::location_of_account( - self.get_ledger_inner(), - &AccountId::new(pkey.clone(), TokenId::default()), - ); - - account_location.map( - #[coverage(off)] - |location| *(LedgerIntf::get(self.get_ledger_inner(), &location).unwrap()).clone(), - ) - } - - #[coverage(off)] - pub fn find_sender(&mut self, pkey: &CompressedPubKey) -> Option<&(Keypair, PermissionModel)> { - self.state.potential_senders.iter().find( - #[coverage(off)] - |(kp, _)| kp.public.into_compressed() == *pkey, - ) - } - - #[coverage(off)] - pub fn find_permissions(&mut self, pkey: &CompressedPubKey) -> Option<&PermissionModel> { - self.find_sender(pkey).map( - #[coverage(off)] - |(_, pm)| pm, - ) - } - - #[coverage(off)] - pub fn find_keypair(&mut self, pkey: &CompressedPubKey) -> Option<&Keypair> { - self.find_sender(pkey).map( - #[coverage(off)] - |(kp, _)| kp, - ) - } - - #[coverage(off)] - pub fn random_keypair(&mut self) -> Keypair { - self.state - .potential_senders - .choose(&mut self.gen.rng) - .unwrap() - .0 - .clone() - } - - #[coverage(off)] - pub fn random_ntransactions(&mut self) -> usize { - self.gen.rng.gen_range(0..400) - } - - #[coverage(off)] - pub fn random_snark_worker_fee(&mut self) -> Fee { - let fee = self.gen.rng.gen_range(0..10_000_000); - Fee::from_u64(fee) - } - - #[coverage(off)] - pub fn random_user_command(&mut self) -> UserCommand { - if self.gen.rng.gen_bool(0.9) { - if !self.state.cache_apply.is_empty() { - // Pick transaction from the applied tx cache and mutate it - let index = self.gen.rng.gen_range(0..self.state.cache_apply.len()); - - if let Some(mut transaction) = self.state.cache_apply.get_relative(index).cloned() { - self.mutate(&mut transaction); - return transaction; - } - } - - // If we can't find a tx in the applied cache, try one from the pool cache - if self.gen.rng.gen_bool(0.5) && !self.state.cache_pool.is_empty() { - let index = self.gen.rng.gen_range(0..self.state.cache_pool.len()); - - if let Some(mut transaction) = self.state.cache_pool.get_relative(index).cloned() { - self.mutate(&mut transaction); - return transaction; - } - } - } - - // Generate random transaction - self.gen() - } - - #[coverage(off)] - pub fn random_tx_proof( - &mut self, - ) -> TransactionSnarkScanStateLedgerProofWithSokMessageStableV2 { - let mut proof = self - .gen - .tx_proof - .clone() - .expect("valid tx proof not set for FuzzerCtx"); - self.mutate(&mut proof); - proof - } - - // #[coverage(off)] - // pub fn random_create_tx_proof_inputs( - // &mut self, - // protocol_state_body: MinaStateProtocolStateBodyValueStableV2, - // mut verify_tx: F, - // ) -> Option<(bool, TxProofCreateInputs)> - // where - // F: FnMut(&Transaction) -> bool, - // { - // let state_body_hash = MinaHash::hash(&protocol_state_body); - // let block_global_slot = protocol_state_body - // .consensus_state - // .global_slot_since_genesis - // .clone(); - // let init_stack = protocol_state_body - // .blockchain_state - // .ledger_proof_statement - // .source - // .pending_coinbase_stack - // .clone(); - - // let tx = self.random_transaction(); - // let is_valid = verify_tx(&tx); - // let transaction = WithStatus::applied(tx.clone()); - // let tx = Tx::from(tx); - - // let ledger = self.get_ledger_inner().make_child(); - // let staged_ledger = - // StagedLedger::create_exn(self.constraint_constants.clone(), ledger).unwrap(); - // let apply_res = StagedLedger::update_ledger_and_get_statements( - // &self.constraint_constants, - // // TODO(binier): construct from passed protocol_state_body. - // self.txn_state_view.global_slot_since_genesis, - // staged_ledger.ledger(), - // &(&init_stack).into(), - // (vec![transaction.clone()], None), - // // TODO(binier): construct from passed protocol_state_body. - // &self.txn_state_view, - // ( - // // TODO(binier): use state hash instead. Not used anyways though. - // state_body_hash, - // state_body_hash, - // ), - // ); - // let tx_with_witness = match apply_res { - // Ok((txs_with_witness, ..)) => txs_with_witness.into_iter().next().unwrap(), - // Err(_) => return None, - // }; - - // Some(( - // is_valid, - // TxProofCreateInputs { - // sok_message: serde_json::from_value(serde_json::json!({ - // "fee":"25000000", - // "prover":"B62qn7G9oFofQDGiAoP8TmYce7185PjWJ39unqjr2v7EgsRDoFCFc1k" - // })) - // .unwrap(), - // snarked_ledger_state: (&tx_with_witness.statement).into(), - // witness: TxWitness { - // transaction: tx, - // first_pass_ledger: (&tx_with_witness.first_pass_ledger_witness).into(), - // second_pass_ledger: (&tx_with_witness.second_pass_ledger_witness).into(), - // protocol_state_body, - // // TODO(binier): should we somehow use value from `tx_with_witness`? - // init_stack, - // status: MinaBaseTransactionStatusStableV2::Applied, - // block_global_slot, - // }, - // }, - // )) - // } - - #[coverage(off)] - pub fn take_snapshot(&mut self) { - println!("Taking snapshot..."); - self.snapshots.push_back(self.state.clone()); - } - - #[coverage(off)] - pub fn restore_snapshot(&mut self) { - if !self.snapshots.is_empty() { - // Pick random snapshot - let index = self.gen.rng.gen_range(0..self.snapshots.len()); - - if let Some(state) = self.snapshots.get_relative(index).cloned() { - println!("Restoring snapshot {}...", index); - self.state = state; - } - } - } - - // #[coverage(off)] - // pub fn serialize_transaction(tx: &Transaction) -> Vec { - // /* - // We don't have generated types for Transaction, but we have one - // for UserCommand (MinaBaseUserCommandStableV2). Extract and - // serialize the inner UserCommand and let a OCaml wrapper build - // the transaction. - // */ - // match &tx { - // Transaction::Command(user_command) => serialize(user_command), - // _ => unimplemented!(), - // } - // } - - // #[coverage(off)] - // pub fn serialize_ledger(&self) -> Vec { - // serialize(&self.get_ledger_accounts()) - // } - - #[coverage(off)] - fn save_fuzzcase(&self, tx: &Transaction, filename: &String) { - let filename = self.fuzzcases_path.clone() + &filename + ".fuzzcase"; - - println!("Saving fuzzcase: {}", filename); - - let user_command = match tx { - Transaction::Command(user_command) => user_command.clone(), - _ => unimplemented!(), - }; - - let mut file = fs::OpenOptions::new() - .write(true) - .truncate(true) - .create(true) - .open(filename) - .unwrap(); - - serialize(&(self.get_ledger_accounts(), user_command), &mut file); - } - - #[coverage(off)] - pub fn load_fuzzcase(&mut self, file_path: &String) -> UserCommand { - println!("Loading fuzzcase: {}", file_path); - let bytes = fs::read(file_path).unwrap(); - let (accounts, user_command): (Vec, UserCommand) = - deserialize(&mut bytes.as_slice()); - - let depth = self.constraint_constants.ledger_depth as usize; - let root = Mask::new_root(Database::create(depth.try_into().unwrap())); - - *self.get_ledger_inner_mut() = root.make_child(); - - for account in accounts { - self.get_ledger_inner_mut() - .create_new_account(account.id(), account) - .unwrap(); - } - - user_command - } - - // #[coverage(off)] - // pub fn apply_staged_ledger_diff( - // &mut self, - // diff: Diff, - // global_slot: Slot, - // coinbase_receiver: CompressedPubKey, - // current_view: ProtocolStateView, - // state_hashes: (Fp, Fp), - // state_tbl: &HashMap, - // iteration: usize, - // ) -> Result, ()> { - // if iteration == 1271 { - // #[derive(Clone, Debug, PartialEq, BinProtRead, BinProtWrite)] - // struct State { - // scan_state: mina_p2p_messages::v2::TransactionSnarkScanStateStableV2, - // pending_coinbase_collection: mina_p2p_messages::v2::MinaBasePendingCoinbaseStableV2, - // states: Vec<( - // mina_p2p_messages::bigint::BigInt, - // mina_p2p_messages::v2::MinaStateProtocolStateValueStableV2, - // )>, - // snarked_ledger: Vec, - // expected_staged_ledger_merkle_root: mina_p2p_messages::bigint::BigInt, - // } - - // let sl = self.get_staged_ledger(); - // let sc = sl.scan_state.clone(); - // let pcc = sl.pending_coinbase_collection.clone(); - // let expected_staged_ledger_merkle_root = sl.ledger().clone().merkle_root(); - // let snarked_ledger = self.get_snarked_ledger(); - - // let state = State { - // scan_state: (&sc).into(), - // pending_coinbase_collection: (&pcc).into(), - // states: state_tbl - // .iter() - // .map(|(h, v)| (h.into(), v.clone())) - // .collect(), - // snarked_ledger: { - // snarked_ledger - // .to_list() - // .into_iter() - // .map(Into::into) - // .collect() - // // todo!() - // }, - // expected_staged_ledger_merkle_root: expected_staged_ledger_merkle_root.into(), - // }; - - // let mut file = std::fs::File::create("/tmp/state.bin").unwrap(); - // BinProtWrite::binprot_write(&state, &mut file).unwrap(); - // file.sync_all().unwrap(); - - // eprintln!("data saved"); - // } - - // let constraint_constants = self.constraint_constants.clone(); - - // let DiffResult { - // hash_after_applying, - // ledger_proof, - // pending_coinbase_update: _, - // } = self - // .get_staged_ledger() - // .apply( - // None, - // &constraint_constants, - // global_slot, - // diff, - // (), - // &Verifier, - // ¤t_view, - // state_hashes, - // coinbase_receiver, - // false, - // ) - // .map_err(|_| ())?; - // // .unwrap(); - - // if let Some((proof, _transactions)) = ledger_proof { - // self.update_snarked_ledger(state_tbl, proof) - // }; - - // self.get_staged_ledger().commit_and_reparent_to_root(); - - // Ok(hash_after_applying) - // } - - // #[coverage(off)] - // fn update_snarked_ledger( - // &mut self, - // state_tbl: &HashMap, - // proof: LedgerProof, - // ) { - // let target_snarked_ledger = { - // let stmt = proof.statement_ref(); - // stmt.target.first_pass_ledger - // }; - - // let apply_first_pass = |global_slot: Slot, - // txn_state_view: &ProtocolStateView, - // ledger: &mut Mask, - // transaction: &Transaction| { - // apply_transaction_first_pass( - // &CONSTRAINT_CONSTANTS, - // global_slot, - // txn_state_view, - // ledger, - // transaction, - // ) - // }; - - // let apply_second_pass = |ledger: &mut Mask, tx: TransactionPartiallyApplied| { - // apply_transaction_second_pass(&CONSTRAINT_CONSTANTS, ledger, tx) - // }; - - // let apply_first_pass_sparse_ledger = - // |global_slot: Slot, - // txn_state_view: &ProtocolStateView, - // sparse_ledger: &mut SparseLedger, - // transaction: &Transaction| { - // apply_transaction_first_pass( - // &CONSTRAINT_CONSTANTS, - // global_slot, - // txn_state_view, - // sparse_ledger, - // transaction, - // ) - // }; - - // let mut ledger = self.get_snarked_ledger().fuzzing_to_root(); - - // let get_state = |hash: Fp| Ok(state_tbl.get(&hash).cloned().unwrap()); - - // assert!(self - // .get_staged_ledger() - // .scan_state() - // .latest_ledger_proof() - // .is_some()); - - // self.get_staged_ledger() - // .scan_state() - // .get_snarked_ledger_sync( - // &mut ledger, - // get_state, - // apply_first_pass, - // apply_second_pass, - // apply_first_pass_sparse_ledger, - // ) - // .unwrap(); - - // eprintln!("#############################################################"); - // eprintln!(" NEW SNARKED LEDGER: {:?}", target_snarked_ledger); - // eprintln!("#############################################################"); - - // assert_eq!(ledger.merkle_root(), target_snarked_ledger); - // self.set_snarked_ledger(ledger); - // assert_eq!( - // self.get_snarked_ledger().merkle_root(), - // target_snarked_ledger - // ); - // } - - // #[coverage(off)] - // pub fn create_staged_ledger_diff( - // &mut self, - // txns: Vec, - // global_slot: Slot, - // prover: CompressedPubKey, - // coinbase_receiver: CompressedPubKey, - // current_view: ProtocolStateView, - // ocaml_result: &Result< - // ( - // StagedLedgerDiffDiffStableV2, - // Vec<(transaction_logic::valid::UserCommand, String)>, - // ), - // String, - // >, - // iteration: usize, - // snark_worker_fees: &mut Vec, - // ) -> Result, ()> { - // eprintln!(); - // eprintln!("###################################################"); - // eprintln!(" CREATE_STAGED_LEDGER_DIFF "); - // eprintln!("###################################################"); - - // eprintln!( - // "get_staged_ledger num_account={:?}", - // self.get_staged_ledger().ledger.account_locations().len() - // ); - // // get_staged_ledger - // self.gen.nonces.clear(); - - // let stmt_to_work_random_prover = |stmt: &Statement| -> Option { - // let fee = snark_worker_fees.pop().unwrap(); - // Some(Checked { - // fee, - // proofs: stmt.map(|statement| { - // LedgerProof::create( - // statement.clone(), - // SokDigest::default(), - // dummy::dummy_transaction_proof(), - // ) - // }), - // prover: prover.clone(), - // }) - // }; - - // let txns = txns - // .into_iter() - // .map(|tx| { - // let Transaction::Command(cmd) = tx else { - // unreachable!() - // }; - // cmd.to_valid() - // }) - // .collect(); - - // let constraint_constants = self.constraint_constants.clone(); - - // dbg!(global_slot); - - // let result = self.get_staged_ledger().create_diff( - // &constraint_constants, - // global_slot, - // None, - // coinbase_receiver, - // (), - // ¤t_view, - // txns, - // stmt_to_work_random_prover, - // false, // Always false on berkeleynet now - // ); - - // // FIXME: ignoring error messages - // if result.is_err() && ocaml_result.is_err() { - // return Ok(None); - // } - - // if !(result.is_ok() && ocaml_result.is_ok()) { - // println!( - // "!!! create_staged_ledger_diff mismatch between OCaml and Rust (result is_ok)\n{:?}\n{:?}\n", - // result, ocaml_result - // ); - - // //let bigint: num_bigint::BigUint = ledger.merkle_root().into(); - // //self.save_fuzzcase(tx, &bigint.to_string()); - // return Err(()); - // } - - // let (diff, invalid_cmds) = result.unwrap(); - // let (ocaml_diff, ocaml_invalid_cmds) = ocaml_result.as_ref().unwrap(); - - // if iteration == 1271 { - // let mut file = std::fs::File::create("/tmp/diff.bin").unwrap(); - // BinProtWrite::binprot_write(ocaml_diff, &mut file).unwrap(); - // file.sync_all().unwrap(); - // eprintln!("SAVED DIFF"); - // } - - // let diff = diff.forget(); - - // // FIXME: ignore error messages as work around for differences in string formatting between Rust and OCaml - // let rust_invalid_cmds: Vec<_> = invalid_cmds.iter().map(|x| x.0.clone()).collect(); - - // let ocaml_invalid_cmds2: Vec<_> = ocaml_invalid_cmds.iter().map(|x| x.0.clone()).collect(); - - // // Make sure we got same result - // if !(rust_invalid_cmds == ocaml_invalid_cmds2) { - // println!( - // "!!! create_staged_ledger_diff mismatch between OCaml and Rust (invalids)\n{}\n", - // self.diagnostic(&rust_invalid_cmds, &ocaml_invalid_cmds2) - // ); - - // eprintln!("last_string={:?}", ocaml_invalid_cmds.last().unwrap().1); - - // //let bigint: num_bigint::BigUint = ledger.merkle_root().into(); - // //self.save_fuzzcase(tx, &bigint.to_string()); - // return Err(()); - // } - - // let ocaml_diff: Diff = ocaml_diff.into(); - - // if !(diff == ocaml_diff) { - // println!( - // "!!! create_staged_ledger_diff mismatch between OCaml and Rust (diff)\n{}\n", - // self.diagnostic(&diff, &ocaml_diff) - // ); - // println!("!!! OCAML=\n{:?}\n", &ocaml_diff,); - - // //let bigint: num_bigint::BigUint = ledger.merkle_root().into(); - // //self.save_fuzzcase(tx, &bigint.to_string()); - // return Err(()); - // } - - // Ok(Some(diff)) - // } - - // #[coverage(off)] - // pub fn of_scan_state_pending_coinbases_and_snarked_ledger( - // &mut self, - // current_state: &MinaStateProtocolStateValueStableV2, - // state_tbl: &HashMap, - // iteration: usize, - // ) { - // eprintln!("#######################################################"); - // eprintln!("of_scan_state_pending_coinbases_and_snarked_ledger"); - // eprintln!("#######################################################"); - - // let get_state = |hash: Fp| state_tbl.get(&hash).cloned().unwrap(); - - // let mut snarked_ledger = self.get_snarked_ledger().fuzzing_to_root(); - // let sl = self.get_staged_ledger(); - // let expected_hash: StagedLedgerHash = sl.hash(); - // let expected_staged_ledger_merkle_root = sl.ledger.clone().merkle_root(); - - // dbg!(snarked_ledger.merkle_root()); - - // let new_staged_ledger = StagedLedger::of_scan_state_pending_coinbases_and_snarked_ledger( - // (), - // &CONSTRAINT_CONSTANTS, - // Verifier, - // sl.scan_state.clone(), - // snarked_ledger.copy(), - // { - // let registers: transaction_snark::Registers = (¤t_state - // .body - // .blockchain_state - // .ledger_proof_statement - // .target) - // .into(); - // registers.local_state - // }, - // expected_staged_ledger_merkle_root, - // sl.pending_coinbase_collection.clone(), - // get_state, - // ); - - // // if new_staged_ledger.is_err() || iteration == 370 { - - // // #[derive(Clone, Debug, PartialEq, binprot_derive::BinProtRead, BinProtWrite)] - // // struct State { - // // scan_state: mina_p2p_messages::v2::TransactionSnarkScanStateStableV2, - // // pending_coinbase_collection: mina_p2p_messages::v2::MinaBasePendingCoinbaseStableV2, - // // states: Vec<(mina_p2p_messages::bigint::BigInt, MinaStateProtocolStateValueStableV2)>, - // // snarked_ledger: Vec, - // // expected_staged_ledger_merkle_root: mina_p2p_messages::bigint::BigInt, - // // } - - // // let sc = sl.scan_state.clone(); - // // let pcc = sl.pending_coinbase_collection.clone(); - - // // let state = State { - // // scan_state: (&sc).into(), - // // pending_coinbase_collection: (&pcc).into(), - // // states: state_tbl.iter().map(|(h, v)| (h.into(), v.clone())).collect(), - // // snarked_ledger: { - // // use crate::BaseLedger; - // // snarked_ledger.to_list().into_iter().map(Into::into).collect() - // // // todo!() - // // }, - // // expected_staged_ledger_merkle_root: expected_staged_ledger_merkle_root.into(), - // // }; - - // // let mut file = std::fs::File::create("/tmp/state.bin").unwrap(); - // // BinProtWrite::binprot_write(&state, &mut file).unwrap(); - // // file.sync_all().unwrap(); - - // // eprintln!("data saved"); - // // } - - // let mut new_staged_ledger = new_staged_ledger.unwrap(); - - // assert_eq!(expected_hash, sl.hash()); - // assert_eq!(expected_hash, new_staged_ledger.hash()); - // eprintln!("#######################################################"); - // eprintln!("of_scan_state_pending_coinbases_and_snarked_ledger OK"); - // eprintln!("#######################################################"); - // } - - #[coverage(off)] - fn diagnostic(&self, applied: &impl Debug, applied_ocaml: &impl Debug) -> String { - use text_diff::{diff, Difference}; - - let orig = format!("{:#?}", applied); - let edit = format!("{:#?}", applied_ocaml); - let split = " "; - let (_, changeset) = diff(orig.as_str(), edit.as_str(), split); - - let mut ret = String::new(); - - for seq in changeset { - match seq { - Difference::Same(ref x) => { - ret.push_str(x); - ret.push_str(split); - } - Difference::Add(ref x) => { - ret.push_str("\x1B[92m"); - ret.push_str(x); - ret.push_str("\x1B[0m"); - ret.push_str(split); - } - Difference::Rem(ref x) => { - ret.push_str("\x1B[91m"); - ret.push_str(x); - ret.push_str("\x1B[0m"); - ret.push_str(split); - } - } - } - - ret - } - - #[coverage(off)] - pub fn apply_transaction( - &mut self, - user_command: &UserCommand, - expected_apply_result: &ApplyTxResult, - ) -> Result<(), ()> { - self.gen.nonces.clear(); - - let mut ledger = self.get_ledger_inner().make_child(); - - // If we called apply_transaction it means we passed the tx pool check, so add tx to the cache - if let UserCommand::ZkAppCommand(command) = user_command { - if !command.account_updates.is_empty() { - //println!("Storing in pool cache {:?}", tx); - self.state.cache_pool.push_back(user_command.clone()); - } - } - - //println!("tx: {:?}\n", tx); - let tx = Transaction::Command(user_command.clone()); - - let applied = apply_transactions( - &self.constraint_constants, - self.txn_state_view.global_slot_since_genesis, - &self.txn_state_view, - &mut ledger, - &[tx.clone()], - ); - - println!( - "tx: {:?}\n applied: {:?}\n expected: {:?}", - tx, applied, expected_apply_result - ); - - match applied { - Ok(applied) => { - // For now we work with one transaction at a time - let applied = &applied[0]; - - if expected_apply_result.apply_result.len() != 1 { - println!( - "!!! Apply failed in OCaml (error: {}) but it didn't in Rust: {:?}", - expected_apply_result.error, applied - ); - let bigint: num_bigint::BigUint = LedgerIntf::merkle_root(&mut ledger).into(); - self.save_fuzzcase(&tx, &bigint.to_string()); - return Err(()); - } else { - if applied != &expected_apply_result.apply_result[0] { - println!( - "!!! Apply result mismatch between OCaml and Rust\n{}\n", - self.diagnostic(applied, &expected_apply_result.apply_result[0]) - ); - - let bigint: num_bigint::BigUint = - LedgerIntf::merkle_root(&mut ledger).into(); - self.save_fuzzcase(&tx, &bigint.to_string()); - return Err(()); - } - } - - // Save applied transactions in the cache for later use (mutation) - if *applied.transaction_status() == TransactionStatus::Applied { - if let UserCommand::ZkAppCommand(command) = user_command { - if !command.account_updates.is_empty() { - //println!("Storing in apply cache {:?}", tx); - self.state.cache_apply.push_back(user_command.clone()); - } - } - } else { - //println!("{:?}", applied.transaction_status()); - } - - // Add new accounts created by the transaction to the potential senders list - let new_accounts = match &applied.varying { - Varying::Command(command) => match command { - CommandApplied::SignedCommand(cmd) => match &cmd.body { - signed_command_applied::Body::Payments { new_accounts } => { - Some(new_accounts) - } - _ => None, - }, - CommandApplied::ZkappCommand(cmd) => Some(&cmd.new_accounts), - }, - _ => unimplemented!(), - }; - - if let Some(new_accounts) = new_accounts { - let new_accounts = self.state.potential_new_accounts.iter().filter( - #[coverage(off)] - |(kp, _)| { - new_accounts.iter().any( - #[coverage(off)] - |acc| acc.public_key == kp.public.into_compressed(), - ) - }, - ); - - for acc in new_accounts { - if !self.state.potential_senders.iter().any( - #[coverage(off)] - |(kp, _)| kp.public == acc.0.public, - ) { - self.state.potential_senders.push(acc.clone()) - } - } - - self.state.potential_new_accounts.clear(); - } - } - Err(error_string) => { - // Currently disabled until invariants are fixed - if error_string.starts_with("Invariant violation") { - let bigint: num_bigint::BigUint = LedgerIntf::merkle_root(&mut ledger).into(); - self.save_fuzzcase(&tx, &bigint.to_string()); - return Err(()); - } - - if expected_apply_result.apply_result.len() == 1 { - println!( - "!!! Apply failed in Rust (error: {}) but it didn't in OCaml: {:?}", - error_string, &expected_apply_result.apply_result[0] - ); - let bigint: num_bigint::BigUint = LedgerIntf::merkle_root(&mut ledger).into(); - self.save_fuzzcase(&tx, &bigint.to_string()); - return Err(()); - } - } - } - - let rust_ledger_root_hash = LedgerIntf::merkle_root(&mut ledger); - - if &expected_apply_result.root_hash != &rust_ledger_root_hash { - println!( - "Ledger hash mismatch: {:?} != {:?} (expected)", - rust_ledger_root_hash, expected_apply_result.root_hash - ); - let bigint: num_bigint::BigUint = rust_ledger_root_hash.into(); - self.save_fuzzcase(&tx, &bigint.to_string()); - Err(()) - } else { - ledger.commit(); - Ok(()) - } - } - - #[coverage(off)] - pub fn get_ledger_root(&mut self) -> Fp { - LedgerIntf::merkle_root(self.get_ledger_inner_mut()) - } - - #[coverage(off)] - pub fn get_ledger_accounts(&self) -> Vec { - let locations = self.get_ledger_inner().account_locations(); - locations - .iter() - .map( - #[coverage(off)] - |x| *(LedgerIntf::get(self.get_ledger_inner(), x).unwrap()), - ) - .collect() - } -} - -pub struct FuzzerCtxBuilder { - constraint_constants: Option, - txn_state_view: Option, - fuzzcases_path: Option, - seed: u64, - minimum_fee: u64, - max_account_balance: u64, - initial_accounts: usize, - cache_size: usize, - snapshots_size: usize, - is_staged_ledger: bool, -} - -impl FuzzerCtxBuilder { - #[coverage(off)] - pub fn new() -> Self { - Self { - constraint_constants: None, - txn_state_view: None, - fuzzcases_path: None, - seed: 0, - minimum_fee: 1_000_000, // Sane default in case we don't obtain it from OCaml - max_account_balance: 1_000_000_000_000_000, - initial_accounts: 10, - cache_size: 4096, - snapshots_size: 128, - is_staged_ledger: false, - } - } - - #[coverage(off)] - pub fn constants(&mut self, constraint_constants: ConstraintConstants) -> &mut Self { - self.constraint_constants = Some(constraint_constants); - self - } - - #[coverage(off)] - pub fn state_view(&mut self, txn_state_view: ProtocolStateView) -> &mut Self { - self.txn_state_view = Some(txn_state_view); - self - } - - #[coverage(off)] - pub fn fuzzcases_path(&mut self, fuzzcases_path: String) -> &mut Self { - self.fuzzcases_path = Some(fuzzcases_path); - self - } - - #[coverage(off)] - pub fn seed(&mut self, seed: u64) -> &mut Self { - self.seed = seed; - self - } - - #[coverage(off)] - pub fn minimum_fee(&mut self, minimum_fee: u64) -> &mut Self { - self.minimum_fee = minimum_fee; - self - } - - #[coverage(off)] - pub fn initial_accounts(&mut self, initial_accounts: usize) -> &mut Self { - self.initial_accounts = initial_accounts; - self - } - - #[coverage(off)] - pub fn cache_size(&mut self, cache_size: usize) -> &mut Self { - assert!(cache_size != 0 && cache_size.is_power_of_two()); - self.cache_size = cache_size; - self - } - - #[coverage(off)] - pub fn snapshots_size(&mut self, snapshots_size: usize) -> &mut Self { - assert!(snapshots_size != 0 && snapshots_size.is_power_of_two()); - self.snapshots_size = snapshots_size; - self - } - - #[coverage(off)] - pub fn is_staged_ledger(&mut self, is_staged_ledger: bool) -> &mut Self { - self.is_staged_ledger = is_staged_ledger; - self - } - - #[coverage(off)] - pub fn build(&mut self) -> FuzzerCtx { - let constraint_constants = self - .constraint_constants - .clone() - .unwrap_or(CONSTRAINT_CONSTANTS); - let depth = constraint_constants.ledger_depth as usize; - let root = Mask::new_root(Database::create(depth.try_into().unwrap())); - let txn_state_view = self - .txn_state_view - .clone() - .unwrap_or(dummy_state_view(None)); - let fuzzcases_path = self.fuzzcases_path.clone().unwrap_or("./".to_string()); - - let ledger = match self.is_staged_ledger { - true => { - let snarked_ledger_mask = root.make_child().fuzzing_to_root(); - // let snarked_ledger_mask = root.make_child(); - LedgerKind::Staged( - StagedLedger::create_exn(constraint_constants.clone(), root.make_child()) - .unwrap(), - snarked_ledger_mask, - ) - } - false => LedgerKind::Mask(root.make_child()), - }; - - let mut ctx = FuzzerCtx { - constraint_constants, - txn_state_view, - fuzzcases_path, - gen: GeneratorCtx { - rng: SmallRng::seed_from_u64(self.seed), - minimum_fee: self.minimum_fee, - excess_fee: Signed::::zero(), - token_id: TokenId::default(), - tx_proof: None, - max_account_balance: self.max_account_balance, - nonces: HashMap::new(), - attempt_valid_zkapp: true, - }, - state: FuzzerState { - ledger, - potential_senders: Vec::new(), - potential_new_accounts: Vec::new(), - cache_pool: RingBuffer::with_capacity(self.cache_size), - cache_apply: RingBuffer::with_capacity(self.cache_size), - }, - snapshots: RingBuffer::with_capacity(self.snapshots_size), - }; - - ctx.create_inital_accounts(self.initial_accounts); - ctx - } -} diff --git a/tools/fuzzing/src/generator.rs b/tools/fuzzing/src/generator.rs deleted file mode 100644 index b12b0498d7..0000000000 --- a/tools/fuzzing/src/generator.rs +++ /dev/null @@ -1,2299 +0,0 @@ -use ark_ec::AffineCurve; -use ark_ec::ProjectiveCurve; -use ark_ff::SquareRootField; -use ark_ff::{Field, UniformRand}; -use ledger::generators::zkapp_command_builder::get_transaction_commitments; -use ledger::proofs::field::FieldWitness; -use ledger::proofs::transaction::InnerCurve; -use ledger::scan_state::currency::{Magnitude, SlotSpan, TxnVersion}; -use ledger::{ - proofs::transaction::PlonkVerificationKeyEvals, - scan_state::{ - currency::{Amount, Balance, BlockTime, Fee, Length, MinMax, Nonce, Sgn, Signed, Slot}, - transaction_logic::{ - signed_command::{ - self, PaymentPayload, SignedCommand, SignedCommandPayload, StakeDelegationPayload, - }, - transaction_union_payload::TransactionUnionPayload, - zkapp_command::{ - self, AccountPreconditions, AccountUpdate, ClosedInterval, FeePayer, FeePayerBody, - MayUseToken, Numeric, OrIgnore, SetOrKeep, Update, ZkAppCommand, - }, - zkapp_statement::TransactionCommitment, - Memo, Transaction, UserCommand, - }, - }, - Account, AuthRequired, Permissions, ProofVerified, TokenId, TokenSymbol, VerificationKey, - VotingFor, ZkAppUri, -}; -use ledger::{SetVerificationKey, TXN_VERSION_CURRENT}; -use mina_curves::pasta::Fq; -use mina_hasher::Fp; -use mina_p2p_messages::array::ArrayN; -use mina_p2p_messages::list::List; -use mina_p2p_messages::v2::{ - PicklesProofProofsVerified2ReprStableV2StatementProofStateDeferredValuesPlonk, - PicklesWrapWireProofCommitmentsStableV1, PicklesWrapWireProofEvaluationsStableV1, - PicklesWrapWireProofStableV1, PicklesWrapWireProofStableV1Bulletproof, -}; -use mina_p2p_messages::{ - number::Number, - pseq::PaddedSeq, - v2::{ - CompositionTypesBranchDataDomainLog2StableV1, CompositionTypesBranchDataStableV1, - CompositionTypesDigestConstantStableV1, CurrencyAmountStableV1, CurrencyFeeStableV1, - LedgerHash, LimbVectorConstantHex64StableV1, MinaBaseAccountIdDigestStableV1, - MinaBaseCallStackDigestStableV1, MinaBaseFeeExcessStableV1, MinaBaseLedgerHash0StableV1, - MinaBasePendingCoinbaseCoinbaseStackStableV1, MinaBasePendingCoinbaseStackHashStableV1, - MinaBasePendingCoinbaseStackVersionedStableV1, MinaBasePendingCoinbaseStateStackStableV1, - MinaBaseStackFrameStableV1, MinaBaseTransactionStatusFailureCollectionStableV1, - MinaStateBlockchainStateValueStableV2LedgerProofStatementSource, - MinaTransactionLogicZkappCommandLogicLocalStateValueStableV1, - PicklesBaseProofsVerifiedStableV1, - PicklesProofProofsVerified2ReprStableV2MessagesForNextStepProof, - PicklesProofProofsVerified2ReprStableV2MessagesForNextWrapProof, - PicklesProofProofsVerified2ReprStableV2PrevEvals, - PicklesProofProofsVerified2ReprStableV2PrevEvalsEvals, - PicklesProofProofsVerified2ReprStableV2PrevEvalsEvalsEvals, - PicklesProofProofsVerified2ReprStableV2Statement, - PicklesProofProofsVerified2ReprStableV2StatementFp, - PicklesProofProofsVerified2ReprStableV2StatementProofState, - PicklesProofProofsVerified2ReprStableV2StatementProofStateDeferredValues, - PicklesProofProofsVerified2ReprStableV2StatementProofStateDeferredValuesPlonkFeatureFlags, - PicklesProofProofsVerifiedMaxStableV2, - PicklesReducedMessagesForNextProofOverSameFieldWrapChallengesVectorStableV2, - PicklesReducedMessagesForNextProofOverSameFieldWrapChallengesVectorStableV2A, - PicklesReducedMessagesForNextProofOverSameFieldWrapChallengesVectorStableV2AChallenge, - SgnStableV1, SignedAmount, TokenFeeExcess, TokenIdKeyHash, UnsignedExtendedUInt32StableV1, - UnsignedExtendedUInt64Int64ForVersionTagsStableV1, - }, -}; -use mina_signer::{ - CompressedPubKey, CurvePoint, Keypair, NetworkId, ScalarField, SecKey, Signature, Signer, -}; -use rand::distributions::DistString; -use rand::Rng; -use rand::{distributions::Alphanumeric, seq::SliceRandom}; -use std::{array, iter, ops::RangeInclusive, sync::Arc}; -use tuple_map::TupleMap2; - -use super::context::{FuzzerCtx, PermissionModel}; - -macro_rules! impl_default_generator_for_wrapper_type { - ($fuzz_ctx: ty, $wrapper: tt) => { - impl Generator<$wrapper> for $fuzz_ctx { - #[coverage(off)] - fn gen(&mut self) -> $wrapper { - $wrapper(self.gen()) - } - } - }; - ($fuzz_ctx: ty, $wrapper: tt, $inner: ty) => { - impl Generator<$wrapper> for $fuzz_ctx { - #[coverage(off)] - fn gen(&mut self) -> $wrapper { - let inner: $inner = self.gen(); - inner.into() - } - } - }; -} - -pub trait Generator { - fn gen(&mut self) -> T; -} - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> bool { - self.gen.rng.gen_bool(0.5) - } -} - -/* -impl Generator for FuzzerCtx { - // rnd_base_field - fn gen(&mut self) -> Fp { - let mut bf = None; - - // TODO: optimize by masking out MSBs from bytes and remove loop - while bf.is_none() { - let bytes = self.gen.rng.gen::<[u8; 32]>(); - bf = Fp::from_random_bytes_with_flags::(&bytes); - } - - bf.unwrap().0 - } -} -*/ - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> Fp { - Fp::rand(&mut self.gen.rng) - } -} - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> Slot { - if self.gen.rng.gen_bool(0.9) { - self.txn_state_view.global_slot_since_genesis - } else { - Slot::from_u32(self.gen.rng.gen_range(0..Slot::max().as_u32())) - } - } -} - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> SlotSpan { - if self.gen.rng.gen_bool(0.9) { - SlotSpan::from_u32(self.txn_state_view.global_slot_since_genesis.as_u32()) - } else { - SlotSpan::from_u32(self.gen.rng.gen_range(0..SlotSpan::max().as_u32())) - } - } -} - -impl Generator for FuzzerCtx { - /* - Reimplement random key generation w/o the restriction on CryptoRgn trait. - Since we are only using this for fuzzing we want a faster (unsafe) Rng like SmallRng. - */ - #[coverage(off)] - fn gen(&mut self) -> SecKey { - let secret: ScalarField = ScalarField::rand(&mut self.gen.rng); - SecKey::new(secret) - } -} - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> Keypair { - let sec_key: SecKey = self.gen(); - let scalar = sec_key.into_scalar(); - let public = CurvePoint::prime_subgroup_generator() - .mul(scalar) - .into_affine(); - - let keypair = Keypair::from_parts_unsafe(scalar, public); - - if !self.state.potential_senders.iter().any( - #[coverage(off)] - |(kp, _)| kp.public == keypair.public, - ) { - let permission_model = self.gen(); - self.state - .potential_new_accounts - .push((keypair.clone(), permission_model)) - } - - keypair - } -} - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> CompressedPubKey { - let keypair = if self.gen.rng.gen_bool(0.9) { - // use existing account - self.random_keypair() - } else { - // create new account - self.gen() - }; - - keypair.public.into_compressed() - } -} - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> Memo { - Memo::with_number(self.gen.rng.gen()) - } -} - -impl + SquareRootField> Generator<(F, F)> for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> (F, F) { - /* - WARNING: we need to generate valid curve points to avoid binprot deserializarion - exceptions in the OCaml side. However this is an expensive task. - - TODO: a more efficient way of doing this? - */ - let mut x = F::rand(&mut self.gen.rng); - - loop { - let y_squared = x.square().mul(x).add(Into::::into(5)); - - if let Some(y) = y_squared.sqrt() { - return (x, y); - } - - x.add_assign(F::one()); - } - } -} - -impl Generator> for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> InnerCurve { - let (x, y) = self.gen(); - InnerCurve::::from((x, y)) - } -} - -impl Generator> for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> PlonkVerificationKeyEvals { - PlonkVerificationKeyEvals { - sigma: array::from_fn( - #[coverage(off)] - |_| self.gen(), - ), - coefficients: array::from_fn( - #[coverage(off)] - |_| self.gen(), - ), - generic: self.gen(), - psm: self.gen(), - complete_add: self.gen(), - mul: self.gen(), - emul: self.gen(), - endomul_scalar: self.gen(), - } - } -} - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> VerificationKey { - VerificationKey { - max_proofs_verified: vec![ProofVerified::N0, ProofVerified::N1, ProofVerified::N2] - .choose(&mut self.gen.rng) - .unwrap() - .clone(), - actual_wrap_domain_size: vec![ProofVerified::N0, ProofVerified::N1, ProofVerified::N2] - .choose(&mut self.gen.rng) - .unwrap() - .clone(), - wrap_index: Box::new(self.gen()), - wrap_vk: None, // TODO - } - } -} - -/* -impl + Hashable> Generator> for FuzzerCtx -where - FuzzerCtx: Generator, -{ - fn gen(&mut self) -> zkapp_command::WithHash { - let data: T = self.gen(); - let hash = data.digest(); - zkapp_command::WithHash { data, hash } - } -} -*/ - -impl Generator> for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> zkapp_command::WithHash { - let data: VerificationKey = self.gen(); - let hash = data.digest(); - zkapp_command::WithHash { data, hash } - } -} - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> AuthRequired { - *vec![ - AuthRequired::None, - AuthRequired::Either, - AuthRequired::Proof, - AuthRequired::Signature, - AuthRequired::Impossible, - //AuthRequired::Both, - ] - .choose(&mut self.gen.rng) - .unwrap() - } -} - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> PermissionModel { - vec![ - PermissionModel::Any, - PermissionModel::Empty, - PermissionModel::Initial, - PermissionModel::Default, - PermissionModel::TokenOwner, - ] - .choose(&mut self.gen.rng) - .unwrap() - .clone() - } -} - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> ZkAppUri { - /* - TODO: this needs to be fixed (assign a boundary) in the protocol since it is - possible to set a zkApp URI of arbitrary size. - - Since the field is opaque to the Mina protocol logic, randomly generating - URIs makes little sense and will consume a significant amount of ledger space. - */ - ZkAppUri::new() - } -} - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> TokenSymbol { - /* - TokenSymbol must be <= 6 **bytes**. This boundary doesn't exist at type-level, - instead it is check by binprot after deserializing the *string* object: - https://github.com/MinaProtocol/mina/blob/develop/src/lib/mina_base/account.ml#L124 - - We will let this function generate strings larger than 6 bytes with low probability, - just to cover the error handling code, but must of the time we want to avoid failing - this check. - */ - if self.gen.rng.gen_bool(0.9) { - TokenSymbol::default() - } else { - let rnd_len = self.gen.rng.gen_range(1..=6); - // TODO: fix n random chars for n random bytes - TokenSymbol(Alphanumeric.sample_string(&mut self.gen.rng, rnd_len)) - } - } -} - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> VotingFor { - VotingFor(self.gen()) - } -} - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> zkapp_command::Events { - /* - An Event is a list of arrays of Fp, there doesn't seem to be any limit - neither in the size of the list or the array's size. The total size should - be bounded by the transport protocol (currently libp2p, ~32MB). - */ - - if self.gen.rng.gen_bool(0.9) { - zkapp_command::Events(Vec::new()) - } else { - // Generate random Events in the same fashion as Mina's generator (up to 5x3 elements). - let n = self.gen.rng.gen_range(0..=5); - - zkapp_command::Events( - (0..=n) - .map( - #[coverage(off)] - |_| { - let n = self.gen.rng.gen_range(0..=3); - zkapp_command::Event( - (0..=n) - .map( - #[coverage(off)] - |_| self.gen(), - ) - .collect(), - ) - }, - ) - .collect(), - ) - } - } -} - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> zkapp_command::Actions { - // See comment in generator above - - if self.gen.rng.gen_bool(0.9) { - zkapp_command::Actions(Vec::new()) - } else { - let n = self.gen.rng.gen_range(0..=5); - - zkapp_command::Actions( - (0..=n) - .map( - #[coverage(off)] - |_| { - let n = self.gen.rng.gen_range(0..=3); - zkapp_command::Event( - (0..=n) - .map( - #[coverage(off)] - |_| self.gen(), - ) - .collect(), - ) - }, - ) - .collect(), - ) - } - } -} - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> BlockTime { - self.gen.rng.gen() - } -} - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> Length { - self.gen.rng.gen() - } -} - -pub trait GeneratorRange32 { - fn gen_range(&mut self, range: RangeInclusive) -> T; -} - -pub trait GeneratorRange64 { - fn gen_range(&mut self, range: RangeInclusive) -> T; -} - -impl GeneratorRange64 for FuzzerCtx { - #[coverage(off)] - fn gen_range(&mut self, range: RangeInclusive) -> Balance { - Balance::from_u64(self.gen.rng.gen_range(range)) - } -} - -impl GeneratorRange64 for FuzzerCtx { - #[coverage(off)] - fn gen_range(&mut self, range: RangeInclusive) -> Fee { - Fee::from_u64(self.gen.rng.gen_range(range)) - } -} - -impl GeneratorRange64 for FuzzerCtx { - #[coverage(off)] - fn gen_range(&mut self, range: RangeInclusive) -> Amount { - Amount::from_u64(self.gen.rng.gen_range(range)) - } -} - -impl GeneratorRange32 for FuzzerCtx { - #[coverage(off)] - fn gen_range(&mut self, range: RangeInclusive) -> Nonce { - Nonce::from_u32(self.gen.rng.gen_range(range)) - } -} - -impl GeneratorRange32 for FuzzerCtx { - #[coverage(off)] - fn gen_range(&mut self, range: RangeInclusive) -> Length { - Length::from_u32(self.gen.rng.gen_range(range)) - } -} - -pub trait GeneratorWrapper T> { - fn gen_wrap(&mut self, f: F) -> W; -} - -impl T> GeneratorWrapper, T, F> for FuzzerCtx { - #[coverage(off)] - fn gen_wrap(&mut self, mut f: F) -> Option { - if self.gen.rng.gen_bool(0.9) { - None - } else { - Some(f(self)) - } - } -} - -impl T> GeneratorWrapper, T, F> for FuzzerCtx { - #[coverage(off)] - fn gen_wrap(&mut self, mut f: F) -> OrIgnore { - if self.gen.rng.gen_bool(0.5) { - OrIgnore::Ignore - } else { - OrIgnore::Check(f(self)) - } - } -} - -impl T> GeneratorWrapper, T, F> for FuzzerCtx { - #[coverage(off)] - fn gen_wrap(&mut self, mut f: F) -> SetOrKeep { - if self.gen.rng.gen_bool(0.5) { - SetOrKeep::Keep - } else { - SetOrKeep::Set(f(self)) - } - } -} - -impl T> GeneratorWrapper, T, F> - for FuzzerCtx -{ - #[coverage(off)] - fn gen_wrap(&mut self, mut f: F) -> ClosedInterval { - if self.gen.rng.gen_bool(0.5) { - // constant case - let val = f(self); - - ClosedInterval { - lower: val.clone(), - upper: val, - } - } else { - ClosedInterval { - lower: f(self), - upper: f(self), - } - } - } -} - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> Sgn { - if self.gen.rng.gen_bool(0.5) { - Sgn::Pos - } else { - Sgn::Neg - } - } -} - -pub trait GeneratorWrapperMany T> { - fn gen_wrap_many(&mut self, f: F) -> W; -} - -impl T, const N: u64> GeneratorWrapperMany, T, F> - for FuzzerCtx -{ - #[coverage(off)] - fn gen_wrap_many(&mut self, mut f: F) -> ArrayN { - iter::repeat_with( - #[coverage(off)] - || f(self), - ) - .take(N as usize) - .collect() - } -} - -impl Generator> for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> Numeric { - self.gen_wrap( - #[coverage(off)] - |x| { - x.gen_wrap( - #[coverage(off)] - |x| -> Amount { GeneratorRange64::gen_range(x, 0..=u64::MAX) }, - ) - }, - ) - } -} - -impl Generator> for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> Numeric { - self.gen_wrap( - #[coverage(off)] - |x| { - x.gen_wrap( - #[coverage(off)] - |x| -> Length { GeneratorRange32::gen_range(x, 0..=u32::MAX) }, - ) - }, - ) - } -} - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> FeePayer { - let public_key = if self.gen.attempt_valid_zkapp || self.gen.rng.gen_bool(0.9) { - self.random_keypair().public.into_compressed() - } else { - self.gen() - }; - - let account = self.get_account(&public_key); - // FIXME: boundary at i64 MAX because OCaml side is encoding it as int - let max_fee = match account.as_ref() { - Some(account) if self.gen.attempt_valid_zkapp || self.gen.rng.gen_bool(0.9) => { - self.gen.minimum_fee.max(account.balance.as_u64()) - } - _ => self - .gen - .rng - .gen_range(self.gen.minimum_fee + 1..=10_000_000), - }; - - let fee: Fee = GeneratorRange64::gen_range(self, self.gen.minimum_fee..=max_fee); - - let nonce = match self.gen.nonces.get(&public_key.into_address()) { - Some(nonce) => *nonce, - None => account - .as_ref() - .map(|account| account.nonce) - .unwrap_or_else(|| { - if self.gen.rng.gen_bool(0.9) { - Nonce::from_u32(0) - } else { - GeneratorRange32::gen_range(self, 0..=u32::MAX) - } - }), - }; - - self.gen - .nonces - .insert(public_key.into_address(), nonce.incr()); - - FeePayer { - body: FeePayerBody { - public_key, - fee, - valid_until: self.gen_wrap( - #[coverage(off)] - |x| -> Slot { x.gen() }, - ), - nonce, - }, - // filled later when tx is complete - authorization: Signature::dummy(), - } - } -} - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> zkapp_command::EpochData { - zkapp_command::EpochData::new( - zkapp_command::EpochLedger { - hash: self.gen_wrap( - #[coverage(off)] - |x| x.gen(), - ), - total_currency: self.gen(), - }, - self.gen_wrap( - #[coverage(off)] - |x| x.gen(), - ), - self.gen_wrap( - #[coverage(off)] - |x| x.gen(), - ), - self.gen_wrap( - #[coverage(off)] - |x| x.gen(), - ), - self.gen(), - ) - } -} - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> LimbVectorConstantHex64StableV1 { - LimbVectorConstantHex64StableV1(Number(self.gen.rng.gen())) - } -} - -impl - Generator< - PicklesProofProofsVerified2ReprStableV2StatementProofStateDeferredValuesPlonkFeatureFlags, - > for FuzzerCtx -{ - #[coverage(off)] - fn gen( - &mut self, - ) -> PicklesProofProofsVerified2ReprStableV2StatementProofStateDeferredValuesPlonkFeatureFlags - { - PicklesProofProofsVerified2ReprStableV2StatementProofStateDeferredValuesPlonkFeatureFlags { - range_check0: self.gen.rng.gen_bool(0.5), - range_check1: self.gen.rng.gen_bool(0.5), - foreign_field_add: self.gen.rng.gen_bool(0.5), - foreign_field_mul: self.gen.rng.gen_bool(0.5), - xor: self.gen.rng.gen_bool(0.5), - rot: self.gen.rng.gen_bool(0.5), - lookup: self.gen.rng.gen_bool(0.5), - runtime_tables: self.gen.rng.gen_bool(0.5), - } - } -} - -impl Generator - for FuzzerCtx -{ - #[coverage(off)] - fn gen( - &mut self, - ) -> PicklesProofProofsVerified2ReprStableV2StatementProofStateDeferredValuesPlonk { - PicklesProofProofsVerified2ReprStableV2StatementProofStateDeferredValuesPlonk { - alpha: self.gen(), - beta: self.gen(), - gamma: self.gen(), - zeta: self.gen(), - joint_combiner: self.gen_wrap( - #[coverage(off)] - |x| x.gen(), - ), - feature_flags: self.gen(), - } - } -} - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> mina_p2p_messages::bigint::BigInt { - mina_p2p_messages::bigint::BigInt::from(Generator::::gen(self)) - } -} - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> PicklesProofProofsVerified2ReprStableV2StatementFp { - PicklesProofProofsVerified2ReprStableV2StatementFp::ShiftedValue(self.gen()) - } -} - -impl Generator - for FuzzerCtx -{ - #[coverage(off)] - fn gen( - &mut self, - ) -> PicklesReducedMessagesForNextProofOverSameFieldWrapChallengesVectorStableV2A { - PicklesReducedMessagesForNextProofOverSameFieldWrapChallengesVectorStableV2A { - prechallenge: self.gen(), - } - } -} - -impl Generator> for FuzzerCtx -where - FuzzerCtx: Generator, -{ - #[coverage(off)] - fn gen(&mut self) -> PaddedSeq { - PaddedSeq::(array::from_fn( - #[coverage(off)] - |_| self.gen(), - )) - } -} - -impl T, const N: usize> GeneratorWrapper, T, F> - for FuzzerCtx -{ - #[coverage(off)] - fn gen_wrap(&mut self, mut f: F) -> PaddedSeq { - PaddedSeq::(array::from_fn( - #[coverage(off)] - |_| f(self), - )) - } -} - -impl - Generator - for FuzzerCtx -{ - #[coverage(off)] - fn gen( - &mut self, - ) -> PicklesReducedMessagesForNextProofOverSameFieldWrapChallengesVectorStableV2AChallenge { - PicklesReducedMessagesForNextProofOverSameFieldWrapChallengesVectorStableV2AChallenge { - inner: self.gen(), - } - } -} - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> CompositionTypesBranchDataDomainLog2StableV1 { - CompositionTypesBranchDataDomainLog2StableV1(mina_p2p_messages::char::Char( - self.gen.rng.gen(), - )) - } -} - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> CompositionTypesBranchDataStableV1 { - CompositionTypesBranchDataStableV1 { - proofs_verified: vec![ - PicklesBaseProofsVerifiedStableV1::N0, - PicklesBaseProofsVerifiedStableV1::N1, - PicklesBaseProofsVerifiedStableV1::N2, - ] - .choose(&mut self.gen.rng) - .unwrap() - .clone(), - domain_log2: self.gen(), - } - } -} - -impl Generator - for FuzzerCtx -{ - #[coverage(off)] - fn gen(&mut self) -> PicklesProofProofsVerified2ReprStableV2StatementProofStateDeferredValues { - PicklesProofProofsVerified2ReprStableV2StatementProofStateDeferredValues { - plonk: self.gen(), - bulletproof_challenges: self.gen(), - branch_data: self.gen(), - } - } -} - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> CompositionTypesDigestConstantStableV1 { - CompositionTypesDigestConstantStableV1(self.gen()) - } -} - -impl Generator - for FuzzerCtx -{ - #[coverage(off)] - fn gen( - &mut self, - ) -> PicklesReducedMessagesForNextProofOverSameFieldWrapChallengesVectorStableV2 { - PicklesReducedMessagesForNextProofOverSameFieldWrapChallengesVectorStableV2(self.gen()) - } -} - -#[coverage(off)] -pub fn gen_curve_point>( - ctx: &mut impl Generator<(T, T)>, -) -> ( - mina_p2p_messages::bigint::BigInt, - mina_p2p_messages::bigint::BigInt, -) -where - mina_p2p_messages::bigint::BigInt: From, -{ - Generator::<(T, T)>::gen(ctx).map(mina_p2p_messages::bigint::BigInt::from) -} - -#[coverage(off)] -pub fn gen_curve_point_many, const N: u64>( - ctx: &mut FuzzerCtx, -) -> ArrayN< - ( - mina_p2p_messages::bigint::BigInt, - mina_p2p_messages::bigint::BigInt, - ), - { N }, -> -where - mina_p2p_messages::bigint::BigInt: From, -{ - ctx.gen_wrap_many( - #[coverage(off)] - |x| gen_curve_point::(x), - ) -} - -#[coverage(off)] -pub fn gen_curve_point_many_unzip, const N: u64>( - ctx: &mut FuzzerCtx, -) -> ( - ArrayN, - ArrayN, -) -where - mina_p2p_messages::bigint::BigInt: From + Default, -{ - let (a, b): (Vec<_>, Vec<_>) = gen_curve_point_many::(ctx).into_iter().unzip(); - - ( - ArrayN::from_iter(a.into_iter()), - ArrayN::from_iter(b.into_iter()), - ) -} - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> PicklesProofProofsVerified2ReprStableV2MessagesForNextWrapProof { - PicklesProofProofsVerified2ReprStableV2MessagesForNextWrapProof { - challenge_polynomial_commitment: gen_curve_point::(self), - old_bulletproof_challenges: self.gen(), - } - } -} - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> PicklesProofProofsVerified2ReprStableV2StatementProofState { - PicklesProofProofsVerified2ReprStableV2StatementProofState { - deferred_values: self.gen(), - sponge_digest_before_evaluations: self.gen(), - messages_for_next_wrap_proof: self.gen(), - } - } -} - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> PicklesProofProofsVerified2ReprStableV2MessagesForNextStepProof { - PicklesProofProofsVerified2ReprStableV2MessagesForNextStepProof { - app_state: (), - challenge_polynomial_commitments: List::one(gen_curve_point::(self)), // TODO: variable num of elements - old_bulletproof_challenges: List::one(self.gen_wrap( - // TODO: variable num of elements - #[coverage(off)] - |x| x.gen(), - )), - } - } -} - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> PicklesProofProofsVerified2ReprStableV2Statement { - PicklesProofProofsVerified2ReprStableV2Statement { - proof_state: self.gen(), - messages_for_next_step_proof: self.gen(), - } - } -} - -// impl Generator for FuzzerCtx { -// #[coverage(off)] -// fn gen(&mut self) -> PicklesProofProofsVerified2ReprStableV2PrevEvalsEvalsEvalsLookupA { -// PicklesProofProofsVerified2ReprStableV2PrevEvalsEvalsEvalsLookupA { -// sorted: self.gen_wrap_many( -// #[coverage(off)] -// |x| gen_curve_point_many_unzip::(x, 1), -// 1, -// ), -// aggreg: gen_curve_point_many_unzip::(self, 1), -// table: gen_curve_point_many_unzip::(self, 1), -// runtime: self.gen_wrap( -// #[coverage(off)] -// |x| gen_curve_point_many_unzip::(x, 1), -// ), -// } -// } -// } - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> PicklesProofProofsVerified2ReprStableV2PrevEvalsEvalsEvals { - PicklesProofProofsVerified2ReprStableV2PrevEvalsEvalsEvals { - w: self.gen_wrap( - #[coverage(off)] - |x| gen_curve_point_many_unzip::(x), - ), - complete_add_selector: gen_curve_point_many_unzip::(self), - mul_selector: gen_curve_point_many_unzip::(self), - emul_selector: gen_curve_point_many_unzip::(self), - endomul_scalar_selector: gen_curve_point_many_unzip::(self), - range_check0_selector: self.gen_wrap( - #[coverage(off)] - |x| gen_curve_point_many_unzip::(x), - ), - range_check1_selector: self.gen_wrap( - #[coverage(off)] - |x| gen_curve_point_many_unzip::(x), - ), - foreign_field_add_selector: self.gen_wrap( - #[coverage(off)] - |x| gen_curve_point_many_unzip::(x), - ), - foreign_field_mul_selector: self.gen_wrap( - #[coverage(off)] - |x| gen_curve_point_many_unzip::(x), - ), - xor_selector: self.gen_wrap( - #[coverage(off)] - |x| gen_curve_point_many_unzip::(x), - ), - rot_selector: self.gen_wrap( - #[coverage(off)] - |x| gen_curve_point_many_unzip::(x), - ), - lookup_aggregation: self.gen_wrap( - #[coverage(off)] - |x| gen_curve_point_many_unzip::(x), - ), - lookup_table: self.gen_wrap( - #[coverage(off)] - |x| gen_curve_point_many_unzip::(x), - ), - lookup_sorted: self.gen_wrap( - #[coverage(off)] - |x| { - x.gen_wrap( - #[coverage(off)] - |x| gen_curve_point_many_unzip::(x), - ) - }, - ), - runtime_lookup_table: self.gen_wrap( - #[coverage(off)] - |x| gen_curve_point_many_unzip::(x), - ), - runtime_lookup_table_selector: self.gen_wrap( - #[coverage(off)] - |x| gen_curve_point_many_unzip::(x), - ), - xor_lookup_selector: self.gen_wrap( - #[coverage(off)] - |x| gen_curve_point_many_unzip::(x), - ), - lookup_gate_lookup_selector: self.gen_wrap( - #[coverage(off)] - |x| gen_curve_point_many_unzip::(x), - ), - range_check_lookup_selector: self.gen_wrap( - #[coverage(off)] - |x| gen_curve_point_many_unzip::(x), - ), - foreign_field_mul_lookup_selector: self.gen_wrap( - #[coverage(off)] - |x| gen_curve_point_many_unzip::(x), - ), - coefficients: self.gen_wrap( - #[coverage(off)] - |x| gen_curve_point_many_unzip::(x), - ), - z: gen_curve_point_many_unzip::(self), - s: self.gen_wrap( - #[coverage(off)] - |x| gen_curve_point_many_unzip::(x), - ), - generic_selector: gen_curve_point_many_unzip::(self), - poseidon_selector: gen_curve_point_many_unzip::(self), - } - } -} - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> PicklesProofProofsVerified2ReprStableV2PrevEvalsEvals { - PicklesProofProofsVerified2ReprStableV2PrevEvalsEvals { - public_input: gen_curve_point::(self), - evals: self.gen(), - } - } -} - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> PicklesProofProofsVerified2ReprStableV2PrevEvals { - PicklesProofProofsVerified2ReprStableV2PrevEvals { - evals: self.gen(), - ft_eval1: mina_p2p_messages::bigint::BigInt::from(Generator::::gen(self)), - } - } -} - -// impl Generator for FuzzerCtx { -// #[coverage(off)] -// fn gen(&mut self) -> PicklesProofProofsVerified2ReprStableV2ProofMessagesLookupA { -// PicklesProofProofsVerified2ReprStableV2ProofMessagesLookupA { -// sorted: self.gen_wrap_many( -// #[coverage(off)] -// |x| gen_curve_point_many::(x, 1), -// 1, -// ), -// aggreg: gen_curve_point_many::(self, 1), -// runtime: self.gen_wrap( -// #[coverage(off)] -// |x| gen_curve_point_many::(x, 1), -// ), -// } -// } -// } - -// impl Generator for FuzzerCtx { -// #[coverage(off)] -// fn gen(&mut self) -> PicklesProofProofsVerified2ReprStableV2ProofMessages { -// PicklesProofProofsVerified2ReprStableV2ProofMessages { -// w_comm: self.gen_wrap( -// #[coverage(off)] -// |x| gen_curve_point_many::(x, 1), -// ), -// z_comm: gen_curve_point_many::(self, 1), -// t_comm: gen_curve_point_many::(self, 1), -// lookup: self.gen_wrap( -// #[coverage(off)] -// |x| x.gen(), -// ), -// } -// } -// } - -// impl Generator for FuzzerCtx { -// #[coverage(off)] -// fn gen(&mut self) -> PicklesProofProofsVerified2ReprStableV2ProofOpeningsProof { -// PicklesProofProofsVerified2ReprStableV2ProofOpeningsProof { -// lr: self.gen_wrap_many( -// #[coverage(off)] -// |x| (gen_curve_point::(x), gen_curve_point::(x)), -// 1, -// ), -// z_1: self.gen(), -// z_2: self.gen(), -// delta: gen_curve_point::(self), -// challenge_polynomial_commitment: gen_curve_point::(self), -// } -// } -// } - -// impl Generator for FuzzerCtx { -// #[coverage(off)] -// fn gen(&mut self) -> PicklesProofProofsVerified2ReprStableV2ProofOpenings { -// PicklesProofProofsVerified2ReprStableV2ProofOpenings { -// proof: self.gen(), -// evals: self.gen(), -// ft_eval1: self.gen(), -// } -// } -// } - -// impl Generator for FuzzerCtx { -// #[coverage(off)] -// fn gen(&mut self) -> PicklesProofProofsVerified2ReprStableV2Proof { -// PicklesProofProofsVerified2ReprStableV2Proof { -// messages: self.gen(), -// openings: self.gen(), -// } -// } -// } - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> PicklesWrapWireProofCommitmentsStableV1 { - PicklesWrapWireProofCommitmentsStableV1 { - w_comm: self.gen_wrap( - #[coverage(off)] - |x| gen_curve_point::(x), - ), - z_comm: gen_curve_point::(self), - t_comm: self.gen_wrap( - #[coverage(off)] - |x| gen_curve_point::(x), - ), - } - } -} - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> PicklesWrapWireProofStableV1Bulletproof { - PicklesWrapWireProofStableV1Bulletproof { - lr: self.gen_wrap_many( - #[coverage(off)] - |x| (gen_curve_point::(x), gen_curve_point::(x)), - ), - z_1: Generator::::gen(self).into(), - z_2: Generator::::gen(self).into(), - delta: gen_curve_point::(self), - challenge_polynomial_commitment: gen_curve_point::(self), - } - } -} - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> PicklesWrapWireProofEvaluationsStableV1 { - PicklesWrapWireProofEvaluationsStableV1 { - w: self.gen_wrap( - #[coverage(off)] - |x| gen_curve_point::(x), - ), - coefficients: self.gen_wrap( - #[coverage(off)] - |x| gen_curve_point::(x), - ), - z: gen_curve_point::(self), - s: self.gen_wrap( - #[coverage(off)] - |x| gen_curve_point::(x), - ), - generic_selector: gen_curve_point::(self), - poseidon_selector: gen_curve_point::(self), - complete_add_selector: gen_curve_point::(self), - mul_selector: gen_curve_point::(self), - emul_selector: gen_curve_point::(self), - endomul_scalar_selector: gen_curve_point::(self), - } - } -} - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> PicklesWrapWireProofStableV1 { - PicklesWrapWireProofStableV1 { - bulletproof: self.gen(), - evaluations: self.gen(), - ft_eval1: self.gen(), - commitments: self.gen(), - } - } -} - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> PicklesProofProofsVerifiedMaxStableV2 { - PicklesProofProofsVerifiedMaxStableV2 { - statement: self.gen(), - prev_evals: self.gen(), - proof: self.gen(), - } - } -} - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> zkapp_command::SideLoadedProof { - Arc::new(self.gen()) - } -} - -impl Generator> for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> SetVerificationKey { - SetVerificationKey { - auth: self.gen(), - txn_version: if self.gen.rng.gen_bool(0.9) { - TXN_VERSION_CURRENT - } else { - TxnVersion::from(self.gen.rng.gen()) - }, - } - } -} - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> Balance { - GeneratorRange64::::gen_range(self, 0..=Balance::max().as_u64()) - } -} - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> Amount { - GeneratorRange64::::gen_range(self, 0..=Amount::max().as_u64()) - } -} - -pub trait GeneratorFromAccount { - fn gen_from_account(&mut self, account: &Account) -> T; -} - -impl GeneratorFromAccount for FuzzerCtx { - #[coverage(off)] - fn gen_from_account(&mut self, account: &Account) -> zkapp_command::AuthorizationKind { - let vk_hash = if self.gen.rng.gen_bool(0.9) - && account.zkapp.is_some() - && account.zkapp.as_ref().unwrap().verification_key.is_some() - { - account - .zkapp - .as_ref() - .unwrap() - .verification_key - .as_ref() - .unwrap() - .hash() - } else { - self.gen() - }; - - let options = vec![ - zkapp_command::AuthorizationKind::NoneGiven, - zkapp_command::AuthorizationKind::Signature, - zkapp_command::AuthorizationKind::Proof(vk_hash), - ]; - - options.choose(&mut self.gen.rng).unwrap().clone() - } -} - -impl GeneratorFromAccount> for FuzzerCtx { - #[coverage(off)] - fn gen_from_account(&mut self, account: &Account) -> Permissions { - let permission_model = match self.find_permissions(&account.public_key) { - Some(model) => model, - None => [ - PermissionModel::Any, - PermissionModel::Empty, - PermissionModel::Initial, - PermissionModel::TokenOwner, - ] - .choose(&mut self.gen.rng) - .unwrap(), - }; - - match permission_model { - PermissionModel::Any => Permissions:: { - edit_state: self.gen(), - access: self.gen(), - send: self.gen(), - receive: self.gen(), - set_delegate: self.gen(), - set_permissions: self.gen(), - set_verification_key: self.gen(), - set_zkapp_uri: self.gen(), - edit_action_state: self.gen(), - set_token_symbol: self.gen(), - increment_nonce: self.gen(), - set_voting_for: self.gen(), - set_timing: self.gen(), - }, - PermissionModel::Empty => Permissions::::empty(), - PermissionModel::Initial => Permissions::::user_default(), - PermissionModel::Default => Permissions:: { - edit_state: AuthRequired::Proof, - access: AuthRequired::None, - send: AuthRequired::Signature, - receive: AuthRequired::None, - set_delegate: AuthRequired::Signature, - set_permissions: AuthRequired::Signature, - set_verification_key: SetVerificationKey:: { - auth: AuthRequired::Signature, - txn_version: TXN_VERSION_CURRENT, - }, - set_zkapp_uri: AuthRequired::Signature, - edit_action_state: AuthRequired::Proof, - set_token_symbol: AuthRequired::Signature, - increment_nonce: AuthRequired::Signature, - set_voting_for: AuthRequired::Signature, - set_timing: AuthRequired::Proof, - }, - PermissionModel::TokenOwner => Permissions:: { - edit_state: AuthRequired::Either, // Proof | Signature - access: AuthRequired::Either, // Proof | Signature - send: AuthRequired::Signature, - receive: AuthRequired::Proof, - set_delegate: AuthRequired::Signature, - set_permissions: AuthRequired::Signature, - set_verification_key: SetVerificationKey:: { - auth: AuthRequired::Signature, - txn_version: TXN_VERSION_CURRENT, - }, - set_zkapp_uri: AuthRequired::Signature, - edit_action_state: AuthRequired::Proof, - set_token_symbol: AuthRequired::Signature, - increment_nonce: AuthRequired::Signature, - set_voting_for: AuthRequired::Signature, - set_timing: AuthRequired::Proof, - }, - } - } -} - -impl GeneratorFromAccount> for FuzzerCtx -where - FuzzerCtx: GeneratorFromAccount, -{ - #[coverage(off)] - fn gen_from_account(&mut self, account: &Account) -> ClosedInterval { - ClosedInterval { - lower: self.gen_from_account(account), - upper: self.gen_from_account(account), - } - } -} - -impl GeneratorFromAccount for FuzzerCtx { - #[coverage(off)] - fn gen_from_account(&mut self, account: &Account) -> Fee { - GeneratorRange64::::gen_range(self, 0..=account.balance.as_u64() / 100) - } -} - -impl GeneratorFromAccount for FuzzerCtx { - #[coverage(off)] - fn gen_from_account(&mut self, account: &Account) -> Balance { - GeneratorRange64::::gen_range(self, 0..=(account.balance.as_u64() / 100)) - } -} - -impl GeneratorFromAccount> for FuzzerCtx { - #[coverage(off)] - fn gen_from_account(&mut self, account: &Account) -> Signed { - if self.gen.rng.gen_bool(0.9) { - Signed::::zero() - } else { - if self.gen.token_id == TokenId::default() { - if self.gen.excess_fee.is_zero() { - let magnitude = GeneratorRange64::::gen_range( - self, - 0..=(account.balance.as_u64().wrapping_div(10).saturating_mul(7)), - ); - self.gen.excess_fee = Signed::::create(magnitude, self.gen()); - self.gen.excess_fee - } else { - let ret = self.gen.excess_fee.negate(); - self.gen.excess_fee = Signed::::zero(); - ret - } - } else { - // Custom Tokens - let magnitude = GeneratorRange64::::gen_range(self, 0..=u64::MAX); - Signed::::create(magnitude, self.gen()) - } - } - } -} - -impl GeneratorFromAccount for FuzzerCtx { - #[coverage(off)] - fn gen_from_account(&mut self, account: &Account) -> Amount { - if self.gen.token_id == TokenId::default() && self.gen.rng.gen_bool(0.9) { - GeneratorRange64::::gen_range(self, 0..=account.balance.as_u64()) - } else { - // Custom Tokens - GeneratorRange64::::gen_range(self, 0..=u64::MAX) - } - } -} - -impl GeneratorFromAccount for FuzzerCtx { - #[coverage(off)] - fn gen_from_account(&mut self, account: &Account) -> zkapp_command::Timing { - if self.gen.rng.gen_bool(0.5) { - zkapp_command::Timing { - initial_minimum_balance: Balance::zero(), - cliff_time: Slot::zero(), - cliff_amount: Amount::zero(), - vesting_period: SlotSpan::from_u32(1), - vesting_increment: Amount::zero(), - } - } else { - zkapp_command::Timing { - initial_minimum_balance: self.gen_from_account(account), - cliff_time: self.gen(), - cliff_amount: self.gen_from_account(account), - vesting_period: self.gen(), - vesting_increment: self.gen_from_account(account), - } - } - } -} - -impl GeneratorFromAccount for FuzzerCtx { - #[coverage(off)] - fn gen_from_account(&mut self, account: &Account) -> Nonce { - let nonce = match self.gen.nonces.get(&account.public_key.into_address()) { - Some(nonce) => *nonce, - None => account.nonce, - }; - // We assume successful aplication - self.gen - .nonces - .insert(account.public_key.into_address(), nonce.incr()); - nonce - } -} - -impl GeneratorFromAccount for FuzzerCtx { - #[coverage(off)] - fn gen_from_account(&mut self, account: &Account) -> Update { - Update { - app_state: if self.gen.rng.gen_bool(0.9) { - array::from_fn( - #[coverage(off)] - |_| { - self.gen_wrap( - #[coverage(off)] - |x| x.gen(), - ) - }, - ) - } else { - // cover changing_entire_app_state - array::from_fn( - #[coverage(off)] - |_| SetOrKeep::Set(self.gen()), - ) - }, - delegate: self.gen_wrap( - #[coverage(off)] - |x| x.gen(), - ), - verification_key: self.gen_wrap( - #[coverage(off)] - |x| x.gen(), - ), - permissions: self.gen_wrap( - #[coverage(off)] - |x| x.gen_from_account(account), - ), - zkapp_uri: self.gen_wrap( - #[coverage(off)] - |x| x.gen(), - ), - token_symbol: self.gen_wrap( - #[coverage(off)] - |x| x.gen(), - ), - timing: self.gen_wrap( - #[coverage(off)] - |x| x.gen_from_account(account), - ), - voting_for: self.gen_wrap( - #[coverage(off)] - |x| x.gen(), - ), - } - } -} - -impl GeneratorFromAccount for FuzzerCtx { - #[coverage(off)] - fn gen_from_account(&mut self, account: &Account) -> zkapp_command::ZkAppPreconditions { - if self.gen.rng.gen_bool(0.9) { - zkapp_command::ZkAppPreconditions::accept() - } else { - zkapp_command::ZkAppPreconditions { - snarked_ledger_hash: self.gen_wrap( - #[coverage(off)] - |x| { - if x.gen.rng.gen_bool(0.9) { - x.txn_state_view.snarked_ledger_hash - } else { - x.gen() - } - }, - ), - blockchain_length: self.gen_wrap( - #[coverage(off)] - |x| { - x.gen_wrap( - #[coverage(off)] - |x| { - if x.gen.rng.gen_bool(0.9) { - x.txn_state_view.blockchain_length - } else { - x.gen() - } - }, - ) - }, - ), - min_window_density: self.gen_wrap( - #[coverage(off)] - |x| { - x.gen_wrap( - #[coverage(off)] - |x| { - if x.gen.rng.gen_bool(0.9) { - x.txn_state_view.min_window_density - } else { - x.gen() - } - }, - ) - }, - ), - total_currency: self.gen_wrap( - #[coverage(off)] - |x| { - x.gen_wrap( - #[coverage(off)] - |x| { - if x.gen.rng.gen_bool(0.9) { - x.txn_state_view.total_currency - } else { - x.gen_from_account(account) - } - }, - ) - }, - ), - global_slot_since_genesis: self.gen_wrap( - #[coverage(off)] - |x| { - x.gen_wrap( - #[coverage(off)] - |x| x.gen(), - ) - }, - ), - - staking_epoch_data: if self.gen.rng.gen_bool(0.9) { - let epoch_data = self.txn_state_view.staking_epoch_data.clone(); - - zkapp_command::EpochData::new( - zkapp_command::EpochLedger { - hash: OrIgnore::Check(epoch_data.ledger.hash), - total_currency: OrIgnore::Check(ClosedInterval:: { - lower: epoch_data.ledger.total_currency.clone(), - upper: epoch_data.ledger.total_currency, - }), - }, - OrIgnore::Check(epoch_data.seed), - OrIgnore::Check(epoch_data.start_checkpoint), - OrIgnore::Check(epoch_data.lock_checkpoint), - OrIgnore::Check(ClosedInterval:: { - lower: epoch_data.epoch_length.clone(), - upper: epoch_data.epoch_length, - }), - ) - } else { - self.gen() - }, - next_epoch_data: if self.gen.rng.gen_bool(0.9) { - let epoch_data = self.txn_state_view.next_epoch_data.clone(); - zkapp_command::EpochData::new( - zkapp_command::EpochLedger { - hash: OrIgnore::Check(epoch_data.ledger.hash), - total_currency: OrIgnore::Check(ClosedInterval:: { - lower: epoch_data.ledger.total_currency.clone(), - upper: epoch_data.ledger.total_currency, - }), - }, - OrIgnore::Check(epoch_data.seed), - OrIgnore::Check(epoch_data.start_checkpoint), - OrIgnore::Check(epoch_data.lock_checkpoint), - OrIgnore::Check(ClosedInterval:: { - lower: epoch_data.epoch_length.clone(), - upper: epoch_data.epoch_length, - }), - ) - } else { - self.gen() - }, - } - } - } -} - -impl GeneratorFromAccount for FuzzerCtx { - #[coverage(off)] - fn gen_from_account(&mut self, account: &Account) -> zkapp_command::Account { - if self.gen.rng.gen_bool(0.9) { - zkapp_command::Account::accept() - } else { - zkapp_command::Account { - balance: self.gen_wrap( - #[coverage(off)] - |x| { - x.gen_wrap( - #[coverage(off)] - |x| x.gen_from_account(account), - ) - }, - ), - nonce: self.gen_wrap( - #[coverage(off)] - |x| { - x.gen_wrap( - #[coverage(off)] - |x| x.gen_from_account(account), - ) - }, - ), - receipt_chain_hash: self.gen_wrap( - #[coverage(off)] - |x| { - if x.gen.rng.gen_bool(0.9) { - account.receipt_chain_hash.0 - } else { - x.gen() - } - }, - ), - delegate: self.gen_wrap( - #[coverage(off)] - |x| { - let rnd_pk: CompressedPubKey = x.gen(); - account - .delegate - .as_ref() - .map( - #[coverage(off)] - |pk| { - if x.gen.rng.gen_bool(0.9) { - pk.clone() - } else { - rnd_pk.clone() - } - }, - ) - .unwrap_or(rnd_pk) - }, - ), - state: { - let rnd_state = array::from_fn( - #[coverage(off)] - |_| { - self.gen_wrap( - #[coverage(off)] - |x| x.gen(), - ) - }, - ); - - account - .zkapp - .as_ref() - .map( - #[coverage(off)] - |zkapp| { - if self.gen.rng.gen_bool(0.9) { - zkapp.app_state.map(OrIgnore::Check) - } else { - rnd_state.clone() - } - }, - ) - .unwrap_or(rnd_state) - }, - action_state: self.gen_wrap( - #[coverage(off)] - |x| x.gen(), - ), - proved_state: self.gen_wrap( - #[coverage(off)] - |x| { - let rnd_bool = x.gen.rng.gen_bool(0.5); - account - .zkapp - .as_ref() - .map( - #[coverage(off)] - |zkapp| { - if x.gen.rng.gen_bool(0.9) { - zkapp.proved_state - } else { - rnd_bool - } - }, - ) - .unwrap_or(rnd_bool) - }, - ), - is_new: self.gen_wrap( - #[coverage(off)] - |x| x.gen.rng.gen_bool(0.5), - ), - } - } - } -} - -impl GeneratorFromAccount for FuzzerCtx { - #[coverage(off)] - fn gen_from_account(&mut self, account: &Account) -> AccountPreconditions { - AccountPreconditions(self.gen_from_account(account)) - } -} - -impl GeneratorFromAccount for FuzzerCtx { - #[coverage(off)] - fn gen_from_account(&mut self, account: &Account) -> zkapp_command::Preconditions { - zkapp_command::Preconditions::new( - self.gen_from_account(account), - self.gen_from_account(account), - self.gen_wrap( - #[coverage(off)] - |x| { - x.gen_wrap( - #[coverage(off)] - |x| x.gen(), - ) - }, - ), - ) - } -} - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> TokenId { - if self.gen.rng.gen_bool(0.9) { - TokenId::default() - } else { - TokenId(self.gen()) - } - } -} - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> MayUseToken { - if self.gen.token_id.is_default() { - MayUseToken::No - } else { - match vec![0, 1, 2].choose(&mut self.gen.rng).unwrap() { - 0 => MayUseToken::No, - 1 => MayUseToken::ParentsOwnToken, - 2 => MayUseToken::InheritFromParent, - _ => unimplemented!(), - } - } - } -} - -impl GeneratorFromAccount for FuzzerCtx { - #[coverage(off)] - fn gen_from_account(&mut self, account: &Account) -> zkapp_command::Body { - zkapp_command::Body { - public_key: account.public_key.clone(), - token_id: self.gen.token_id.clone(), - update: self.gen_from_account(&account), - balance_change: self.gen_from_account(&account), - increment_nonce: self.gen.rng.gen_bool(0.5), - events: self.gen(), - actions: self.gen(), - call_data: self.gen(), - preconditions: self.gen_from_account(&account), - use_full_commitment: self.gen.rng.gen_bool(0.9), - implicit_account_creation_fee: self.gen.rng.gen_bool(0.1), - may_use_token: self.gen(), - authorization_kind: self.gen_from_account(&account), - } - } -} - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> zkapp_command::Body { - let account = Account::empty(); - - zkapp_command::Body { - public_key: self.gen(), - token_id: self.gen(), - update: self.gen_from_account(&account), - balance_change: self.gen_from_account(&account), - increment_nonce: self.gen.rng.gen_bool(0.5), - events: self.gen(), - actions: self.gen(), - call_data: self.gen(), - preconditions: self.gen_from_account(&account), - use_full_commitment: self.gen.rng.gen_bool(0.9), - implicit_account_creation_fee: self.gen.rng.gen_bool(0.1), - may_use_token: self.gen(), - authorization_kind: self.gen_from_account(&account), - } - } -} - -pub trait GeneratorFromToken { - fn gen_from_token(&mut self, token_id: TokenId, depth: usize) -> T; -} - -impl GeneratorFromToken for FuzzerCtx { - #[coverage(off)] - fn gen_from_token(&mut self, token_id: TokenId, _depth: usize) -> AccountUpdate { - self.gen.token_id = token_id; - - let public_key = if self.gen.attempt_valid_zkapp || self.gen.rng.gen_bool(0.9) { - self.random_keypair().public.into_compressed() - } else { - self.gen() - }; - - // let public_key = self.random_keypair().public.into_compressed(); - let account = self.get_account(&public_key); - let body: zkapp_command::Body = if account.is_some() && self.gen.rng.gen_bool(0.9) { - self.gen_from_account(account.as_ref().unwrap()) - } else { - self.gen() - }; - - let authorization = match body.authorization_kind { - zkapp_command::AuthorizationKind::NoneGiven => zkapp_command::Control::NoneGiven, - zkapp_command::AuthorizationKind::Signature => { - zkapp_command::Control::Signature(Signature::dummy()) - } - zkapp_command::AuthorizationKind::Proof(_) => zkapp_command::Control::Proof(self.gen()), - }; - - AccountUpdate { - body, - authorization, - } - } -} - -impl GeneratorFromToken> for FuzzerCtx { - #[coverage(off)] - fn gen_from_token( - &mut self, - token_id: TokenId, - depth: usize, - ) -> zkapp_command::CallForest { - let mut forest = zkapp_command::CallForest::::new(); - let max_count = 3usize.saturating_sub(depth); - let count = self.gen.rng.gen_range(0..=max_count); - - for _ in 0..count { - let account_update: AccountUpdate = self.gen_from_token(token_id.clone(), depth); - let token_id = account_update.account_id().derive_token_id(); - let calls = if self.gen.rng.gen_bool(0.8) || depth >= 3 { - None - } else { - // recursion - Some(self.gen_from_token(token_id, depth + 1)) - }; - - forest = forest.cons(calls, account_update); - } - - forest - } -} - -#[coverage(off)] -pub fn sign_account_updates( - ctx: &mut FuzzerCtx, - signer: &mut impl Signer, - txn_commitment: &TransactionCommitment, - full_txn_commitment: &TransactionCommitment, - account_updates: &mut zkapp_command::CallForest, -) { - for acc_update in account_updates.0.iter_mut() { - let account_update = &mut acc_update.elt.account_update; - - let signature = match account_update.authorization { - zkapp_command::Control::Signature(_) => { - let kp = ctx - .find_keypair(&account_update.body.public_key) - .cloned() - .unwrap_or_else(|| ctx.gen()); - let input = match account_update.body.use_full_commitment { - true => full_txn_commitment, - false => txn_commitment, - }; - Some(signer.sign(&kp, &input)) - } - _ => None, - }; - - if let Some(signature) = signature { - account_update.authorization = zkapp_command::Control::Signature(signature); - } - - sign_account_updates( - ctx, - signer, - txn_commitment, - full_txn_commitment, - &mut acc_update.elt.calls, - ); - } -} - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> ZkAppCommand { - self.gen.attempt_valid_zkapp = self.gen.rng.gen_bool(0.9); - - let mut zkapp_command = ZkAppCommand { - fee_payer: self.gen(), - account_updates: self.gen_from_token(TokenId::default(), 0), - memo: self.gen(), - }; - let (txn_commitment, full_txn_commitment) = get_transaction_commitments(&zkapp_command); - let mut signer = mina_signer::create_kimchi(NetworkId::TESTNET); - - let keypair = match self.find_keypair(&zkapp_command.fee_payer.body.public_key) { - Some(keypair) => keypair.clone(), - None => self.gen(), - }; - zkapp_command.fee_payer.authorization = signer.sign(&keypair, &full_txn_commitment); - - sign_account_updates( - self, - &mut signer, - &txn_commitment, - &full_txn_commitment, - &mut zkapp_command.account_updates, - ); - zkapp_command - } -} - -impl GeneratorFromAccount for FuzzerCtx { - #[coverage(off)] - fn gen_from_account(&mut self, account: &Account) -> PaymentPayload { - let is_source_account = self.gen.rng.gen_bool(0.9); - - let source_pk = if is_source_account { - account.public_key.clone() - } else { - self.gen() - }; - - let receiver_pk = if is_source_account && self.gen.rng.gen_bool(0.9) { - // same source & receiver - source_pk.clone() - } else { - self.gen() - }; - - PaymentPayload { - receiver_pk, - amount: self.gen_from_account(account), - } - } -} - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> StakeDelegationPayload { - StakeDelegationPayload::SetDelegate { - new_delegate: self.gen(), - } - } -} - -#[coverage(off)] -fn sign_payload(keypair: &Keypair, payload: &SignedCommandPayload) -> Signature { - let tx = TransactionUnionPayload::of_user_command_payload(payload); - let mut signer = mina_signer::create_legacy(NetworkId::TESTNET); - signer.sign(keypair, &tx) -} - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> SignedCommandPayload { - let fee_payer_pk = if self.gen.rng.gen_bool(0.8) { - self.random_keypair().public.into_compressed() - } else { - self.gen() - }; - - let account = self.get_account(&fee_payer_pk); - - let body = if account.is_some() && self.gen.rng.gen_bool(0.8) { - signed_command::Body::Payment(self.gen_from_account(account.as_ref().unwrap())) - } else { - signed_command::Body::StakeDelegation(self.gen()) - }; - - let fee = match account.as_ref() { - Some(account) => self.gen_from_account(account), - None => GeneratorRange64::gen_range(self, 0u64..=10_000_000u64), - }; - - let nonce = match account.as_ref() { - Some(account) => self.gen_from_account(account), - None => GeneratorRange32::gen_range(self, 0u32..=10_000_000u32), - }; - - SignedCommandPayload::create( - fee, - fee_payer_pk, - nonce, - self.gen_wrap( - #[coverage(off)] - |x| x.gen(), - ), - self.gen(), - body, - ) - } -} - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> SignedCommand { - let payload: SignedCommandPayload = self.gen(); - let keypair = if self.gen.rng.gen_bool(0.9) { - self.find_keypair(&payload.common.fee_payer_pk) - .cloned() - .unwrap_or_else(|| self.gen()) - } else { - self.gen() - }; - - let signature = sign_payload(&keypair, &payload); - - SignedCommand { - payload, - signer: keypair.public.into_compressed(), - signature, - } - } -} - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> UserCommand { - match vec![0, 1].choose(&mut self.gen.rng).unwrap() { - 0 => UserCommand::SignedCommand(Box::new(self.gen())), - 1 => UserCommand::ZkAppCommand(Box::new(self.gen())), - _ => unimplemented!(), - } - } -} - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> Transaction { - Transaction::Command(self.gen()) - } -} - -impl Generator> for FuzzerCtx { - fn gen(&mut self) -> Number { - Number(self.gen.rng.gen()) - } -} - -impl Generator> for FuzzerCtx { - fn gen(&mut self) -> Number { - Number(self.gen.rng.gen()) - } -} - -impl Generator> for FuzzerCtx { - fn gen(&mut self) -> Number { - Number(self.gen.rng.gen()) - } -} - -impl Generator> for FuzzerCtx { - fn gen(&mut self) -> Number { - Number(self.gen.rng.gen()) - } -} - -impl_default_generator_for_wrapper_type!(FuzzerCtx, MinaBaseLedgerHash0StableV1); -impl_default_generator_for_wrapper_type!(FuzzerCtx, LedgerHash, MinaBaseLedgerHash0StableV1); - -impl_default_generator_for_wrapper_type!(FuzzerCtx, MinaBaseAccountIdDigestStableV1); -impl_default_generator_for_wrapper_type!( - FuzzerCtx, - TokenIdKeyHash, - MinaBaseAccountIdDigestStableV1 -); - -impl_default_generator_for_wrapper_type!(FuzzerCtx, MinaBasePendingCoinbaseStackHashStableV1); -impl_default_generator_for_wrapper_type!(FuzzerCtx, MinaBasePendingCoinbaseCoinbaseStackStableV1); -impl_default_generator_for_wrapper_type!(FuzzerCtx, MinaBaseStackFrameStableV1); -impl_default_generator_for_wrapper_type!(FuzzerCtx, MinaBaseCallStackDigestStableV1); - -impl_default_generator_for_wrapper_type!( - FuzzerCtx, - UnsignedExtendedUInt64Int64ForVersionTagsStableV1 -); -impl_default_generator_for_wrapper_type!(FuzzerCtx, CurrencyAmountStableV1); -impl_default_generator_for_wrapper_type!(FuzzerCtx, CurrencyFeeStableV1); - -impl_default_generator_for_wrapper_type!(FuzzerCtx, UnsignedExtendedUInt32StableV1); - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> MinaBasePendingCoinbaseStateStackStableV1 { - let init: MinaBasePendingCoinbaseStackHashStableV1 = self.gen(); - let curr: MinaBasePendingCoinbaseStackHashStableV1 = self.gen(); - - MinaBasePendingCoinbaseStateStackStableV1 { - init: init.into(), - curr: curr.into(), - } - } -} - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> MinaBasePendingCoinbaseStackVersionedStableV1 { - let data: MinaBasePendingCoinbaseCoinbaseStackStableV1 = self.gen(); - - MinaBasePendingCoinbaseStackVersionedStableV1 { - data: data.into(), - state: self.gen(), - } - } -} - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> SgnStableV1 { - match self.gen.rng.gen_bool(0.5) { - true => SgnStableV1::Pos, - false => SgnStableV1::Neg, - } - } -} - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> SignedAmount { - SignedAmount { - magnitude: self.gen(), - sgn: self.gen(), - } - } -} - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> MinaBaseFeeExcessStableV1 { - MinaBaseFeeExcessStableV1( - TokenFeeExcess { - token: self.gen(), - amount: self.gen(), - }, - TokenFeeExcess { - token: self.gen(), - amount: self.gen(), - }, - ) - } -} - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> MinaTransactionLogicZkappCommandLogicLocalStateValueStableV1 { - MinaTransactionLogicZkappCommandLogicLocalStateValueStableV1 { - stack_frame: self.gen(), - call_stack: self.gen(), - transaction_commitment: self.gen(), - full_transaction_commitment: self.gen(), - excess: self.gen(), - supply_increase: self.gen(), - ledger: self.gen(), - success: self.gen(), - account_update_index: self.gen(), - failure_status_tbl: MinaBaseTransactionStatusFailureCollectionStableV1(List::new()), - will_succeed: self.gen(), - } - } -} - -impl Generator for FuzzerCtx { - #[coverage(off)] - fn gen(&mut self) -> MinaStateBlockchainStateValueStableV2LedgerProofStatementSource { - MinaStateBlockchainStateValueStableV2LedgerProofStatementSource { - first_pass_ledger: self.gen(), - second_pass_ledger: self.gen(), - pending_coinbase_stack: self.gen(), - local_state: self.gen(), - } - } -} diff --git a/tools/fuzzing/src/invariants.rs b/tools/fuzzing/src/invariants.rs deleted file mode 100644 index 8e9bc10cd3..0000000000 --- a/tools/fuzzing/src/invariants.rs +++ /dev/null @@ -1,353 +0,0 @@ -use ledger::{ - scan_state::{ - currency::TxnVersion, - transaction_logic::zkapp_command::{AccountUpdate, Control}, - }, - Account, AccountId, AuthRequired, ControlTag, Permissions, SetVerificationKey, TokenId, - ZkAppAccount, TXN_VERSION_CURRENT, -}; -use once_cell::sync::Lazy; -use std::sync::{Mutex, RwLock}; -use text_diff::{diff, Difference}; - -pub struct Checks { - pub caller_id: TokenId, - pub account_id: AccountId, - pub account_before: Account, - pub account_after: Option, - pub check_account: Permissions, - pub acc_update: AccountUpdate, // added for extra diagnostics -} - -pub static BREAK: Lazy> = Lazy::new( - #[coverage(off)] - || RwLock::new(false), -); -pub static STATE: Lazy>> = Lazy::new( - #[coverage(off)] - || RwLock::new(Vec::new()), -); -pub static LAST_RESULT: LastResult = LastResult::new(); - -pub struct LastResult { - result: Mutex>>, -} - -impl LastResult { - pub const fn new() -> Self { - Self { - result: Mutex::new(None), - } - } - - fn set(&self, result: Result<(), String>) { - *self.result.lock().unwrap() = Some(result); - } - - pub fn get(&self) -> Option> { - self.result.lock().unwrap().clone() - } - - pub fn take(&self) -> Option> { - self.result.lock().unwrap().take() - } -} - -impl Checks { - // We are duplicating the implementation here because we don't want changes in the logic to affect invariant checks - #[coverage(off)] - fn check_permission(auth: AuthRequired, tag: ControlTag) -> bool { - use AuthRequired as Auth; - use ControlTag as Tag; - - match (auth, tag) { - (Auth::Impossible, _) => false, - (Auth::None, _) => true, - (Auth::Proof, Tag::Proof) => true, - (Auth::Signature, Tag::Signature) => true, - (Auth::Either, Tag::Proof | Tag::Signature) => true, - (Auth::Signature, Tag::Proof) => false, - (Auth::Proof, Tag::Signature) => false, - (Auth::Proof | Auth::Signature | Auth::Either, Tag::NoneGiven) => false, - (Auth::Both, _) => unimplemented!(), - } - } - - #[coverage(off)] - fn setvk_auth(auth: AuthRequired, txn_version: TxnVersion) -> AuthRequired { - if txn_version <= TXN_VERSION_CURRENT { - if txn_version == TXN_VERSION_CURRENT { - auth - } else { - AuthRequired::Signature - } - } else { - panic!("invalid txn_version: {}", txn_version.as_u32()); - } - } - - #[coverage(off)] - pub fn new(caller_id: &TokenId, account_update: &AccountUpdate, account: &Account) -> Self { - let caller_id = caller_id.clone(); - let account_id = account_update.account_id(); - let account_before = account.clone(); - let tag = match account_update.authorization { - Control::Signature(_) => ControlTag::Signature, - Control::Proof(_) => ControlTag::Proof, - Control::NoneGiven => ControlTag::NoneGiven, - }; - let Permissions:: { - edit_state, - access, - send, - receive, - set_delegate, - set_permissions, - set_verification_key: SetVerificationKey { auth, txn_version }, - set_zkapp_uri, - edit_action_state, - set_token_symbol, - increment_nonce, - set_voting_for, - set_timing, - } = account_before.permissions; - let check_account = Permissions:: { - edit_state: !Self::check_permission(edit_state, tag), - access: !Self::check_permission(access, tag), - send: !Self::check_permission(send, tag), - receive: !Self::check_permission(receive, tag), - set_delegate: !Self::check_permission(set_delegate, tag), - set_permissions: !Self::check_permission(set_permissions, tag), - set_verification_key: SetVerificationKey { - auth: !Self::check_permission(Self::setvk_auth(auth, txn_version), tag), - txn_version, - }, - set_zkapp_uri: !Self::check_permission(set_zkapp_uri, tag), - edit_action_state: !Self::check_permission(edit_action_state, tag), - set_token_symbol: !Self::check_permission(set_token_symbol, tag), - increment_nonce: !Self::check_permission(increment_nonce, tag), - set_voting_for: !Self::check_permission(set_voting_for, tag), - set_timing: !Self::check_permission(set_timing, tag), - }; - - Self { - caller_id, - account_id, - account_before, - account_after: None, - check_account, - acc_update: account_update.clone(), - } - } - - #[coverage(off)] - fn check_authorization(caller_id: &TokenId) -> Result<(), String> { - for check in STATE.read().unwrap().iter().rev() { - // find parent's check - if caller_id == &check.account_id.derive_token_id() { - if check.check_account.access { - return Err("Invariant violation: caller access permission".to_string()); - } - - return Ok(()); - } - } - - panic!() - } - - #[coverage(off)] - pub fn add_after_account(&mut self, account: Account) { - self.account_after = Some(account); - } - - #[coverage(off)] - fn diagnostic(&self, err: &str) -> String { - let orig = format!("{:#?}", self.account_before); - let edit = format!("{:#?}", self.account_after.as_ref().unwrap()); - let split = " "; - let (_, changeset) = diff(orig.as_str(), edit.as_str(), split); - - let mut ret = String::new(); - - for seq in changeset { - match seq { - Difference::Same(ref x) => { - ret.push_str(x); - ret.push_str(split); - } - Difference::Add(ref x) => { - ret.push_str("\x1B[92m"); - ret.push_str(x); - ret.push_str("\x1B[0m"); - ret.push_str(split); - } - Difference::Rem(ref x) => { - ret.push_str("\x1B[91m"); - ret.push_str(x); - ret.push_str("\x1B[0m"); - ret.push_str(split); - } - } - } - - format!("{}\n{}\nUpdate:\n{:#?}\n", err, ret, self.acc_update) - } - - #[coverage(off)] - pub fn check_exit(&self) -> Result<(), String> { - let res = self._check_exit(); - LAST_RESULT.set(res.clone()); - res - } - - #[coverage(off)] - fn _check_exit(&self) -> Result<(), String> { - let Permissions:: { - edit_state, - access, - send, - receive, - set_delegate, - set_permissions, - set_verification_key: - SetVerificationKey { - auth: set_vk_auth, .. - }, - set_zkapp_uri, - edit_action_state, - set_token_symbol, - increment_nonce, - set_voting_for, - set_timing, - } = self.check_account; - - // Token owner approval of children account updates - if self.caller_id != TokenId::default() { - Self::check_authorization(&self.caller_id)?; - } - - let account = self.account_after.as_ref().unwrap(); - - if access && self.account_before != *account { - return Err(self.diagnostic("Invariant violation: access permission")); - } - - if send && self.account_before.balance > account.balance { - return Err(self.diagnostic("Invariant violation: send permission")); - } - - if receive && self.account_before.balance < account.balance { - return Err(self.diagnostic("Invariant violation: receive permission")); - } - - let is_change_from_none_to_default = self.account_before.delegate.is_none() - && account.delegate.as_ref() == Some(&account.public_key); - if set_delegate - && self.account_before.delegate != account.delegate - && !is_change_from_none_to_default - { - return Err(self.diagnostic("Invariant violation: set_delegate permission")); - } - - if set_permissions && self.account_before.permissions != account.permissions { - return Err(self.diagnostic("Invariant violation: set_permissions permission")); - } - - if set_token_symbol && self.account_before.token_symbol != account.token_symbol { - return Err(self.diagnostic("Invariant violation: set_token_symbol permission")); - } - - if increment_nonce && self.account_before.nonce != account.nonce { - return Err(self.diagnostic("Invariant violation: increment_nonce permission")); - } - - if set_voting_for && self.account_before.voting_for != account.voting_for { - return Err(self.diagnostic("Invariant violation: set_voting_for permission")); - } - - if set_timing && self.account_before.timing != account.timing { - return Err(self.diagnostic("Invariant violation: set_timing permission")); - } - - let default_values = ZkAppAccount::default(); - - if edit_state { - let invariant_violation = match &self.account_before.zkapp { - Some(zkapp) => account.zkapp.as_ref().map_or( - true, - #[coverage(off)] - |x| x.app_state != zkapp.app_state, - ), - None => account.zkapp.as_ref().map_or( - false, - #[coverage(off)] - |x| x.app_state != default_values.app_state, - ), - }; - - if invariant_violation { - return Err(self.diagnostic("Invariant violation: edit_state permission")); - } - } - - if set_vk_auth { - let invariant_violation = match &self.account_before.zkapp { - Some(zkapp) => account.zkapp.as_ref().map_or( - true, - #[coverage(off)] - |x| x.verification_key != zkapp.verification_key, - ), - None => account.zkapp.as_ref().map_or( - false, - #[coverage(off)] - |x| x.verification_key != default_values.verification_key, - ), - }; - - if invariant_violation { - return Err(self.diagnostic("Invariant violation: set_verification_key permission")); - } - } - - if set_zkapp_uri { - let invariant_violation = match &self.account_before.zkapp { - Some(zkapp) => account.zkapp.as_ref().map_or( - true, - #[coverage(off)] - |x| x.zkapp_uri != zkapp.zkapp_uri, - ), - None => account.zkapp.as_ref().map_or( - false, - #[coverage(off)] - |x| x.zkapp_uri != default_values.zkapp_uri, - ), - }; - - if invariant_violation { - return Err(self.diagnostic("Invariant violation: set_zkapp_uri permission")); - } - } - - if edit_action_state { - let invariant_violation = match &self.account_before.zkapp { - Some(zkapp) => account.zkapp.as_ref().map_or( - true, - #[coverage(off)] - |x| x.action_state != zkapp.action_state, - ), - None => account.zkapp.as_ref().map_or( - false, - #[coverage(off)] - |x| x.action_state != default_values.action_state, - ), - }; - - if invariant_violation { - return Err(self.diagnostic("Invariant violation: edit_action_state permission")); - } - } - - Ok(()) - } -} diff --git a/tools/fuzzing/src/main.rs b/tools/fuzzing/src/main.rs index fd9f1098a4..ec842a85c4 100644 --- a/tools/fuzzing/src/main.rs +++ b/tools/fuzzing/src/main.rs @@ -21,7 +21,8 @@ pub mod transaction_fuzzer { }; use ledger::{ scan_state::transaction_logic::{transaction_applied, UserCommand}, - Account, + sparse_ledger::LedgerIntf, + Account, BaseLedger, }; use mina_hasher::Fp; use mina_p2p_messages::bigint::BigInt; @@ -57,9 +58,9 @@ pub mod transaction_fuzzer { pub rust: Option, } - impl CoverageStats { + impl Default for CoverageStats { #[coverage(off)] - pub fn new() -> Self { + fn default() -> Self { let mut cov = Cov::new(); let file_counters = cov.get_file_counters(); Self { @@ -68,12 +69,19 @@ pub mod transaction_fuzzer { rust: None, } } + } + + impl CoverageStats { + #[coverage(off)] + pub fn new() -> Self { + Self::default() + } #[coverage(off)] pub fn update_rust(&mut self) -> bool { let rust_cov_stats = Stats::from_file_counters(&self.file_counters); let coverage_increased = self.rust.is_none() - || rust_cov_stats.has_coverage_increased(&self.rust.as_ref().unwrap()); + || rust_cov_stats.has_coverage_increased(self.rust.as_ref().unwrap()); if coverage_increased { let llvm_dump = self.cov.dump(); @@ -107,6 +115,7 @@ pub mod transaction_fuzzer { enum Action { SetConstraintConstants(ConstraintConstantsUnversioned), SetInitialAccounts(Vec), + GetAccounts, ApplyTx(UserCommand), #[allow(dead_code)] Exit, @@ -116,6 +125,7 @@ pub mod transaction_fuzzer { enum ActionOutput { ConstraintConstantsSet, InitialAccountsSet(BigInt), + Accounts(Vec), TxApplied(ApplyTxResult), ExitAck, } @@ -138,6 +148,18 @@ pub mod transaction_fuzzer { rust_ledger_root_hash } + #[coverage(off)] + fn ocaml_get_accounts(stdin: &mut ChildStdin, stdout: &mut ChildStdout) -> Vec { + let action = Action::GetAccounts; + serialize(&action, stdin); + let output: ActionOutput = deserialize(stdout); + + match output { + ActionOutput::Accounts(accounts) => accounts, + _ => unreachable!(), + } + } + #[coverage(off)] fn ocaml_apply_transaction( stdin: &mut ChildStdin, @@ -201,8 +223,8 @@ pub mod transaction_fuzzer { *invariants::BREAK.write().unwrap() = break_on_invariant; let mut cov_stats = CoverageStats::new(); let mut ctx = FuzzerCtxBuilder::new() - .seed(seed as u64) - .minimum_fee(minimum_fee as u64) + .seed(seed) + .minimum_fee(minimum_fee) .initial_accounts(10) .fuzzcases_path(env::var("FUZZCASES_PATH").unwrap_or("/tmp/".to_string())) .build(); @@ -216,7 +238,7 @@ pub mod transaction_fuzzer { print!("Iteration {}\r", iteration); std::io::stdout().flush().unwrap(); - if (iteration % 5000) == 0 { + if (iteration % 10000) == 0 { if fuzzer_made_progress { fuzzer_made_progress = false; ctx.take_snapshot(); @@ -227,8 +249,8 @@ pub mod transaction_fuzzer { } } - // Update coverage statistics every 100 iterations - if (iteration % 100) == 0 { + // Update coverage statistics every 1000 iterations + if (iteration % 1000) == 0 { let update_rust_increased_coverage = cov_stats.update_rust(); if update_rust_increased_coverage { @@ -239,12 +261,54 @@ pub mod transaction_fuzzer { let user_command: UserCommand = ctx.random_user_command(); let ocaml_apply_result = ocaml_apply_transaction(stdin, stdout, user_command.clone()); + let mut ledger = ctx.get_ledger_inner().make_child(); // Apply transaction on the Rust side - if ctx - .apply_transaction(&user_command, &ocaml_apply_result) - .is_err() + if let Err(error) = + ctx.apply_transaction(&mut ledger, &user_command, &ocaml_apply_result) { + println!("!!! {error}"); + + let ocaml_accounts = ocaml_get_accounts(stdin, stdout); + let rust_accounts = ledger.to_list(); + + for ocaml_account in ocaml_accounts.iter() { + match rust_accounts.iter().find( + #[coverage(off)] + |account| account.public_key == ocaml_account.public_key, + ) { + Some(rust_account) => { + if rust_account != ocaml_account { + println!( + "Content mismatch between OCaml and Rust account:\n{}", + ctx.diagnostic(rust_account, ocaml_account) + ); + } + } + None => { + println!( + "OCaml account not present in Rust ledger: {:?}", + ocaml_account + ); + } + } + } + + for rust_account in rust_accounts.iter() { + if !ocaml_accounts.iter().any( + #[coverage(off)] + |account| account.public_key == rust_account.public_key, + ) { + println!( + "Rust account not present in Ocaml ledger: {:?}", + rust_account + ); + } + } + + let bigint: num_bigint::BigUint = LedgerIntf::merkle_root(&mut ledger).into(); + ctx.save_fuzzcase(&user_command, &bigint.to_string()); + // Exiting due to inconsistent state std::process::exit(0); } @@ -259,13 +323,17 @@ pub mod transaction_fuzzer { ocaml_set_constraint_constants(&mut ctx, stdin, stdout); ocaml_set_initial_accounts(&mut ctx, stdin, stdout); + let mut ledger = ctx.get_ledger_inner().make_child(); let ocaml_apply_result = ocaml_apply_transaction(stdin, stdout, user_command.clone()); - let rust_apply_result = ctx.apply_transaction(&user_command, &ocaml_apply_result); + let rust_apply_result = + ctx.apply_transaction(&mut ledger, &user_command, &ocaml_apply_result); println!("apply_transaction: {:?}", rust_apply_result); } } +#[cfg(feature = "nightly")] +#[coverage(off)] fn main() { #[cfg(feature = "nightly")] { @@ -288,7 +356,7 @@ fn main() { .get_matches(); let mut child = Command::new( - &std::env::var("OCAML_TRANSACTION_FUZZER_PATH").unwrap_or_else( + std::env::var("OCAML_TRANSACTION_FUZZER_PATH").unwrap_or_else( #[coverage(off)] |_| { format!( diff --git a/tools/fuzzing/src/transaction_fuzzer/context.rs b/tools/fuzzing/src/transaction_fuzzer/context.rs index cc74e89bab..48ca7f42af 100644 --- a/tools/fuzzing/src/transaction_fuzzer/context.rs +++ b/tools/fuzzing/src/transaction_fuzzer/context.rs @@ -204,7 +204,8 @@ impl binprot::BinProtRead for ApplyTxResult { previous_hash, varying, }| { - let previous_hash = (&previous_hash.0) + let previous_hash = previous_hash + .0 .to_field() .map_err(|x| binprot::Error::CustomError(Box::new(x)))?; @@ -313,7 +314,7 @@ pub struct FuzzerCtx { impl FuzzerCtx { #[coverage(off)] - fn get_ledger_inner(&self) -> &Mask { + pub fn get_ledger_inner(&self) -> &Mask { match &self.state.ledger { LedgerKind::Mask(ledger) => ledger, LedgerKind::Staged(ledger, _) => ledger.ledger_ref(), @@ -612,16 +613,11 @@ impl FuzzerCtx { // } #[coverage(off)] - fn save_fuzzcase(&self, tx: &Transaction, filename: &String) { - let filename = self.fuzzcases_path.clone() + &filename + ".fuzzcase"; + pub fn save_fuzzcase(&self, user_command: &UserCommand, filename: &str) { + let filename = self.fuzzcases_path.clone() + filename + ".fuzzcase"; println!("Saving fuzzcase: {}", filename); - let user_command = match tx { - Transaction::Command(user_command) => user_command.clone(), - _ => unimplemented!(), - }; - let mut file = fs::OpenOptions::new() .write(true) .truncate(true) @@ -629,7 +625,10 @@ impl FuzzerCtx { .open(filename) .unwrap(); - serialize(&(self.get_ledger_accounts(), user_command), &mut file); + serialize( + &(self.get_ledger_accounts(), user_command.clone()), + &mut file, + ); } #[coverage(off)] @@ -1033,7 +1032,7 @@ impl FuzzerCtx { // } #[coverage(off)] - fn diagnostic(&self, applied: &impl Debug, applied_ocaml: &impl Debug) -> String { + pub fn diagnostic(&self, applied: &impl Debug, applied_ocaml: &impl Debug) -> String { use text_diff::{diff, Difference}; let orig = format!("{:#?}", applied); @@ -1070,15 +1069,16 @@ impl FuzzerCtx { #[coverage(off)] pub fn apply_transaction( &mut self, + ledger: &mut Mask, user_command: &UserCommand, expected_apply_result: &ApplyTxResult, - ) -> Result<(), ()> { + ) -> Result<(), String> { self.gen.nonces.clear(); - let mut ledger = self.get_ledger_inner().make_child(); - // If we called apply_transaction it means we passed the tx pool check, so add tx to the cache if let UserCommand::ZkAppCommand(command) = user_command { + command.account_updates.accumulate_hashes(); + if !command.account_updates.is_empty() { //println!("Storing in pool cache {:?}", tx); self.state.cache_pool.push_back(user_command.clone()); @@ -1092,7 +1092,7 @@ impl FuzzerCtx { &self.constraint_constants, self.txn_state_view.global_slot_since_genesis, &self.txn_state_view, - &mut ledger, + ledger, &[tx.clone()], ); @@ -1126,27 +1126,20 @@ impl FuzzerCtx { } if expected_apply_result.apply_result.len() != 1 { - println!( - "!!! Apply failed in OCaml (error: {}) but it didn't in Rust: {:?}", + return Err(format!( + "Apply failed in OCaml (error: {}) but it didn't in Rust: {:?}", expected_apply_result.error, applied - ); - let bigint: num_bigint::BigUint = LedgerIntf::merkle_root(&mut ledger).into(); - self.save_fuzzcase(&tx, &bigint.to_string()); - return Err(()); - } else { - if applied != &expected_apply_result.apply_result[0] { - println!( - "!!! Apply result mismatch between OCaml and Rust\n{}\n", - self.diagnostic(applied, &expected_apply_result.apply_result[0]) - ); - - let bigint: num_bigint::BigUint = - LedgerIntf::merkle_root(&mut ledger).into(); - self.save_fuzzcase(&tx, &bigint.to_string()); - return Err(()); - } + )); + } else if applied != &expected_apply_result.apply_result[0] { + return Err(format!( + "Apply result mismatch between OCaml and Rust\n{}\n", + self.diagnostic(applied, &expected_apply_result.apply_result[0]) + )); } + //println!("RUST: {:?}", applied); + //println!("OCAML: {:?}", expected_apply_result); + // Save applied transactions in the cache for later use (mutation) if *applied.transaction_status() == TransactionStatus::Applied { if let UserCommand::ZkAppCommand(command) = user_command { @@ -1199,35 +1192,40 @@ impl FuzzerCtx { Err(error_string) => { // Currently disabled until invariants are fixed if error_string.starts_with("Invariant violation") { - let bigint: num_bigint::BigUint = LedgerIntf::merkle_root(&mut ledger).into(); - self.save_fuzzcase(&tx, &bigint.to_string()); - return Err(()); + return Err(error_string); } if expected_apply_result.apply_result.len() == 1 { - println!( - "!!! Apply failed in Rust (error: {}) but it didn't in OCaml: {:?}", + return Err(format!( + "Apply failed in Rust (error: {}) but it didn't in OCaml: {:?}", error_string, &expected_apply_result.apply_result[0] - ); - let bigint: num_bigint::BigUint = LedgerIntf::merkle_root(&mut ledger).into(); - self.save_fuzzcase(&tx, &bigint.to_string()); - return Err(()); + )); + } else { + //println!("ERROR RUST: {error_string}"); + //println!("ERROR OCAML: {:?}", expected_apply_result); } } } - let rust_ledger_root_hash = LedgerIntf::merkle_root(&mut ledger); + let rust_ledger_root_hash = LedgerIntf::merkle_root(ledger); - if &expected_apply_result.root_hash != &rust_ledger_root_hash { - println!( + if expected_apply_result.root_hash != rust_ledger_root_hash { + Err(format!( "Ledger hash mismatch: {:?} != {:?} (expected)", rust_ledger_root_hash, expected_apply_result.root_hash - ); - let bigint: num_bigint::BigUint = rust_ledger_root_hash.into(); - self.save_fuzzcase(&tx, &bigint.to_string()); - Err(()) + )) } else { ledger.commit(); + + let rust_ledger_root_hash = LedgerIntf::merkle_root(self.get_ledger_inner_mut()); + + if expected_apply_result.root_hash != rust_ledger_root_hash { + return Err(format!( + "Ledger hash mismatch (AFTER COMMIT!): {:?} != {:?} (expected)", + rust_ledger_root_hash, expected_apply_result.root_hash + )); + } + Ok(()) } } @@ -1263,15 +1261,15 @@ pub struct FuzzerCtxBuilder { is_staged_ledger: bool, } -impl FuzzerCtxBuilder { +impl Default for FuzzerCtxBuilder { #[coverage(off)] - pub fn new() -> Self { + fn default() -> Self { Self { constraint_constants: None, txn_state_view: None, fuzzcases_path: None, seed: 0, - minimum_fee: 1_000_000, // Sane default in case we don't obtain it from OCaml + minimum_fee: 1_000_000, max_account_balance: 1_000_000_000_000_000, initial_accounts: 10, cache_size: 4096, @@ -1279,6 +1277,13 @@ impl FuzzerCtxBuilder { is_staged_ledger: false, } } +} + +impl FuzzerCtxBuilder { + #[coverage(off)] + pub fn new() -> Self { + Self::default() + } #[coverage(off)] pub fn constants(&mut self, constraint_constants: ConstraintConstants) -> &mut Self { diff --git a/tools/fuzzing/src/transaction_fuzzer/coverage/cov.rs b/tools/fuzzing/src/transaction_fuzzer/coverage/cov.rs index 001bf04561..6e4a4f11aa 100644 --- a/tools/fuzzing/src/transaction_fuzzer/coverage/cov.rs +++ b/tools/fuzzing/src/transaction_fuzzer/coverage/cov.rs @@ -15,9 +15,9 @@ pub struct Sections { pub covfun: Vec, } -impl Sections { +impl Default for Sections { #[coverage(off)] - pub fn new() -> Self { + fn default() -> Self { let section_names = vec!["__llvm_covmap", "__llvm_covfun"]; let sections = get_elf_sections(get_module_path(), §ion_names); let covmap = §ions["__llvm_covmap"]; @@ -42,6 +42,13 @@ impl Sections { } } +impl Sections { + #[coverage(off)] + pub fn new() -> Self { + Self::default() + } +} + #[derive(Debug, Clone)] pub struct FunCounters { pub name_hash: u64, @@ -68,9 +75,9 @@ pub struct Cov { pub sections: Sections, } -impl Cov { +impl Default for Cov { #[coverage(off)] - pub fn new() -> Self { + fn default() -> Self { Self { counters: unsafe { get_counters() }, names: Names::new(), @@ -78,6 +85,13 @@ impl Cov { sections: Sections::new(), } } +} + +impl Cov { + #[coverage(off)] + pub fn new() -> Self { + Self::default() + } #[coverage(off)] pub fn get_functions_counters(&mut self) -> Vec { diff --git a/tools/fuzzing/src/transaction_fuzzer/coverage/names.rs b/tools/fuzzing/src/transaction_fuzzer/coverage/names.rs index 814e980aea..e2dd5e8cdb 100644 --- a/tools/fuzzing/src/transaction_fuzzer/coverage/names.rs +++ b/tools/fuzzing/src/transaction_fuzzer/coverage/names.rs @@ -6,9 +6,9 @@ use super::util::{get_names, Leb128}; #[allow(dead_code)] pub struct Names(Vec); -impl Names { +impl Default for Names { #[coverage(off)] - pub fn new() -> Self { + fn default() -> Self { let names_buf = unsafe { get_names() }.to_vec(); let mut cursor = Cursor::new(&names_buf); let mut output = Vec::new(); @@ -39,6 +39,13 @@ impl Names { Self(output) } +} + +impl Names { + #[coverage(off)] + pub fn new() -> Self { + Self::default() + } #[coverage(off)] fn read_names(names: &[u8], output: &mut Vec) { diff --git a/tools/fuzzing/src/transaction_fuzzer/coverage/profile_data.rs b/tools/fuzzing/src/transaction_fuzzer/coverage/profile_data.rs index e139621cae..e5952a03d9 100644 --- a/tools/fuzzing/src/transaction_fuzzer/coverage/profile_data.rs +++ b/tools/fuzzing/src/transaction_fuzzer/coverage/profile_data.rs @@ -41,9 +41,9 @@ impl FunControl { #[derive(Debug)] pub struct ProfileData(pub Vec); -impl ProfileData { +impl Default for ProfileData { #[coverage(off)] - pub fn new() -> Self { + fn default() -> Self { let data_buf = unsafe { get_data() }.to_vec(); let mut cursor = Cursor::new(&data_buf); let mut output = Vec::new(); @@ -56,3 +56,10 @@ impl ProfileData { Self(output) } } + +impl ProfileData { + #[coverage(off)] + pub fn new() -> Self { + Self::default() + } +} diff --git a/tools/fuzzing/src/transaction_fuzzer/coverage/reports.rs b/tools/fuzzing/src/transaction_fuzzer/coverage/reports.rs index 3364c10134..2ed446b9c9 100644 --- a/tools/fuzzing/src/transaction_fuzzer/coverage/reports.rs +++ b/tools/fuzzing/src/transaction_fuzzer/coverage/reports.rs @@ -128,16 +128,14 @@ impl LineCounter { #[coverage(off)] fn split(&self, rhs: &Self) -> Vec { - if self.contains(&rhs) { - self.split3(&rhs) + if self.contains(rhs) { + self.split3(rhs) } else if rhs.contains(self) { rhs.split3(self) + } else if self.col_start < rhs.col_start { + self.split2(rhs) } else { - if self.col_start < rhs.col_start { - self.split2(rhs) - } else { - rhs.split2(self) - } + rhs.split2(self) } } @@ -146,12 +144,10 @@ impl LineCounter { if self.overlap(rhs) { if self.count == rhs.count { Some(vec![self.merge(rhs, self.count)]) + } else if self.col_start == rhs.col_start && self.col_end == rhs.col_end { + Some(vec![self.merge(rhs, self.count.max(rhs.count))]) } else { - if self.col_start == rhs.col_start && self.col_end == rhs.col_end { - Some(vec![self.merge(rhs, self.count.max(rhs.count))]) - } else { - Some(self.split(rhs)) - } + Some(self.split(rhs)) } } else { None @@ -160,7 +156,7 @@ impl LineCounter { } #[coverage(off)] -fn color_line_counters(line: &str, counters: &Vec) -> String { +fn color_line_counters(line: &str, counters: &[LineCounter]) -> String { let mut result = String::new(); if counters.is_empty() { @@ -210,13 +206,10 @@ fn color_line_counters(line: &str, counters: &Vec) -> String { // avoid reset colors if there is another counter if column == counter.col_end && (counter.col_start == counter.col_end - || counters - .iter() - .find( - #[coverage(off)] - |LineCounter { col_start, .. }| *col_start == column, - ) - .is_none()) + || !counters.iter().any( + #[coverage(off)] + |LineCounter { col_start, .. }| *col_start == column, + )) { result.push_str(&format!("\x1b[1;{}m\x1b[1;37m", line_color)); } @@ -345,10 +338,10 @@ impl FileCoverage { impl fmt::Display for FileCoverage { #[coverage(off)] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}:\n", self.filename)?; + writeln!(f, "{}:", self.filename)?; for (i, line) in self.lines.iter().enumerate() { - write!(f, "{:>6}: {}\n", i, line)?; + writeln!(f, "{:>6}: {}", i, line)?; } Ok(()) @@ -362,7 +355,7 @@ impl fmt::Display for CoverageReport { #[coverage(off)] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { for file in self.0.iter() { - write!(f, "{}\n", file)?; + writeln!(f, "{}", file)?; } Ok(()) @@ -428,7 +421,7 @@ impl CoverageReport { break; } - if let Some(new_counters) = counters[idx].join(&counter) { + if let Some(new_counters) = counters[idx].join(counter) { counters.remove(idx); for counter in new_counters.iter() { @@ -436,17 +429,15 @@ impl CoverageReport { } break; - } else { - if counters[idx].col_end > counter.col_end { - counters.insert(idx, counter.clone()); - break; - } + } else if counters[idx].col_end > counter.col_end { + counters.insert(idx, counter.clone()); + break; } } } #[coverage(off)] - pub fn from_llvm_dump(llvm_dump: &Vec) -> Self { + pub fn from_llvm_dump(llvm_dump: &[FileDump]) -> Self { let sources_path = env::var("RUST_BUILD_PATH").unwrap_or_else(|_| { env::current_dir() .unwrap() @@ -546,7 +537,7 @@ impl CoverageReport { } #[coverage(off)] - pub fn from_bisect_dump(bisect_dump: &Vec<(String, Vec, Vec)>) -> Self { + pub fn from_bisect_dump(bisect_dump: &[(String, Vec, Vec)]) -> Self { let sources_path = env::var("OCAML_BUILD_PATH").unwrap(); let mut file_coverage_vec = Vec::new(); @@ -572,7 +563,7 @@ impl CoverageReport { line_offset_vec[i - 1] + 1 }; LineCoverage { - line: String::from_utf8((&file_contents[start_pos..end_pos]).to_vec()) + line: String::from_utf8(file_contents[start_pos..end_pos].to_vec()) .unwrap(), counters: Vec::new(), } @@ -609,17 +600,16 @@ impl CoverageReport { .unwrap(); let col = if line_num == 0 { - point as usize + point } else { - point as usize - line_offset_vec[line_num - 1] + point - line_offset_vec[line_num - 1] }; // TODO: find a better way to convert bytes position to char position - let col_start = - String::from_utf8((&lines[line_num].line.as_bytes()[..col]).to_vec()) - .unwrap() - .chars() - .count(); + let col_start = String::from_utf8(lines[line_num].line.as_bytes()[..col].to_vec()) + .unwrap() + .chars() + .count(); // It seems there isn't an "end column" in bisect-ppx let col_end = col_start; diff --git a/tools/fuzzing/src/transaction_fuzzer/coverage/stats.rs b/tools/fuzzing/src/transaction_fuzzer/coverage/stats.rs index 3bf473c9be..304c591675 100644 --- a/tools/fuzzing/src/transaction_fuzzer/coverage/stats.rs +++ b/tools/fuzzing/src/transaction_fuzzer/coverage/stats.rs @@ -76,7 +76,7 @@ impl Stats { } #[coverage(off)] - pub fn from_file_counters(filecounters: &Vec) -> Self { + pub fn from_file_counters(filecounters: &[FileCounters]) -> Self { let mut result = BTreeMultiMap::new(); for FileCounters { @@ -109,7 +109,7 @@ impl Stats { } #[coverage(off)] - pub fn from_bisect_dump(bisect_dump: &Vec<(String, Vec, Vec)>) -> Self { + pub fn from_bisect_dump(bisect_dump: &[(String, Vec, Vec)]) -> Self { let mut result = BTreeMultiMap::new(); for (filename, _points, counts) in bisect_dump.iter() { @@ -134,13 +134,13 @@ impl fmt::Display for Stats { #[coverage(off)] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { for (percent, (filename, total, covered)) in self.0.iter() { - write!( + writeln!( f, - "{:>3}% {:>4}/{:>4}: {}\n", + "{:>3}% {:>4}/{:>4}: {}", percent, covered, total, filename )?; } let (percent, total, covered) = self.get_total(); - write!(f, "{:>3}% {:>4}/{:>4}: Total\n", percent, covered, total) + writeln!(f, "{:>3}% {:>4}/{:>4}: Total", percent, covered, total) } } diff --git a/tools/fuzzing/src/transaction_fuzzer/coverage/util.rs b/tools/fuzzing/src/transaction_fuzzer/coverage/util.rs index c8c323a28d..977a9c6af0 100644 --- a/tools/fuzzing/src/transaction_fuzzer/coverage/util.rs +++ b/tools/fuzzing/src/transaction_fuzzer/coverage/util.rs @@ -50,7 +50,7 @@ pub fn get_module_path() -> String { let rsprocmaps::AddressRange { begin, end } = map.address_range; - if (begin..end).contains(&(get_module_path as u64)) { + if (begin..end).contains(&(get_module_path as usize as u64)) { if let rsprocmaps::Pathname::Path(path) = map.pathname { return path; } else { diff --git a/tools/fuzzing/src/transaction_fuzzer/generator.rs b/tools/fuzzing/src/transaction_fuzzer/generator.rs index bd78705917..f26e51ada1 100644 --- a/tools/fuzzing/src/transaction_fuzzer/generator.rs +++ b/tools/fuzzing/src/transaction_fuzzer/generator.rs @@ -5,7 +5,7 @@ use ark_ff::{Field, UniformRand}; use ledger::generators::zkapp_command_builder::get_transaction_commitments; use ledger::proofs::field::FieldWitness; use ledger::proofs::transaction::InnerCurve; -use ledger::scan_state::currency::{Magnitude, SlotSpan, TxnVersion}; +use ledger::scan_state::currency::{Magnitude, SlotSpan}; use ledger::VerificationKeyWire; use ledger::{ proofs::transaction::PlonkVerificationKeyEvals, @@ -272,11 +272,11 @@ impl Generator for FuzzerCtx { #[coverage(off)] fn gen(&mut self) -> VerificationKey { VerificationKey { - max_proofs_verified: vec![ProofVerified::N0, ProofVerified::N1, ProofVerified::N2] + max_proofs_verified: [ProofVerified::N0, ProofVerified::N1, ProofVerified::N2] .choose(&mut self.gen.rng) .unwrap() .clone(), - actual_wrap_domain_size: vec![ProofVerified::N0, ProofVerified::N1, ProofVerified::N2] + actual_wrap_domain_size: [ProofVerified::N0, ProofVerified::N1, ProofVerified::N2] .choose(&mut self.gen.rng) .unwrap() .clone(), @@ -311,7 +311,7 @@ impl Generator> for FuzzerCtx { impl Generator for FuzzerCtx { #[coverage(off)] fn gen(&mut self) -> AuthRequired { - *vec![ + *[ AuthRequired::None, AuthRequired::Either, AuthRequired::Proof, @@ -327,7 +327,7 @@ impl Generator for FuzzerCtx { impl Generator for FuzzerCtx { #[coverage(off)] fn gen(&mut self) -> PermissionModel { - vec![ + [ PermissionModel::Any, PermissionModel::Empty, PermissionModel::Initial, @@ -841,7 +841,7 @@ impl Generator for FuzzerCtx { #[coverage(off)] fn gen(&mut self) -> CompositionTypesBranchDataStableV1 { CompositionTypesBranchDataStableV1 { - proofs_verified: vec![ + proofs_verified: [ PicklesBaseProofsVerifiedStableV1::N0, PicklesBaseProofsVerifiedStableV1::N1, PicklesBaseProofsVerifiedStableV1::N2, @@ -929,10 +929,7 @@ where { let (a, b): (Vec<_>, Vec<_>) = gen_curve_point_many::(ctx).into_iter().unzip(); - ( - ArrayN::from_iter(a.into_iter()), - ArrayN::from_iter(b.into_iter()), - ) + (ArrayN::from_iter(a), ArrayN::from_iter(b)) } impl Generator for FuzzerCtx { @@ -1004,88 +1001,32 @@ impl Generator for F #[coverage(off)] fn gen(&mut self) -> PicklesProofProofsVerified2ReprStableV2PrevEvalsEvalsEvals { PicklesProofProofsVerified2ReprStableV2PrevEvalsEvalsEvals { - w: self.gen_wrap( - #[coverage(off)] - |x| gen_curve_point_many_unzip::(x), - ), + w: self.gen_wrap(gen_curve_point_many_unzip::), complete_add_selector: gen_curve_point_many_unzip::(self), mul_selector: gen_curve_point_many_unzip::(self), emul_selector: gen_curve_point_many_unzip::(self), endomul_scalar_selector: gen_curve_point_many_unzip::(self), - range_check0_selector: self.gen_wrap( - #[coverage(off)] - |x| gen_curve_point_many_unzip::(x), - ), - range_check1_selector: self.gen_wrap( - #[coverage(off)] - |x| gen_curve_point_many_unzip::(x), - ), - foreign_field_add_selector: self.gen_wrap( - #[coverage(off)] - |x| gen_curve_point_many_unzip::(x), - ), - foreign_field_mul_selector: self.gen_wrap( - #[coverage(off)] - |x| gen_curve_point_many_unzip::(x), - ), - xor_selector: self.gen_wrap( - #[coverage(off)] - |x| gen_curve_point_many_unzip::(x), - ), - rot_selector: self.gen_wrap( - #[coverage(off)] - |x| gen_curve_point_many_unzip::(x), - ), - lookup_aggregation: self.gen_wrap( - #[coverage(off)] - |x| gen_curve_point_many_unzip::(x), - ), - lookup_table: self.gen_wrap( - #[coverage(off)] - |x| gen_curve_point_many_unzip::(x), - ), + range_check0_selector: self.gen_wrap(gen_curve_point_many_unzip::), + range_check1_selector: self.gen_wrap(gen_curve_point_many_unzip::), + foreign_field_add_selector: self.gen_wrap(gen_curve_point_many_unzip::), + foreign_field_mul_selector: self.gen_wrap(gen_curve_point_many_unzip::), + xor_selector: self.gen_wrap(gen_curve_point_many_unzip::), + rot_selector: self.gen_wrap(gen_curve_point_many_unzip::), + lookup_aggregation: self.gen_wrap(gen_curve_point_many_unzip::), + lookup_table: self.gen_wrap(gen_curve_point_many_unzip::), lookup_sorted: self.gen_wrap( #[coverage(off)] - |x| { - x.gen_wrap( - #[coverage(off)] - |x| gen_curve_point_many_unzip::(x), - ) - }, - ), - runtime_lookup_table: self.gen_wrap( - #[coverage(off)] - |x| gen_curve_point_many_unzip::(x), - ), - runtime_lookup_table_selector: self.gen_wrap( - #[coverage(off)] - |x| gen_curve_point_many_unzip::(x), - ), - xor_lookup_selector: self.gen_wrap( - #[coverage(off)] - |x| gen_curve_point_many_unzip::(x), - ), - lookup_gate_lookup_selector: self.gen_wrap( - #[coverage(off)] - |x| gen_curve_point_many_unzip::(x), - ), - range_check_lookup_selector: self.gen_wrap( - #[coverage(off)] - |x| gen_curve_point_many_unzip::(x), - ), - foreign_field_mul_lookup_selector: self.gen_wrap( - #[coverage(off)] - |x| gen_curve_point_many_unzip::(x), - ), - coefficients: self.gen_wrap( - #[coverage(off)] - |x| gen_curve_point_many_unzip::(x), + |x| x.gen_wrap(gen_curve_point_many_unzip::), ), + runtime_lookup_table: self.gen_wrap(gen_curve_point_many_unzip::), + runtime_lookup_table_selector: self.gen_wrap(gen_curve_point_many_unzip::), + xor_lookup_selector: self.gen_wrap(gen_curve_point_many_unzip::), + lookup_gate_lookup_selector: self.gen_wrap(gen_curve_point_many_unzip::), + range_check_lookup_selector: self.gen_wrap(gen_curve_point_many_unzip::), + foreign_field_mul_lookup_selector: self.gen_wrap(gen_curve_point_many_unzip::), + coefficients: self.gen_wrap(gen_curve_point_many_unzip::), z: gen_curve_point_many_unzip::(self), - s: self.gen_wrap( - #[coverage(off)] - |x| gen_curve_point_many_unzip::(x), - ), + s: self.gen_wrap(gen_curve_point_many_unzip::), generic_selector: gen_curve_point_many_unzip::(self), poseidon_selector: gen_curve_point_many_unzip::(self), } @@ -1190,15 +1131,9 @@ impl Generator for FuzzerCtx { #[coverage(off)] fn gen(&mut self) -> PicklesWrapWireProofCommitmentsStableV1 { PicklesWrapWireProofCommitmentsStableV1 { - w_comm: self.gen_wrap( - #[coverage(off)] - |x| gen_curve_point::(x), - ), + w_comm: self.gen_wrap(gen_curve_point::), z_comm: gen_curve_point::(self), - t_comm: self.gen_wrap( - #[coverage(off)] - |x| gen_curve_point::(x), - ), + t_comm: self.gen_wrap(gen_curve_point::), } } } @@ -1223,19 +1158,10 @@ impl Generator for FuzzerCtx { #[coverage(off)] fn gen(&mut self) -> PicklesWrapWireProofEvaluationsStableV1 { PicklesWrapWireProofEvaluationsStableV1 { - w: self.gen_wrap( - #[coverage(off)] - |x| gen_curve_point::(x), - ), - coefficients: self.gen_wrap( - #[coverage(off)] - |x| gen_curve_point::(x), - ), + w: self.gen_wrap(gen_curve_point::), + coefficients: self.gen_wrap(gen_curve_point::), z: gen_curve_point::(self), - s: self.gen_wrap( - #[coverage(off)] - |x| gen_curve_point::(x), - ), + s: self.gen_wrap(gen_curve_point::), generic_selector: gen_curve_point::(self), poseidon_selector: gen_curve_point::(self), complete_add_selector: gen_curve_point::(self), @@ -1284,7 +1210,7 @@ impl Generator> for FuzzerCtx { txn_version: if self.gen.rng.gen_bool(0.9) { TXN_VERSION_CURRENT } else { - TxnVersion::from(self.gen.rng.gen()) + self.gen.rng.gen() }, } } @@ -1336,7 +1262,7 @@ impl GeneratorFromAccount for FuzzerCtx { self.gen() }; - let options = vec![ + let options = [ zkapp_command::AuthorizationKind::NoneGiven, zkapp_command::AuthorizationKind::Signature, zkapp_command::AuthorizationKind::Proof(vk_hash), @@ -1451,25 +1377,23 @@ impl GeneratorFromAccount> for FuzzerCtx { fn gen_from_account(&mut self, account: &Account) -> Signed { if self.gen.rng.gen_bool(0.9) { Signed::::zero() - } else { - if self.gen.token_id == TokenId::default() { - if self.gen.excess_fee.is_zero() { - let magnitude = GeneratorRange64::::gen_range( - self, - 0..=(account.balance.as_u64().wrapping_div(10).saturating_mul(7)), - ); - self.gen.excess_fee = Signed::::create(magnitude, self.gen()); - self.gen.excess_fee - } else { - let ret = self.gen.excess_fee.negate(); - self.gen.excess_fee = Signed::::zero(); - ret - } + } else if self.gen.token_id == TokenId::default() { + if self.gen.excess_fee.is_zero() { + let magnitude = GeneratorRange64::::gen_range( + self, + 0..=(account.balance.as_u64().wrapping_div(10).saturating_mul(7)), + ); + self.gen.excess_fee = Signed::::create(magnitude, self.gen()); + self.gen.excess_fee } else { - // Custom Tokens - let magnitude = GeneratorRange64::::gen_range(self, 0..=u64::MAX); - Signed::::create(magnitude, self.gen()) + let ret = self.gen.excess_fee.negate(); + self.gen.excess_fee = Signed::::zero(); + ret } + } else { + // Custom Tokens + let magnitude = GeneratorRange64::::gen_range(self, 0..=u64::MAX); + Signed::::create(magnitude, self.gen()) } } } @@ -1656,7 +1580,7 @@ impl GeneratorFromAccount for FuzzerCtx { zkapp_command::EpochLedger { hash: OrIgnore::Check(epoch_data.ledger.hash), total_currency: OrIgnore::Check(ClosedInterval:: { - lower: epoch_data.ledger.total_currency.clone(), + lower: epoch_data.ledger.total_currency, upper: epoch_data.ledger.total_currency, }), }, @@ -1664,7 +1588,7 @@ impl GeneratorFromAccount for FuzzerCtx { OrIgnore::Check(epoch_data.start_checkpoint), OrIgnore::Check(epoch_data.lock_checkpoint), OrIgnore::Check(ClosedInterval:: { - lower: epoch_data.epoch_length.clone(), + lower: epoch_data.epoch_length, upper: epoch_data.epoch_length, }), ) @@ -1677,7 +1601,7 @@ impl GeneratorFromAccount for FuzzerCtx { zkapp_command::EpochLedger { hash: OrIgnore::Check(epoch_data.ledger.hash), total_currency: OrIgnore::Check(ClosedInterval:: { - lower: epoch_data.ledger.total_currency.clone(), + lower: epoch_data.ledger.total_currency, upper: epoch_data.ledger.total_currency, }), }, @@ -1685,7 +1609,7 @@ impl GeneratorFromAccount for FuzzerCtx { OrIgnore::Check(epoch_data.start_checkpoint), OrIgnore::Check(epoch_data.lock_checkpoint), OrIgnore::Check(ClosedInterval:: { - lower: epoch_data.epoch_length.clone(), + lower: epoch_data.epoch_length, upper: epoch_data.epoch_length, }), ) @@ -1854,7 +1778,7 @@ impl Generator for FuzzerCtx { if self.gen.token_id.is_default() { MayUseToken::No } else { - match vec![0, 1, 2].choose(&mut self.gen.rng).unwrap() { + match [0, 1, 2].choose(&mut self.gen.rng).unwrap() { 0 => MayUseToken::No, 1 => MayUseToken::ParentsOwnToken, 2 => MayUseToken::InheritFromParent, @@ -1870,17 +1794,17 @@ impl GeneratorFromAccount for FuzzerCtx { zkapp_command::Body { public_key: account.public_key.clone(), token_id: self.gen.token_id.clone(), - update: self.gen_from_account(&account), - balance_change: self.gen_from_account(&account), + update: self.gen_from_account(account), + balance_change: self.gen_from_account(account), increment_nonce: self.gen.rng.gen_bool(0.5), events: self.gen(), actions: self.gen(), call_data: self.gen(), - preconditions: self.gen_from_account(&account), + preconditions: self.gen_from_account(account), use_full_commitment: self.gen.rng.gen_bool(0.9), implicit_account_creation_fee: self.gen.rng.gen_bool(0.1), may_use_token: self.gen(), - authorization_kind: self.gen_from_account(&account), + authorization_kind: self.gen_from_account(account), } } } @@ -1924,9 +1848,12 @@ impl GeneratorFromToken for FuzzerCtx { }; // let public_key = self.random_keypair().public.into_compressed(); - let account = self.get_account(&public_key); - let body: zkapp_command::Body = if account.is_some() && self.gen.rng.gen_bool(0.9) { - self.gen_from_account(account.as_ref().unwrap()) + + let body: zkapp_command::Body = if self.gen.rng.gen_bool(0.9) { + match self.get_account(&public_key).as_ref() { + Some(account) => self.gen_from_account(account), + None => self.gen(), + } } else { self.gen() }; @@ -1995,7 +1922,7 @@ pub fn sign_account_updates( true => full_txn_commitment, false => txn_commitment, }; - Some(signer.sign(&kp, &input)) + Some(signer.sign(&kp, input)) } _ => None, }; @@ -2095,11 +2022,15 @@ impl Generator for FuzzerCtx { }; let account = self.get_account(&fee_payer_pk); - - let body = if account.is_some() && self.gen.rng.gen_bool(0.8) { - signed_command::Body::Payment(self.gen_from_account(account.as_ref().unwrap())) - } else { - signed_command::Body::StakeDelegation(self.gen()) + let body = match account.as_ref() { + Some(account) => { + if self.gen.rng.gen_bool(0.8) { + signed_command::Body::Payment(self.gen_from_account(account)) + } else { + signed_command::Body::StakeDelegation(self.gen()) + } + } + None => signed_command::Body::StakeDelegation(self.gen()), }; let fee = match account.as_ref() { @@ -2151,7 +2082,7 @@ impl Generator for FuzzerCtx { impl Generator for FuzzerCtx { #[coverage(off)] fn gen(&mut self) -> UserCommand { - match vec![0, 1].choose(&mut self.gen.rng).unwrap() { + match [0, 1].choose(&mut self.gen.rng).unwrap() { 0 => UserCommand::SignedCommand(Box::new(self.gen())), 1 => UserCommand::ZkAppCommand(Box::new(self.gen())), _ => unimplemented!(), diff --git a/tools/fuzzing/src/transaction_fuzzer/invariants.rs b/tools/fuzzing/src/transaction_fuzzer/invariants.rs index 8e9bc10cd3..f0b1a34ec4 100644 --- a/tools/fuzzing/src/transaction_fuzzer/invariants.rs +++ b/tools/fuzzing/src/transaction_fuzzer/invariants.rs @@ -34,6 +34,7 @@ pub struct LastResult { } impl LastResult { + #[coverage(off)] pub const fn new() -> Self { Self { result: Mutex::new(None), diff --git a/tools/fuzzing/src/transaction_fuzzer/mutator.rs b/tools/fuzzing/src/transaction_fuzzer/mutator.rs index 19b2e72deb..e55c989852 100644 --- a/tools/fuzzing/src/transaction_fuzzer/mutator.rs +++ b/tools/fuzzing/src/transaction_fuzzer/mutator.rs @@ -631,7 +631,7 @@ impl Mutator for FuzzerCtx { self.gen() }; - let options = vec![ + let options = [ zkapp_command::AuthorizationKind::NoneGiven, zkapp_command::AuthorizationKind::Signature, zkapp_command::AuthorizationKind::Proof(vk_hash), @@ -664,7 +664,7 @@ impl Mutator for FuzzerCtx { } }; } else { - t.authorization = match vec![0, 1, 2].choose(&mut self.gen.rng).unwrap() { + t.authorization = match [0, 1, 2].choose(&mut self.gen.rng).unwrap() { 0 => zkapp_command::Control::NoneGiven, 1 => zkapp_command::Control::Signature(Signature::dummy()), 2 => zkapp_command::Control::Proof(self.gen()), diff --git a/tools/fuzzing/src/util.rs b/tools/fuzzing/src/util.rs deleted file mode 100644 index f239e0dff0..0000000000 --- a/tools/fuzzing/src/util.rs +++ /dev/null @@ -1,95 +0,0 @@ -use std::{collections::HashSet, hash::Hash, io::Cursor}; - -use binprot::{BinProtRead, BinProtWrite}; -use mina_hasher::Fp; -use mina_p2p_messages::bigint::BigInt; -use ocaml_interop::*; - -use crate::{Account, AccountIndex, Address}; - -#[no_coverage] -pub fn get_list_of(rt: &mut &mut OCamlRuntime, list: OCamlRef>) -> Vec -where - T: BinProtRead, -{ - let mut list_ref = rt.get(list); - let mut list = Vec::with_capacity(2048); - - while let Some((head, tail)) = list_ref.uncons() { - let object: T = deserialize(head.as_bytes()); - list.push(object); - list_ref = tail; - } - - list -} - -#[no_coverage] -pub fn get_set_of( - rt: &mut &mut OCamlRuntime, - list: OCamlRef>, -) -> HashSet -where - T: BinProtRead + Hash + Eq, -{ - let mut list_ref = rt.get(list); - let mut set = HashSet::with_capacity(2048); - - while let Some((head, tail)) = list_ref.uncons() { - let object: T = deserialize(head.as_bytes()); - set.insert(object); - list_ref = tail; - } - - set -} - -#[no_coverage] -pub fn get_list_addr_account( - rt: &mut &mut OCamlRuntime, - list: OCamlRef>, -) -> Vec<(Address, Account)> { - let mut list_ref = rt.get(list); - let mut list = Vec::with_capacity(2048); - - while let Some((head, tail)) = list_ref.uncons() { - let addr = head.fst().as_str(); - let account = head.snd().as_bytes(); - - let addr = Address::try_from(addr).unwrap(); - let object: Account = deserialize(account); - list.push((addr, object)); - - list_ref = tail; - } - - list -} - -#[no_coverage] -pub fn get_addr(rt: &mut &mut OCamlRuntime, addr: OCamlRef) -> Address { - let addr_ref = rt.get(addr); - Address::try_from(addr_ref.as_str()).unwrap() -} - -#[no_coverage] -pub fn get(rt: &mut &mut OCamlRuntime, object: OCamlRef) -> T -where - T: BinProtRead, -{ - let object_ref = rt.get(object); - deserialize(object_ref.as_bytes()) -} - -#[no_coverage] -pub fn get_index(rt: &mut &mut OCamlRuntime, index: OCamlRef) -> AccountIndex { - let index: i64 = index.to_rust(rt); - let index: u64 = index.try_into().unwrap(); - AccountIndex(index) -} - -#[no_coverage] -pub fn hash_to_ocaml(hash: Fp) -> Vec { - let hash: BigInt = hash.into(); - serialize(&hash) -} From 804a112aefb3afcccc1a10e6c3733e64b198c584 Mon Sep 17 00:00:00 2001 From: Daniel Kuehr Date: Thu, 5 Dec 2024 12:42:33 -0500 Subject: [PATCH 2/2] transaction_fuzzer: speed improvements and cleanup --- ledger/src/account/account.rs | 11 + ledger/src/scan_state/transaction_logic.rs | 3 +- tools/fuzzing/src/main.rs | 30 +- tools/fuzzing/src/mutator.rs | 1008 ----------------- .../fuzzing/src/transaction_fuzzer/context.rs | 578 +--------- .../src/transaction_fuzzer/generator.rs | 348 +++--- .../fuzzing/src/transaction_fuzzer/mutator.rs | 93 +- 7 files changed, 174 insertions(+), 1897 deletions(-) delete mode 100644 tools/fuzzing/src/mutator.rs diff --git a/ledger/src/account/account.rs b/ledger/src/account/account.rs index 171d0eca3a..c5a17b4ec0 100644 --- a/ledger/src/account/account.rs +++ b/ledger/src/account/account.rs @@ -683,10 +683,21 @@ pub struct MutableFp { fp: Arc>>, } +// We skip some hashing during fuzzing to speedup things, but we still need to catch potential in transaction application. +// The fuzzer will call apply_transactions with GLOBAL_SKIP_PARTIAL_EQ disabled and enable it for everything else. +#[cfg(feature = "fuzzing")] +pub static GLOBAL_SKIP_PARTIAL_EQ: Lazy> = + Lazy::new(|| std::sync::RwLock::new(false)); + impl Eq for MutableFp {} impl PartialEq for MutableFp { fn eq(&self, other: &Self) -> bool { + #[cfg(feature = "fuzzing")] + if *GLOBAL_SKIP_PARTIAL_EQ.read().unwrap() { + return true; + } + self.get().unwrap() == other.get().unwrap() } } diff --git a/ledger/src/scan_state/transaction_logic.rs b/ledger/src/scan_state/transaction_logic.rs index b1c21037f3..e5f1882899 100644 --- a/ledger/src/scan_state/transaction_logic.rs +++ b/ledger/src/scan_state/transaction_logic.rs @@ -3163,8 +3163,7 @@ pub mod zkapp_command { impl PartialEq for WithStackHash { fn eq(&self, other: &Self) -> bool { - self.elt == other.elt - && self.stack_hash.get().unwrap() == other.stack_hash.get().unwrap() + self.elt == other.elt && self.stack_hash == other.stack_hash } } diff --git a/tools/fuzzing/src/main.rs b/tools/fuzzing/src/main.rs index ec842a85c4..bfccdb938c 100644 --- a/tools/fuzzing/src/main.rs +++ b/tools/fuzzing/src/main.rs @@ -20,9 +20,7 @@ pub mod transaction_fuzzer { stats::Stats, }; use ledger::{ - scan_state::transaction_logic::{transaction_applied, UserCommand}, - sparse_ledger::LedgerIntf, - Account, BaseLedger, + scan_state::transaction_logic::UserCommand, sparse_ledger::LedgerIntf, Account, BaseLedger, }; use mina_hasher::Fp; use mina_p2p_messages::bigint::BigInt; @@ -170,29 +168,7 @@ pub mod transaction_fuzzer { serialize(&action, stdin); let output: ActionOutput = deserialize(stdout); match output { - ActionOutput::TxApplied(result) => { - for applied_tx in result.apply_result.iter() { - match &applied_tx.varying { - transaction_applied::Varying::Command(command_applied) => { - match command_applied { - transaction_applied::CommandApplied::SignedCommand( - _signed_command_applied, - ) => {} - transaction_applied::CommandApplied::ZkappCommand( - zkapp_command_applied, - ) => zkapp_command_applied - .command - .data - .account_updates - .accumulate_hashes(), // Needed because of delayed hashing - } - } - transaction_applied::Varying::FeeTransfer(_fee_transfer_applied) => {} - transaction_applied::Varying::Coinbase(_coinbase_applied) => {} - } - } - result - } + ActionOutput::TxApplied(result) => result, _ => panic!("Expected TxApplied"), } } @@ -332,8 +308,6 @@ pub mod transaction_fuzzer { } } -#[cfg(feature = "nightly")] -#[coverage(off)] fn main() { #[cfg(feature = "nightly")] { diff --git a/tools/fuzzing/src/mutator.rs b/tools/fuzzing/src/mutator.rs deleted file mode 100644 index 29e1a6b51a..0000000000 --- a/tools/fuzzing/src/mutator.rs +++ /dev/null @@ -1,1008 +0,0 @@ -use super::{ - context::{FuzzerCtx, PermissionModel}, - generator::{ - sign_account_updates, Generator, GeneratorFromAccount, GeneratorRange32, GeneratorRange64, - GeneratorWrapper, - }, -}; -use crate::generator::gen_curve_point; -use ark_ff::Zero; -use ledger::{ - generators::zkapp_command_builder::get_transaction_commitments, - hash_with_kimchi, - scan_state::{ - currency::{Amount, Balance, Fee, MinMax, Nonce, Signed, Slot}, - transaction_logic::{ - zkapp_command::{ - self, AccountPreconditions, AccountUpdate, Body, ClosedInterval, FeePayer, - FeePayerBody, OrIgnore, Preconditions, SetOrKeep, Update, ZkAppCommand, - ZkAppPreconditions, - }, - Transaction, UserCommand, - }, - }, - Account, AuthRequired, Permissions, Timing, TokenId, TokenSymbol, VerificationKey, -}; -use mina_hasher::Fp; -use mina_p2p_messages::{ - array::ArrayN16, - bigint::BigInt, - pseq::PaddedSeq, - v2::{ - PicklesProofProofsVerified2ReprStableV2, PicklesProofProofsVerified2ReprStableV2PrevEvals, - PicklesProofProofsVerified2ReprStableV2PrevEvalsEvals, - PicklesProofProofsVerified2ReprStableV2PrevEvalsEvalsEvals, - PicklesWrapWireProofCommitmentsStableV1, PicklesWrapWireProofEvaluationsStableV1, - PicklesWrapWireProofStableV1, PicklesWrapWireProofStableV1Bulletproof, - TransactionSnarkProofStableV2, TransactionSnarkScanStateLedgerProofWithSokMessageStableV2, - TransactionSnarkStableV2, - }, -}; -use mina_signer::{CompressedPubKey, NetworkId, Signature, Signer}; -use rand::{ - distributions::{Alphanumeric, DistString}, - seq::SliceRandom, - Rng, -}; - -#[coverage(off)] -fn rand_elements(ctx: &mut FuzzerCtx, count: usize) -> Vec { - let elements: Vec = (0..count).collect(); - // We give more weight to smaller amount of elements since in general we want to perform fewer mutations - if let Ok(amount) = elements.choose_weighted( - &mut ctx.gen.rng, - #[coverage(off)] - |x| elements.len() - x, - ) { - elements - .choose_multiple(&mut ctx.gen.rng, *amount) - .cloned() - .collect() - } else { - Vec::new() - } -} - -pub trait Mutator { - fn mutate(&mut self, t: &mut T); -} - -impl Mutator for FuzzerCtx { - #[coverage(off)] - fn mutate(&mut self, t: &mut BigInt) { - *t = self.gen(); - } -} - -impl Mutator<(BigInt, BigInt)> for FuzzerCtx { - #[coverage(off)] - fn mutate(&mut self, t: &mut (BigInt, BigInt)) { - *t = gen_curve_point::(self); - } -} - -impl Mutator<((BigInt, BigInt), (BigInt, BigInt))> for FuzzerCtx { - #[coverage(off)] - fn mutate(&mut self, t: &mut ((BigInt, BigInt), (BigInt, BigInt))) { - if self.gen.rng.gen_bool(0.5) { - self.mutate(&mut t.0 .0); - } - - if self.gen.rng.gen_bool(0.5) { - self.mutate(&mut t.0 .1); - } - - if self.gen.rng.gen_bool(0.5) { - self.mutate(&mut t.1 .0); - } - - if self.gen.rng.gen_bool(0.5) { - self.mutate(&mut t.1 .1); - } - } -} - -impl Mutator<(Vec, Vec)> for FuzzerCtx { - #[coverage(off)] - fn mutate(&mut self, t: &mut (Vec, Vec)) { - if self.gen.rng.gen_bool(0.5) { - self.mutate(&mut t.0); - } - - if self.gen.rng.gen_bool(0.5) { - self.mutate(&mut t.1); - } - } -} - -impl Mutator<(ArrayN16, ArrayN16)> for FuzzerCtx -where - FuzzerCtx: Mutator>, -{ - #[coverage(off)] - fn mutate(&mut self, t: &mut (ArrayN16, ArrayN16)) { - if self.gen.rng.gen_bool(0.5) { - self.mutate(&mut t.0); - } - - if self.gen.rng.gen_bool(0.5) { - self.mutate(&mut t.1); - } - } -} - -impl Mutator> for FuzzerCtx -where - FuzzerCtx: Mutator, -{ - #[coverage(off)] - fn mutate(&mut self, t: &mut Vec) { - if t.is_empty() { - // TODO(binier): maybe gen - // t.lr = self.gen(); - return; - } - for i in rand_elements(self, t.len()) { - self.mutate(&mut t[i]); - } - } -} - -impl Mutator> for FuzzerCtx -where - FuzzerCtx: Mutator, -{ - #[coverage(off)] - fn mutate(&mut self, t: &mut PaddedSeq) { - for i in rand_elements(self, N) { - self.mutate(&mut t.0[i]) - } - } -} - -impl Mutator for FuzzerCtx { - #[coverage(off)] - fn mutate(&mut self, t: &mut FeePayerBody) { - //let account = self.get_account(&t.public_key).unwrap(); - - for option in rand_elements(self, 2) { - match option { - 0 => t.fee = GeneratorRange64::::gen_range(self, 0..=Fee::max().as_u64()), - 1 => { - t.valid_until = if self.gen.rng.gen_bool(0.5) { - Some(Slot::from_u32( - self.gen.rng.gen_range(0..=Slot::max().as_u32()), - )) - } else { - None - } - } - //2 => { - // t.nonce = GeneratorRange32::::gen_range(self, 0..=Nonce::max().as_u32()) - //} - _ => unimplemented!(), - } - } - } -} - -impl Mutator for FuzzerCtx { - #[coverage(off)] - fn mutate(&mut self, t: &mut FeePayer) { - self.mutate(&mut t.body) - } -} - -impl Mutator for FuzzerCtx { - #[coverage(off)] - fn mutate(&mut self, t: &mut Fp) { - *t = self.gen(); - } -} - -impl Mutator> for FuzzerCtx -where - FuzzerCtx: Mutator + Generator, -{ - #[coverage(off)] - fn mutate(&mut self, t: &mut SetOrKeep) { - match t { - SetOrKeep::Set(inner) => { - if self.gen.rng.gen_bool(0.5) { - self.mutate(inner) - } else { - *t = SetOrKeep::Keep; - } - } - SetOrKeep::Keep => *t = SetOrKeep::Set(self.gen()), - } - } -} - -impl Mutator<[T; N]> for FuzzerCtx -where - FuzzerCtx: Mutator, -{ - #[coverage(off)] - fn mutate(&mut self, t: &mut [T; N]) { - for i in rand_elements(self, t.len()) { - self.mutate(&mut t[i]) - } - } -} - -pub trait MutatorFromAccount { - fn mutate_from_account(&mut self, t: &mut T, account: &Account); -} - -impl MutatorFromAccount> for FuzzerCtx { - #[coverage(off)] - fn mutate_from_account(&mut self, t: &mut Permissions, account: &Account) { - let permission_model = self.find_permissions(&account.public_key).unwrap(); - - match permission_model { - PermissionModel::Any => { - for option in rand_elements(self, 11) { - match option { - 0 => t.edit_state = self.gen(), - 1 => t.send = self.gen(), - 2 => t.receive = self.gen(), - 3 => t.set_delegate = self.gen(), - 4 => t.set_permissions = self.gen(), - 5 => t.set_verification_key = self.gen(), - 6 => t.set_zkapp_uri = self.gen(), - 7 => t.edit_action_state = self.gen(), - 8 => t.set_token_symbol = self.gen(), - 9 => t.increment_nonce = self.gen(), - 10 => t.set_voting_for = self.gen(), - _ => unimplemented!(), - } - } - } - // Don't mutate permissions in the rest of the models - PermissionModel::Empty => (), - PermissionModel::Initial => (), - PermissionModel::Default => (), - PermissionModel::TokenOwner => (), - } - } -} - -impl MutatorFromAccount> for FuzzerCtx -where - FuzzerCtx: MutatorFromAccount + GeneratorFromAccount, -{ - #[coverage(off)] - fn mutate_from_account(&mut self, t: &mut SetOrKeep, account: &Account) { - match t { - SetOrKeep::Set(inner) => { - if self.gen.rng.gen_bool(0.5) { - self.mutate_from_account(inner, account) - } else { - *t = SetOrKeep::Keep; - } - } - SetOrKeep::Keep => *t = SetOrKeep::Set(self.gen_from_account(account)), - } - } -} - -impl MutatorFromAccount for FuzzerCtx { - #[coverage(off)] - fn mutate_from_account(&mut self, t: &mut zkapp_command::Timing, _account: &Account) { - for option in rand_elements(self, 5) { - match option { - 0 => t.initial_minimum_balance = self.gen(), - 1 => t.cliff_time = self.gen(), - 2 => t.cliff_amount = self.gen(), - 3 => t.vesting_period = self.gen(), - 4 => t.vesting_increment = self.gen(), - _ => unimplemented!(), - } - } - } -} - -impl MutatorFromAccount for FuzzerCtx { - #[coverage(off)] - fn mutate_from_account(&mut self, t: &mut Timing, _account: &Account) { - if let Timing::Timed { - initial_minimum_balance, - cliff_time, - cliff_amount, - vesting_period, - vesting_increment, - } = t - { - for option in rand_elements(self, 5) { - match option { - 0 => *initial_minimum_balance = self.gen(), - 1 => *cliff_time = self.gen(), - 2 => *cliff_amount = self.gen(), - 3 => *vesting_period = self.gen(), - 4 => *vesting_increment = self.gen(), - _ => unimplemented!(), - } - } - } else { - if self.gen.rng.gen_bool(0.5) { - *t = Timing::Timed { - initial_minimum_balance: self.gen(), - cliff_time: self.gen(), - cliff_amount: self.gen(), - vesting_period: self.gen(), - vesting_increment: self.gen(), - } - } - } - } -} - -impl MutatorFromAccount for FuzzerCtx { - #[coverage(off)] - fn mutate_from_account(&mut self, t: &mut Update, account: &Account) { - for option in rand_elements(self, 8) { - match option { - 0 => self.mutate(&mut t.app_state), - 1 => { - let keypair = if self.gen.rng.gen_bool(0.5) { - self.random_keypair() - } else { - self.gen() - }; - - t.delegate = SetOrKeep::Set(keypair.public.into_compressed()) - } - 2 => { - let data: VerificationKey = self.gen(); - let hash = if self.gen.rng.gen_bool(0.5) { - data.digest() - } else { - self.gen() - }; - - t.verification_key = SetOrKeep::Set(zkapp_command::WithHash { data, hash }); - } - 3 => self.mutate_from_account(&mut t.permissions, account), - 4 => { - t.zkapp_uri = self.gen_wrap( - #[coverage(off)] - |x| x.gen(), // TODO - ) - } - 5 => { - let rnd_len = self.gen.rng.gen_range(1..=6); - // TODO: fix n random chars for n random bytes - t.token_symbol = SetOrKeep::Set(TokenSymbol( - Alphanumeric.sample_string(&mut self.gen.rng, rnd_len), - )); - } - 6 => self.mutate_from_account(&mut t.timing, account), - 7 => t.voting_for = SetOrKeep::Set(self.gen()), - _ => unimplemented!(), - } - } - } -} - -impl Mutator> for FuzzerCtx -where - FuzzerCtx: Mutator + Generator, -{ - #[coverage(off)] - fn mutate(&mut self, t: &mut OrIgnore) { - match t { - OrIgnore::Check(inner) => { - if self.gen.rng.gen_bool(0.9) { - self.mutate(inner) - } else { - *t = OrIgnore::Ignore; - } - } - OrIgnore::Ignore => *t = OrIgnore::Check(self.gen()), - } - } -} - -impl MutatorFromAccount> for FuzzerCtx -where - FuzzerCtx: MutatorFromAccount + GeneratorFromAccount, -{ - #[coverage(off)] - fn mutate_from_account(&mut self, t: &mut OrIgnore, account: &Account) { - match t { - OrIgnore::Check(inner) => { - if self.gen.rng.gen_bool(0.9) { - self.mutate_from_account(inner, account) - } else { - *t = OrIgnore::Ignore; - } - } - OrIgnore::Ignore => *t = OrIgnore::Check(self.gen_from_account(account)), - } - } -} - -impl Mutator for FuzzerCtx { - #[coverage(off)] - fn mutate(&mut self, t: &mut CompressedPubKey) { - *t = self.gen(); - } -} - -impl Mutator for FuzzerCtx { - #[coverage(off)] - fn mutate(&mut self, t: &mut bool) { - *t = !*t; - } -} - -impl Mutator> for FuzzerCtx -where - FuzzerCtx: Mutator, -{ - #[coverage(off)] - fn mutate(&mut self, t: &mut ClosedInterval) { - for option in rand_elements(self, 8) { - match option { - 0 => self.mutate(&mut t.lower), - 1 => self.mutate(&mut t.upper), - _ => unimplemented!(), - } - } - } -} - -impl MutatorFromAccount for FuzzerCtx { - #[coverage(off)] - fn mutate_from_account(&mut self, t: &mut Balance, _account: &Account) { - //*t = self.gen_from_account(account); - *t = GeneratorRange64::::gen_range(self, 0..=Balance::max().as_u64()) - } -} - -impl MutatorFromAccount for FuzzerCtx { - #[coverage(off)] - fn mutate_from_account(&mut self, t: &mut Nonce, _account: &Account) { - //*t = self.gen_from_account(account); - *t = GeneratorRange32::::gen_range(self, 0..=u32::MAX); - } -} - -impl MutatorFromAccount> for FuzzerCtx -where - FuzzerCtx: MutatorFromAccount, -{ - #[coverage(off)] - fn mutate_from_account(&mut self, t: &mut ClosedInterval, account: &Account) { - for option in rand_elements(self, 8) { - match option { - 0 => self.mutate_from_account(&mut t.lower, account), - 1 => self.mutate_from_account(&mut t.upper, account), - _ => unimplemented!(), - } - } - } -} - -impl MutatorFromAccount for FuzzerCtx { - #[coverage(off)] - fn mutate_from_account(&mut self, t: &mut zkapp_command::Account, account: &Account) { - for option in rand_elements(self, 8) { - match option { - 0 => self.mutate_from_account(&mut t.balance, account), - 1 => self.mutate_from_account(&mut t.nonce, account), - 2 => self.mutate(&mut t.receipt_chain_hash), - 3 => self.mutate(&mut t.delegate), - 4 => self.mutate(&mut t.state), - 5 => self.mutate(&mut t.action_state), - 6 => self.mutate(&mut t.proved_state), - 7 => self.mutate(&mut t.is_new), - _ => unimplemented!(), - } - } - } -} - -impl MutatorFromAccount for FuzzerCtx { - #[coverage(off)] - fn mutate_from_account(&mut self, t: &mut AccountPreconditions, account: &Account) { - self.mutate_from_account(&mut t.0, account) - } -} - -impl Mutator for FuzzerCtx { - #[coverage(off)] - fn mutate(&mut self, t: &mut zkapp_command::EpochData) { - for option in rand_elements(self, 5) { - match option { - 0 => { - *t.ledger_mut() = zkapp_command::EpochLedger { - hash: OrIgnore::Check(self.gen()), - total_currency: OrIgnore::Check(self.gen_wrap( - #[coverage(off)] - |x| GeneratorRange64::::gen_range(x, 0..=u64::MAX), - )), - } - } - 1 => t.seed = OrIgnore::Check(self.gen()), - 2 => t.start_checkpoint = OrIgnore::Check(self.gen()), - 3 => t.lock_checkpoint = OrIgnore::Check(self.gen()), - 4 => { - t.epoch_length = OrIgnore::Check(self.gen_wrap( - #[coverage(off)] - |x| x.gen(), - )) - } - _ => unimplemented!(), - } - } - } -} - -impl MutatorFromAccount for FuzzerCtx { - #[coverage(off)] - fn mutate_from_account(&mut self, t: &mut ZkAppPreconditions, _account: &Account) { - for option in rand_elements(self, 7) { - match option { - 0 => t.snarked_ledger_hash = OrIgnore::Check(self.gen()), - 1 => { - let blockchain_length = self.gen_wrap( - #[coverage(off)] - |x| x.gen(), - ); - t.blockchain_length = OrIgnore::Check(blockchain_length); - } - 2 => { - let min_window_density = self.gen_wrap( - #[coverage(off)] - |x| x.gen(), - ); - t.min_window_density = OrIgnore::Check(min_window_density); - } - 3 => { - let total_currency = self.gen_wrap( - #[coverage(off)] - |x| GeneratorRange64::::gen_range(x, 0..=u64::MAX), - ); - t.total_currency = OrIgnore::Check(total_currency); - } - 4 => { - let global_slot_since_genesis = self.gen_wrap( - #[coverage(off)] - |x| Slot::from_u32(x.gen.rng.gen_range(0..Slot::max().as_u32())), - ); - t.global_slot_since_genesis = OrIgnore::Check(global_slot_since_genesis); - } - 5 => self.mutate(&mut t.staking_epoch_data), - 6 => self.mutate(&mut t.next_epoch_data), - _ => unimplemented!(), - } - } - } -} - -impl MutatorFromAccount for FuzzerCtx { - #[coverage(off)] - fn mutate_from_account(&mut self, t: &mut Preconditions, account: &Account) { - for option in rand_elements(self, 2) { - match option { - 0 => self.mutate_from_account(t.network_mut(), account), - 1 => self.mutate_from_account(&mut t.account, account), - _ => unimplemented!(), - } - } - } -} - -impl Mutator for FuzzerCtx { - #[coverage(off)] - fn mutate(&mut self, t: &mut Body) { - let account = self.get_account(&t.public_key).unwrap(); - - for option in rand_elements(self, 11) { - match option { - 0 => t.token_id = TokenId(self.gen()), - 1 => self.mutate_from_account(&mut t.update, &account), - 2 => { - t.balance_change = if self.gen.rng.gen_bool(0.5) { - let magnitude = - GeneratorRange64::::gen_range(self, 0..=Amount::max().as_u64()); - Signed::::create(magnitude, self.gen()) - } else { - Signed::::zero() - } - } - 3 => self.mutate(&mut t.increment_nonce), - 4 => t.events = self.gen(), - 5 => t.actions = self.gen(), - 6 => t.call_data = self.gen(), - 7 => self.mutate_from_account(&mut t.preconditions, &account), - 8 => self.mutate(&mut t.use_full_commitment), - 9 => (), // Can't mutate because it breaks binprot - 10 => { - let vk_hash = if self.gen.rng.gen_bool(0.5) - && account.zkapp.is_some() - && account.zkapp.as_ref().unwrap().verification_key.is_some() - { - account - .zkapp - .as_ref() - .unwrap() - .verification_key - .as_ref() - .unwrap() - .hash() - } else { - self.gen() - }; - - let options = vec![ - zkapp_command::AuthorizationKind::NoneGiven, - zkapp_command::AuthorizationKind::Signature, - zkapp_command::AuthorizationKind::Proof(vk_hash), - ]; - t.authorization_kind = options.choose(&mut self.gen.rng).unwrap().clone(); - } - _ => unimplemented!(), - } - } - } -} - -impl Mutator for FuzzerCtx { - #[coverage(off)] - fn mutate(&mut self, t: &mut AccountUpdate) { - for option in rand_elements(self, 2) { - match option { - 0 => self.mutate(&mut t.body), - 1 => { - if self.gen.rng.gen_bool(0.5) { - t.authorization = match t.body.authorization_kind { - zkapp_command::AuthorizationKind::NoneGiven => { - zkapp_command::Control::NoneGiven - } - zkapp_command::AuthorizationKind::Signature => { - zkapp_command::Control::Signature(Signature::dummy()) - } - zkapp_command::AuthorizationKind::Proof(_) => { - zkapp_command::Control::Proof(self.gen()) - } - }; - } else { - t.authorization = match vec![0, 1, 2].choose(&mut self.gen.rng).unwrap() { - 0 => zkapp_command::Control::NoneGiven, - 1 => zkapp_command::Control::Signature(Signature::dummy()), - 2 => zkapp_command::Control::Proof(self.gen()), - _ => unimplemented!(), - }; - } - } - _ => unimplemented!(), - } - } - } -} - -impl Mutator> for FuzzerCtx { - #[coverage(off)] - fn mutate(&mut self, t: &mut zkapp_command::CallForest) { - for i in rand_elements(self, t.0.len()) { - let tree_digest = { - let tree = &mut t.0[i].elt; - - for option in rand_elements(self, 2) { - match option { - 0 => { - self.mutate(&mut tree.account_update); - tree.account_update_digest = tree.account_update.digest(); - } - 1 => self.mutate(&mut tree.calls), - _ => unimplemented!(), - } - } - - tree.digest() - }; - - let h_tl = if let Some(x) = t.0.get(i + 1) { - x.stack_hash - } else { - Fp::zero() - }; - - t.0[i].stack_hash = hash_with_kimchi("MinaAcctUpdateCons", &[tree_digest, h_tl]); - } - } -} - -#[coverage(off)] -pub fn fix_nonces( - ctx: &mut FuzzerCtx, - account_updates: &mut zkapp_command::CallForest, -) { - for acc_update in account_updates.0.iter_mut() { - let account_update = &mut acc_update.elt.account_update; - - if let zkapp_command::Account { - nonce: OrIgnore::Check(_), - .. - } = &account_update.body.preconditions.account.0 - { - let account = ctx.get_account(&account_update.public_key()).unwrap(); - - account_update.body.preconditions.account.0.nonce = - OrIgnore::Check(ctx.gen_from_account(&account)); - } - - fix_nonces(ctx, &mut acc_update.elt.calls); - } -} - -impl Mutator for FuzzerCtx { - #[coverage(off)] - fn mutate(&mut self, t: &mut ZkAppCommand) { - for option in rand_elements(self, 3) { - match option { - 0 => self.mutate(&mut t.fee_payer), - 1 => self.mutate(&mut t.account_updates), - 2 => t.memo = self.gen(), - _ => unimplemented!(), - } - } - - // Fix fee_payer nonce. - let public_key = t.fee_payer.body.public_key.clone(); - let account = self.get_account(&public_key).unwrap(); - t.fee_payer.body.nonce = self.gen_from_account(&account); - - // Fix account updates nonces. - fix_nonces(self, &mut t.account_updates); - - let (txn_commitment, full_txn_commitment) = get_transaction_commitments(t); - let mut signer = mina_signer::create_kimchi(NetworkId::TESTNET); - - if self.gen.rng.gen_bool(0.9) { - let keypair = self.find_keypair(&t.fee_payer.body.public_key).unwrap(); - t.fee_payer.authorization = signer.sign(keypair, &full_txn_commitment); - } - - if self.gen.rng.gen_bool(0.9) { - sign_account_updates( - self, - &mut signer, - &txn_commitment, - &full_txn_commitment, - &mut t.account_updates, - ); - } - } -} - -impl Mutator for FuzzerCtx { - #[coverage(off)] - fn mutate(&mut self, t: &mut UserCommand) { - match t { - UserCommand::ZkAppCommand(zkapp_command) => self.mutate(zkapp_command.as_mut()), - _ => unimplemented!(), - } - } -} - -impl Mutator for FuzzerCtx { - #[coverage(off)] - fn mutate(&mut self, t: &mut Transaction) { - match t { - Transaction::Command(user_command) => self.mutate(user_command), - _ => unimplemented!(), - } - } -} - -// impl Mutator for FuzzerCtx { -// #[no_coverage] -// fn mutate(&mut self, t: &mut MinaStateSnarkedLedgerStateWithSokStableV2) { -// for option in rand_elements(self, 6) { -// match option { -// // 0 => self.mutate(&mut t.source), -// // 1 => self.mutate(&mut t.target), -// // 2 => self.mutate(&mut t.connecting_ledger_left), -// // 3 => self.mutate(&mut t.connecting_ledger_right), -// // 4 => self.mutate(&mut t.supply_increase), -// // 5 => self.mutate(&mut t.fee_excess), -// // // 6 => self.mutate(&mut t.sok_digest), -// _ => unimplemented!(), -// } -// } -// } -// } - -impl Mutator for FuzzerCtx { - #[coverage(off)] - fn mutate(&mut self, t: &mut PicklesProofProofsVerified2ReprStableV2PrevEvals) { - for option in rand_elements(self, 2) { - match option { - // 0 => self.mutate(&mut t.statement), - 0 => self.mutate(&mut t.evals), - 1 => self.mutate(&mut t.ft_eval1), - _ => unimplemented!(), - } - } - } -} - -impl Mutator> for FuzzerCtx -where - FuzzerCtx: Mutator>, -{ - #[coverage(off)] - fn mutate(&mut self, t: &mut ArrayN16) { - self.mutate(t.inner_mut()); - } -} - -impl Mutator for FuzzerCtx { - #[coverage(off)] - fn mutate(&mut self, t: &mut PicklesWrapWireProofStableV1Bulletproof) { - for option in rand_elements(self, 3) { - match option { - 0 => self.mutate(&mut t.lr), - 1 => self.mutate(&mut t.z_1), - 2 => self.mutate(&mut t.z_2), - 3 => self.mutate(&mut t.delta), - 4 => self.mutate(&mut t.challenge_polynomial_commitment), - _ => unimplemented!(), - } - } - } -} - -impl Mutator for FuzzerCtx { - #[coverage(off)] - fn mutate(&mut self, t: &mut PicklesProofProofsVerified2ReprStableV2PrevEvalsEvalsEvals) { - for option in rand_elements(self, 6) { - match option { - 0 => self.mutate(&mut t.w), - 1 => self.mutate(&mut t.coefficients), - 2 => self.mutate(&mut t.z), - 3 => self.mutate(&mut t.s), - 4 => self.mutate(&mut t.generic_selector), - 5 => self.mutate(&mut t.poseidon_selector), - _ => unimplemented!(), - } - } - } -} - -impl Mutator for FuzzerCtx { - #[coverage(off)] - fn mutate(&mut self, t: &mut PicklesProofProofsVerified2ReprStableV2PrevEvalsEvals) { - for option in rand_elements(self, 2) { - match option { - 0 => self.mutate(&mut t.public_input), - 1 => self.mutate(&mut t.evals), - _ => unimplemented!(), - } - } - } -} - -// impl Mutator for FuzzerCtx { -// #[coverage(off)] -// fn mutate(&mut self, t: &mut PicklesProofProofsVerified2ReprStableV2ProofOpenings) { -// for option in rand_elements(self, 3) { -// match option { -// 0 => self.mutate(&mut t.proof), -// 1 => self.mutate(&mut t.evals), -// 2 => self.mutate(&mut t.ft_eval1), -// _ => unimplemented!(), -// } -// } -// } -// } - -// impl Mutator for FuzzerCtx { -// #[coverage(off)] -// fn mutate(&mut self, t: &mut PicklesProofProofsVerified2ReprStableV2Proof) { -// for option in rand_elements(self, 2) { -// match option { -// // 0 => self.mutate(&mut t.statement), -// 0 => self.mutate(&mut t.messages), -// 1 => self.mutate(&mut t.openings), -// _ => unimplemented!(), -// } -// } -// } -// } - -impl Mutator for FuzzerCtx { - #[coverage(off)] - fn mutate(&mut self, t: &mut PicklesWrapWireProofCommitmentsStableV1) { - for option in rand_elements(self, 3) { - match option { - 0 => self.mutate(&mut t.w_comm), - 1 => self.mutate(&mut t.z_comm), - 2 => self.mutate(&mut t.t_comm), - _ => unreachable!(), - } - } - } -} - -impl Mutator for FuzzerCtx { - #[coverage(off)] - fn mutate(&mut self, t: &mut PicklesWrapWireProofEvaluationsStableV1) { - for option in rand_elements(self, 10) { - match option { - 0 => self.mutate(&mut t.w), - 1 => self.mutate(&mut t.coefficients), - 2 => self.mutate(&mut t.z), - 3 => self.mutate(&mut t.s), - 4 => self.mutate(&mut t.generic_selector), - 5 => self.mutate(&mut t.poseidon_selector), - 6 => self.mutate(&mut t.complete_add_selector), - 7 => self.mutate(&mut t.mul_selector), - 8 => self.mutate(&mut t.emul_selector), - 9 => self.mutate(&mut t.endomul_scalar_selector), - _ => unreachable!(), - } - } - } -} - -impl Mutator for FuzzerCtx { - #[coverage(off)] - fn mutate(&mut self, t: &mut PicklesWrapWireProofStableV1) { - for option in rand_elements(self, 4) { - match option { - 0 => self.mutate(&mut t.commitments), - 1 => self.mutate(&mut t.evaluations), - 2 => self.mutate(&mut t.ft_eval1), - 3 => self.mutate(&mut t.bulletproof), - _ => unimplemented!(), - } - } - } -} - -impl Mutator for FuzzerCtx { - #[coverage(off)] - fn mutate(&mut self, t: &mut PicklesProofProofsVerified2ReprStableV2) { - for option in rand_elements(self, 2) { - match option { - // 0 => self.mutate(&mut t.statement), - 0 => self.mutate(&mut t.prev_evals), - 1 => self.mutate(&mut t.proof), - _ => unimplemented!(), - } - } - } -} - -impl Mutator for FuzzerCtx { - #[coverage(off)] - fn mutate(&mut self, t: &mut TransactionSnarkProofStableV2) { - self.mutate(&mut t.0) - } -} - -impl Mutator for FuzzerCtx { - #[coverage(off)] - fn mutate(&mut self, t: &mut TransactionSnarkStableV2) { - self.mutate(&mut t.proof) - // for option in rand_elements(self, 2) { - // match option { - // 0 => self.mutate(&mut t.statement), - // 1 => self.mutate(&mut t.proof), - // _ => unimplemented!(), - // } - // } - } -} - -impl Mutator for FuzzerCtx { - #[coverage(off)] - fn mutate(&mut self, t: &mut TransactionSnarkScanStateLedgerProofWithSokMessageStableV2) { - self.mutate(&mut t.0 .0) - } -} diff --git a/tools/fuzzing/src/transaction_fuzzer/context.rs b/tools/fuzzing/src/transaction_fuzzer/context.rs index 48ca7f42af..693cbd883d 100644 --- a/tools/fuzzing/src/transaction_fuzzer/context.rs +++ b/tools/fuzzing/src/transaction_fuzzer/context.rs @@ -5,6 +5,7 @@ use crate::transaction_fuzzer::{ }; use ark_ff::fields::arithmetic::InvalidBigInt; use ark_ff::Zero; +use ledger::scan_state::currency::{Amount, Fee, Length, Magnitude, Nonce, Signed, Slot}; use ledger::scan_state::transaction_logic::protocol_state::{ protocol_state_view, EpochData, EpochLedger, ProtocolStateView, }; @@ -14,13 +15,10 @@ use ledger::scan_state::transaction_logic::transaction_applied::{ use ledger::scan_state::transaction_logic::{ apply_transactions, Transaction, TransactionStatus, UserCommand, }; -use ledger::scan_state::{ - currency::{Amount, Fee, Length, Magnitude, Nonce, Signed, Slot}, - transaction_logic::transaction_applied, -}; use ledger::sparse_ledger::LedgerIntf; use ledger::staged_ledger::staged_ledger::StagedLedger; use ledger::{dummy, Account, AccountId, Database, Mask, Timing, TokenId}; +use mina_curves::pasta::Fq; use mina_hasher::Fp; use mina_p2p_messages::binprot::SmallString1k; use mina_p2p_messages::{ @@ -161,24 +159,6 @@ impl Clone for PermissionModel { } } -// #[derive(BinProtWrite, Debug)] -// pub struct TxProofCreateInputs { -// pub sok_message: MinaBaseSokMessageStableV1, -// pub snarked_ledger_state: MinaStateSnarkedLedgerStateStableV2, -// pub witness: TxWitness, -// } - -// #[derive(BinProtWrite, Debug)] -// pub struct TxWitness { -// pub transaction: Tx, -// pub first_pass_ledger: MinaBaseSparseLedgerBaseStableV2, -// pub second_pass_ledger: MinaBaseSparseLedgerBaseStableV2, -// pub protocol_state_body: MinaStateProtocolStateBodyValueStableV2, -// pub init_stack: MinaBasePendingCoinbaseStackVersionedStableV1, -// pub status: MinaBaseTransactionStatusStableV2, -// pub block_global_slot: UnsignedExtendedUInt32StableV1, -// } - #[derive(Debug)] pub struct ApplyTxResult { root_hash: Fp, @@ -230,29 +210,6 @@ impl binprot::BinProtRead for ApplyTxResult { } } -// // TODO: remove this type once `Transaction` implements `BinProtWrite`. -// #[derive(BinProtWrite, Debug, Clone)] -// pub enum Tx { -// UserCommand(UserCommand), -// } - -// impl From for Transaction { -// fn from(value: Tx) -> Self { -// match value { -// Tx::UserCommand(v) => Self::Command(v), -// } -// } -// } - -// impl From for Tx { -// fn from(value: Transaction) -> Self { -// match value { -// Transaction::Command(v) => Tx::UserCommand(v), -// _ => unimplemented!(), -// } -// } -// } - pub enum LedgerKind { Mask(Mask), Staged(StagedLedger, Mask), @@ -276,6 +233,8 @@ pub struct FuzzerState { pub potential_new_accounts: Vec<(Keypair, PermissionModel)>, pub cache_pool: RingBuffer, pub cache_apply: RingBuffer, + pub cache_curve_point_fp: Option<(Fp, Fp)>, + pub cache_curve_point_fq: Option<(Fq, Fq)>, } impl Clone for FuzzerState { @@ -287,6 +246,8 @@ impl Clone for FuzzerState { potential_new_accounts: self.potential_new_accounts.clone(), cache_pool: self.cache_pool.clone(), cache_apply: self.cache_apply.clone(), + cache_curve_point_fp: self.cache_curve_point_fp, + cache_curve_point_fq: self.cache_curve_point_fq, } } } @@ -337,22 +298,6 @@ impl FuzzerCtx { } } - // #[coverage(off)] - // fn set_snarked_ledger(&mut self, snarked_ledger: Mask) { - // match &mut self.state.ledger { - // LedgerKind::Mask(_) => panic!(), - // LedgerKind::Staged(_, old_snarked_ledger) => *old_snarked_ledger = snarked_ledger, - // } - // } - - // #[coverage(off)] - // fn get_staged_ledger(&mut self) -> &mut StagedLedger { - // match &mut self.state.ledger { - // LedgerKind::Staged(ledger, _) => ledger, - // _ => panic!(), - // } - // } - #[coverage(off)] pub fn get_snarked_ledger(&mut self) -> &mut Mask { match &mut self.state.ledger { @@ -502,78 +447,6 @@ impl FuzzerCtx { proof } - // #[coverage(off)] - // pub fn random_create_tx_proof_inputs( - // &mut self, - // protocol_state_body: MinaStateProtocolStateBodyValueStableV2, - // mut verify_tx: F, - // ) -> Option<(bool, TxProofCreateInputs)> - // where - // F: FnMut(&Transaction) -> bool, - // { - // let state_body_hash = MinaHash::hash(&protocol_state_body); - // let block_global_slot = protocol_state_body - // .consensus_state - // .global_slot_since_genesis - // .clone(); - // let init_stack = protocol_state_body - // .blockchain_state - // .ledger_proof_statement - // .source - // .pending_coinbase_stack - // .clone(); - - // let tx = self.random_transaction(); - // let is_valid = verify_tx(&tx); - // let transaction = WithStatus::applied(tx.clone()); - // let tx = Tx::from(tx); - - // let ledger = self.get_ledger_inner().make_child(); - // let staged_ledger = - // StagedLedger::create_exn(self.constraint_constants.clone(), ledger).unwrap(); - // let apply_res = StagedLedger::update_ledger_and_get_statements( - // &self.constraint_constants, - // // TODO(binier): construct from passed protocol_state_body. - // self.txn_state_view.global_slot_since_genesis, - // staged_ledger.ledger(), - // &(&init_stack).into(), - // (vec![transaction.clone()], None), - // // TODO(binier): construct from passed protocol_state_body. - // &self.txn_state_view, - // ( - // // TODO(binier): use state hash instead. Not used anyways though. - // state_body_hash, - // state_body_hash, - // ), - // ); - // let tx_with_witness = match apply_res { - // Ok((txs_with_witness, ..)) => txs_with_witness.into_iter().next().unwrap(), - // Err(_) => return None, - // }; - - // Some(( - // is_valid, - // TxProofCreateInputs { - // sok_message: serde_json::from_value(serde_json::json!({ - // "fee":"25000000", - // "prover":"B62qn7G9oFofQDGiAoP8TmYce7185PjWJ39unqjr2v7EgsRDoFCFc1k" - // })) - // .unwrap(), - // snarked_ledger_state: (&tx_with_witness.statement).into(), - // witness: TxWitness { - // transaction: tx, - // first_pass_ledger: (&tx_with_witness.first_pass_ledger_witness).into(), - // second_pass_ledger: (&tx_with_witness.second_pass_ledger_witness).into(), - // protocol_state_body, - // // TODO(binier): should we somehow use value from `tx_with_witness`? - // init_stack, - // status: MinaBaseTransactionStatusStableV2::Applied, - // block_global_slot, - // }, - // }, - // )) - // } - #[coverage(off)] pub fn take_snapshot(&mut self) { println!("Taking snapshot..."); @@ -593,25 +466,6 @@ impl FuzzerCtx { } } - // #[coverage(off)] - // pub fn serialize_transaction(tx: &Transaction) -> Vec { - // /* - // We don't have generated types for Transaction, but we have one - // for UserCommand (MinaBaseUserCommandStableV2). Extract and - // serialize the inner UserCommand and let a OCaml wrapper build - // the transaction. - // */ - // match &tx { - // Transaction::Command(user_command) => serialize(user_command), - // _ => unimplemented!(), - // } - // } - - // #[coverage(off)] - // pub fn serialize_ledger(&self) -> Vec { - // serialize(&self.get_ledger_accounts()) - // } - #[coverage(off)] pub fn save_fuzzcase(&self, user_command: &UserCommand, filename: &str) { let filename = self.fuzzcases_path.clone() + filename + ".fuzzcase"; @@ -652,385 +506,6 @@ impl FuzzerCtx { user_command } - // #[coverage(off)] - // pub fn apply_staged_ledger_diff( - // &mut self, - // diff: Diff, - // global_slot: Slot, - // coinbase_receiver: CompressedPubKey, - // current_view: ProtocolStateView, - // state_hashes: (Fp, Fp), - // state_tbl: &HashMap, - // iteration: usize, - // ) -> Result, ()> { - // if iteration == 1271 { - // #[derive(Clone, Debug, PartialEq, BinProtRead, BinProtWrite)] - // struct State { - // scan_state: mina_p2p_messages::v2::TransactionSnarkScanStateStableV2, - // pending_coinbase_collection: mina_p2p_messages::v2::MinaBasePendingCoinbaseStableV2, - // states: Vec<( - // mina_p2p_messages::bigint::BigInt, - // mina_p2p_messages::v2::MinaStateProtocolStateValueStableV2, - // )>, - // snarked_ledger: Vec, - // expected_staged_ledger_merkle_root: mina_p2p_messages::bigint::BigInt, - // } - - // let sl = self.get_staged_ledger(); - // let sc = sl.scan_state.clone(); - // let pcc = sl.pending_coinbase_collection.clone(); - // let expected_staged_ledger_merkle_root = sl.ledger().clone().merkle_root(); - // let snarked_ledger = self.get_snarked_ledger(); - - // let state = State { - // scan_state: (&sc).into(), - // pending_coinbase_collection: (&pcc).into(), - // states: state_tbl - // .iter() - // .map(|(h, v)| (h.into(), v.clone())) - // .collect(), - // snarked_ledger: { - // snarked_ledger - // .to_list() - // .into_iter() - // .map(Into::into) - // .collect() - // // todo!() - // }, - // expected_staged_ledger_merkle_root: expected_staged_ledger_merkle_root.into(), - // }; - - // let mut file = std::fs::File::create("/tmp/state.bin").unwrap(); - // BinProtWrite::binprot_write(&state, &mut file).unwrap(); - // file.sync_all().unwrap(); - - // eprintln!("data saved"); - // } - - // let constraint_constants = self.constraint_constants.clone(); - - // let DiffResult { - // hash_after_applying, - // ledger_proof, - // pending_coinbase_update: _, - // } = self - // .get_staged_ledger() - // .apply( - // None, - // &constraint_constants, - // global_slot, - // diff, - // (), - // &Verifier, - // ¤t_view, - // state_hashes, - // coinbase_receiver, - // false, - // ) - // .map_err(|_| ())?; - // // .unwrap(); - - // if let Some((proof, _transactions)) = ledger_proof { - // self.update_snarked_ledger(state_tbl, proof) - // }; - - // self.get_staged_ledger().commit_and_reparent_to_root(); - - // Ok(hash_after_applying) - // } - - // #[coverage(off)] - // fn update_snarked_ledger( - // &mut self, - // state_tbl: &HashMap, - // proof: LedgerProof, - // ) { - // let target_snarked_ledger = { - // let stmt = proof.statement_ref(); - // stmt.target.first_pass_ledger - // }; - - // let apply_first_pass = |global_slot: Slot, - // txn_state_view: &ProtocolStateView, - // ledger: &mut Mask, - // transaction: &Transaction| { - // apply_transaction_first_pass( - // &CONSTRAINT_CONSTANTS, - // global_slot, - // txn_state_view, - // ledger, - // transaction, - // ) - // }; - - // let apply_second_pass = |ledger: &mut Mask, tx: TransactionPartiallyApplied| { - // apply_transaction_second_pass(&CONSTRAINT_CONSTANTS, ledger, tx) - // }; - - // let apply_first_pass_sparse_ledger = - // |global_slot: Slot, - // txn_state_view: &ProtocolStateView, - // sparse_ledger: &mut SparseLedger, - // transaction: &Transaction| { - // apply_transaction_first_pass( - // &CONSTRAINT_CONSTANTS, - // global_slot, - // txn_state_view, - // sparse_ledger, - // transaction, - // ) - // }; - - // let mut ledger = self.get_snarked_ledger().fuzzing_to_root(); - - // let get_state = |hash: Fp| Ok(state_tbl.get(&hash).cloned().unwrap()); - - // assert!(self - // .get_staged_ledger() - // .scan_state() - // .latest_ledger_proof() - // .is_some()); - - // self.get_staged_ledger() - // .scan_state() - // .get_snarked_ledger_sync( - // &mut ledger, - // get_state, - // apply_first_pass, - // apply_second_pass, - // apply_first_pass_sparse_ledger, - // ) - // .unwrap(); - - // eprintln!("#############################################################"); - // eprintln!(" NEW SNARKED LEDGER: {:?}", target_snarked_ledger); - // eprintln!("#############################################################"); - - // assert_eq!(ledger.merkle_root(), target_snarked_ledger); - // self.set_snarked_ledger(ledger); - // assert_eq!( - // self.get_snarked_ledger().merkle_root(), - // target_snarked_ledger - // ); - // } - - // #[coverage(off)] - // pub fn create_staged_ledger_diff( - // &mut self, - // txns: Vec, - // global_slot: Slot, - // prover: CompressedPubKey, - // coinbase_receiver: CompressedPubKey, - // current_view: ProtocolStateView, - // ocaml_result: &Result< - // ( - // StagedLedgerDiffDiffStableV2, - // Vec<(transaction_logic::valid::UserCommand, String)>, - // ), - // String, - // >, - // iteration: usize, - // snark_worker_fees: &mut Vec, - // ) -> Result, ()> { - // eprintln!(); - // eprintln!("###################################################"); - // eprintln!(" CREATE_STAGED_LEDGER_DIFF "); - // eprintln!("###################################################"); - - // eprintln!( - // "get_staged_ledger num_account={:?}", - // self.get_staged_ledger().ledger.account_locations().len() - // ); - // // get_staged_ledger - // self.gen.nonces.clear(); - - // let stmt_to_work_random_prover = |stmt: &Statement| -> Option { - // let fee = snark_worker_fees.pop().unwrap(); - // Some(Checked { - // fee, - // proofs: stmt.map(|statement| { - // LedgerProof::create( - // statement.clone(), - // SokDigest::default(), - // dummy::dummy_transaction_proof(), - // ) - // }), - // prover: prover.clone(), - // }) - // }; - - // let txns = txns - // .into_iter() - // .map(|tx| { - // let Transaction::Command(cmd) = tx else { - // unreachable!() - // }; - // cmd.to_valid() - // }) - // .collect(); - - // let constraint_constants = self.constraint_constants.clone(); - - // dbg!(global_slot); - - // let result = self.get_staged_ledger().create_diff( - // &constraint_constants, - // global_slot, - // None, - // coinbase_receiver, - // (), - // ¤t_view, - // txns, - // stmt_to_work_random_prover, - // false, // Always false on berkeleynet now - // ); - - // // FIXME: ignoring error messages - // if result.is_err() && ocaml_result.is_err() { - // return Ok(None); - // } - - // if !(result.is_ok() && ocaml_result.is_ok()) { - // println!( - // "!!! create_staged_ledger_diff mismatch between OCaml and Rust (result is_ok)\n{:?}\n{:?}\n", - // result, ocaml_result - // ); - - // //let bigint: num_bigint::BigUint = ledger.merkle_root().into(); - // //self.save_fuzzcase(tx, &bigint.to_string()); - // return Err(()); - // } - - // let (diff, invalid_cmds) = result.unwrap(); - // let (ocaml_diff, ocaml_invalid_cmds) = ocaml_result.as_ref().unwrap(); - - // if iteration == 1271 { - // let mut file = std::fs::File::create("/tmp/diff.bin").unwrap(); - // BinProtWrite::binprot_write(ocaml_diff, &mut file).unwrap(); - // file.sync_all().unwrap(); - // eprintln!("SAVED DIFF"); - // } - - // let diff = diff.forget(); - - // // FIXME: ignore error messages as work around for differences in string formatting between Rust and OCaml - // let rust_invalid_cmds: Vec<_> = invalid_cmds.iter().map(|x| x.0.clone()).collect(); - - // let ocaml_invalid_cmds2: Vec<_> = ocaml_invalid_cmds.iter().map(|x| x.0.clone()).collect(); - - // // Make sure we got same result - // if !(rust_invalid_cmds == ocaml_invalid_cmds2) { - // println!( - // "!!! create_staged_ledger_diff mismatch between OCaml and Rust (invalids)\n{}\n", - // self.diagnostic(&rust_invalid_cmds, &ocaml_invalid_cmds2) - // ); - - // eprintln!("last_string={:?}", ocaml_invalid_cmds.last().unwrap().1); - - // //let bigint: num_bigint::BigUint = ledger.merkle_root().into(); - // //self.save_fuzzcase(tx, &bigint.to_string()); - // return Err(()); - // } - - // let ocaml_diff: Diff = ocaml_diff.into(); - - // if !(diff == ocaml_diff) { - // println!( - // "!!! create_staged_ledger_diff mismatch between OCaml and Rust (diff)\n{}\n", - // self.diagnostic(&diff, &ocaml_diff) - // ); - // println!("!!! OCAML=\n{:?}\n", &ocaml_diff,); - - // //let bigint: num_bigint::BigUint = ledger.merkle_root().into(); - // //self.save_fuzzcase(tx, &bigint.to_string()); - // return Err(()); - // } - - // Ok(Some(diff)) - // } - - // #[coverage(off)] - // pub fn of_scan_state_pending_coinbases_and_snarked_ledger( - // &mut self, - // current_state: &MinaStateProtocolStateValueStableV2, - // state_tbl: &HashMap, - // iteration: usize, - // ) { - // eprintln!("#######################################################"); - // eprintln!("of_scan_state_pending_coinbases_and_snarked_ledger"); - // eprintln!("#######################################################"); - - // let get_state = |hash: Fp| state_tbl.get(&hash).cloned().unwrap(); - - // let mut snarked_ledger = self.get_snarked_ledger().fuzzing_to_root(); - // let sl = self.get_staged_ledger(); - // let expected_hash: StagedLedgerHash = sl.hash(); - // let expected_staged_ledger_merkle_root = sl.ledger.clone().merkle_root(); - - // dbg!(snarked_ledger.merkle_root()); - - // let new_staged_ledger = StagedLedger::of_scan_state_pending_coinbases_and_snarked_ledger( - // (), - // &CONSTRAINT_CONSTANTS, - // Verifier, - // sl.scan_state.clone(), - // snarked_ledger.copy(), - // { - // let registers: transaction_snark::Registers = (¤t_state - // .body - // .blockchain_state - // .ledger_proof_statement - // .target) - // .into(); - // registers.local_state - // }, - // expected_staged_ledger_merkle_root, - // sl.pending_coinbase_collection.clone(), - // get_state, - // ); - - // // if new_staged_ledger.is_err() || iteration == 370 { - - // // #[derive(Clone, Debug, PartialEq, binprot_derive::BinProtRead, BinProtWrite)] - // // struct State { - // // scan_state: mina_p2p_messages::v2::TransactionSnarkScanStateStableV2, - // // pending_coinbase_collection: mina_p2p_messages::v2::MinaBasePendingCoinbaseStableV2, - // // states: Vec<(mina_p2p_messages::bigint::BigInt, MinaStateProtocolStateValueStableV2)>, - // // snarked_ledger: Vec, - // // expected_staged_ledger_merkle_root: mina_p2p_messages::bigint::BigInt, - // // } - - // // let sc = sl.scan_state.clone(); - // // let pcc = sl.pending_coinbase_collection.clone(); - - // // let state = State { - // // scan_state: (&sc).into(), - // // pending_coinbase_collection: (&pcc).into(), - // // states: state_tbl.iter().map(|(h, v)| (h.into(), v.clone())).collect(), - // // snarked_ledger: { - // // use crate::BaseLedger; - // // snarked_ledger.to_list().into_iter().map(Into::into).collect() - // // // todo!() - // // }, - // // expected_staged_ledger_merkle_root: expected_staged_ledger_merkle_root.into(), - // // }; - - // // let mut file = std::fs::File::create("/tmp/state.bin").unwrap(); - // // BinProtWrite::binprot_write(&state, &mut file).unwrap(); - // // file.sync_all().unwrap(); - - // // eprintln!("data saved"); - // // } - - // let mut new_staged_ledger = new_staged_ledger.unwrap(); - - // assert_eq!(expected_hash, sl.hash()); - // assert_eq!(expected_hash, new_staged_ledger.hash()); - // eprintln!("#######################################################"); - // eprintln!("of_scan_state_pending_coinbases_and_snarked_ledger OK"); - // eprintln!("#######################################################"); - // } - #[coverage(off)] pub fn diagnostic(&self, applied: &impl Debug, applied_ocaml: &impl Debug) -> String { use text_diff::{diff, Difference}; @@ -1077,8 +552,6 @@ impl FuzzerCtx { // If we called apply_transaction it means we passed the tx pool check, so add tx to the cache if let UserCommand::ZkAppCommand(command) = user_command { - command.account_updates.accumulate_hashes(); - if !command.account_updates.is_empty() { //println!("Storing in pool cache {:?}", tx); self.state.cache_pool.push_back(user_command.clone()); @@ -1088,6 +561,8 @@ impl FuzzerCtx { //println!("tx: {:?}\n", tx); let tx = Transaction::Command(user_command.clone()); + *ledger::GLOBAL_SKIP_PARTIAL_EQ.write().unwrap() = false; + let applied = apply_transactions( &self.constraint_constants, self.txn_state_view.global_slot_since_genesis, @@ -1096,35 +571,13 @@ impl FuzzerCtx { &[tx.clone()], ); - // println!( - // "tx: {:?}\n applied: {:?}\n expected: {:?}", - // tx, applied, expected_apply_result - // ); + *ledger::GLOBAL_SKIP_PARTIAL_EQ.write().unwrap() = true; match applied { Ok(applied) => { // For now we work with one transaction at a time let applied = &applied[0]; - match &applied.varying { - transaction_applied::Varying::Command(command_applied) => { - match command_applied { - transaction_applied::CommandApplied::SignedCommand( - _signed_command_applied, - ) => {} - transaction_applied::CommandApplied::ZkappCommand( - zkapp_command_applied, - ) => zkapp_command_applied - .command - .data - .account_updates - .accumulate_hashes(), // Needed because of delayed hashing - } - } - transaction_applied::Varying::FeeTransfer(_fee_transfer_applied) => {} - transaction_applied::Varying::Coinbase(_coinbase_applied) => {} - } - if expected_apply_result.apply_result.len() != 1 { return Err(format!( "Apply failed in OCaml (error: {}) but it didn't in Rust: {:?}", @@ -1216,16 +669,6 @@ impl FuzzerCtx { )) } else { ledger.commit(); - - let rust_ledger_root_hash = LedgerIntf::merkle_root(self.get_ledger_inner_mut()); - - if expected_apply_result.root_hash != rust_ledger_root_hash { - return Err(format!( - "Ledger hash mismatch (AFTER COMMIT!): {:?} != {:?} (expected)", - rust_ledger_root_hash, expected_apply_result.root_hash - )); - } - Ok(()) } } @@ -1358,7 +801,6 @@ impl FuzzerCtxBuilder { let ledger = match self.is_staged_ledger { true => { let snarked_ledger_mask = root.make_child().fuzzing_to_root(); - // let snarked_ledger_mask = root.make_child(); LedgerKind::Staged( StagedLedger::create_exn(constraint_constants.clone(), root.make_child()) .unwrap(), @@ -1388,6 +830,8 @@ impl FuzzerCtxBuilder { potential_new_accounts: Vec::new(), cache_pool: RingBuffer::with_capacity(self.cache_size), cache_apply: RingBuffer::with_capacity(self.cache_size), + cache_curve_point_fp: None, + cache_curve_point_fq: None, }, snapshots: RingBuffer::with_capacity(self.snapshots_size), }; diff --git a/tools/fuzzing/src/transaction_fuzzer/generator.rs b/tools/fuzzing/src/transaction_fuzzer/generator.rs index f26e51ada1..b705cb8b97 100644 --- a/tools/fuzzing/src/transaction_fuzzer/generator.rs +++ b/tools/fuzzing/src/transaction_fuzzer/generator.rs @@ -3,7 +3,7 @@ use ark_ec::ProjectiveCurve; use ark_ff::SquareRootField; use ark_ff::{Field, UniformRand}; use ledger::generators::zkapp_command_builder::get_transaction_commitments; -use ledger::proofs::field::FieldWitness; +use ledger::proofs::field::GroupAffine; use ledger::proofs::transaction::InnerCurve; use ledger::scan_state::currency::{Magnitude, SlotSpan}; use ledger::VerificationKeyWire; @@ -110,23 +110,6 @@ impl Generator for FuzzerCtx { } } -/* -impl Generator for FuzzerCtx { - // rnd_base_field - fn gen(&mut self) -> Fp { - let mut bf = None; - - // TODO: optimize by masking out MSBs from bytes and remove loop - while bf.is_none() { - let bytes = self.gen.rng.gen::<[u8; 32]>(); - bf = Fp::from_random_bytes_with_flags::(&bytes); - } - - bf.unwrap().0 - } -} -*/ - impl Generator for FuzzerCtx { #[coverage(off)] fn gen(&mut self) -> Fp { @@ -215,14 +198,14 @@ impl Generator for FuzzerCtx { } } -impl + SquareRootField> Generator<(F, F)> for FuzzerCtx { +pub struct CurvePointGenerator(F, F); + +impl + SquareRootField> Generator> for FuzzerCtx { #[coverage(off)] - fn gen(&mut self) -> (F, F) { + fn gen(&mut self) -> CurvePointGenerator { /* WARNING: we need to generate valid curve points to avoid binprot deserializarion - exceptions in the OCaml side. However this is an expensive task. - - TODO: a more efficient way of doing this? + exceptions in the OCaml side. */ let mut x = F::rand(&mut self.gen.rng); @@ -230,7 +213,7 @@ impl + SquareRootField> Generator<(F, F)> for FuzzerCtx { let y_squared = x.square().mul(x).add(Into::::into(5)); if let Some(y) = y_squared.sqrt() { - return (x, y); + return CurvePointGenerator(x, y); } x.add_assign(F::one()); @@ -238,17 +221,57 @@ impl + SquareRootField> Generator<(F, F)> for FuzzerCtx { } } -impl Generator> for FuzzerCtx { +impl Generator<(Fp, Fp)> for FuzzerCtx { #[coverage(off)] - fn gen(&mut self) -> InnerCurve { + fn gen(&mut self) -> (Fp, Fp) { + if let Some((x, y)) = self.state.cache_curve_point_fp { + let p = GroupAffine::::new(x, y, false); + let rand_scalar: u64 = self.gen.rng.gen(); + let new_p: GroupAffine = p.mul(rand_scalar).into(); + (new_p.x, new_p.y) + } else { + let p: CurvePointGenerator = self.gen(); + self.state.cache_curve_point_fp = Some((p.0, p.1)); + (p.0, p.1) + } + } +} + +impl Generator<(Fq, Fq)> for FuzzerCtx { + #[coverage(off)] + fn gen(&mut self) -> (Fq, Fq) { + if let Some((x, y)) = self.state.cache_curve_point_fq { + let p = GroupAffine::::new(x, y, false); + let rand_scalar: u64 = self.gen.rng.gen(); + let new_p: GroupAffine = p.mul(rand_scalar).into(); + (new_p.x, new_p.y) + } else { + let p: CurvePointGenerator = self.gen(); + self.state.cache_curve_point_fq = Some((p.0, p.1)); + (p.0, p.1) + } + } +} + +impl Generator> for FuzzerCtx { + #[coverage(off)] + fn gen(&mut self) -> InnerCurve { + let (x, y) = self.gen(); + InnerCurve::::from((x, y)) + } +} + +impl Generator> for FuzzerCtx { + #[coverage(off)] + fn gen(&mut self) -> InnerCurve { let (x, y) = self.gen(); - InnerCurve::::from((x, y)) + InnerCurve::::from((x, y)) } } -impl Generator> for FuzzerCtx { +impl Generator> for FuzzerCtx { #[coverage(off)] - fn gen(&mut self) -> PlonkVerificationKeyEvals { + fn gen(&mut self) -> PlonkVerificationKeyEvals { PlonkVerificationKeyEvals { sigma: array::from_fn( #[coverage(off)] @@ -286,19 +309,6 @@ impl Generator for FuzzerCtx { } } -/* -impl + Hashable> Generator> for FuzzerCtx -where - FuzzerCtx: Generator, -{ - fn gen(&mut self) -> zkapp_command::WithHash { - let data: T = self.gen(); - let hash = data.digest(); - zkapp_command::WithHash { data, hash } - } -} -*/ - impl Generator> for FuzzerCtx { #[coverage(off)] fn gen(&mut self) -> zkapp_command::WithHash { @@ -886,20 +896,27 @@ impl Generator>( - ctx: &mut impl Generator<(T, T)>, +pub fn gen_curve_point_fp( + ctx: &mut impl Generator<(Fp, Fp)>, ) -> ( mina_p2p_messages::bigint::BigInt, mina_p2p_messages::bigint::BigInt, -) -where - mina_p2p_messages::bigint::BigInt: From, -{ - Generator::<(T, T)>::gen(ctx).map(mina_p2p_messages::bigint::BigInt::from) +) { + Generator::<(Fp, Fp)>::gen(ctx).map(mina_p2p_messages::bigint::BigInt::from) } #[coverage(off)] -pub fn gen_curve_point_many, const N: u64>( +pub fn gen_curve_point_fq( + ctx: &mut impl Generator<(Fq, Fq)>, +) -> ( + mina_p2p_messages::bigint::BigInt, + mina_p2p_messages::bigint::BigInt, +) { + Generator::<(Fq, Fq)>::gen(ctx).map(mina_p2p_messages::bigint::BigInt::from) +} + +#[coverage(off)] +pub fn gen_curve_point_many_fp( ctx: &mut FuzzerCtx, ) -> ArrayN< ( @@ -907,27 +924,43 @@ pub fn gen_curve_point_many, const N: u64 mina_p2p_messages::bigint::BigInt, ), { N }, -> -where - mina_p2p_messages::bigint::BigInt: From, -{ - ctx.gen_wrap_many( - #[coverage(off)] - |x| gen_curve_point::(x), - ) +> { + ctx.gen_wrap_many(gen_curve_point_fp) } #[coverage(off)] -pub fn gen_curve_point_many_unzip, const N: u64>( +pub fn gen_curve_point_many_fq( + ctx: &mut FuzzerCtx, +) -> ArrayN< + ( + mina_p2p_messages::bigint::BigInt, + mina_p2p_messages::bigint::BigInt, + ), + { N }, +> { + ctx.gen_wrap_many(gen_curve_point_fq) +} + +#[coverage(off)] +pub fn gen_curve_point_many_unzip_fp( ctx: &mut FuzzerCtx, ) -> ( ArrayN, ArrayN, -) -where - mina_p2p_messages::bigint::BigInt: From + Default, -{ - let (a, b): (Vec<_>, Vec<_>) = gen_curve_point_many::(ctx).into_iter().unzip(); +) { + let (a, b): (Vec<_>, Vec<_>) = gen_curve_point_many_fp::(ctx).into_iter().unzip(); + + (ArrayN::from_iter(a), ArrayN::from_iter(b)) +} + +#[coverage(off)] +pub fn gen_curve_point_many_unzip_fq( + ctx: &mut FuzzerCtx, +) -> ( + ArrayN, + ArrayN, +) { + let (a, b): (Vec<_>, Vec<_>) = gen_curve_point_many_fq::(ctx).into_iter().unzip(); (ArrayN::from_iter(a), ArrayN::from_iter(b)) } @@ -936,7 +969,7 @@ impl Generator #[coverage(off)] fn gen(&mut self) -> PicklesProofProofsVerified2ReprStableV2MessagesForNextWrapProof { PicklesProofProofsVerified2ReprStableV2MessagesForNextWrapProof { - challenge_polynomial_commitment: gen_curve_point::(self), + challenge_polynomial_commitment: gen_curve_point_fq(self), old_bulletproof_challenges: self.gen(), } } @@ -958,7 +991,7 @@ impl Generator fn gen(&mut self) -> PicklesProofProofsVerified2ReprStableV2MessagesForNextStepProof { PicklesProofProofsVerified2ReprStableV2MessagesForNextStepProof { app_state: (), - challenge_polynomial_commitments: List::one(gen_curve_point::(self)), // TODO: variable num of elements + challenge_polynomial_commitments: List::one(gen_curve_point_fp(self)), // TODO: variable num of elements old_bulletproof_challenges: List::one(self.gen_wrap( // TODO: variable num of elements #[coverage(off)] @@ -978,57 +1011,38 @@ impl Generator for FuzzerCtx { } } -// impl Generator for FuzzerCtx { -// #[coverage(off)] -// fn gen(&mut self) -> PicklesProofProofsVerified2ReprStableV2PrevEvalsEvalsEvalsLookupA { -// PicklesProofProofsVerified2ReprStableV2PrevEvalsEvalsEvalsLookupA { -// sorted: self.gen_wrap_many( -// #[coverage(off)] -// |x| gen_curve_point_many_unzip::(x, 1), -// 1, -// ), -// aggreg: gen_curve_point_many_unzip::(self, 1), -// table: gen_curve_point_many_unzip::(self, 1), -// runtime: self.gen_wrap( -// #[coverage(off)] -// |x| gen_curve_point_many_unzip::(x, 1), -// ), -// } -// } -// } - impl Generator for FuzzerCtx { #[coverage(off)] fn gen(&mut self) -> PicklesProofProofsVerified2ReprStableV2PrevEvalsEvalsEvals { PicklesProofProofsVerified2ReprStableV2PrevEvalsEvalsEvals { - w: self.gen_wrap(gen_curve_point_many_unzip::), - complete_add_selector: gen_curve_point_many_unzip::(self), - mul_selector: gen_curve_point_many_unzip::(self), - emul_selector: gen_curve_point_many_unzip::(self), - endomul_scalar_selector: gen_curve_point_many_unzip::(self), - range_check0_selector: self.gen_wrap(gen_curve_point_many_unzip::), - range_check1_selector: self.gen_wrap(gen_curve_point_many_unzip::), - foreign_field_add_selector: self.gen_wrap(gen_curve_point_many_unzip::), - foreign_field_mul_selector: self.gen_wrap(gen_curve_point_many_unzip::), - xor_selector: self.gen_wrap(gen_curve_point_many_unzip::), - rot_selector: self.gen_wrap(gen_curve_point_many_unzip::), - lookup_aggregation: self.gen_wrap(gen_curve_point_many_unzip::), - lookup_table: self.gen_wrap(gen_curve_point_many_unzip::), + w: self.gen_wrap(gen_curve_point_many_unzip_fp::<16>), + complete_add_selector: gen_curve_point_many_unzip_fp::<16>(self), + mul_selector: gen_curve_point_many_unzip_fp::<16>(self), + emul_selector: gen_curve_point_many_unzip_fp::<16>(self), + endomul_scalar_selector: gen_curve_point_many_unzip_fp::<16>(self), + range_check0_selector: self.gen_wrap(gen_curve_point_many_unzip_fp::<16>), + range_check1_selector: self.gen_wrap(gen_curve_point_many_unzip_fp::<16>), + foreign_field_add_selector: self.gen_wrap(gen_curve_point_many_unzip_fp::<16>), + foreign_field_mul_selector: self.gen_wrap(gen_curve_point_many_unzip_fp::<16>), + xor_selector: self.gen_wrap(gen_curve_point_many_unzip_fp::<16>), + rot_selector: self.gen_wrap(gen_curve_point_many_unzip_fp::<16>), + lookup_aggregation: self.gen_wrap(gen_curve_point_many_unzip_fp::<16>), + lookup_table: self.gen_wrap(gen_curve_point_many_unzip_fp::<16>), lookup_sorted: self.gen_wrap( #[coverage(off)] - |x| x.gen_wrap(gen_curve_point_many_unzip::), + |x| x.gen_wrap(gen_curve_point_many_unzip_fp::<16>), ), - runtime_lookup_table: self.gen_wrap(gen_curve_point_many_unzip::), - runtime_lookup_table_selector: self.gen_wrap(gen_curve_point_many_unzip::), - xor_lookup_selector: self.gen_wrap(gen_curve_point_many_unzip::), - lookup_gate_lookup_selector: self.gen_wrap(gen_curve_point_many_unzip::), - range_check_lookup_selector: self.gen_wrap(gen_curve_point_many_unzip::), - foreign_field_mul_lookup_selector: self.gen_wrap(gen_curve_point_many_unzip::), - coefficients: self.gen_wrap(gen_curve_point_many_unzip::), - z: gen_curve_point_many_unzip::(self), - s: self.gen_wrap(gen_curve_point_many_unzip::), - generic_selector: gen_curve_point_many_unzip::(self), - poseidon_selector: gen_curve_point_many_unzip::(self), + runtime_lookup_table: self.gen_wrap(gen_curve_point_many_unzip_fp::<16>), + runtime_lookup_table_selector: self.gen_wrap(gen_curve_point_many_unzip_fp::<16>), + xor_lookup_selector: self.gen_wrap(gen_curve_point_many_unzip_fp::<16>), + lookup_gate_lookup_selector: self.gen_wrap(gen_curve_point_many_unzip_fp::<16>), + range_check_lookup_selector: self.gen_wrap(gen_curve_point_many_unzip_fp::<16>), + foreign_field_mul_lookup_selector: self.gen_wrap(gen_curve_point_many_unzip_fp::<16>), + coefficients: self.gen_wrap(gen_curve_point_many_unzip_fp::<16>), + z: gen_curve_point_many_unzip_fp::<16>(self), + s: self.gen_wrap(gen_curve_point_many_unzip_fp::<16>), + generic_selector: gen_curve_point_many_unzip_fp::<16>(self), + poseidon_selector: gen_curve_point_many_unzip_fp::<16>(self), } } } @@ -1037,7 +1051,7 @@ impl Generator for Fuzzer #[coverage(off)] fn gen(&mut self) -> PicklesProofProofsVerified2ReprStableV2PrevEvalsEvals { PicklesProofProofsVerified2ReprStableV2PrevEvalsEvals { - public_input: gen_curve_point::(self), + public_input: gen_curve_point_fp(self), evals: self.gen(), } } @@ -1053,87 +1067,13 @@ impl Generator for FuzzerCtx { } } -// impl Generator for FuzzerCtx { -// #[coverage(off)] -// fn gen(&mut self) -> PicklesProofProofsVerified2ReprStableV2ProofMessagesLookupA { -// PicklesProofProofsVerified2ReprStableV2ProofMessagesLookupA { -// sorted: self.gen_wrap_many( -// #[coverage(off)] -// |x| gen_curve_point_many::(x, 1), -// 1, -// ), -// aggreg: gen_curve_point_many::(self, 1), -// runtime: self.gen_wrap( -// #[coverage(off)] -// |x| gen_curve_point_many::(x, 1), -// ), -// } -// } -// } - -// impl Generator for FuzzerCtx { -// #[coverage(off)] -// fn gen(&mut self) -> PicklesProofProofsVerified2ReprStableV2ProofMessages { -// PicklesProofProofsVerified2ReprStableV2ProofMessages { -// w_comm: self.gen_wrap( -// #[coverage(off)] -// |x| gen_curve_point_many::(x, 1), -// ), -// z_comm: gen_curve_point_many::(self, 1), -// t_comm: gen_curve_point_many::(self, 1), -// lookup: self.gen_wrap( -// #[coverage(off)] -// |x| x.gen(), -// ), -// } -// } -// } - -// impl Generator for FuzzerCtx { -// #[coverage(off)] -// fn gen(&mut self) -> PicklesProofProofsVerified2ReprStableV2ProofOpeningsProof { -// PicklesProofProofsVerified2ReprStableV2ProofOpeningsProof { -// lr: self.gen_wrap_many( -// #[coverage(off)] -// |x| (gen_curve_point::(x), gen_curve_point::(x)), -// 1, -// ), -// z_1: self.gen(), -// z_2: self.gen(), -// delta: gen_curve_point::(self), -// challenge_polynomial_commitment: gen_curve_point::(self), -// } -// } -// } - -// impl Generator for FuzzerCtx { -// #[coverage(off)] -// fn gen(&mut self) -> PicklesProofProofsVerified2ReprStableV2ProofOpenings { -// PicklesProofProofsVerified2ReprStableV2ProofOpenings { -// proof: self.gen(), -// evals: self.gen(), -// ft_eval1: self.gen(), -// } -// } -// } - -// impl Generator for FuzzerCtx { -// #[coverage(off)] -// fn gen(&mut self) -> PicklesProofProofsVerified2ReprStableV2Proof { -// PicklesProofProofsVerified2ReprStableV2Proof { -// messages: self.gen(), -// openings: self.gen(), -// } -// } -// } - impl Generator for FuzzerCtx { #[coverage(off)] fn gen(&mut self) -> PicklesWrapWireProofCommitmentsStableV1 { PicklesWrapWireProofCommitmentsStableV1 { - w_comm: self.gen_wrap(gen_curve_point::), - z_comm: gen_curve_point::(self), - t_comm: self.gen_wrap(gen_curve_point::), + w_comm: self.gen_wrap(gen_curve_point_fp), + z_comm: gen_curve_point_fp(self), + t_comm: self.gen_wrap(gen_curve_point_fp), } } } @@ -1144,12 +1084,12 @@ impl Generator for FuzzerCtx { PicklesWrapWireProofStableV1Bulletproof { lr: self.gen_wrap_many( #[coverage(off)] - |x| (gen_curve_point::(x), gen_curve_point::(x)), + |x| (gen_curve_point_fp(x), gen_curve_point_fp(x)), ), z_1: Generator::::gen(self).into(), z_2: Generator::::gen(self).into(), - delta: gen_curve_point::(self), - challenge_polynomial_commitment: gen_curve_point::(self), + delta: gen_curve_point_fp(self), + challenge_polynomial_commitment: gen_curve_point_fp(self), } } } @@ -1158,16 +1098,16 @@ impl Generator for FuzzerCtx { #[coverage(off)] fn gen(&mut self) -> PicklesWrapWireProofEvaluationsStableV1 { PicklesWrapWireProofEvaluationsStableV1 { - w: self.gen_wrap(gen_curve_point::), - coefficients: self.gen_wrap(gen_curve_point::), - z: gen_curve_point::(self), - s: self.gen_wrap(gen_curve_point::), - generic_selector: gen_curve_point::(self), - poseidon_selector: gen_curve_point::(self), - complete_add_selector: gen_curve_point::(self), - mul_selector: gen_curve_point::(self), - emul_selector: gen_curve_point::(self), - endomul_scalar_selector: gen_curve_point::(self), + w: self.gen_wrap(gen_curve_point_fp), + coefficients: self.gen_wrap(gen_curve_point_fp), + z: gen_curve_point_fp(self), + s: self.gen_wrap(gen_curve_point_fp), + generic_selector: gen_curve_point_fp(self), + poseidon_selector: gen_curve_point_fp(self), + complete_add_selector: gen_curve_point_fp(self), + mul_selector: gen_curve_point_fp(self), + emul_selector: gen_curve_point_fp(self), + endomul_scalar_selector: gen_curve_point_fp(self), } } } @@ -1847,8 +1787,6 @@ impl GeneratorFromToken for FuzzerCtx { self.gen() }; - // let public_key = self.random_keypair().public.into_compressed(); - let body: zkapp_command::Body = if self.gen.rng.gen_bool(0.9) { match self.get_account(&public_key).as_ref() { Some(account) => self.gen_from_account(account), @@ -2098,24 +2036,28 @@ impl Generator for FuzzerCtx { } impl Generator> for FuzzerCtx { + #[coverage(off)] fn gen(&mut self) -> Number { Number(self.gen.rng.gen()) } } impl Generator> for FuzzerCtx { + #[coverage(off)] fn gen(&mut self) -> Number { Number(self.gen.rng.gen()) } } impl Generator> for FuzzerCtx { + #[coverage(off)] fn gen(&mut self) -> Number { Number(self.gen.rng.gen()) } } impl Generator> for FuzzerCtx { + #[coverage(off)] fn gen(&mut self) -> Number { Number(self.gen.rng.gen()) } diff --git a/tools/fuzzing/src/transaction_fuzzer/mutator.rs b/tools/fuzzing/src/transaction_fuzzer/mutator.rs index e55c989852..f76e7d2fb9 100644 --- a/tools/fuzzing/src/transaction_fuzzer/mutator.rs +++ b/tools/fuzzing/src/transaction_fuzzer/mutator.rs @@ -1,12 +1,10 @@ use super::{ context::{FuzzerCtx, PermissionModel}, generator::{ - sign_account_updates, Generator, GeneratorFromAccount, GeneratorRange32, GeneratorRange64, - GeneratorWrapper, + gen_curve_point_fp, sign_account_updates, Generator, GeneratorFromAccount, + GeneratorRange32, GeneratorRange64, GeneratorWrapper, }, }; -use crate::transaction_fuzzer::generator::gen_curve_point; -use ark_ff::Zero; use ledger::{ generators::zkapp_command_builder::get_transaction_commitments, scan_state::{ @@ -39,7 +37,6 @@ use mina_p2p_messages::{ }, }; use mina_signer::{CompressedPubKey, NetworkId, Signature, Signer}; -use poseidon::hash::{hash_with_kimchi, params::MINA_ACCOUNT_UPDATE_CONS}; use rand::{seq::SliceRandom, Rng}; #[coverage(off)] @@ -74,7 +71,7 @@ impl Mutator for FuzzerCtx { impl Mutator<(BigInt, BigInt)> for FuzzerCtx { #[coverage(off)] fn mutate(&mut self, t: &mut (BigInt, BigInt)) { - *t = gen_curve_point::(self); + *t = gen_curve_point_fp(self); } } @@ -160,8 +157,6 @@ where impl Mutator for FuzzerCtx { #[coverage(off)] fn mutate(&mut self, t: &mut FeePayerBody) { - //let account = self.get_account(&t.public_key).unwrap(); - for option in rand_elements(self, 2) { match option { 0 => t.fee = GeneratorRange64::::gen_range(self, 0..=Fee::max().as_u64()), @@ -682,34 +677,7 @@ impl Mutator> for FuzzerCtx { #[coverage(off)] fn mutate(&mut self, t: &mut zkapp_command::CallForest) { for i in rand_elements(self, t.0.len()) { - let tree_digest = { - let tree = &mut t.0[i].elt; - - for option in rand_elements(self, 2) { - match option { - 0 => { - self.mutate(&mut tree.account_update); - tree.account_update_digest = - MutableFp::new(tree.account_update.digest()); - } - 1 => self.mutate(&mut tree.calls), - _ => unimplemented!(), - } - } - - tree.digest() - }; - - let h_tl = if let Some(x) = t.0.get(i + 1) { - x.stack_hash.get().unwrap() - } else { - Fp::zero() - }; - - t.0[i].stack_hash = MutableFp::new(hash_with_kimchi( - &MINA_ACCOUNT_UPDATE_CONS, - &[tree_digest, h_tl], - )); + t.0[i].stack_hash = MutableFp::empty(); } } } @@ -797,24 +765,6 @@ impl Mutator for FuzzerCtx { } } -// impl Mutator for FuzzerCtx { -// #[no_coverage] -// fn mutate(&mut self, t: &mut MinaStateSnarkedLedgerStateWithSokStableV2) { -// for option in rand_elements(self, 6) { -// match option { -// // 0 => self.mutate(&mut t.source), -// // 1 => self.mutate(&mut t.target), -// // 2 => self.mutate(&mut t.connecting_ledger_left), -// // 3 => self.mutate(&mut t.connecting_ledger_right), -// // 4 => self.mutate(&mut t.supply_increase), -// // 5 => self.mutate(&mut t.fee_excess), -// // // 6 => self.mutate(&mut t.sok_digest), -// _ => unimplemented!(), -// } -// } -// } -// } - impl Mutator for FuzzerCtx { #[coverage(off)] fn mutate(&mut self, t: &mut PicklesProofProofsVerified2ReprStableV2PrevEvals) { @@ -885,34 +835,6 @@ impl Mutator for FuzzerCt } } -// impl Mutator for FuzzerCtx { -// #[coverage(off)] -// fn mutate(&mut self, t: &mut PicklesProofProofsVerified2ReprStableV2ProofOpenings) { -// for option in rand_elements(self, 3) { -// match option { -// 0 => self.mutate(&mut t.proof), -// 1 => self.mutate(&mut t.evals), -// 2 => self.mutate(&mut t.ft_eval1), -// _ => unimplemented!(), -// } -// } -// } -// } - -// impl Mutator for FuzzerCtx { -// #[coverage(off)] -// fn mutate(&mut self, t: &mut PicklesProofProofsVerified2ReprStableV2Proof) { -// for option in rand_elements(self, 2) { -// match option { -// // 0 => self.mutate(&mut t.statement), -// 0 => self.mutate(&mut t.messages), -// 1 => self.mutate(&mut t.openings), -// _ => unimplemented!(), -// } -// } -// } -// } - impl Mutator for FuzzerCtx { #[coverage(off)] fn mutate(&mut self, t: &mut PicklesWrapWireProofCommitmentsStableV1) { @@ -988,13 +910,6 @@ impl Mutator for FuzzerCtx { #[coverage(off)] fn mutate(&mut self, t: &mut TransactionSnarkStableV2) { self.mutate(&mut t.proof) - // for option in rand_elements(self, 2) { - // match option { - // 0 => self.mutate(&mut t.statement), - // 1 => self.mutate(&mut t.proof), - // _ => unimplemented!(), - // } - // } } }