pepper_sync/wallet/
serialization.rs

1//! Serialization and de-serialization of wallet structs in [`crate::wallet`] including utilities.
2
3use std::{
4    collections::{BTreeMap, BTreeSet},
5    io::{Read, Write},
6};
7
8use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
9
10use incrementalmerkletree::{Hashable, Position};
11use shardtree::{
12    LocatedPrunableTree, ShardTree,
13    store::{Checkpoint, ShardStore, TreeState, memory::MemoryShardStore},
14};
15use zcash_client_backend::{
16    data_api::scanning::{ScanPriority, ScanRange},
17    serialization::shardtree::{read_shard, write_shard},
18};
19use zcash_encoding::{Optional, Vector};
20use zcash_primitives::{
21    block::BlockHash,
22    legacy::Script,
23    memo::Memo,
24    merkle_tree::HashSer,
25    transaction::{Transaction, TxId},
26};
27use zcash_protocol::{
28    consensus::{self, BlockHeight},
29    value::Zatoshis,
30};
31
32use zcash_transparent::keys::NonHardenedChildIndex;
33use zingo_status::confirmation_status::ConfirmationStatus;
34
35use crate::{
36    keys::{
37        KeyId, decode_unified_address,
38        transparent::{TransparentAddressId, TransparentScope},
39    },
40    sync::MAX_VERIFICATION_WINDOW,
41};
42
43use super::{
44    InitialSyncState, NullifierMap, OrchardNote, OutgoingNote, OutgoingNoteInterface,
45    OutgoingOrchardNote, OutgoingSaplingNote, OutputId, OutputInterface, SaplingNote, ShardTrees,
46    SyncState, TransparentCoin, TreeBounds, WalletBlock, WalletNote, WalletTransaction,
47};
48
49fn read_string<R: Read>(mut reader: R) -> std::io::Result<String> {
50    let str_len = reader.read_u64::<LittleEndian>()?;
51    let mut str_bytes = vec![0; str_len as usize];
52    reader.read_exact(&mut str_bytes)?;
53
54    String::from_utf8(str_bytes)
55        .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e.to_string()))
56}
57
58fn write_string<W: Write>(mut writer: W, str: &str) -> std::io::Result<()> {
59    writer.write_u64::<LittleEndian>(str.len() as u64)?;
60    writer.write_all(str.as_bytes())
61}
62
63impl SyncState {
64    fn serialized_version() -> u8 {
65        0
66    }
67
68    /// Deserialize into `reader`
69    pub fn read<R: Read>(mut reader: R) -> std::io::Result<Self> {
70        let _version = reader.read_u8()?;
71        let scan_ranges = Vector::read(&mut reader, |r| {
72            let start = BlockHeight::from_u32(r.read_u32::<LittleEndian>()?);
73            let end = BlockHeight::from_u32(r.read_u32::<LittleEndian>()?);
74            let priority = match r.read_u8()? {
75                0 => Ok(ScanPriority::Ignored),
76                1 => Ok(ScanPriority::Scanned),
77                2 => Ok(ScanPriority::Historic),
78                3 => Ok(ScanPriority::OpenAdjacent),
79                4 => Ok(ScanPriority::FoundNote),
80                5 => Ok(ScanPriority::ChainTip),
81                6 => Ok(ScanPriority::Verify),
82                _ => Err(std::io::Error::new(
83                    std::io::ErrorKind::InvalidData,
84                    "invalid scan priority",
85                )),
86            }?;
87
88            Ok(ScanRange::from_parts(start..end, priority))
89        })?;
90        let sapling_shard_ranges = Vector::read(&mut reader, |r| {
91            let start = BlockHeight::from_u32(r.read_u32::<LittleEndian>()?);
92            let end = BlockHeight::from_u32(r.read_u32::<LittleEndian>()?);
93
94            Ok(start..end)
95        })?;
96        let orchard_shard_ranges = Vector::read(&mut reader, |r| {
97            let start = BlockHeight::from_u32(r.read_u32::<LittleEndian>()?);
98            let end = BlockHeight::from_u32(r.read_u32::<LittleEndian>()?);
99
100            Ok(start..end)
101        })?;
102        let locators = Vector::read(&mut reader, |r| {
103            let block_height = BlockHeight::from_u32(r.read_u32::<LittleEndian>()?);
104            let txid = TxId::read(r)?;
105
106            Ok((block_height, txid))
107        })?
108        .into_iter()
109        .collect::<BTreeSet<_>>();
110
111        Ok(Self {
112            scan_ranges,
113            sapling_shard_ranges,
114            orchard_shard_ranges,
115            locators,
116            initial_sync_state: InitialSyncState::new(),
117        })
118    }
119
120    /// Serialize into `writer`
121    pub fn write<W: Write>(&mut self, mut writer: W) -> std::io::Result<()> {
122        writer.write_u8(Self::serialized_version())?;
123        Vector::write(&mut writer, self.scan_ranges(), |w, scan_range| {
124            w.write_u32::<LittleEndian>(scan_range.block_range().start.into())?;
125            w.write_u32::<LittleEndian>(scan_range.block_range().end.into())?;
126            w.write_u8(scan_range.priority() as u8)
127        })?;
128        Vector::write(&mut writer, &self.sapling_shard_ranges, |w, shard_range| {
129            w.write_u32::<LittleEndian>(shard_range.start.into())?;
130            w.write_u32::<LittleEndian>(shard_range.end.into())
131        })?;
132        Vector::write(&mut writer, &self.orchard_shard_ranges, |w, shard_range| {
133            w.write_u32::<LittleEndian>(shard_range.start.into())?;
134            w.write_u32::<LittleEndian>(shard_range.end.into())
135        })?;
136        Vector::write(
137            &mut writer,
138            &self.locators.iter().collect::<Vec<_>>(),
139            |w, &locator| {
140                w.write_u32::<LittleEndian>(locator.0.into())?;
141                locator.1.write(w)
142            },
143        )
144    }
145}
146
147impl TreeBounds {
148    fn serialized_version() -> u8 {
149        0
150    }
151
152    /// Deserialize into `reader`
153    pub fn read<R: Read>(mut reader: R) -> std::io::Result<Self> {
154        let _version = reader.read_u8()?;
155        let sapling_initial_tree_size = reader.read_u32::<LittleEndian>()?;
156        let sapling_final_tree_size = reader.read_u32::<LittleEndian>()?;
157        let orchard_initial_tree_size = reader.read_u32::<LittleEndian>()?;
158        let orchard_final_tree_size = reader.read_u32::<LittleEndian>()?;
159
160        Ok(Self {
161            sapling_initial_tree_size,
162            sapling_final_tree_size,
163            orchard_initial_tree_size,
164            orchard_final_tree_size,
165        })
166    }
167
168    /// Serialize into `writer`
169    pub fn write<W: Write>(&self, writer: &mut W) -> std::io::Result<()> {
170        writer.write_u8(Self::serialized_version())?;
171        writer.write_u32::<LittleEndian>(self.sapling_initial_tree_size)?;
172        writer.write_u32::<LittleEndian>(self.sapling_final_tree_size)?;
173        writer.write_u32::<LittleEndian>(self.orchard_initial_tree_size)?;
174        writer.write_u32::<LittleEndian>(self.orchard_final_tree_size)
175    }
176}
177
178impl NullifierMap {
179    fn serialized_version() -> u8 {
180        0
181    }
182
183    /// Deserialize into `reader`
184    pub fn read<R: Read>(mut reader: R) -> std::io::Result<Self> {
185        let _version = reader.read_u8()?;
186        let sapling = Vector::read(&mut reader, |mut r| {
187            let mut nullifier_bytes = [0u8; 32];
188            r.read_exact(&mut nullifier_bytes)?;
189            let nullifier =
190                sapling_crypto::Nullifier::from_slice(&nullifier_bytes).map_err(|e| {
191                    std::io::Error::new(
192                        std::io::ErrorKind::InvalidData,
193                        format!("failed to read nullifier. {e}"),
194                    )
195                })?;
196            let locator_height = BlockHeight::from_u32(r.read_u32::<LittleEndian>()?);
197            let locator_txid = TxId::read(&mut r)?;
198
199            Ok((nullifier, (locator_height, locator_txid)))
200        })?
201        .into_iter()
202        .collect::<BTreeMap<_, _>>();
203
204        let orchard = Vector::read(&mut reader, |mut r| {
205            let mut nullifier_bytes = [0u8; 32];
206            r.read_exact(&mut nullifier_bytes)?;
207            let nullifier = orchard::note::Nullifier::from_bytes(&nullifier_bytes)
208                .expect("nullifier bytes should be valid");
209            let locator_height = BlockHeight::from_u32(r.read_u32::<LittleEndian>()?);
210            let locator_txid = TxId::read(&mut r)?;
211
212            Ok((nullifier, (locator_height, locator_txid)))
213        })?
214        .into_iter()
215        .collect::<BTreeMap<_, _>>();
216
217        Ok(NullifierMap { sapling, orchard })
218    }
219
220    /// Serialize into `writer`
221    pub fn write<W: Write>(&self, mut writer: W) -> std::io::Result<()> {
222        writer.write_u8(Self::serialized_version())?;
223        Vector::write(
224            &mut writer,
225            &self.sapling.iter().collect::<Vec<_>>(),
226            |w, &(&nullifier, &locator)| {
227                w.write_all(nullifier.as_ref())?;
228                w.write_u32::<LittleEndian>(locator.0.into())?;
229                locator.1.write(w)
230            },
231        )?;
232        Vector::write(
233            &mut writer,
234            &self.orchard.iter().collect::<Vec<_>>(),
235            |w, &(&nullifier, &locator)| {
236                w.write_all(&nullifier.to_bytes())?;
237                w.write_u32::<LittleEndian>(locator.0.into())?;
238                locator.1.write(w)
239            },
240        )
241    }
242}
243
244impl WalletBlock {
245    fn serialized_version() -> u8 {
246        0
247    }
248
249    /// Deserialize into `reader`
250    pub fn read<R: Read>(mut reader: R) -> std::io::Result<Self> {
251        let _version = reader.read_u8()?;
252        let block_height = BlockHeight::from_u32(reader.read_u32::<LittleEndian>()?);
253        let mut block_hash = BlockHash([0u8; 32]);
254        reader.read_exact(&mut block_hash.0)?;
255        let mut prev_hash = BlockHash([0u8; 32]);
256        reader.read_exact(&mut prev_hash.0)?;
257        let time = reader.read_u32::<LittleEndian>()?;
258        let txids = Vector::read(&mut reader, |r| TxId::read(r))?;
259        let tree_bounds = TreeBounds::read(&mut reader)?;
260
261        Ok(Self {
262            block_height,
263            block_hash,
264            prev_hash,
265            time,
266            txids,
267            tree_bounds,
268        })
269    }
270
271    /// Serialize into `writer`
272    pub fn write<W: Write>(&self, mut writer: W) -> std::io::Result<()> {
273        writer.write_u8(Self::serialized_version())?;
274        writer.write_u32::<LittleEndian>(self.block_height.into())?;
275        writer.write_all(&self.block_hash.0)?;
276        writer.write_all(&self.prev_hash.0)?;
277        writer.write_u32::<LittleEndian>(self.time)?;
278        Vector::write(&mut writer, self.txids(), |w, txid| txid.write(w))?;
279        self.tree_bounds.write(&mut writer)
280    }
281}
282
283impl WalletTransaction {
284    fn serialized_version() -> u8 {
285        0
286    }
287
288    /// Deserialize into `reader`
289    pub fn read<R: Read>(
290        mut reader: R,
291        consensus_parameters: &impl consensus::Parameters,
292    ) -> std::io::Result<Self> {
293        let _version = reader.read_u8()?;
294        let txid = TxId::read(&mut reader)?;
295        let status = ConfirmationStatus::read(&mut reader)?;
296        let transaction = Transaction::read(
297            &mut reader,
298            consensus::BranchId::for_height(consensus_parameters, status.get_height()),
299        )?;
300        let datetime = reader.read_u32::<LittleEndian>()?;
301        let transparent_coins = Vector::read(&mut reader, |r| TransparentCoin::read(r))?;
302        let sapling_notes = Vector::read(&mut reader, |r| SaplingNote::read(r))?;
303        let orchard_notes = Vector::read(&mut reader, |r| OrchardNote::read(r))?;
304        let outgoing_sapling_notes = Vector::read(&mut reader, |r| {
305            OutgoingSaplingNote::read(r, consensus_parameters)
306        })?;
307        let outgoing_orchard_notes = Vector::read(&mut reader, |r| {
308            OutgoingOrchardNote::read(r, consensus_parameters)
309        })?;
310
311        Ok(Self {
312            txid,
313            status,
314            transaction,
315            datetime,
316            transparent_coins,
317            sapling_notes,
318            orchard_notes,
319            outgoing_sapling_notes,
320            outgoing_orchard_notes,
321        })
322    }
323
324    /// Serialize into `writer`
325    pub fn write<W: Write>(
326        &self,
327        mut writer: W,
328        consensus_parameters: &impl consensus::Parameters,
329    ) -> std::io::Result<()> {
330        writer.write_u8(Self::serialized_version())?;
331        self.txid.write(&mut writer)?;
332        self.status.write(&mut writer)?;
333        self.transaction.write(&mut writer)?;
334        writer.write_u32::<LittleEndian>(self.datetime)?;
335        Vector::write(&mut writer, self.transparent_coins(), |w, output| {
336            output.write(w)
337        })?;
338        Vector::write(&mut writer, self.sapling_notes(), |w, output| {
339            output.write(w)
340        })?;
341        Vector::write(&mut writer, self.orchard_notes(), |w, output| {
342            output.write(w)
343        })?;
344        Vector::write(&mut writer, self.outgoing_sapling_notes(), |w, output| {
345            output.write(w, consensus_parameters)
346        })?;
347        Vector::write(&mut writer, self.outgoing_orchard_notes(), |w, output| {
348            output.write(w, consensus_parameters)
349        })
350    }
351}
352
353impl TransparentCoin {
354    fn serialized_version() -> u8 {
355        0
356    }
357
358    /// Deserialize into `reader`
359    pub fn read<R: Read>(mut reader: R) -> std::io::Result<Self> {
360        let _version = reader.read_u8()?;
361
362        let txid = TxId::read(&mut reader)?;
363        let output_index = reader.read_u16::<LittleEndian>()?;
364
365        let account_id = zip32::AccountId::try_from(reader.read_u32::<LittleEndian>()?)
366            .expect("only valid account ids written");
367        let scope = TransparentScope::try_from(reader.read_u8()?)?;
368        let address_index = reader.read_u32::<LittleEndian>()?;
369
370        let address = read_string(&mut reader)?;
371        let script = Script::read(&mut reader)?;
372        let value = Zatoshis::from_u64(reader.read_u64::<LittleEndian>()?)
373            .expect("only valid values written");
374        let spending_transaction = Optional::read(&mut reader, TxId::read)?;
375
376        Ok(Self {
377            output_id: OutputId { txid, output_index },
378            key_id: TransparentAddressId::new(
379                account_id,
380                scope,
381                NonHardenedChildIndex::from_index(address_index)
382                    .expect("only non-hardened child indexes should be written"),
383            ),
384            address,
385            value,
386            script,
387            spending_transaction,
388        })
389    }
390
391    /// Serialize into `writer`
392    pub fn write<W: Write>(&self, mut writer: W) -> std::io::Result<()> {
393        writer.write_u8(Self::serialized_version())?;
394
395        self.output_id.txid().write(&mut writer)?;
396        writer.write_u16::<LittleEndian>(self.output_id.output_index())?;
397
398        writer.write_u32::<LittleEndian>(self.key_id.account_id().into())?;
399        writer.write_u8(self.key_id.scope() as u8)?;
400        writer.write_u32::<LittleEndian>(self.key_id.address_index().index())?;
401
402        write_string(&mut writer, &self.address)?;
403        self.script.write(&mut writer)?;
404        writer.write_u64::<LittleEndian>(self.value())?;
405        Optional::write(&mut writer, self.spending_transaction, |w, txid| {
406            txid.write(w)
407        })?;
408
409        Ok(())
410    }
411}
412
413impl<N, Nf: Copy> WalletNote<N, Nf> {
414    fn serialized_version() -> u8 {
415        0
416    }
417}
418
419impl SaplingNote {
420    /// Deserialize into `reader`
421    pub fn read<R: Read>(mut reader: R) -> std::io::Result<Self> {
422        let _version = reader.read_u8()?;
423
424        let txid = TxId::read(&mut reader)?;
425        let output_index = reader.read_u16::<LittleEndian>()?;
426
427        let account_id =
428            zip32::AccountId::try_from(reader.read_u32::<LittleEndian>()?).map_err(|e| {
429                std::io::Error::new(
430                    std::io::ErrorKind::InvalidData,
431                    format!("failed to read account id. {e}"),
432                )
433            })?;
434        let scope = match reader.read_u8()? {
435            0 => Ok(zip32::Scope::External),
436            1 => Ok(zip32::Scope::Internal),
437            _ => Err(std::io::Error::new(
438                std::io::ErrorKind::InvalidData,
439                "invalid scope value",
440            )),
441        }?;
442
443        let mut address_bytes = [0u8; 43];
444        reader.read_exact(&mut address_bytes)?;
445        let recipient =
446            sapling_crypto::PaymentAddress::from_bytes(&address_bytes).ok_or_else(|| {
447                std::io::Error::new(
448                    std::io::ErrorKind::InvalidData,
449                    "failed to read payment address",
450                )
451            })?;
452        let value = sapling_crypto::value::NoteValue::from_raw(reader.read_u64::<LittleEndian>()?);
453        let rseed_zip212 = reader.read_u8()?;
454        let mut rseed_bytes = [0u8; 32];
455        reader.read_exact(&mut rseed_bytes)?;
456        let rseed = match rseed_zip212 {
457            0 => sapling_crypto::Rseed::BeforeZip212(
458                jubjub::Fr::from_bytes(&rseed_bytes).expect("should read valid jubjub bytes"),
459            ),
460            1 => sapling_crypto::Rseed::AfterZip212(rseed_bytes),
461            _ => {
462                return Err(std::io::Error::new(
463                    std::io::ErrorKind::InvalidData,
464                    "invalid rseed zip212 byte",
465                ));
466            }
467        };
468
469        let nullifier = Optional::read(&mut reader, |r| {
470            let mut nullifier_bytes = [0u8; 32];
471            r.read_exact(&mut nullifier_bytes)?;
472
473            sapling_crypto::Nullifier::from_slice(&nullifier_bytes).map_err(|e| {
474                std::io::Error::new(
475                    std::io::ErrorKind::InvalidData,
476                    format!("failed to read nullifier. {e}"),
477                )
478            })
479        })?;
480        let position = Optional::read(&mut reader, |r| {
481            Ok(Position::from(r.read_u64::<LittleEndian>()?))
482        })?;
483        let mut memo_bytes = [0u8; 512];
484        reader.read_exact(&mut memo_bytes)?;
485        let memo = Memo::from_bytes(&memo_bytes).map_err(|e| {
486            std::io::Error::new(
487                std::io::ErrorKind::InvalidData,
488                format!("failed to read memo. {e}"),
489            )
490        })?;
491
492        let spending_transaction = Optional::read(&mut reader, TxId::read)?;
493
494        Ok(Self {
495            output_id: OutputId::new(txid, output_index),
496            key_id: KeyId::from_parts(account_id, scope),
497            note: sapling_crypto::Note::from_parts(recipient, value, rseed),
498            nullifier,
499            position,
500            memo,
501            spending_transaction,
502        })
503    }
504
505    /// Serialize into `writer`
506    pub fn write<W: Write>(&self, mut writer: W) -> std::io::Result<()> {
507        writer.write_u8(Self::serialized_version())?;
508
509        self.output_id.txid().write(&mut writer)?;
510        writer.write_u16::<LittleEndian>(self.output_id.output_index())?;
511
512        writer.write_u32::<LittleEndian>(self.key_id.account_id.into())?;
513        writer.write_u8(self.key_id.scope as u8)?;
514
515        writer.write_all(&self.note.recipient().to_bytes())?;
516        writer.write_u64::<LittleEndian>(self.value())?;
517        match self.note.rseed() {
518            sapling_crypto::Rseed::BeforeZip212(fr) => {
519                writer.write_u8(0)?;
520                writer.write_all(&fr.to_bytes())?;
521            }
522            sapling_crypto::Rseed::AfterZip212(bytes) => {
523                writer.write_u8(1)?;
524                writer.write_all(bytes)?;
525            }
526        }
527
528        Optional::write(&mut writer, self.nullifier, |w, nullifier| {
529            w.write_all(nullifier.as_ref())
530        })?;
531        Optional::write(&mut writer, self.position, |w, position| {
532            w.write_u64::<LittleEndian>(position.into())
533        })?;
534        writer.write_all(self.memo.encode().as_array())?;
535
536        Optional::write(&mut writer, self.spending_transaction, |w, txid| {
537            txid.write(w)
538        })
539    }
540}
541
542impl OrchardNote {
543    /// Deserialize into `reader`
544    pub fn read<R: Read>(mut reader: R) -> std::io::Result<Self> {
545        let _version = reader.read_u8()?;
546
547        let txid = TxId::read(&mut reader)?;
548        let output_index = reader.read_u16::<LittleEndian>()?;
549
550        let account_id =
551            zip32::AccountId::try_from(reader.read_u32::<LittleEndian>()?).map_err(|e| {
552                std::io::Error::new(
553                    std::io::ErrorKind::InvalidData,
554                    format!("failed to read account id. {e}"),
555                )
556            })?;
557        let scope = match reader.read_u8()? {
558            0 => Ok(zip32::Scope::External),
559            1 => Ok(zip32::Scope::Internal),
560            _ => Err(std::io::Error::new(
561                std::io::ErrorKind::InvalidData,
562                "invalid scope value",
563            )),
564        }?;
565
566        let mut address_bytes = [0u8; 43];
567        reader.read_exact(&mut address_bytes)?;
568        let recipient = orchard::Address::from_raw_address_bytes(&address_bytes)
569            .expect("should be a valid address");
570        let value = orchard::value::NoteValue::from_raw(reader.read_u64::<LittleEndian>()?);
571        let mut rho_bytes = [0u8; 32];
572        reader.read_exact(&mut rho_bytes)?;
573        let rho = orchard::note::Rho::from_bytes(&rho_bytes).expect("should be valid rho bytes");
574        let mut rseed_bytes = [0u8; 32];
575        reader.read_exact(&mut rseed_bytes)?;
576        let rseed = orchard::note::RandomSeed::from_bytes(rseed_bytes, &rho)
577            .expect("should be valid random seed bytes");
578
579        let nullifier = Optional::read(&mut reader, |r| {
580            let mut nullifier_bytes = [0u8; 32];
581            r.read_exact(&mut nullifier_bytes)?;
582
583            Ok(orchard::note::Nullifier::from_bytes(&nullifier_bytes)
584                .expect("should be valid nullfiier bytes"))
585        })?;
586        let position = Optional::read(&mut reader, |r| {
587            Ok(Position::from(r.read_u64::<LittleEndian>()?))
588        })?;
589        let mut memo_bytes = [0u8; 512];
590        reader.read_exact(&mut memo_bytes)?;
591        let memo = Memo::from_bytes(&memo_bytes).map_err(|e| {
592            std::io::Error::new(
593                std::io::ErrorKind::InvalidData,
594                format!("failed to read memo. {e}"),
595            )
596        })?;
597
598        let spending_transaction = Optional::read(&mut reader, TxId::read)?;
599
600        Ok(Self {
601            output_id: OutputId::new(txid, output_index),
602            key_id: KeyId::from_parts(account_id, scope),
603            note: orchard::note::Note::from_parts(recipient, value, rho, rseed)
604                .expect("should be a valid orchard note"),
605            nullifier,
606            position,
607            memo,
608            spending_transaction,
609        })
610    }
611
612    /// Serialize into `writer`
613    pub fn write<W: Write>(&self, mut writer: W) -> std::io::Result<()> {
614        writer.write_u8(Self::serialized_version())?;
615
616        self.output_id.txid().write(&mut writer)?;
617        writer.write_u16::<LittleEndian>(self.output_id.output_index())?;
618
619        writer.write_u32::<LittleEndian>(self.key_id.account_id.into())?;
620        writer.write_u8(self.key_id.scope as u8)?;
621
622        writer.write_all(&self.note.recipient().to_raw_address_bytes())?;
623        writer.write_u64::<LittleEndian>(self.value())?;
624        writer.write_all(&self.note.rho().to_bytes())?;
625        writer.write_all(self.note.rseed().as_bytes())?;
626
627        Optional::write(&mut writer, self.nullifier, |w, nullifier| {
628            w.write_all(&nullifier.to_bytes())
629        })?;
630        Optional::write(&mut writer, self.position, |w, position| {
631            w.write_u64::<LittleEndian>(position.into())
632        })?;
633        writer.write_all(self.memo.encode().as_array())?;
634        Optional::write(&mut writer, self.spending_transaction, |w, txid| {
635            txid.write(w)
636        })?;
637
638        Ok(())
639    }
640}
641
642impl<N> OutgoingNote<N> {
643    fn serialized_version() -> u8 {
644        0
645    }
646}
647
648impl OutgoingSaplingNote {
649    /// Deserialize into `reader`
650    pub fn read<R: Read>(
651        mut reader: R,
652        consensus_parameters: &impl consensus::Parameters,
653    ) -> std::io::Result<Self> {
654        let _version = reader.read_u8()?;
655
656        let txid = TxId::read(&mut reader)?;
657        let output_index = reader.read_u16::<LittleEndian>()?;
658
659        let account_id =
660            zip32::AccountId::try_from(reader.read_u32::<LittleEndian>()?).map_err(|e| {
661                std::io::Error::new(
662                    std::io::ErrorKind::InvalidData,
663                    format!("failed to read account id. {e}"),
664                )
665            })?;
666        let scope = match reader.read_u8()? {
667            0 => Ok(zip32::Scope::External),
668            1 => Ok(zip32::Scope::Internal),
669            _ => Err(std::io::Error::new(
670                std::io::ErrorKind::InvalidData,
671                "invalid scope value",
672            )),
673        }?;
674
675        let mut address_bytes = [0u8; 43];
676        reader.read_exact(&mut address_bytes)?;
677        let recipient =
678            sapling_crypto::PaymentAddress::from_bytes(&address_bytes).ok_or_else(|| {
679                std::io::Error::new(
680                    std::io::ErrorKind::InvalidData,
681                    "failed to read payment address",
682                )
683            })?;
684        let value = sapling_crypto::value::NoteValue::from_raw(reader.read_u64::<LittleEndian>()?);
685        let rseed_zip212 = reader.read_u8()?;
686        let mut rseed_bytes = [0u8; 32];
687        reader.read_exact(&mut rseed_bytes)?;
688        let rseed = match rseed_zip212 {
689            0 => sapling_crypto::Rseed::BeforeZip212(
690                jubjub::Fr::from_bytes(&rseed_bytes).expect("should read valid jubjub bytes"),
691            ),
692            1 => sapling_crypto::Rseed::AfterZip212(rseed_bytes),
693            _ => {
694                return Err(std::io::Error::new(
695                    std::io::ErrorKind::InvalidData,
696                    "invalid rseed zip212 byte",
697                ));
698            }
699        };
700
701        let mut memo_bytes = [0u8; 512];
702        reader.read_exact(&mut memo_bytes)?;
703        let memo = Memo::from_bytes(&memo_bytes).map_err(|e| {
704            std::io::Error::new(
705                std::io::ErrorKind::InvalidData,
706                format!("failed to read memo. {e}"),
707            )
708        })?;
709
710        let recipient_unified_address = Optional::read(&mut reader, |r| {
711            let encoded_address = read_string(r)?;
712
713            decode_unified_address(consensus_parameters, &encoded_address)
714        })?;
715
716        Ok(Self {
717            output_id: OutputId::new(txid, output_index),
718            key_id: KeyId::from_parts(account_id, scope),
719            note: sapling_crypto::Note::from_parts(recipient, value, rseed),
720            memo,
721            recipient_full_unified_address: recipient_unified_address,
722        })
723    }
724
725    /// Serialize into `writer`
726    pub fn write<W: Write>(
727        &self,
728        mut writer: W,
729        consensus_parameters: &impl consensus::Parameters,
730    ) -> std::io::Result<()> {
731        writer.write_u8(Self::serialized_version())?;
732
733        self.output_id.txid().write(&mut writer)?;
734        writer.write_u16::<LittleEndian>(self.output_id.output_index())?;
735
736        writer.write_u32::<LittleEndian>(self.key_id.account_id.into())?;
737        writer.write_u8(self.key_id.scope as u8)?;
738
739        writer.write_all(&self.note.recipient().to_bytes())?;
740        writer.write_u64::<LittleEndian>(self.value())?;
741        match self.note.rseed() {
742            sapling_crypto::Rseed::BeforeZip212(fr) => {
743                writer.write_u8(0)?;
744                writer.write_all(&fr.to_bytes())?;
745            }
746            sapling_crypto::Rseed::AfterZip212(bytes) => {
747                writer.write_u8(1)?;
748                writer.write_all(bytes)?;
749            }
750        }
751
752        writer.write_all(self.memo.encode().as_array())?;
753        Optional::write(
754            &mut writer,
755            self.recipient_full_unified_address.as_ref(),
756            |w, unified_address| write_string(w, &unified_address.encode(consensus_parameters)),
757        )?;
758
759        Ok(())
760    }
761}
762
763impl OutgoingOrchardNote {
764    /// Deserialize into `reader`
765    pub fn read<R: Read>(
766        mut reader: R,
767        consensus_parameters: &impl consensus::Parameters,
768    ) -> std::io::Result<Self> {
769        let _version = reader.read_u8()?;
770
771        let txid = TxId::read(&mut reader)?;
772        let output_index = reader.read_u16::<LittleEndian>()?;
773
774        let account_id =
775            zip32::AccountId::try_from(reader.read_u32::<LittleEndian>()?).map_err(|e| {
776                std::io::Error::new(
777                    std::io::ErrorKind::InvalidData,
778                    format!("failed to read account id. {e}"),
779                )
780            })?;
781        let scope = match reader.read_u8()? {
782            0 => Ok(zip32::Scope::External),
783            1 => Ok(zip32::Scope::Internal),
784            _ => Err(std::io::Error::new(
785                std::io::ErrorKind::InvalidData,
786                "invalid scope value",
787            )),
788        }?;
789
790        let mut address_bytes = [0u8; 43];
791        reader.read_exact(&mut address_bytes)?;
792        let recipient = orchard::Address::from_raw_address_bytes(&address_bytes)
793            .expect("should be a valid address");
794        let value = orchard::value::NoteValue::from_raw(reader.read_u64::<LittleEndian>()?);
795        let mut rho_bytes = [0u8; 32];
796        reader.read_exact(&mut rho_bytes)?;
797        let rho = orchard::note::Rho::from_bytes(&rho_bytes).expect("should be valid rho bytes");
798        let mut rseed_bytes = [0u8; 32];
799        reader.read_exact(&mut rseed_bytes)?;
800        let rseed = orchard::note::RandomSeed::from_bytes(rseed_bytes, &rho)
801            .expect("should be valid random seed bytes");
802
803        let mut memo_bytes = [0u8; 512];
804        reader.read_exact(&mut memo_bytes)?;
805        let memo = Memo::from_bytes(&memo_bytes).map_err(|e| {
806            std::io::Error::new(
807                std::io::ErrorKind::InvalidData,
808                format!("failed to read memo. {e}"),
809            )
810        })?;
811
812        let recipient_unified_address = Optional::read(&mut reader, |r| {
813            let encoded_address = read_string(r)?;
814
815            decode_unified_address(consensus_parameters, &encoded_address)
816        })?;
817
818        Ok(Self {
819            output_id: OutputId::new(txid, output_index),
820            key_id: KeyId::from_parts(account_id, scope),
821            note: orchard::note::Note::from_parts(recipient, value, rho, rseed)
822                .expect("should be a valid orchard note"),
823            memo,
824            recipient_full_unified_address: recipient_unified_address,
825        })
826    }
827
828    /// Serialize into `writer`
829    pub fn write<W: Write>(
830        &self,
831        mut writer: W,
832        consensus_parameters: &impl consensus::Parameters,
833    ) -> std::io::Result<()> {
834        writer.write_u8(Self::serialized_version())?;
835
836        self.output_id.txid().write(&mut writer)?;
837        writer.write_u16::<LittleEndian>(self.output_id.output_index())?;
838
839        writer.write_u32::<LittleEndian>(self.key_id.account_id.into())?;
840        writer.write_u8(self.key_id.scope as u8)?;
841
842        writer.write_all(&self.note.recipient().to_raw_address_bytes())?;
843        writer.write_u64::<LittleEndian>(self.value())?;
844        writer.write_all(&self.note.rho().to_bytes())?;
845        writer.write_all(self.note.rseed().as_bytes())?;
846
847        writer.write_all(self.memo.encode().as_array())?;
848        Optional::write(
849            &mut writer,
850            self.recipient_full_unified_address.as_ref(),
851            |w, unified_address| write_string(w, &unified_address.encode(consensus_parameters)),
852        )?;
853
854        Ok(())
855    }
856}
857
858impl ShardTrees {
859    fn serialized_version() -> u8 {
860        0
861    }
862
863    /// Deserialize into `reader`
864    pub fn read<R: Read>(mut reader: R) -> std::io::Result<Self> {
865        let _version = reader.read_u8()?;
866        let sapling = Self::read_shardtree(&mut reader)?;
867        let orchard = Self::read_shardtree(&mut reader)?;
868
869        Ok(Self { sapling, orchard })
870    }
871
872    /// Serialize into `writer`
873    pub fn write<W: Write>(&mut self, mut writer: W) -> std::io::Result<()> {
874        writer.write_u8(Self::serialized_version())?;
875        Self::write_shardtree(&mut writer, &mut self.sapling)?;
876        Self::write_shardtree(&mut writer, &mut self.orchard)?;
877
878        Ok(())
879    }
880
881    fn read_shardtree<
882        H: Hashable + Clone + HashSer + Eq,
883        C: Ord + std::fmt::Debug + Copy + From<u32>,
884        R: Read,
885        const DEPTH: u8,
886        const SHARD_HEIGHT: u8,
887    >(
888        mut reader: R,
889    ) -> std::io::Result<ShardTree<MemoryShardStore<H, C>, DEPTH, SHARD_HEIGHT>> {
890        let shards = Vector::read(&mut reader, |r| {
891            let level = incrementalmerkletree::Level::from(r.read_u8()?);
892            let index = r.read_u64::<LittleEndian>()?;
893            let root_addr = incrementalmerkletree::Address::from_parts(level, index);
894            let shard = read_shard(r)?;
895
896            LocatedPrunableTree::from_parts(root_addr, shard).map_err(|addr| {
897                std::io::Error::new(
898                    std::io::ErrorKind::InvalidData,
899                    format!(
900                        "parent node in root has level 0 relative to root address: {:?}",
901                        addr
902                    ),
903                )
904            })
905        })?;
906        let mut store = MemoryShardStore::empty();
907        for shard in shards {
908            store.put_shard(shard).expect("infallible");
909        }
910        let checkpoints = Vector::read(&mut reader, |r| {
911            let checkpoint_id = C::from(r.read_u32::<LittleEndian>()?);
912            let tree_state = match r.read_u8()? {
913                0 => TreeState::Empty,
914                1 => TreeState::AtPosition(Position::from(r.read_u64::<LittleEndian>()?)),
915                otherwise => {
916                    return Err(std::io::Error::new(
917                        std::io::ErrorKind::InvalidData,
918                        format!(
919                            "failed to read TreeState. expected boolean value, found {otherwise}"
920                        ),
921                    ));
922                }
923            };
924            let marks_removed =
925                Vector::read(r, |r| r.read_u64::<LittleEndian>().map(Position::from))?;
926            Ok((
927                checkpoint_id,
928                Checkpoint::from_parts(tree_state, marks_removed.into_iter().collect()),
929            ))
930        })?;
931        for (checkpoint_id, checkpoint) in checkpoints {
932            store
933                .add_checkpoint(checkpoint_id, checkpoint)
934                .expect("Infallible");
935        }
936        store.put_cap(read_shard(reader)?).expect("Infallible");
937
938        Ok(shardtree::ShardTree::new(
939            store,
940            MAX_VERIFICATION_WINDOW as usize,
941        ))
942    }
943
944    /// Write memory-backed shardstore, represented tree.
945    fn write_shardtree<
946        H: Hashable + Clone + Eq + HashSer,
947        C: Ord + std::fmt::Debug + Copy,
948        W: Write,
949        const DEPTH: u8,
950        const SHARD_HEIGHT: u8,
951    >(
952        mut writer: W,
953        shardtree: &mut ShardTree<MemoryShardStore<H, C>, DEPTH, SHARD_HEIGHT>,
954    ) -> std::io::Result<()>
955    where
956        u32: From<C>,
957    {
958        fn write_shards<W, H, C>(
959            mut writer: W,
960            store: &MemoryShardStore<H, C>,
961        ) -> std::io::Result<()>
962        where
963            H: Hashable + Clone + Eq + HashSer,
964            C: Ord + std::fmt::Debug + Copy,
965            W: Write,
966        {
967            let roots = store.get_shard_roots().expect("Infallible");
968            Vector::write(&mut writer, &roots, |w, root| {
969                w.write_u8(root.level().into())?;
970                w.write_u64::<LittleEndian>(root.index())?;
971                let shard = store
972                    .get_shard(*root)
973                    .expect("Infallible")
974                    .expect("cannot find root that shard store claims to have");
975                write_shard(w, shard.root())
976            })
977        }
978
979        fn write_checkpoints<W, Cid>(
980            mut writer: W,
981            checkpoints: &[(Cid, Checkpoint)],
982        ) -> std::io::Result<()>
983        where
984            W: Write,
985            Cid: Ord + std::fmt::Debug + Copy,
986            u32: From<Cid>,
987        {
988            Vector::write(
989                &mut writer,
990                checkpoints,
991                |mut w, (checkpoint_id, checkpoint)| {
992                    w.write_u32::<LittleEndian>(u32::from(*checkpoint_id))?;
993                    match checkpoint.tree_state() {
994                        shardtree::store::TreeState::Empty => w.write_u8(0),
995                        shardtree::store::TreeState::AtPosition(pos) => {
996                            w.write_u8(1)?;
997                            w.write_u64::<LittleEndian>(<u64 as From<Position>>::from(pos))
998                        }
999                    }?;
1000                    Vector::write(
1001                        &mut w,
1002                        &checkpoint.marks_removed().iter().collect::<Vec<_>>(),
1003                        |w, mark| {
1004                            w.write_u64::<LittleEndian>(<u64 as From<Position>>::from(**mark))
1005                        },
1006                    )
1007                },
1008            )
1009        }
1010
1011        // Replace original tree with empty tree, and mutate new version into store.
1012        let mut store = std::mem::replace(
1013            shardtree,
1014            shardtree::ShardTree::new(MemoryShardStore::empty(), 0),
1015        )
1016        .into_store();
1017
1018        macro_rules! write_with_error_handling {
1019            ($writer: ident, $from: ident) => {
1020                if let Err(e) = $writer(&mut writer, &$from) {
1021                    *shardtree = shardtree::ShardTree::new(store, MAX_VERIFICATION_WINDOW as usize);
1022                    return Err(e);
1023                }
1024            };
1025        }
1026
1027        // Write located prunable trees
1028        write_with_error_handling!(write_shards, store);
1029
1030        // Write checkpoints
1031        let mut checkpoints = Vec::new();
1032        store
1033            .with_checkpoints(
1034                MAX_VERIFICATION_WINDOW as usize,
1035                |checkpoint_id, checkpoint| {
1036                    checkpoints.push((*checkpoint_id, checkpoint.clone()));
1037                    Ok(())
1038                },
1039            )
1040            .expect("Infallible");
1041        write_with_error_handling!(write_checkpoints, checkpoints);
1042
1043        // Write cap
1044        let cap = store.get_cap().expect("Infallible");
1045        write_with_error_handling!(write_shard, cap);
1046
1047        *shardtree = shardtree::ShardTree::new(store, MAX_VERIFICATION_WINDOW as usize);
1048
1049        Ok(())
1050    }
1051}