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