185 lines
4.6 KiB
Rust
Raw Normal View History

2024-11-22 18:15:56 +01:00
use cl::{
crust::{
balance::{UnitWitness, NOP_COVENANT},
BundleWitness, InputWitness, NoteCommitment, Nullifier, NullifierCommitment,
NullifierSecret, OutputWitness, TxWitness,
2024-11-22 18:15:56 +01:00
},
ds::mmr::{MMRProof, MMR},
mantle::{
2024-12-06 13:44:53 +04:00
ledger::LedgerState,
update::{BatchUpdate, Update},
ZoneId, ZoneState,
2024-11-25 13:06:53 +01:00
},
2024-11-22 18:15:56 +01:00
};
2024-11-18 14:07:04 +01:00
use ledger::{
bundle::ProvedBundle, ledger::ProvedLedgerTransition, stf::StfProof, tx::ProvedTx,
update::ProvedBatchUpdate,
2024-11-18 14:07:04 +01:00
};
use ledger_proof_statements::stf::StfPublic;
use rand::{Rng, RngCore};
2024-11-18 14:07:04 +01:00
use rand_core::CryptoRngCore;
2024-11-25 13:06:53 +01:00
const ZONE_A: ZoneId = [0u8; 32];
const ZONE_B: ZoneId = [1u8; 32];
fn nmo() -> UnitWitness {
UnitWitness {
spending_covenant: NOP_COVENANT,
minting_covenant: NOP_COVENANT,
burning_covenant: NOP_COVENANT,
2025-02-27 18:07:25 +01:00
arg: [0; 32],
}
2024-11-25 13:06:53 +01:00
}
2024-11-18 14:07:04 +01:00
2024-11-22 18:15:56 +01:00
struct User(NullifierSecret);
2024-11-18 14:07:04 +01:00
impl User {
fn random(mut rng: impl CryptoRngCore) -> Self {
2024-11-22 18:15:56 +01:00
Self(NullifierSecret::random(&mut rng))
2024-11-18 14:07:04 +01:00
}
2024-11-22 18:15:56 +01:00
fn pk(&self) -> NullifierCommitment {
2024-11-18 14:07:04 +01:00
self.0.commit()
}
2024-11-22 18:15:56 +01:00
fn sk(&self) -> NullifierSecret {
2024-11-18 14:07:04 +01:00
self.0
}
}
2024-11-25 13:06:53 +01:00
fn cross_transfer_transition(
input: InputWitness,
2024-12-06 23:47:54 +04:00
input_proof: (MMR, MMRProof),
2024-11-25 13:06:53 +01:00
to: User,
amount: u64,
to_zone: ZoneId,
ledger_in: &mut LedgerState,
ledger_out: &mut LedgerState,
2024-11-25 13:06:53 +01:00
) -> (ProvedLedgerTransition, ProvedLedgerTransition) {
assert!(amount <= input.value);
2024-12-06 13:44:53 +04:00
let mut rng = rand::thread_rng();
let (transfer, change) =
OutputWitness::spend_with_change(input, amount, to.pk(), to_zone, &mut rng);
2024-11-18 14:07:04 +01:00
let tx_witness = TxWitness::default()
.add_input(input, input_proof)
2025-03-11 22:15:16 +01:00
.add_output(transfer, "")
.add_output(change, "");
let proved_tx = ProvedTx::prove(
tx_witness.clone(),
vec![],
vec![], // we can skip covenant proofs since NMO uses no-op spend covenants
)
.unwrap();
2024-11-18 14:07:04 +01:00
2025-03-11 22:15:16 +01:00
let bundle = ProvedBundle::prove(vec![proved_tx]);
2024-11-18 14:07:04 +01:00
2024-12-09 15:23:43 +04:00
println!("proving ledger A transition");
let ledger_in_transition =
ProvedLedgerTransition::prove(ledger_in, input.zone_id, vec![bundle.clone()]);
2024-11-18 14:07:04 +01:00
2024-12-09 15:23:43 +04:00
println!("proving ledger B transition");
let ledger_out_transition = ProvedLedgerTransition::prove(ledger_out, to_zone, vec![bundle]);
(ledger_in_transition, ledger_out_transition)
}
2024-11-18 14:07:04 +01:00
struct ZoneWitness {
ledger: LedgerState,
}
2024-11-25 13:06:53 +01:00
impl ZoneWitness {
fn new() -> Self {
let ledger = LedgerState::default();
2024-11-25 13:06:53 +01:00
Self { ledger }
}
2024-11-25 13:06:53 +01:00
fn state(&self) -> ZoneState {
ZoneState {
stf: StfProof::nop_stf(),
zone_data: [0; 32],
ledger: self.ledger.to_witness().commit(),
}
}
fn fill_nfs(&mut self, amount: usize, mut rng: impl RngCore) {
self.ledger.add_nullifiers(
std::iter::repeat_with(|| Nullifier(rng.gen()))
.take(amount)
.collect(),
);
}
fn add_commitment(&mut self, cm: &NoteCommitment) -> (MMR, MMRProof) {
self.ledger.add_commitment(cm)
}
2024-11-25 13:06:53 +01:00
}
#[test]
fn zone_update_cross() {
let mut rng = rand::thread_rng();
// Alice is sending 8 NMO to bob.
2024-11-25 13:06:53 +01:00
let alice = User::random(&mut rng);
let bob = User::random(&mut rng);
// Alice has an unspent note worth 10 NMO
let utxo = OutputWitness::new(10, nmo().unit(), alice.pk(), ZONE_A, &mut rng);
2024-11-25 13:06:53 +01:00
let alice_input = InputWitness::from_output(utxo, alice.sk(), nmo());
2024-11-25 13:06:53 +01:00
let mut zone_a = ZoneWitness::new();
zone_a.fill_nfs(2_usize.pow(10), &mut rng);
let alice_cm_proof = zone_a.add_commitment(&utxo.note_commitment());
2024-11-25 13:06:53 +01:00
let mut zone_b = ZoneWitness::new();
let (zone_a_old, zone_b_old) = (zone_a.state(), zone_b.state());
2024-11-25 13:06:53 +01:00
let (ledger_proof_a, ledger_proof_b) = cross_transfer_transition(
2024-11-25 13:06:53 +01:00
alice_input,
2024-12-06 23:47:54 +04:00
alice_cm_proof,
2024-11-25 13:06:53 +01:00
bob,
8,
ZONE_B,
&mut zone_a.ledger,
&mut zone_b.ledger,
2024-11-25 13:06:53 +01:00
);
let (zone_a_new, zone_b_new) = (zone_a.state(), zone_b.state());
2024-11-25 13:06:53 +01:00
let stf_proof_a = StfProof::prove_nop(StfPublic {
old: zone_a_old,
new: zone_a_new,
});
let stf_proof_b = StfProof::prove_nop(StfPublic {
old: zone_b_old,
new: zone_b_new,
});
let batch = BatchUpdate {
2024-11-25 13:06:53 +01:00
updates: vec![
Update {
2024-11-25 13:06:53 +01:00
old: zone_a_old,
new: zone_a_new,
},
Update {
2024-11-25 13:06:53 +01:00
old: zone_b_old,
new: zone_b_new,
},
],
};
let proved_batch = ProvedBatchUpdate {
batch,
ledger_proofs: vec![ledger_proof_a, ledger_proof_b],
2024-11-25 13:06:53 +01:00
stf_proofs: vec![stf_proof_a, stf_proof_b],
};
assert!(proved_batch.verify());
2024-11-18 14:07:04 +01:00
}