diff --git a/prover/Cargo.lock b/prover/Cargo.lock index 610ff69a..1c86c739 100644 --- a/prover/Cargo.lock +++ b/prover/Cargo.lock @@ -989,7 +989,7 @@ checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "plonkish_backend" version = "0.1.0" -source = "git+https://github.com/summa-dev/plonkish?branch=nonzero-constraints#e37ba53dcc8f8bd6e7add4e479d0e3295ee80661" +source = "git+https://github.com/summa-dev/plonkish?branch=nonzero-constraints#c9dc12571d4a9aa06a419598ff2422b42770ae91" dependencies = [ "bincode", "bitvec", diff --git a/prover/Cargo.toml b/prover/Cargo.toml index a897e375..16740928 100644 --- a/prover/Cargo.toml +++ b/prover/Cargo.toml @@ -30,4 +30,4 @@ criterion= "0.3" [[bench]] name = "proof_of_liabilities" -harness = false \ No newline at end of file +harness = false diff --git a/prover/benches/proof_of_liabilities.rs b/prover/benches/proof_of_liabilities.rs index 0ac4a505..a2ec9ed4 100644 --- a/prover/benches/proof_of_liabilities.rs +++ b/prover/benches/proof_of_liabilities.rs @@ -18,8 +18,9 @@ use summa_hyperplonk::{ utils::{big_uint_to_fp, generate_dummy_entries, uni_to_multivar_binary_index}, }; -fn bench_summa() { - let name = format!("K = {K}, N_USERS = {N_USERS}, N_CURRENCIES = {N_CURRENCIES}"); +// There is only one currency in V3c +fn bench_summa() { + let name = format!("K = {K}, N_USERS = {N_USERS}"); let mut c = Criterion::default().sample_size(10); let grand_sum_proof_bench_name = format!("<{}> grand sum proof", name); @@ -29,16 +30,13 @@ fn bench_summa() let inclusion_verification_bench_name = format!("<{}> user inclusion verification", name); type ProvingBackend = HyperPlonk>; - let entries = generate_dummy_entries::().unwrap(); + let entries = generate_dummy_entries::().unwrap(); let halo2_circuit = - SummaHyperplonk::>::init( - entries.to_vec(), - ); + SummaHyperplonk::>::init(entries.to_vec()); - let circuit = Halo2Circuit::< - Fp, - SummaHyperplonk>, - >::new::(K as usize, halo2_circuit.clone()); + let circuit = Halo2Circuit::>>::new::< + ProvingBackend, + >(K as usize, halo2_circuit.clone()); let circuit_info: PlonkishCircuitInfo<_> = circuit.circuit_info().unwrap(); let instances = circuit.instances(); @@ -49,10 +47,9 @@ fn bench_summa() c.bench_function(&grand_sum_proof_bench_name, |b| { b.iter_batched( || { - Halo2Circuit::< - Fp, - SummaHyperplonk>, - >::new::(K as usize, halo2_circuit.clone()) + Halo2Circuit::>>::new::< + ProvingBackend, + >(K as usize, halo2_circuit.clone()) }, |circuit| { let mut transcript = Keccak256Transcript::default(); @@ -79,7 +76,7 @@ fn bench_summa() .unwrap(); (witness_polys, proof_transcript) }; - let num_points = N_CURRENCIES + 1; + let num_points = 2; let user_entry_polynomials = witness_polys.iter().take(num_points).collect::>(); let mut transcript = Keccak256Transcript::default(); @@ -106,23 +103,18 @@ fn bench_summa() let multivariate_challenge = uni_to_multivar_binary_index(&random_user_index, num_vars as usize); - let mut evals = vec![]; - - for i in 0..N_CURRENCIES + 1 { - if i == 0 { - evals.push(Evaluation::new( - i, - 0, - big_uint_to_fp::(entries[random_user_index].username_as_big_uint()), - )); - } else { - evals.push(Evaluation::new( - i, - 0, - big_uint_to_fp::(&entries[random_user_index].balances()[i - 1]), - )); - } - } + let evals: Vec> = vec![ + Evaluation::new( + 0, + 0, + big_uint_to_fp::(entries[random_user_index].username_as_big_uint()), + ), + Evaluation::new( + 1, + 0, + big_uint_to_fp::(&entries[random_user_index].balance()), + ), + ]; c.bench_function(&inclusion_proof_bench_name, |b| { b.iter_batched( @@ -192,12 +184,11 @@ fn bench_summa() } fn criterion_benchmark(_c: &mut Criterion) { - const N_CURRENCIES: usize = 100; - + // Only one currency will be handled in V3c { const K: u32 = 17; const N_USERS: usize = (1 << K as usize) - 6; - bench_summa::(); + bench_summa::(); } } diff --git a/prover/src/circuits/config/circuit_config.rs b/prover/src/circuits/config/circuit_config.rs index 51382773..5b76a230 100644 --- a/prover/src/circuits/config/circuit_config.rs +++ b/prover/src/circuits/config/circuit_config.rs @@ -13,18 +13,18 @@ use halo2_proofs::halo2curves::bn256::Fr as Fp; /// grand total to the instance values. /// /// The specific implementations have to provide the range check logic. -pub trait CircuitConfig: Clone { +pub trait CircuitConfig: Clone { /// Configures the circuit fn configure( meta: &mut ConstraintSystem, username: Column, - balances: [Column; N_CURRENCIES], + balance: Column, instance: Column, ) -> Self; fn get_username(&self) -> Column; - fn get_balances(&self) -> [Column; N_CURRENCIES]; + fn get_balance(&self) -> Column; fn get_instance(&self) -> Column; @@ -32,14 +32,14 @@ pub trait CircuitConfig: Clone fn synthesize( &self, mut layouter: impl Layouter, - entries: &[Entry], - grand_total: &[Fp], + entries: &[Entry], + grand_total: &Fp, ) -> Result<(), Error> { // Initiate the range check chips - let range_check_chips = self.initialize_range_check_chips(); + let range_check_chip = self.initialize_range_check_chip(); for (i, entry) in entries.iter().enumerate() { - let last_decompositions = layouter.assign_region( + let last_decomposition = layouter.assign_region( || format!("assign entry {} to the table", i), |mut region| { region.assign_advice( @@ -49,55 +49,49 @@ pub trait CircuitConfig: Clone || Value::known(big_uint_to_fp::(entry.username_as_big_uint())), )?; - let mut last_decompositions = vec![]; + let mut zs = Vec::with_capacity(4); - for (j, balance) in entry.balances().iter().enumerate() { - let assigned_balance = region.assign_advice( - || format!("balance {}", j), - self.get_balances()[j], + // The range check chip is empty when perform with "no_range_check_config" + if range_check_chip.is_empty() { + let zero_balance = region.assign_advice( + || "balance", + self.get_balance(), 0, - || Value::known(big_uint_to_fp(balance)), + || Value::known(Fp::zero()), )?; - let mut zs = Vec::with_capacity(4); - - if !range_check_chips.is_empty() { - range_check_chips[j].assign(&mut region, &mut zs, &assigned_balance)?; - - last_decompositions.push(zs[3].clone()); - } + Ok(zero_balance) + } else { + let assigned_balance = region.assign_advice( + || "balance", + self.get_balance(), + 0, + || Value::known(big_uint_to_fp(entry.balance())), + )?; + range_check_chip[0].assign(&mut region, &mut zs, &assigned_balance)?; + Ok(zs[3].clone()) } - - Ok(last_decompositions) }, )?; - self.constrain_decompositions(last_decompositions, &mut layouter)?; + self.constrain_decompositions(last_decomposition, &mut layouter)?; } let assigned_total = layouter.assign_region( || "assign total".to_string(), |mut region| { - let mut assigned_total = vec![]; - - for (j, total) in grand_total.iter().enumerate() { - let balance_total = region.assign_advice( - || format!("total {}", j), - self.get_balances()[j], - 0, - || Value::known(total.neg()), - )?; - - assigned_total.push(balance_total); - } - - Ok(assigned_total) + let balance_total = region.assign_advice( + || "total balance", + self.get_balance(), + 0, + || Value::known(grand_total.neg()), + )?; + + Ok(balance_total) }, )?; - for (j, total) in assigned_total.iter().enumerate() { - layouter.constrain_instance(total.cell(), self.get_instance(), 1 + j)?; - } + layouter.constrain_instance(assigned_total.cell(), self.get_instance(), 1)?; self.load_lookup_table(layouter)?; @@ -105,7 +99,7 @@ pub trait CircuitConfig: Clone } /// Initializes the range check chips - fn initialize_range_check_chips(&self) -> Vec; + fn initialize_range_check_chip(&self) -> Vec; /// Loads the lookup table fn load_lookup_table(&self, layouter: impl Layouter) -> Result<(), Error>; @@ -113,7 +107,7 @@ pub trait CircuitConfig: Clone /// Constrains the last decompositions of the balances to be zero fn constrain_decompositions( &self, - last_decompositions: Vec>, + last_decomposition: halo2_proofs::circuit::AssignedCell, layouter: &mut impl Layouter, ) -> Result<(), Error>; } diff --git a/prover/src/circuits/config/no_range_check_config.rs b/prover/src/circuits/config/no_range_check_config.rs index 5d6d4ada..4139b912 100644 --- a/prover/src/circuits/config/no_range_check_config.rs +++ b/prover/src/circuits/config/no_range_check_config.rs @@ -13,32 +13,29 @@ use super::circuit_config::CircuitConfig; /// /// # Type Parameters /// -/// * `N_CURRENCIES`: The number of currencies for which the solvency is verified. /// * `N_USERS`: The number of users for which the solvency is verified. /// /// # Fields /// /// * `username`: Advice column used to store the usernames of the users -/// * `balances`: Advice columns used to store the balances of the users +/// * `balance`: Advice columns used to store the balance of the users #[derive(Clone)] -pub struct NoRangeCheckConfig { +pub struct NoRangeCheckConfig { username: Column, - balances: [Column; N_CURRENCIES], + balance: Column, instance: Column, } -impl CircuitConfig - for NoRangeCheckConfig -{ +impl CircuitConfig for NoRangeCheckConfig { fn configure( _: &mut ConstraintSystem, username: Column, - balances: [Column; N_CURRENCIES], + balance: Column, instance: Column, - ) -> NoRangeCheckConfig { + ) -> NoRangeCheckConfig { Self { username, - balances, + balance, instance, } } @@ -47,8 +44,8 @@ impl CircuitConfig [Column; N_CURRENCIES] { - self.balances + fn get_balance(&self) -> Column { + self.balance } fn get_instance(&self) -> Column { @@ -57,7 +54,7 @@ impl CircuitConfig Vec { + fn initialize_range_check_chip(&self) -> Vec { vec![] } @@ -67,7 +64,7 @@ impl CircuitConfig>, + _: halo2_proofs::circuit::AssignedCell, _: &mut impl Layouter, ) -> Result<(), Error> { Ok(()) diff --git a/prover/src/circuits/config/range_check_config.rs b/prover/src/circuits/config/range_check_config.rs index 7a7c0e8a..411afdd0 100644 --- a/prover/src/circuits/config/range_check_config.rs +++ b/prover/src/circuits/config/range_check_config.rs @@ -12,7 +12,6 @@ use super::circuit_config::CircuitConfig; /// /// # Type Parameters /// -/// * `N_CURRENCIES`: The number of currencies for which the solvency is verified. /// * `N_USERS`: The number of users for which the solvency is verified. /// /// # Fields @@ -23,21 +22,19 @@ use super::circuit_config::CircuitConfig; /// * `range_u16`: Fixed column used to store the lookup table /// * `instance`: Instance column used to constrain the last balance decomposition #[derive(Clone)] -pub struct RangeCheckConfig { +pub struct RangeCheckConfig { username: Column, - balances: [Column; N_CURRENCIES], - range_check_configs: [RangeCheckChipConfig; N_CURRENCIES], + balance: Column, + range_check_config: RangeCheckChipConfig, range_u16: Column, instance: Column, } -impl CircuitConfig - for RangeCheckConfig -{ +impl CircuitConfig for RangeCheckConfig { fn configure( meta: &mut ConstraintSystem, username: Column, - balances: [Column; N_CURRENCIES], + balance: Column, instance: Column, ) -> Self { let range_u16 = meta.fixed_column(); @@ -48,28 +45,21 @@ impl CircuitConfig CircuitConfig [Column; N_CURRENCIES] { - self.balances + fn get_balance(&self) -> Column { + self.balance } fn get_instance(&self) -> Column { self.instance } - fn initialize_range_check_chips(&self) -> Vec { - self.range_check_configs - .iter() - .map(|config| RangeCheckU64Chip::construct(*config)) - .collect::>() + fn initialize_range_check_chip(&self) -> Vec { + vec![RangeCheckU64Chip::construct(self.range_check_config)] } fn load_lookup_table(&self, mut layouter: impl Layouter) -> Result<(), Error> { @@ -119,12 +106,10 @@ impl CircuitConfig>, + last_decomposition: halo2_proofs::circuit::AssignedCell, layouter: &mut impl Layouter, ) -> Result<(), Error> { - for last_decomposition in last_decompositions { - layouter.constrain_instance(last_decomposition.cell(), self.instance, 0)?; - } + layouter.constrain_instance(last_decomposition.cell(), self.instance, 0)?; Ok(()) } } diff --git a/prover/src/circuits/summa_circuit.rs b/prover/src/circuits/summa_circuit.rs index e8762d45..e26c8b5d 100644 --- a/prover/src/circuits/summa_circuit.rs +++ b/prover/src/circuits/summa_circuit.rs @@ -16,28 +16,17 @@ use rand::RngCore; use super::config::circuit_config::CircuitConfig; #[derive(Clone, Default)] -pub struct SummaHyperplonk< - const N_USERS: usize, - const N_CURRENCIES: usize, - CONFIG: CircuitConfig, -> { - pub entries: Vec>, - pub grand_total: Vec, +pub struct SummaHyperplonk> { + pub entries: Vec, + pub grand_total: Fp, _marker: PhantomData, } -impl< - const N_USERS: usize, - const N_CURRENCIES: usize, - CONFIG: CircuitConfig, - > SummaHyperplonk -{ - pub fn init(user_entries: Vec>) -> Self { - let mut grand_total = vec![Fp::ZERO; N_CURRENCIES]; +impl> SummaHyperplonk { + pub fn init(user_entries: Vec) -> Self { + let mut grand_total = Fp::zero(); for entry in user_entries.iter() { - for (i, balance) in entry.balances().iter().enumerate() { - grand_total[i] += big_uint_to_fp::(balance); - } + grand_total += big_uint_to_fp::(entry.balance()); } Self { @@ -50,13 +39,10 @@ impl< /// Initialize the circuit with an invalid grand total /// (for testing purposes only). #[cfg(test)] - pub fn init_invalid_grand_total(user_entries: Vec>) -> Self { + pub fn init_invalid_grand_total(user_entries: Vec) -> Self { use plonkish_backend::util::test::seeded_std_rng; - let mut grand_total = vec![Fp::ZERO; N_CURRENCIES]; - for i in 0..N_CURRENCIES { - grand_total[i] = Fp::random(seeded_std_rng()); - } + let grand_total = Fp::random(seeded_std_rng()); Self { entries: user_entries, @@ -66,11 +52,8 @@ impl< } } -impl< - const N_USERS: usize, - const N_CURRENCIES: usize, - CONFIG: CircuitConfig, - > Circuit for SummaHyperplonk +impl> Circuit + for SummaHyperplonk { type Config = CONFIG; type FloorPlanner = SimpleFloorPlanner; @@ -84,24 +67,17 @@ impl< let username = meta.advice_column(); - let balances = [(); N_CURRENCIES].map(|_| meta.advice_column()); - for column in &balances { - meta.enable_equality(*column); - } + let balance = meta.advice_column(); + meta.enable_equality(balance); meta.create_gate("Balance sumcheck gate", |meta| { - let mut nonzero_constraint = vec![]; - for balance in balances { - let current_balance = meta.query_advice(balance, Rotation::cur()); - nonzero_constraint.push(current_balance.clone()); - } - nonzero_constraint + vec![meta.query_advice(balance, Rotation::cur())] }); let instance = meta.instance_column(); meta.enable_equality(instance); - CONFIG::configure(meta, username, balances, instance) + CONFIG::configure(meta, username, balance, instance) } fn synthesize(&self, config: Self::Config, layouter: impl Layouter) -> Result<(), Error> { @@ -109,11 +85,8 @@ impl< } } -impl< - const N_USERS: usize, - const N_CURRENCIES: usize, - CONFIG: CircuitConfig, - > CircuitExt for SummaHyperplonk +impl> CircuitExt + for SummaHyperplonk { fn rand(_: usize, _: impl RngCore) -> Self { unimplemented!() @@ -121,9 +94,6 @@ impl< fn instances(&self) -> Vec> { // The 1st element is zero because the last decomposition of each range check chip should be zero - vec![vec![Fp::ZERO] - .into_iter() - .chain(self.grand_total.iter().map(|x| x.neg())) - .collect::>()] + vec![vec![Fp::ZERO, self.grand_total.neg()]] } } diff --git a/prover/src/circuits/tests.rs b/prover/src/circuits/tests.rs index 88bbb4af..e01dc58a 100644 --- a/prover/src/circuits/tests.rs +++ b/prover/src/circuits/tests.rs @@ -29,7 +29,6 @@ use crate::{ }, }; const K: u32 = 17; -const N_CURRENCIES: usize = 2; // One row is reserved for the grand total. // TODO find out what occupies one extra row const N_USERS: usize = (1 << K) - 2; @@ -41,18 +40,12 @@ pub fn seeded_std_rng() -> impl RngCore + CryptoRng { #[test] fn test_summa_hyperplonk_e2e() { type ProvingBackend = HyperPlonk>; - let entries = generate_dummy_entries::().unwrap(); + let entries = generate_dummy_entries::().unwrap(); let halo2_circuit = - SummaHyperplonk::>::init( - entries.to_vec(), - ); + SummaHyperplonk::>::init(entries.to_vec()); - let neg_grand_total = halo2_circuit - .grand_total - .iter() - .fold(Fp::ZERO, |acc, f| acc + f) - .neg(); + let neg_grand_total = halo2_circuit.grand_total.neg(); // We're putting the negated grand total at the end of each balance column, // so the sumcheck over such balance column would yield zero (given the special gate, @@ -67,10 +60,9 @@ fn test_summa_hyperplonk_e2e() { let num_vars = K; let circuit_fn = |num_vars| { - let circuit = Halo2Circuit::< - Fp, - SummaHyperplonk>, - >::new::(num_vars, halo2_circuit.clone()); + let circuit = Halo2Circuit::>>::new::< + ProvingBackend, + >(num_vars, halo2_circuit.clone()); (circuit.circuit_info().unwrap(), circuit) }; @@ -95,7 +87,7 @@ fn test_summa_hyperplonk_e2e() { (witness_polys, proof_transcript) }; - let num_points = N_CURRENCIES + 1; + let num_points = 2; let proof = proof_transcript.into_proof(); @@ -177,7 +169,7 @@ fn test_summa_hyperplonk_e2e() { ); assert_eq!( fp_to_big_uint(&witness_polys[1].evaluate_as_univariate(&random_user_index)), - entries[random_user_index].balances()[0] + entries[random_user_index].balance().clone() ); // Convert challenge into a multivariate form @@ -240,23 +232,18 @@ fn test_summa_hyperplonk_e2e() { } //The user knows their evaluation at the challenge point - let evals: Vec> = (0..N_CURRENCIES + 1) - .map(|i| { - if i == 0 { - Evaluation::new( - i, - 0, - big_uint_to_fp::(entries[random_user_index].username_as_big_uint()), - ) - } else { - Evaluation::new( - i, - 0, - big_uint_to_fp::(&entries[random_user_index].balances()[i - 1]), - ) - } - }) - .collect(); + let evals: Vec> = vec![ + Evaluation::new( + 0, + 0, + big_uint_to_fp::(entries[random_user_index].username_as_big_uint()), + ), + Evaluation::new( + 1, + 0, + big_uint_to_fp::(&entries[random_user_index].balance()), + ), + ]; MultilinearKzg::::batch_verify( &verifier_parameters.pcs, @@ -274,21 +261,20 @@ fn test_summa_hyperplonk_e2e() { #[test] fn test_sumcheck_fail() { type ProvingBackend = HyperPlonk>; - let entries = generate_dummy_entries::().unwrap(); + let entries = generate_dummy_entries::().unwrap(); - let halo2_circuit = SummaHyperplonk::< - N_USERS, - N_CURRENCIES, - NoRangeCheckConfig, - >::init_invalid_grand_total(entries.to_vec()); + let halo2_circuit = + SummaHyperplonk::>::init_invalid_grand_total( + entries.to_vec(), + ); let num_vars = K; let circuit_fn = |num_vars| { - let circuit = Halo2Circuit::< - Fp, - SummaHyperplonk>, - >::new::(num_vars, halo2_circuit.clone()); + let circuit = + Halo2Circuit::>>::new::< + ProvingBackend, + >(num_vars, halo2_circuit.clone()); (circuit.circuit_info().unwrap(), circuit) }; @@ -338,9 +324,9 @@ fn test_sumcheck_fail() { fn print_univariate_grand_sum_circuit() { use plotters::prelude::*; - let entries = generate_dummy_entries::().unwrap(); + let entries = generate_dummy_entries::().unwrap(); - let circuit = SummaHyperplonk::::init(entries.to_vec()); + let circuit = SummaHyperplonk::::init(entries.to_vec()); let root = BitMapBackend::new("prints/summa-hyperplonk-layout.png", (2048, 32768)).into_drawing_area(); @@ -350,6 +336,6 @@ fn print_univariate_grand_sum_circuit() { .unwrap(); halo2_proofs::dev::CircuitLayout::default() - .render::, _, true>(K, &circuit, &root) + .render::, _, true>(K, &circuit, &root) .unwrap(); } diff --git a/prover/src/entry.rs b/prover/src/entry.rs index daaef76c..5286c025 100644 --- a/prover/src/entry.rs +++ b/prover/src/entry.rs @@ -5,33 +5,31 @@ use crate::utils::big_intify_username; /// An entry in the Merkle Sum Tree from the database of the CEX. /// It contains the username and the balances of the user. #[derive(Clone, Debug)] -pub struct Entry { +pub struct Entry { username_as_big_uint: BigUint, - balances: [BigUint; N_CURRENCIES], + balance: BigUint, username: String, } -impl Entry { - pub fn new(username: String, balances: [BigUint; N_CURRENCIES]) -> Result { +impl Entry { + pub fn new(username: String, balance: BigUint) -> Result { Ok(Entry { username_as_big_uint: big_intify_username(&username), - balances, + balance, username, }) } pub fn init_empty() -> Self { - let empty_balances: [BigUint; N_CURRENCIES] = std::array::from_fn(|_| BigUint::from(0u32)); - Entry { username_as_big_uint: BigUint::from(0u32), - balances: empty_balances, + balance: BigUint::from(0u32), username: String::new(), } } - pub fn balances(&self) -> &[BigUint; N_CURRENCIES] { - &self.balances + pub fn balance(&self) -> &BigUint { + &self.balance } pub fn username_as_big_uint(&self) -> &BigUint { diff --git a/prover/src/utils/dummy_entries.rs b/prover/src/utils/dummy_entries.rs index f566b9c0..bad3a831 100644 --- a/prover/src/utils/dummy_entries.rs +++ b/prover/src/utils/dummy_entries.rs @@ -6,24 +6,17 @@ use std::error::Error; use crate::entry::Entry; // This is for testing purposes with a large dataset instead of using a CSV file -pub fn generate_dummy_entries( -) -> Result>, Box> { - // Ensure N_CURRENCIES is greater than 0. - if N_CURRENCIES == 0 { - return Err("N_CURRENCIES must be greater than 0".into()); - } - - let mut entries: Vec> = vec![Entry::init_empty(); N_USERS]; +pub fn generate_dummy_entries() -> Result, Box> { + let mut entries: Vec = vec![Entry::init_empty(); N_USERS]; entries.par_iter_mut().for_each(|entry| { let mut rng = rand::thread_rng(); let username: String = (0..10).map(|_| rng.sample(Alphanumeric) as char).collect(); - let balances: [BigUint; N_CURRENCIES] = - std::array::from_fn(|_| BigUint::from(rng.gen_range(1000..90000) as u32)); + let balance = BigUint::from(rng.gen_range(1000..90000) as u32); - *entry = Entry::new(username, balances).expect("Failed to create entry"); + *entry = Entry::new(username, balance).expect("Failed to create entry"); }); Ok(entries) @@ -36,25 +29,14 @@ mod tests { #[test] fn test_generate_random_entries() { const N_USERS: usize = 1 << 17; - const N_CURRENCIES: usize = 2; // Attempt to generate random entries - let entries = generate_dummy_entries::().unwrap(); + let entries = generate_dummy_entries::().unwrap(); // Verify that entries are populated assert_eq!(entries.len(), N_USERS); for entry in entries { assert!(!entry.username().is_empty()); - assert_eq!(entry.balances().len(), N_CURRENCIES); } } - - #[test] - fn test_asset_not_zero() { - const N_USERS: usize = 1 << 17; - const N_CURRENCIES: usize = 0; - - // `N_CURRENCIES` is zero, so this should fail - assert!(generate_dummy_entries::().is_err()); - } }