From 7be3820a9fd63e073722fd903dbbf6386d8bdd15 Mon Sep 17 00:00:00 2001 From: David Rusu Date: Mon, 24 Feb 2025 18:08:24 +0400 Subject: [PATCH] builder apis --- emmarin/cl/cl/src/crust/iow.rs | 61 ++++++++++++++++++++++ emmarin/cl/cl/src/crust/tx.rs | 13 ++++- emmarin/cl/cl/src/mantle/ledger.rs | 5 +- emmarin/cl/ledger/tests/simple_transfer.rs | 56 +++++--------------- 4 files changed, 89 insertions(+), 46 deletions(-) diff --git a/emmarin/cl/cl/src/crust/iow.rs b/emmarin/cl/cl/src/crust/iow.rs index c6b2386..71f1e12 100644 --- a/emmarin/cl/cl/src/crust/iow.rs +++ b/emmarin/cl/cl/src/crust/iow.rs @@ -86,6 +86,67 @@ pub struct OutputWitness { } impl OutputWitness { + pub fn new( + value: u64, + unit: Unit, + nf_pk: NullifierCommitment, + zone_id: ZoneId, + rng: impl RngCore, + ) -> Self { + Self { + state: [0; 32], + value, + unit, + nonce: Nonce::random(rng), + zone_id, + nf_pk, + } + } + + pub fn reissue(input: InputWitness, rng: impl RngCore) -> Self { + Self::new( + input.value, + input.unit_witness.unit(), + input.nf_sk.commit(), + input.zone_id, + rng, + ) + } + + pub fn split_input( + input: InputWitness, + amount: u64, + to_pk: NullifierCommitment, + to_zone: ZoneId, + mut rng: impl RngCore, + ) -> (OutputWitness, OutputWitness) { + assert!(input.value > amount); + + let transfer = OutputWitness::reissue(input, &mut rng) + .set_value(amount) + .set_nf_pk(to_pk) + .set_zone(to_zone); + + let change = OutputWitness::reissue(input, &mut rng).set_value(input.value - amount); + + (transfer, change) + } + + pub fn set_value(mut self, value: u64) -> Self { + self.value = value; + self + } + + pub fn set_nf_pk(mut self, nf_pk: NullifierCommitment) -> Self { + self.nf_pk = nf_pk; + self + } + + pub fn set_zone(mut self, zone_id: ZoneId) -> Self { + self.zone_id = zone_id; + self + } + pub fn note_commitment(&self) -> NoteCommitment { NoteCommitment::commit( self.state, diff --git a/emmarin/cl/cl/src/crust/tx.rs b/emmarin/cl/cl/src/crust/tx.rs index 08da634..2e13860 100644 --- a/emmarin/cl/cl/src/crust/tx.rs +++ b/emmarin/cl/cl/src/crust/tx.rs @@ -53,7 +53,7 @@ pub struct Tx { pub updates: Vec, } -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)] pub struct TxWitness { pub inputs: Vec, pub outputs: Vec<(OutputWitness, Vec)>, @@ -107,6 +107,17 @@ impl LedgerUpdateWitness { } impl TxWitness { + pub fn add_input(mut self, input: InputWitness, input_cm_proof: (MMR, MMRProof)) -> Self { + self.inputs.push(input); + self.frontier_paths.push(input_cm_proof); + self + } + + pub fn add_output(mut self, output: OutputWitness, data: Vec) -> Self { + self.outputs.push((output, data)); + self + } + pub fn compute_updates(&self, inputs: &[InputDerivedFields]) -> Vec { let mut updates = BTreeMap::new(); assert_eq!(self.inputs.len(), self.frontier_paths.len()); diff --git a/emmarin/cl/cl/src/mantle/ledger.rs b/emmarin/cl/cl/src/mantle/ledger.rs index d17d62e..212f2ba 100644 --- a/emmarin/cl/cl/src/mantle/ledger.rs +++ b/emmarin/cl/cl/src/mantle/ledger.rs @@ -57,8 +57,9 @@ impl LedgerState { self.nullifiers.root() } - pub fn add_commitment(&mut self, cm: &NoteCommitment) -> MMRProof { - self.commitments.push(&cm.0) + pub fn add_commitment(&mut self, cm: &NoteCommitment) -> (MMR, MMRProof) { + let proof = self.commitments.push(&cm.0); + (self.commitments.clone(), proof) } pub fn add_nullifiers(&mut self, nfs: Vec) -> BatchUpdateProof { diff --git a/emmarin/cl/ledger/tests/simple_transfer.rs b/emmarin/cl/ledger/tests/simple_transfer.rs index 36fae69..a90b9eb 100644 --- a/emmarin/cl/ledger/tests/simple_transfer.rs +++ b/emmarin/cl/ledger/tests/simple_transfer.rs @@ -19,6 +19,9 @@ use ledger_proof_statements::stf::StfPublic; use rand::Rng; use rand_core::CryptoRngCore; +const ZONE_A: ZoneId = [0u8; 32]; +const ZONE_B: ZoneId = [1u8; 32]; + fn nmo() -> UnitWitness { UnitWitness { spending_covenant: NOP_COVENANT, @@ -53,38 +56,14 @@ fn cross_transfer_transition( mut ledger_out: LedgerState, ) -> (ProvedLedgerTransition, ProvedLedgerTransition) { assert!(amount <= input.value); - println!("nfs in zone_a: {}", ledger_in.nullifiers.len()); - println!("nfs in zone_b: {}", ledger_out.nullifiers.len()); - let mut rng = rand::thread_rng(); - let change = input.value - amount; - let transfer = OutputWitness { - state: Default::default(), - value: amount, - unit: nmo().unit(), - nonce: Nonce::random(&mut rng), - zone_id: to_zone, - nf_pk: to.pk(), - }; - let change = OutputWitness { - state: Default::default(), - value: change, - unit: nmo().unit(), - nonce: Nonce::random(&mut rng), - zone_id: input.zone_id, - nf_pk: input.nf_sk.commit(), // return change to sender - }; + let (transfer, change) = OutputWitness::split_input(input, amount, to.pk(), to_zone, &mut rng); - // Construct the tx consuming the input and producing the two outputs. - let tx_witness = TxWitness { - inputs: vec![input], - outputs: vec![(transfer, vec![]), (change, vec![])], - data: Default::default(), - mints: vec![], - burns: vec![], - frontier_paths: vec![input_proof], - }; + let tx_witness = TxWitness::default() + .add_input(input, input_proof) + .add_output(transfer, vec![]) + .add_output(change, vec![]); let proved_tx = ProvedTx::prove( tx_witness.clone(), @@ -129,34 +108,25 @@ fn cross_transfer_transition( fn zone_update_cross() { let mut rng = rand::thread_rng(); - let zone_a_id = [0; 32]; - let zone_b_id = [1; 32]; - // alice is sending 8 NMO to bob. let alice = User::random(&mut rng); let bob = User::random(&mut rng); // Alice has an unspent note worth 10 NMO - let utxo = OutputWitness { - state: Default::default(), - value: 10, - unit: nmo().unit(), - nonce: Nonce::random(&mut rng), - zone_id: zone_a_id, - nf_pk: alice.pk(), - }; + let utxo = OutputWitness::new(10, nmo().unit(), alice.pk(), ZONE_A, &mut rng); let alice_input = InputWitness::from_output(utxo, alice.sk(), nmo()); let mut ledger_a = LedgerState::default(); + + // To make the scenario a bit more realistic, we fill the nullifier set with a bunch of nullififiers ledger_a.add_nullifiers( std::iter::repeat_with(|| Nullifier(rng.gen())) .take(2_usize.pow(10)) .collect(), ); - let alice_cm_path = ledger_a.add_commitment(&utxo.note_commitment()); - let alice_cm_proof = (ledger_a.commitments.clone(), alice_cm_path); + let alice_cm_proof = ledger_a.add_commitment(&utxo.note_commitment()); let ledger_b = LedgerState::default(); @@ -177,7 +147,7 @@ fn zone_update_cross() { alice_cm_proof, bob, 8, - zone_b_id, + ZONE_B, ledger_a, ledger_b, );