pepper_sync/
config.rs

1//! Sync configuration.
2
3#[cfg(feature = "wallet_essentials")]
4use std::io::{Read, Write};
5
6#[cfg(feature = "wallet_essentials")]
7use byteorder::{ReadBytesExt, WriteBytesExt};
8
9/// Performance level.
10///
11/// The higher the performance level the higher the memory usage and storage.
12// TODO: revisit after implementing nullifier refetching
13#[derive(Default, Debug, Clone, Copy)]
14pub enum PerformanceLevel {
15    /// - number of outputs per batch is quartered
16    /// - nullifier map only contains chain tip
17    Low,
18    /// - nullifier map has a small maximum size
19    /// - nullifier map only contains chain tip
20    Medium,
21    /// - nullifier map has a large maximum size
22    #[default]
23    High,
24    /// - number of outputs per batch is quadrupled
25    /// - nullifier map has no maximum size
26    ///
27    /// WARNING: this may cause the wallet to become less responsive on slower systems and may use a lot of memory for
28    /// wallets with a lot of transactions.
29    Maximum,
30}
31
32#[cfg(feature = "wallet_essentials")]
33impl PerformanceLevel {
34    fn serialized_version() -> u8 {
35        0
36    }
37
38    /// Deserialize into `reader`
39    pub fn read<R: Read>(mut reader: R) -> std::io::Result<Self> {
40        let _version = reader.read_u8()?;
41
42        Ok(match reader.read_u8()? {
43            0 => Self::Low,
44            1 => Self::Medium,
45            2 => Self::High,
46            3 => Self::Maximum,
47            _ => {
48                return Err(std::io::Error::new(
49                    std::io::ErrorKind::InvalidData,
50                    "failed to read valid performance level",
51                ));
52            }
53        })
54    }
55
56    /// Serialize into `writer`
57    pub fn write<W: Write>(&mut self, mut writer: W) -> std::io::Result<()> {
58        writer.write_u8(Self::serialized_version())?;
59
60        writer.write_u8(match self {
61            Self::Low => 0,
62            Self::Medium => 1,
63            Self::High => 2,
64            Self::Maximum => 3,
65        })?;
66
67        Ok(())
68    }
69}
70
71impl std::fmt::Display for PerformanceLevel {
72    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
73        match self {
74            Self::Low => write!(f, "low"),
75            Self::Medium => write!(f, "medium"),
76            Self::High => write!(f, "high"),
77            Self::Maximum => write!(f, "maximum"),
78        }
79    }
80}
81
82/// Sync configuration.
83#[derive(Default, Debug, Clone)]
84pub struct SyncConfig {
85    /// Transparent address discovery configuration.
86    pub transparent_address_discovery: TransparentAddressDiscovery,
87    /// Performance level
88    pub performance_level: PerformanceLevel,
89}
90
91#[cfg(feature = "wallet_essentials")]
92impl SyncConfig {
93    fn serialized_version() -> u8 {
94        1
95    }
96
97    /// Deserialize into `reader`
98    pub fn read<R: Read>(mut reader: R) -> std::io::Result<Self> {
99        let version = reader.read_u8()?;
100
101        let gap_limit = reader.read_u8()?;
102        let scopes = reader.read_u8()?;
103        let performance_level = if version >= 1 {
104            PerformanceLevel::read(reader)?
105        } else {
106            PerformanceLevel::High
107        };
108        Ok(Self {
109            transparent_address_discovery: TransparentAddressDiscovery {
110                gap_limit,
111                scopes: TransparentAddressDiscoveryScopes {
112                    external: scopes & 0b1 != 0,
113                    internal: scopes & 0b10 != 0,
114                    refund: scopes & 0b100 != 0,
115                },
116            },
117            performance_level,
118        })
119    }
120
121    /// Serialize into `writer`
122    pub fn write<W: Write>(&mut self, mut writer: W) -> std::io::Result<()> {
123        writer.write_u8(Self::serialized_version())?;
124        writer.write_u8(self.transparent_address_discovery.gap_limit)?;
125        let mut scopes = 0;
126        if self.transparent_address_discovery.scopes.external {
127            scopes |= 0b1;
128        }
129        if self.transparent_address_discovery.scopes.internal {
130            scopes |= 0b10;
131        }
132        if self.transparent_address_discovery.scopes.refund {
133            scopes |= 0b100;
134        }
135        writer.write_u8(scopes)?;
136        self.performance_level.write(writer)?;
137
138        Ok(())
139    }
140}
141
142/// Transparent address configuration.
143///
144/// Sets which `scopes` will be searched for addresses in use, scanning relevant transactions, up to a given `gap_limit`.
145#[derive(Debug, Clone)]
146pub struct TransparentAddressDiscovery {
147    /// Sets the gap limit for transparent address discovery.
148    pub gap_limit: u8,
149    /// Sets the scopes for transparent address discovery.
150    pub scopes: TransparentAddressDiscoveryScopes,
151}
152
153impl Default for TransparentAddressDiscovery {
154    fn default() -> Self {
155        Self {
156            gap_limit: 10,
157            scopes: TransparentAddressDiscoveryScopes::default(),
158        }
159    }
160}
161
162impl TransparentAddressDiscovery {
163    /// Constructs a transparent address discovery config with a gap limit of 1 and ignoring the internal scope.
164    #[must_use]
165    pub fn minimal() -> Self {
166        Self {
167            gap_limit: 1,
168            scopes: TransparentAddressDiscoveryScopes::default(),
169        }
170    }
171
172    /// Constructs a transparent address discovery config with a gap limit of 20 for all scopes.
173    #[must_use]
174    pub fn recovery() -> Self {
175        Self {
176            gap_limit: 20,
177            scopes: TransparentAddressDiscoveryScopes::recovery(),
178        }
179    }
180
181    /// Disables transparent address discovery. Sync will only scan transparent outputs for addresses already in the
182    /// wallet in transactions that also contain shielded inputs or outputs relevant to the wallet.
183    #[must_use]
184    pub fn disabled() -> Self {
185        Self {
186            gap_limit: 0,
187            scopes: TransparentAddressDiscoveryScopes {
188                external: false,
189                internal: false,
190                refund: false,
191            },
192        }
193    }
194}
195
196/// Sets the active scopes for transparent address recovery.
197#[derive(Debug, Clone)]
198pub struct TransparentAddressDiscoveryScopes {
199    /// External.
200    pub external: bool,
201    /// Internal.
202    pub internal: bool,
203    /// Refund.
204    pub refund: bool,
205}
206
207impl Default for TransparentAddressDiscoveryScopes {
208    fn default() -> Self {
209        Self {
210            external: true,
211            internal: false,
212            refund: true,
213        }
214    }
215}
216
217impl TransparentAddressDiscoveryScopes {
218    /// Constructor with all all scopes active.
219    #[must_use]
220    pub fn recovery() -> Self {
221        Self {
222            external: true,
223            internal: true,
224            refund: true,
225        }
226    }
227}