1#![cfg_attr(feature = "std", doc = "## Feature flags")]
12#![cfg_attr(feature = "std", doc = document_features::document_features!())]
13#![no_std]
16#![cfg_attr(docsrs, feature(doc_cfg))]
17#![cfg_attr(docsrs, feature(doc_auto_cfg))]
18#![deny(rustdoc::broken_intra_doc_links)]
20
21#[macro_use]
22extern crate alloc;
23
24use alloc::vec::Vec;
25
26use getset::Getters;
27use serde::{Deserialize, Serialize};
28
29#[cfg(feature = "signer")]
30use {roles::signer::EffectsOnly, zcash_primitives::transaction::TransactionData};
31
32pub mod roles;
33
34pub mod common;
35pub mod orchard;
36pub mod sapling;
37pub mod transparent;
38
39const MAGIC_BYTES: &[u8] = b"PCZT";
40const PCZT_VERSION_1: u32 = 1;
41
42#[derive(Clone, Debug, Serialize, Deserialize, Getters)]
44pub struct Pczt {
45 #[getset(get = "pub")]
47 global: common::Global,
48
49 #[getset(get = "pub")]
58 transparent: transparent::Bundle,
59 #[getset(get = "pub")]
60 sapling: sapling::Bundle,
61 #[getset(get = "pub")]
62 orchard: orchard::Bundle,
63}
64
65impl Pczt {
66 pub fn parse(bytes: &[u8]) -> Result<Self, ParseError> {
68 if bytes.len() < 8 {
69 return Err(ParseError::TooShort);
70 }
71 if &bytes[..4] != MAGIC_BYTES {
72 return Err(ParseError::NotPczt);
73 }
74 let version = u32::from_le_bytes(bytes[4..8].try_into().unwrap());
75 if version != PCZT_VERSION_1 {
76 return Err(ParseError::UnknownVersion(version));
77 }
78
79 postcard::from_bytes(&bytes[8..]).map_err(ParseError::Invalid)
81 }
82
83 pub fn serialize(&self) -> Vec<u8> {
85 let mut bytes = vec![];
86 bytes.extend_from_slice(MAGIC_BYTES);
87 bytes.extend_from_slice(&PCZT_VERSION_1.to_le_bytes());
88 postcard::to_extend(self, bytes).expect("can serialize into memory")
89 }
90
91 #[cfg(feature = "signer")]
93 pub fn into_effects(self) -> Option<TransactionData<EffectsOnly>> {
94 let Self {
95 global,
96 transparent,
97 sapling,
98 orchard,
99 } = self;
100
101 let transparent = transparent.into_parsed().ok()?;
102 let sapling = sapling.into_parsed().ok()?;
103 let orchard = orchard.into_parsed().ok()?;
104
105 roles::signer::pczt_to_tx_data(&global, &transparent, &sapling, &orchard).ok()
106 }
107}
108
109#[derive(Debug)]
111pub enum ParseError {
112 NotPczt,
114 Invalid(postcard::Error),
116 TooShort,
118 UnknownVersion(u32),
120}