1#[cfg(feature = "wallet_essentials")]
4use std::io::{Read, Write};
5
6#[cfg(feature = "wallet_essentials")]
7use byteorder::{ReadBytesExt, WriteBytesExt};
8
9#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
14pub enum PerformanceLevel {
15 Low,
18 Medium,
21 #[default]
23 High,
24 Maximum,
30}
31
32#[cfg(feature = "wallet_essentials")]
33impl PerformanceLevel {
34 fn serialized_version() -> u8 {
35 0
36 }
37
38 pub fn read<R: Read>(mut reader: R) -> std::io::Result<Self> {
40 crate::wallet::serialization::read_version(
41 &mut reader,
42 "PerformanceLevel",
43 Self::serialized_version(),
44 )?;
45
46 Ok(match reader.read_u8()? {
47 0 => Self::Low,
48 1 => Self::Medium,
49 2 => Self::High,
50 3 => Self::Maximum,
51 _ => {
52 return Err(std::io::Error::new(
53 std::io::ErrorKind::InvalidData,
54 "failed to read valid performance level",
55 ));
56 }
57 })
58 }
59
60 pub fn write<W: Write>(&mut self, mut writer: W) -> std::io::Result<()> {
62 writer.write_u8(Self::serialized_version())?;
63
64 writer.write_u8(match self {
65 Self::Low => 0,
66 Self::Medium => 1,
67 Self::High => 2,
68 Self::Maximum => 3,
69 })?;
70
71 Ok(())
72 }
73}
74
75impl std::fmt::Display for PerformanceLevel {
76 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
77 match self {
78 Self::Low => write!(f, "low"),
79 Self::Medium => write!(f, "medium"),
80 Self::High => write!(f, "high"),
81 Self::Maximum => write!(f, "maximum"),
82 }
83 }
84}
85
86#[derive(Default, Debug, Clone, PartialEq, Eq)]
88pub struct SyncConfig {
89 pub transparent_address_discovery: TransparentAddressDiscovery,
91 pub performance_level: PerformanceLevel,
93 pub shutdown_on_completion: bool,
103}
104
105#[cfg(feature = "wallet_essentials")]
106impl SyncConfig {
107 fn serialized_version() -> u8 {
108 2
109 }
110
111 pub fn read<R: Read>(mut reader: R) -> std::io::Result<Self> {
113 let version = crate::wallet::serialization::read_version(
114 &mut reader,
115 "SyncConfig",
116 Self::serialized_version(),
117 )?;
118
119 let gap_limit = reader.read_u8()?;
120 let scopes = reader.read_u8()?;
121 let performance_level = if version >= 1 {
122 PerformanceLevel::read(&mut reader)?
123 } else {
124 PerformanceLevel::High
125 };
126 let shutdown_on_completion = if version >= 2 {
127 reader.read_u8()? != 0
128 } else {
129 false
130 };
131
132 Ok(Self {
133 transparent_address_discovery: TransparentAddressDiscovery {
134 gap_limit,
135 scopes: TransparentAddressDiscoveryScopes {
136 external: scopes & 0b1 != 0,
137 internal: scopes & 0b10 != 0,
138 refund: scopes & 0b100 != 0,
139 },
140 },
141 performance_level,
142 shutdown_on_completion,
143 })
144 }
145
146 pub fn write<W: Write>(&mut self, mut writer: W) -> std::io::Result<()> {
148 writer.write_u8(Self::serialized_version())?;
149 writer.write_u8(self.transparent_address_discovery.gap_limit)?;
150 let mut scopes = 0;
151 if self.transparent_address_discovery.scopes.external {
152 scopes |= 0b1;
153 }
154 if self.transparent_address_discovery.scopes.internal {
155 scopes |= 0b10;
156 }
157 if self.transparent_address_discovery.scopes.refund {
158 scopes |= 0b100;
159 }
160 writer.write_u8(scopes)?;
161 self.performance_level.write(&mut writer)?;
162 writer.write_u8(self.shutdown_on_completion as u8)?;
163
164 Ok(())
165 }
166}
167
168#[derive(Debug, Clone, PartialEq, Eq)]
172pub struct TransparentAddressDiscovery {
173 pub gap_limit: u8,
175 pub scopes: TransparentAddressDiscoveryScopes,
177}
178
179impl Default for TransparentAddressDiscovery {
180 fn default() -> Self {
181 Self {
182 gap_limit: 10,
183 scopes: TransparentAddressDiscoveryScopes::default(),
184 }
185 }
186}
187
188impl TransparentAddressDiscovery {
189 #[must_use]
191 pub fn minimal() -> Self {
192 Self {
193 gap_limit: 1,
194 scopes: TransparentAddressDiscoveryScopes::default(),
195 }
196 }
197
198 #[must_use]
200 pub fn recovery() -> Self {
201 Self {
202 gap_limit: 20,
203 scopes: TransparentAddressDiscoveryScopes::recovery(),
204 }
205 }
206
207 #[must_use]
210 pub fn disabled() -> Self {
211 Self {
212 gap_limit: 0,
213 scopes: TransparentAddressDiscoveryScopes {
214 external: false,
215 internal: false,
216 refund: false,
217 },
218 }
219 }
220}
221
222#[derive(Debug, Clone, PartialEq, Eq)]
224pub struct TransparentAddressDiscoveryScopes {
225 pub external: bool,
227 pub internal: bool,
229 pub refund: bool,
231}
232
233impl Default for TransparentAddressDiscoveryScopes {
234 fn default() -> Self {
235 Self {
236 external: true,
237 internal: false,
238 refund: true,
239 }
240 }
241}
242
243impl TransparentAddressDiscoveryScopes {
244 #[must_use]
246 pub fn recovery() -> Self {
247 Self {
248 external: true,
249 internal: true,
250 refund: true,
251 }
252 }
253}
254
255#[cfg(all(test, feature = "wallet_essentials"))]
256mod tests {
257 use super::*;
258
259 #[test]
262 fn readers_refuse_serialized_versions_above_their_own() {
263 let newer_sync_config = [SyncConfig::serialized_version() + 1];
264 let newer_performance_level = [PerformanceLevel::serialized_version() + 1];
265
266 for (type_name, read) in [
267 (
268 "SyncConfig",
269 SyncConfig::read(newer_sync_config.as_slice()).map(drop),
270 ),
271 (
272 "PerformanceLevel",
273 PerformanceLevel::read(newer_performance_level.as_slice()).map(drop),
274 ),
275 ] {
276 assert_eq!(
277 read.expect_err(type_name).kind(),
278 std::io::ErrorKind::InvalidData,
279 "{type_name}"
280 );
281 }
282 }
283}