sapling_crypto/pczt/
updater.rs

1use alloc::string::String;
2use alloc::vec::Vec;
3
4use crate::ProofGenerationKey;
5
6use super::{Bundle, Output, Spend, Zip32Derivation};
7
8impl Bundle {
9    /// Updates the bundle with information provided in the given closure.
10    pub fn update_with<F>(&mut self, f: F) -> Result<(), UpdaterError>
11    where
12        F: FnOnce(Updater<'_>) -> Result<(), UpdaterError>,
13    {
14        f(Updater(self))
15    }
16}
17
18/// An updater for a Sapling PCZT bundle.
19pub struct Updater<'a>(&'a mut Bundle);
20
21impl Updater<'_> {
22    /// Provides read access to the bundle being updated.
23    pub fn bundle(&self) -> &Bundle {
24        self.0
25    }
26
27    /// Updates the spend at the given index with information provided in the given
28    /// closure.
29    pub fn update_spend_with<F>(&mut self, index: usize, f: F) -> Result<(), UpdaterError>
30    where
31        F: FnOnce(SpendUpdater<'_>) -> Result<(), UpdaterError>,
32    {
33        f(SpendUpdater(
34            self.0
35                .spends
36                .get_mut(index)
37                .ok_or(UpdaterError::InvalidIndex)?,
38        ))
39    }
40
41    /// Updates the output at the given index with information provided in the given
42    /// closure.
43    pub fn update_output_with<F>(&mut self, index: usize, f: F) -> Result<(), UpdaterError>
44    where
45        F: FnOnce(OutputUpdater<'_>) -> Result<(), UpdaterError>,
46    {
47        f(OutputUpdater(
48            self.0
49                .outputs
50                .get_mut(index)
51                .ok_or(UpdaterError::InvalidIndex)?,
52        ))
53    }
54}
55
56/// An updater for a Sapling PCZT spend.
57pub struct SpendUpdater<'a>(&'a mut Spend);
58
59impl SpendUpdater<'_> {
60    /// Sets the proof generation key for this spend.
61    ///
62    /// Returns an error if the proof generation key does not match the spend.
63    pub fn set_proof_generation_key(
64        &mut self,
65        proof_generation_key: ProofGenerationKey,
66    ) -> Result<(), UpdaterError> {
67        // TODO: Verify that the proof generation key matches the spend, if possible.
68        self.0.proof_generation_key = Some(proof_generation_key);
69        Ok(())
70    }
71
72    /// Sets the ZIP 32 derivation path for the spent note's signing key.
73    pub fn set_zip32_derivation(&mut self, derivation: Zip32Derivation) {
74        self.0.zip32_derivation = Some(derivation);
75    }
76
77    /// Stores the given proprietary value at the given key.
78    pub fn set_proprietary(&mut self, key: String, value: Vec<u8>) {
79        self.0.proprietary.insert(key, value);
80    }
81}
82
83/// An updater for a Sapling PCZT output.
84pub struct OutputUpdater<'a>(&'a mut Output);
85
86impl OutputUpdater<'_> {
87    /// Sets the ZIP 32 derivation path for the new note's signing key.
88    pub fn set_zip32_derivation(&mut self, derivation: Zip32Derivation) {
89        self.0.zip32_derivation = Some(derivation);
90    }
91
92    /// Sets the user-facing address that the new note is being sent to.
93    pub fn set_user_address(&mut self, user_address: String) {
94        self.0.user_address = Some(user_address);
95    }
96
97    /// Stores the given proprietary value at the given key.
98    pub fn set_proprietary(&mut self, key: String, value: Vec<u8>) {
99        self.0.proprietary.insert(key, value);
100    }
101}
102
103/// Errors that can occur while updating a Sapling bundle in a PCZT.
104#[derive(Debug)]
105pub enum UpdaterError {
106    /// An out-of-bounds index was provided when looking up a spend or output.
107    InvalidIndex,
108    /// The provided `proof_generation_key` does not match the spend.
109    WrongProofGenerationKey,
110}