mirror of
https://github.com/logos-blockchain/logos-blockchain-pocs.git
synced 2026-02-19 20:43:07 +00:00
consume goal notes in the executor tx
This commit is contained in:
parent
2947329764
commit
bfb8594112
@ -69,14 +69,14 @@ impl SwapArgs {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn swap_goal_note(nonce: Nonce) -> OutputWitness {
|
||||
OutputWitness {
|
||||
pub fn swap_goal_note(nonce: Nonce) -> InputWitness {
|
||||
InputWitness {
|
||||
state: [0u8; 32],
|
||||
value: 1,
|
||||
unit: swap_goal_unit().unit(),
|
||||
unit_witness: swap_goal_unit(),
|
||||
nonce,
|
||||
zone_id: ZONE_ID,
|
||||
nf_pk: NullifierSecret::zero().commit(),
|
||||
nf_sk: NullifierSecret::zero(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
use app::ZoneData;
|
||||
use cl::crust::{NullifierSecret, UnitWitness};
|
||||
use cl::crust::UnitWitness;
|
||||
|
||||
fn nmo() -> UnitWitness {
|
||||
UnitWitness::nop(b"NMO")
|
||||
@ -10,8 +10,6 @@ fn mem() -> UnitWitness {
|
||||
|
||||
#[test]
|
||||
fn pair_price() {
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
let mut swapvm_state = ZoneData::new();
|
||||
|
||||
// initially there is no NMO/MEM pair
|
||||
|
||||
@ -1,16 +1,15 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use app::{swap_goal_unit, SwapArgs, ZoneData};
|
||||
use cl::crust::{
|
||||
BundleWitness, InputWitness, Nonce, NoteCommitment, Nullifier, NullifierSecret, Tx, TxWitness,
|
||||
Unit,
|
||||
};
|
||||
use cl::ds::mmr::{MMRProof, MMR};
|
||||
use cl::crust::{BundleWitness, InputWitness, NoteCommitment, Nullifier, Tx, TxWitness, Unit};
|
||||
use cl::ds::mmr::{MMRFolds, MMRProof, MMR};
|
||||
use cl::mantle::ledger::Ledger;
|
||||
use cl::mantle::ledger::LedgerState;
|
||||
use cl::mantle::ZoneState;
|
||||
use ledger::stf::{risc0_stf, StfProof};
|
||||
use ledger_proof_statements::ledger::SyncLog;
|
||||
use methods::{STF_ELF, STF_ID};
|
||||
use risc0_zkvm::{ExecutorEnv, Prover, Receipt, Result};
|
||||
use risc0_zkvm::{ExecutorEnv, Prover, Result};
|
||||
|
||||
#[derive(Debug)]
|
||||
struct FundNote {
|
||||
@ -33,31 +32,84 @@ pub struct ExecutorState {
|
||||
pub ledger: LedgerState,
|
||||
pub swapvm: ZoneData,
|
||||
fund_notes: BTreeMap<Unit, FundNote>,
|
||||
goal_notes: Vec<(InputWitness, MMR, MMRProof)>,
|
||||
}
|
||||
|
||||
impl ExecutorState {
|
||||
pub fn observe_cms(&mut self, cms: impl IntoIterator<Item = NoteCommitment>) {
|
||||
for cm in cms {
|
||||
self.ledger.add_commitment(&cm);
|
||||
pub fn zone_state(&self) -> ZoneState {
|
||||
ZoneState {
|
||||
stf: risc0_stf(STF_ID),
|
||||
zone_data: self.swapvm.commit(),
|
||||
ledger: self.ledger.to_witness().commit(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn observe_cm(&mut self, cm: &NoteCommitment) -> ((MMR, MMRProof), MMRFolds) {
|
||||
let folds = self.ledger.commitments.folds(&cm.0);
|
||||
|
||||
for (_, fund_note) in self.fund_notes.iter_mut() {
|
||||
assert_eq!(fund_note.mmr, self.ledger.commitments);
|
||||
fund_note
|
||||
.path
|
||||
.update(&fund_note.note.note_commitment().0, &folds);
|
||||
}
|
||||
|
||||
let proof = self.ledger.add_commitment(cm);
|
||||
|
||||
for (_, fund_note) in self.fund_notes.iter_mut() {
|
||||
fund_note.mmr = self.ledger.commitments.clone();
|
||||
}
|
||||
|
||||
(proof, folds)
|
||||
}
|
||||
|
||||
pub fn observe_nfs(&mut self, nfs: Vec<Nullifier>) {
|
||||
self.ledger.add_nullifiers(nfs);
|
||||
}
|
||||
|
||||
pub fn process_tx(&mut self, tx: &Tx) {
|
||||
let Some(swapvm_update) = tx.updates.get(&self.swapvm.zone_id) else {
|
||||
// this tx is not related to the swapvm zone
|
||||
return;
|
||||
};
|
||||
|
||||
let mut output_mmr_proofs = BTreeMap::<NoteCommitment, MMRProof>::new();
|
||||
|
||||
for (cm, _) in &swapvm_update.outputs {
|
||||
let (proof, folds) = self.observe_cm(cm);
|
||||
|
||||
for (other_cm, other_cm_proof) in output_mmr_proofs.iter_mut() {
|
||||
other_cm_proof.update(&other_cm.0, &folds);
|
||||
}
|
||||
|
||||
output_mmr_proofs.insert(*cm, proof.1);
|
||||
|
||||
for (other_cm, other_cm_proof) in &output_mmr_proofs {
|
||||
assert!(self
|
||||
.ledger
|
||||
.commitments
|
||||
.verify_proof(&other_cm.0, &other_cm_proof))
|
||||
}
|
||||
}
|
||||
|
||||
for nf in &swapvm_update.inputs {
|
||||
self.ledger.add_nullifiers(vec![*nf]);
|
||||
}
|
||||
|
||||
if tx.balance.unit_balance(swap_goal_unit().unit()).is_neg() {
|
||||
// this is a SWAP
|
||||
let (swap_cm, swap_args_bytes) =
|
||||
&tx.updates.get(&self.swapvm.zone_id).unwrap().outputs[0];
|
||||
let (swap_goal_cm, swap_args_bytes) = &swapvm_update.outputs[0];
|
||||
let swap_args: SwapArgs = cl::deserialize(&swap_args_bytes);
|
||||
|
||||
// verify the user proved the correct swap goal note
|
||||
assert_eq!(
|
||||
swap_cm,
|
||||
&app::swap_goal_note(swap_args.nonce).note_commitment()
|
||||
);
|
||||
let swap_goal_witness = app::swap_goal_note(swap_args.nonce);
|
||||
assert_eq!(swap_goal_cm, &swap_goal_witness.note_commitment());
|
||||
|
||||
self.goal_notes.push((
|
||||
swap_goal_witness,
|
||||
self.ledger.commitments.clone(),
|
||||
output_mmr_proofs[swap_goal_cm].clone(),
|
||||
));
|
||||
|
||||
// assume there are only the goal unit and tokenIn units at play
|
||||
assert_eq!(tx.balance.balances.len(), 2);
|
||||
@ -76,14 +128,6 @@ impl ExecutorState {
|
||||
let amount_in = balance_in.pos;
|
||||
self.swapvm.swap(token_in, amount_in, swap_args);
|
||||
}
|
||||
for (cm, _) in tx
|
||||
.updates
|
||||
.get(&self.swapvm.zone_id)
|
||||
.map(|u| u.outputs.iter())
|
||||
.unwrap_or_default()
|
||||
{
|
||||
self.ledger.add_commitment(cm);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_and_get_executor_tx(&mut self) -> (TxWitness, Vec<InputWitness>) {
|
||||
@ -103,14 +147,7 @@ impl ExecutorState {
|
||||
let note = if let Some(note) = fund_notes.get(&unit) {
|
||||
note.evolve(value)
|
||||
} else {
|
||||
InputWitness {
|
||||
state: [0; 32],
|
||||
value,
|
||||
unit_witness: todo!(),
|
||||
nonce: Nonce::from_bytes([0; 32]),
|
||||
zone_id: self.swapvm.zone_id,
|
||||
nf_sk: NullifierSecret([0; 16]),
|
||||
}
|
||||
panic!("dynamically created fund notes are not supported");
|
||||
};
|
||||
new_fund_notes.push(note);
|
||||
let output = note.to_output();
|
||||
@ -124,6 +161,10 @@ impl ExecutorState {
|
||||
tx = tx.add_input(note, (mmr, path));
|
||||
}
|
||||
|
||||
for (goal_note, mmr, path) in std::mem::take(&mut self.goal_notes) {
|
||||
tx = tx.add_input(goal_note, (mmr, path));
|
||||
}
|
||||
|
||||
(tx, new_fund_notes)
|
||||
}
|
||||
|
||||
@ -143,7 +184,7 @@ pub struct StfPrivate {
|
||||
}
|
||||
|
||||
impl StfPrivate {
|
||||
pub fn prove(&self, prover: &dyn Prover) -> Result<Receipt> {
|
||||
pub fn prove(&self, prover: &dyn Prover) -> Result<StfProof> {
|
||||
let env = ExecutorEnv::builder()
|
||||
.write(&self.zone_data)?
|
||||
.write(&self.old_ledger)?
|
||||
@ -156,6 +197,7 @@ impl StfPrivate {
|
||||
let prove_info = prover.prove(env, STF_ELF)?;
|
||||
|
||||
debug_assert!(prove_info.receipt.verify(STF_ID).is_ok());
|
||||
Ok(prove_info.receipt)
|
||||
|
||||
Ok(StfProof::from_risc0(risc0_stf(STF_ID), prove_info.receipt))
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,10 @@
|
||||
use app::ZONE_ID;
|
||||
use cl::crust::{BundleWitness, InputWitness, Nonce, NullifierSecret, TxWitness, UnitWitness};
|
||||
use cl::mantle::ledger::LedgerState;
|
||||
use cl::mantle::update::{BatchUpdate, Update};
|
||||
use host::{ExecutorState, StfPrivate};
|
||||
use ledger::ledger::ProvedLedgerTransition;
|
||||
use ledger::update::ProvedBatchUpdate;
|
||||
use ledger::{bundle::ProvedBundle, tx::ProvedTx};
|
||||
use rand::RngCore;
|
||||
|
||||
@ -25,9 +28,7 @@ fn setup_executor(mut rng: impl RngCore, ledger: LedgerState) -> ExecutorState {
|
||||
nf_sk: NullifierSecret::zero(),
|
||||
};
|
||||
|
||||
let (mmr, mmr_proof) = exec_state
|
||||
.ledger
|
||||
.add_commitment(&nmo_fund.note_commitment());
|
||||
let ((mmr, mmr_proof), _) = exec_state.observe_cm(&nmo_fund.note_commitment());
|
||||
exec_state.set_fund_note(nmo_fund, mmr, mmr_proof);
|
||||
|
||||
let mem_fund = InputWitness {
|
||||
@ -38,9 +39,7 @@ fn setup_executor(mut rng: impl RngCore, ledger: LedgerState) -> ExecutorState {
|
||||
zone_id: ZONE_ID,
|
||||
nf_sk: NullifierSecret::zero(),
|
||||
};
|
||||
let (mmr, mmr_proof) = exec_state
|
||||
.ledger
|
||||
.add_commitment(&mem_fund.note_commitment());
|
||||
let ((mmr, mmr_proof), _) = exec_state.observe_cm(&mem_fund.note_commitment());
|
||||
exec_state.set_fund_note(mem_fund, mmr, mmr_proof);
|
||||
|
||||
// HACK: we don't currently support liquidity notes, we directly hard code the corresponding liquidity
|
||||
@ -77,11 +76,15 @@ fn simple_swap() {
|
||||
// Alice now has a valid 10 NMO note, she wants to swap it for 90 MEM
|
||||
// ---- begin swap ----
|
||||
|
||||
let old_zone_state = exec_state.zone_state();
|
||||
|
||||
let mut temp_ledger_state = exec_state.ledger.clone();
|
||||
|
||||
let swap_goal_nonce = Nonce::random(&mut rng);
|
||||
let swap_tx = TxWitness::default()
|
||||
.add_input(alice_in, alice_in_proof)
|
||||
.add_output(
|
||||
app::swap_goal_note(swap_goal_nonce),
|
||||
app::swap_goal_note(swap_goal_nonce).to_output(),
|
||||
app::SwapArgs {
|
||||
output: app::SwapOutput::basic(mem().unit(), ZONE_ID, alice_sk.commit(), &mut rng),
|
||||
limit: 90,
|
||||
@ -101,16 +104,44 @@ fn simple_swap() {
|
||||
let (exec_tx, fund_notes) = exec_state.update_and_get_executor_tx();
|
||||
let proved_exec_tx = ProvedTx::prove(exec_tx, vec![], vec![]).unwrap();
|
||||
|
||||
let swap_bundle = BundleWitness {
|
||||
txs: vec![swap_tx_proof.public(), proved_exec_tx.public()],
|
||||
};
|
||||
|
||||
let _ = swap_bundle.clone().commit();
|
||||
|
||||
let swap_bundle_proof = ProvedBundle::prove(vec![swap_tx_proof, proved_exec_tx]);
|
||||
|
||||
// prove stf
|
||||
StfPrivate {
|
||||
let stf_proof = StfPrivate {
|
||||
zone_data: exec_state.swapvm.clone(),
|
||||
old_ledger: ledger.to_witness().commit(),
|
||||
new_ledger: exec_state.ledger.clone().to_witness().commit(),
|
||||
sync_logs: Vec::new(),
|
||||
fund_notes,
|
||||
bundle: BundleWitness {
|
||||
txs: vec![swap_tx_proof.public(), proved_exec_tx.public()],
|
||||
},
|
||||
bundle: swap_bundle,
|
||||
}
|
||||
.prove(risc0_zkvm::default_prover().as_ref());
|
||||
.prove(risc0_zkvm::default_prover().as_ref())
|
||||
.unwrap();
|
||||
|
||||
let ledger_proof =
|
||||
ProvedLedgerTransition::prove(&mut temp_ledger_state, ZONE_ID, vec![swap_bundle_proof]);
|
||||
|
||||
let new_zone_state = exec_state.zone_state();
|
||||
|
||||
assert_eq!(ledger_proof.public().old_ledger, old_zone_state.ledger);
|
||||
assert_eq!(ledger_proof.public().ledger, new_zone_state.ledger);
|
||||
|
||||
let zone_update = ProvedBatchUpdate {
|
||||
batch: BatchUpdate {
|
||||
updates: vec![Update {
|
||||
old: old_zone_state,
|
||||
new: new_zone_state,
|
||||
}],
|
||||
},
|
||||
ledger_proofs: vec![ledger_proof],
|
||||
stf_proofs: vec![stf_proof],
|
||||
};
|
||||
|
||||
assert!(zone_update.verify())
|
||||
}
|
||||
|
||||
@ -108,8 +108,20 @@ impl LedgerUpdate {
|
||||
|
||||
impl TxWitness {
|
||||
pub fn add_input(mut self, input: InputWitness, input_cm_proof: (MMR, MMRProof)) -> Self {
|
||||
assert!(input_cm_proof
|
||||
.0
|
||||
.verify_proof(&input.note_commitment().0, &input_cm_proof.1));
|
||||
|
||||
for (i, other_input) in self.inputs.iter().enumerate() {
|
||||
if other_input.zone_id == input.zone_id {
|
||||
// ensure a single MMR per zone per tx
|
||||
assert_eq!(self.frontier_paths[i].0, input_cm_proof.0);
|
||||
}
|
||||
}
|
||||
|
||||
self.inputs.push(input);
|
||||
self.frontier_paths.push(input_cm_proof);
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
|
||||
@ -153,13 +153,13 @@ impl MMRProof {
|
||||
merkle::path_root(leaf, &self.path)
|
||||
}
|
||||
|
||||
pub fn update(&mut self, elem: &[u8], folds: MMRFolds) {
|
||||
for (l, r) in folds.folds {
|
||||
pub fn update(&mut self, elem: &[u8], folds: &MMRFolds) {
|
||||
for (l, r) in &folds.folds {
|
||||
let root = self.root(elem);
|
||||
if root == l {
|
||||
self.path.push(merkle::PathNode::Right(r))
|
||||
} else if root == r {
|
||||
self.path.push(merkle::PathNode::Left(l))
|
||||
if &root == l {
|
||||
self.path.push(merkle::PathNode::Right(*r))
|
||||
} else if &root == r {
|
||||
self.path.push(merkle::PathNode::Left(*l))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
@ -1 +1 @@
|
||||
48099ec33aa35c95b7bbe614fb6ca00accd456371a63b9c7720cd3a614301aa8
|
||||
beb565f9da33f558659da6d9f9fd68ebe3d7d14a3e7e8bba8aaadd32e9836f93
|
||||
Binary file not shown.
@ -1 +1 @@
|
||||
a1d3accfcff20421924c30f8195e956b522bda0847b3b3fab726c49e3205423b
|
||||
555127aec2abe879def82c31b50c2f2b19bf4e5456e7de31d9126fb77a9650d1
|
||||
Binary file not shown.
@ -1 +1 @@
|
||||
29a96bc98531b44e806051daff1be35fe84e00f4cd7f45de0213c1387184c12e
|
||||
557a0804bbf1220e66f4a695c24d57de02cb9fd52d646cb99dd43572561a6807
|
||||
Binary file not shown.
@ -1 +1 @@
|
||||
327c489a2c52ea70bcf161ed4b90d1d681afb2bc82be7f4e5cf12ebbb5595f71
|
||||
b332bcd5db82793c52664324cec76b67332d449bc4d7a2425a1e84c6d2282857
|
||||
Loading…
x
Reference in New Issue
Block a user