diff --git a/emmarin/cl/cl/src/crust/tx.rs b/emmarin/cl/cl/src/crust/tx.rs index 2e13860..e56f95b 100644 --- a/emmarin/cl/cl/src/crust/tx.rs +++ b/emmarin/cl/cl/src/crust/tx.rs @@ -50,7 +50,7 @@ impl TxRoot { pub struct Tx { pub root: TxRoot, pub balance: Balance, - pub updates: Vec, + pub updates: BTreeMap, } #[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)] @@ -63,16 +63,16 @@ pub struct TxWitness { pub frontier_paths: Vec<(MMR, MMRProof)>, } -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +// TODO: this LedgerUpdate and LedgerUpdateWitness need to be merged +#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)] pub struct LedgerUpdate { - pub zone_id: ZoneId, pub frontier_nodes: Vec, pub inputs: Vec, pub outputs: Vec, } +#[derive(Debug, Clone, PartialEq, Eq, Default)] pub struct LedgerUpdateWitness { - pub zone_id: ZoneId, pub frontier_nodes: Vec, pub inputs: Vec, pub outputs: Vec<(NoteCommitment, Vec)>, @@ -88,15 +88,10 @@ impl LedgerUpdateWitness { .collect::>() }, ))); - let root = merkle::root(&merkle::padded_leaves([ - input_root, - output_root, - self.zone_id, - ])); + let root = merkle::root(&merkle::padded_leaves([input_root, output_root])); ( LedgerUpdate { - zone_id: self.zone_id, inputs: self.inputs, outputs: self.outputs.into_iter().map(|(cm, _)| cm).collect(), frontier_nodes: self.frontier_nodes, @@ -104,6 +99,19 @@ impl LedgerUpdateWitness { root, ) } + + pub fn add_input(&mut self, nf: Nullifier, mmr: MMR) -> &mut Self { + self.inputs.push(nf); + self.frontier_nodes.extend(mmr.roots); + self.frontier_nodes.sort(); + self.frontier_nodes.dedup(); + self + } + + pub fn add_output(&mut self, cm: NoteCommitment, data: Vec) -> &mut Self { + self.outputs.push((cm, data)); + self + } } impl TxWitness { @@ -118,17 +126,19 @@ impl TxWitness { self } - pub fn compute_updates(&self, inputs: &[InputDerivedFields]) -> Vec { - let mut updates = BTreeMap::new(); + pub fn compute_updates( + &self, + inputs: &[InputDerivedFields], + ) -> BTreeMap { + let mut updates: BTreeMap = Default::default(); + assert_eq!(self.inputs.len(), self.frontier_paths.len()); for (input, (mmr, path)) in inputs.iter().zip(&self.frontier_paths) { - let entry = updates.entry(input.zone_id).or_insert(LedgerUpdateWitness { - zone_id: input.zone_id, - inputs: vec![], - outputs: vec![], - frontier_nodes: mmr.roots.clone(), - }); - entry.inputs.push(input.nf); + let entry = updates + .entry(input.zone_id) + .or_default() + .add_input(input.nf, mmr.clone()); + assert!(mmr.verify_proof(&input.cm.0, path)); // ensure a single MMR per zone per tx assert_eq!(&mmr.roots, &entry.frontier_nodes); @@ -138,17 +148,11 @@ impl TxWitness { assert!(output.value > 0); updates .entry(output.zone_id) - .or_insert(LedgerUpdateWitness { - zone_id: output.zone_id, - inputs: vec![], - outputs: vec![], - frontier_nodes: vec![], - }) - .outputs - .push((output.note_commitment(), data.clone())); // TODO: avoid clone + .or_default() + .add_output(output.note_commitment(), data.clone()); // TODO: avoid clone } - updates.into_values().collect() + updates } pub fn mint_amounts(&self) -> Vec { @@ -232,11 +236,15 @@ impl TxWitness { ) -> Tx { let mint_burn_root = Self::mint_burn_root(mints, burns); - let (updates, updates_roots): (Vec<_>, Vec<_>) = self + let (updates, updates_roots): (BTreeMap<_, _>, Vec<_>) = self .compute_updates(inputs) .into_iter() - .map(LedgerUpdateWitness::commit) + .map(|(zone_id, update)| { + let (update_cm, update_root) = update.commit(); + ((zone_id, update_cm), merkle::node(zone_id, update_root)) + }) .unzip(); + let update_root = merkle::root(&merkle::padded_leaves(updates_roots)); let root = self.root(update_root, mint_burn_root); let balance = self.balance(mints, burns); @@ -251,7 +259,7 @@ impl TxWitness { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct Bundle { - pub updates: Vec, + pub updates: BTreeMap, pub root: BundleRoot, } @@ -268,37 +276,25 @@ impl BundleWitness { self.txs.iter().map(|tx| tx.root.0), ))); - let updates = self + let mut updates = self .txs .into_iter() .fold(BTreeMap::new(), |mut updates, tx| { - for update in tx.updates { - let entry = updates.entry(update.zone_id).or_insert(LedgerUpdate { - zone_id: update.zone_id, - inputs: vec![], - outputs: vec![], - frontier_nodes: vec![], - }); - + for (zone_id, update) in tx.updates { + let entry: &mut LedgerUpdate = updates.entry(zone_id).or_default(); entry.inputs.extend(update.inputs); entry.outputs.extend(update.outputs); entry.frontier_nodes.extend(update.frontier_nodes); // TODO: maybe merge? } updates - }) - .into_values() - .collect::>(); + }); // de-dup frontier nodes - let updates = updates - .into_iter() - .map(|mut update| { - update.frontier_nodes.sort(); - update.frontier_nodes.dedup(); - update - }) - .collect(); + updates.iter_mut().for_each(|(_, update)| { + update.frontier_nodes.sort(); + update.frontier_nodes.dedup(); + }); Bundle { updates, root } } diff --git a/emmarin/cl/cl/src/mantle/ledger.rs b/emmarin/cl/cl/src/mantle/ledger.rs index f0a358f..b4e4dbf 100644 --- a/emmarin/cl/cl/src/mantle/ledger.rs +++ b/emmarin/cl/cl/src/mantle/ledger.rs @@ -1,5 +1,5 @@ use crate::{ - crust::{tx::LedgerUpdate, Bundle, NoteCommitment, Nullifier}, + crust::{BundleRoot, NoteCommitment, Nullifier}, ds::{ indexed::{BatchUpdateProof, NullifierTree}, mmr::{MMRProof, MMR}, @@ -38,8 +38,8 @@ impl LedgerWitness { self.commitments.push(&cm.0); } - pub fn add_bundle(&mut self, bundle_root: [u8; 32]) { - self.bundles.push(&bundle_root); + pub fn add_bundle(&mut self, bundle_root: BundleRoot) { + self.bundles.push(&bundle_root.0); } pub fn assert_nfs_update(&mut self, nullifiers: &[Nullifier], proof: &BatchUpdateProof) { @@ -77,8 +77,8 @@ impl LedgerState { self.nullifiers.insert_batch(nfs) } - pub fn add_bundle(&mut self, bundle_root: [u8; 32]) -> (MMR, MMRProof) { - let proof = self.bundles.push(&bundle_root); + pub fn add_bundle(&mut self, bundle_root: BundleRoot) -> (MMR, MMRProof) { + let proof = self.bundles.push(&bundle_root.0); (self.bundles.clone(), proof) } } diff --git a/emmarin/cl/ledger/src/ledger.rs b/emmarin/cl/ledger/src/ledger.rs index f26c1b9..d2496f4 100644 --- a/emmarin/cl/ledger/src/ledger.rs +++ b/emmarin/cl/ledger/src/ledger.rs @@ -25,8 +25,7 @@ impl ProvedLedgerTransition { let zone_ledger_update = bundle .updates - .iter() - .find(|update| update.zone_id == zone_id) + .get(&zone_id) .expect("why are we proving this bundle for this zone if it's not involved?"); let cm_root_proofs = @@ -45,7 +44,7 @@ impl ProvedLedgerTransition { cm_root_proofs, }; - w_bundles.push(ledger_bundle) + w_bundles.push(ledger_bundle); } let witness = LedgerProofPrivate { @@ -56,13 +55,17 @@ impl ProvedLedgerTransition { }; for bundle in &witness.bundles { - for update in &bundle.bundle.updates { - if update.zone_id == zone_id { - for cm in &update.outputs { - ledger.add_commitment(cm); - } - } + let update = bundle + .bundle + .updates + .get(&zone_id) + .expect("should have a bundle from the zone we are proofing for"); + + for cm in &update.outputs { + ledger.add_commitment(cm); } + + ledger.add_bundle(bundle.bundle.root); } witness.write(&mut env); diff --git a/emmarin/cl/ledger/src/update.rs b/emmarin/cl/ledger/src/update.rs index 4876e38..6ee2935 100644 --- a/emmarin/cl/ledger/src/update.rs +++ b/emmarin/cl/ledger/src/update.rs @@ -45,15 +45,10 @@ impl ProvedBatchUpdate { .zip(self.stf_proofs.iter()) .zip(self.ledger_proofs.iter()) { - if ledger_proof.public().old_ledger != update.old.ledger - || ledger_proof.public().ledger != update.new.ledger - { - return false; - } - - if stf_proof.public.old != update.old || stf_proof.public.new != update.new { - return false; - } + assert_eq!(ledger_proof.public().old_ledger, update.old.ledger); + assert_eq!(ledger_proof.public().ledger, update.new.ledger); + assert_eq!(stf_proof.public.old, update.old); + assert_eq!(stf_proof.public.new, update.new); } true diff --git a/emmarin/cl/ledger_risc0_proof/src/bin/ledger.rs b/emmarin/cl/ledger_risc0_proof/src/bin/ledger.rs index 1ff387a..7014183 100644 --- a/emmarin/cl/ledger_risc0_proof/src/bin/ledger.rs +++ b/emmarin/cl/ledger_risc0_proof/src/bin/ledger.rs @@ -29,38 +29,37 @@ fn main() { ) .unwrap(); - let zones = Vec::from_iter(bundle.updates.iter().map(|update| update.zone_id)); - if !(zones.len() == 1 && zones[0] == id) { + if bundle.updates.len() > 1 { // This is a cross zone bundle, add a sync log for it to ensure all zones // also approve it. sync_logs.push(SyncLog { bundle: bundle.root, - zones, + zones: bundle.updates.keys().copied().collect(), }); } - if let Some(ledger_update) = bundle + let ledger_update = bundle .updates - .into_iter() - .find(|update| update.zone_id == id) - { - for node in &ledger_update.frontier_nodes { - let past_cm_root_proof = cm_root_proofs - .get(&node.root) - .expect("missing cm root proof"); - let expected_current_cm_root = merkle::path_root(node.root, past_cm_root_proof); - assert!(old_ledger.valid_cm_root(expected_current_cm_root)) - } + .get(&id) + .expect("attempting to prove a bundle that is not for this zone"); - for cm in &ledger_update.outputs { - ledger.add_commitment(cm); - outputs.push(*cm); - } + for node in &ledger_update.frontier_nodes { + let past_cm_root_proof = cm_root_proofs + .get(&node.root) + .expect("missing cm root proof"); - nullifiers.extend(ledger_update.inputs); + let expected_current_cm_root = merkle::path_root(node.root, past_cm_root_proof); + assert!(old_ledger.valid_cm_root(expected_current_cm_root)) } - ledger.add_bundle(bundle.root.0); + for cm in &ledger_update.outputs { + ledger.add_commitment(cm); + outputs.push(*cm); + } + + nullifiers.extend(ledger_update.inputs.clone()); + + ledger.add_bundle(bundle.root); } // TODO: sort outside and check diff --git a/emmarin/cl/risc0_images/src/BUNDLE_ELF b/emmarin/cl/risc0_images/src/BUNDLE_ELF index 2e6ecc2..b6fa81b 100755 Binary files a/emmarin/cl/risc0_images/src/BUNDLE_ELF and b/emmarin/cl/risc0_images/src/BUNDLE_ELF differ diff --git a/emmarin/cl/risc0_images/src/BUNDLE_ID b/emmarin/cl/risc0_images/src/BUNDLE_ID index e11a90d..6865f9d 100644 --- a/emmarin/cl/risc0_images/src/BUNDLE_ID +++ b/emmarin/cl/risc0_images/src/BUNDLE_ID @@ -1 +1 @@ -d6149899df54b0114942f4be1ec773ba771d7f6a9d4201c31a4d75038455eaf3 \ No newline at end of file +8ad828fccc168801663aea5e10c8d17019f0bdbb69fa1a169400603535880fcd \ No newline at end of file diff --git a/emmarin/cl/risc0_images/src/LEDGER_ELF b/emmarin/cl/risc0_images/src/LEDGER_ELF index 40b250d..78cd0b3 100755 Binary files a/emmarin/cl/risc0_images/src/LEDGER_ELF and b/emmarin/cl/risc0_images/src/LEDGER_ELF differ diff --git a/emmarin/cl/risc0_images/src/LEDGER_ID b/emmarin/cl/risc0_images/src/LEDGER_ID index bd4bb63..55474e4 100644 --- a/emmarin/cl/risc0_images/src/LEDGER_ID +++ b/emmarin/cl/risc0_images/src/LEDGER_ID @@ -1 +1 @@ -02ed858ba11b19067319841ec824903318526d6c87c3dd1b0ac2330783d7078e \ No newline at end of file +fef663705ca009bdaa893c842d084848ddfbbf737441a801b6778125a3a5493c \ No newline at end of file diff --git a/emmarin/cl/risc0_images/src/STF_NOP_ELF b/emmarin/cl/risc0_images/src/STF_NOP_ELF index 16e4f77..fc51403 100755 Binary files a/emmarin/cl/risc0_images/src/STF_NOP_ELF and b/emmarin/cl/risc0_images/src/STF_NOP_ELF differ diff --git a/emmarin/cl/risc0_images/src/STF_NOP_ID b/emmarin/cl/risc0_images/src/STF_NOP_ID index a4c8cd1..c6ac81c 100644 --- a/emmarin/cl/risc0_images/src/STF_NOP_ID +++ b/emmarin/cl/risc0_images/src/STF_NOP_ID @@ -1 +1 @@ -400ac4e7c9cc351b84227e090e474c299546cce1db2f6836a8fc22b25aa4a317 \ No newline at end of file +29a96bc98531b44e806051daff1be35fe84e00f4cd7f45de0213c1387184c12e \ No newline at end of file diff --git a/emmarin/cl/risc0_images/src/TX_ELF b/emmarin/cl/risc0_images/src/TX_ELF index c8e910c..adec01d 100755 Binary files a/emmarin/cl/risc0_images/src/TX_ELF and b/emmarin/cl/risc0_images/src/TX_ELF differ diff --git a/emmarin/cl/risc0_images/src/TX_ID b/emmarin/cl/risc0_images/src/TX_ID index fdf4b21..2da2300 100644 --- a/emmarin/cl/risc0_images/src/TX_ID +++ b/emmarin/cl/risc0_images/src/TX_ID @@ -1 +1 @@ -ec8a16b24c6ba20fe44b3758bed22da59fe7012d2dd8e5b184c1d17f7f8d2c1f \ No newline at end of file +68a7c458b6ff62901c0176a1ff9433e431d635a3a94b169af7227ac5b1681606 \ No newline at end of file