penumbra_sdk_shielded_pool/component/
note_manager.rs1use anyhow::Result;
2use async_trait::async_trait;
3use cnidarium::StateWrite;
4use penumbra_sdk_asset::Value;
5use penumbra_sdk_keys::Address;
6use penumbra_sdk_sct::component::tree::{SctManager, SctRead};
7use penumbra_sdk_sct::CommitmentSource;
8use penumbra_sdk_tct as tct;
9use tct::StateCommitment;
10use tracing::instrument;
11
12use crate::state_key;
13use crate::{Note, NotePayload, Rseed};
14
15#[async_trait]
17pub trait NoteManager: StateWrite {
18 #[instrument(skip(self, value, address, source))]
24 async fn mint_note(
25 &mut self,
26 value: Value,
27 address: &Address,
28 source: CommitmentSource,
29 ) -> Result<()> {
30 tracing::debug!(?value, ?address, "minting tokens");
31
32 let position: u64 = self
41 .get_sct()
42 .await
43 .position()
44 .expect("state commitment tree is not full")
45 .into();
46
47 let rseed_bytes: [u8; 32] = blake2b_simd::Params::default()
48 .personal(b"PenumbraMint")
49 .to_state()
50 .update(&position.to_le_bytes())
51 .finalize()
52 .as_bytes()[0..32]
53 .try_into()?;
54
55 let note = Note::from_parts(address.clone(), value, Rseed(rseed_bytes))?;
56 self.add_note_payload(note.payload(), source).await;
57
58 Ok(())
59 }
60
61 #[instrument(skip(self, note_payload, source), fields(commitment = ?note_payload.note_commitment))]
62 async fn add_note_payload(&mut self, note_payload: NotePayload, source: CommitmentSource) {
63 tracing::debug!(source = ?source);
64
65 let position = self.add_sct_commitment(note_payload.note_commitment, source.clone())
70 .await
71 .expect("inserting into the state commitment tree should not fail because we should budget commitments per block (currently unimplemented)");
73
74 let mut payloads = self.pending_note_payloads();
76 payloads.push_back((position, note_payload, source));
77 self.object_put(state_key::pending_notes(), payloads);
78 }
79
80 #[instrument(skip(self, note_commitment))]
81 async fn add_rolled_up_payload(
82 &mut self,
83 note_commitment: StateCommitment,
84 source: CommitmentSource,
85 ) {
86 tracing::debug!(?note_commitment);
87
88 let position = self.add_sct_commitment(note_commitment, source)
93 .await
94 .expect("inserting into the state commitment tree should not fail because we should budget commitments per block (currently unimplemented)");
96
97 let mut payloads = self.pending_rolled_up_payloads();
99 payloads.push_back((position, note_commitment));
100 self.object_put(state_key::pending_rolled_up_payloads(), payloads);
101 }
102
103 fn pending_note_payloads(&self) -> im::Vector<(tct::Position, NotePayload, CommitmentSource)> {
104 self.object_get(state_key::pending_notes())
105 .unwrap_or_default()
106 }
107
108 fn pending_rolled_up_payloads(&self) -> im::Vector<(tct::Position, StateCommitment)> {
109 self.object_get(state_key::pending_rolled_up_payloads())
110 .unwrap_or_default()
111 }
112}
113
114impl<T: StateWrite + ?Sized> NoteManager for T {}