Skip to main content

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