zebra_chain/transaction/
serialize.rs

1//! Contains impls of `ZcashSerialize`, `ZcashDeserialize` for all of the
2//! transaction types, so that all of the serialization logic is in one place.
3
4use std::{borrow::Borrow, io, sync::Arc};
5
6use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
7use halo2::pasta::group::ff::PrimeField;
8use hex::FromHex;
9use reddsa::{orchard::Binding, orchard::SpendAuth, Signature};
10
11use crate::{
12    amount,
13    block::MAX_BLOCK_BYTES,
14    parameters::{OVERWINTER_VERSION_GROUP_ID, SAPLING_VERSION_GROUP_ID, TX_V5_VERSION_GROUP_ID},
15    primitives::{Halo2Proof, ZkSnarkProof},
16    serialization::{
17        zcash_deserialize_external_count, zcash_serialize_empty_list,
18        zcash_serialize_external_count, AtLeastOne, ReadZcashExt, SerializationError,
19        TrustedPreallocate, ZcashDeserialize, ZcashDeserializeInto, ZcashSerialize,
20    },
21};
22
23use super::*;
24use crate::sapling;
25
26impl ZcashDeserialize for jubjub::Fq {
27    fn zcash_deserialize<R: io::Read>(mut reader: R) -> Result<Self, SerializationError> {
28        let possible_scalar = jubjub::Fq::from_bytes(&reader.read_32_bytes()?);
29
30        if possible_scalar.is_some().into() {
31            Ok(possible_scalar.unwrap())
32        } else {
33            Err(SerializationError::Parse(
34                "Invalid jubjub::Fq, input not canonical",
35            ))
36        }
37    }
38}
39
40impl ZcashDeserialize for pallas::Scalar {
41    fn zcash_deserialize<R: io::Read>(mut reader: R) -> Result<Self, SerializationError> {
42        let possible_scalar = pallas::Scalar::from_repr(reader.read_32_bytes()?);
43
44        if possible_scalar.is_some().into() {
45            Ok(possible_scalar.unwrap())
46        } else {
47            Err(SerializationError::Parse(
48                "Invalid pallas::Scalar, input not canonical",
49            ))
50        }
51    }
52}
53
54impl ZcashDeserialize for pallas::Base {
55    fn zcash_deserialize<R: io::Read>(mut reader: R) -> Result<Self, SerializationError> {
56        let possible_field_element = pallas::Base::from_repr(reader.read_32_bytes()?);
57
58        if possible_field_element.is_some().into() {
59            Ok(possible_field_element.unwrap())
60        } else {
61            Err(SerializationError::Parse(
62                "Invalid pallas::Base, input not canonical",
63            ))
64        }
65    }
66}
67
68impl<P: ZkSnarkProof> ZcashSerialize for JoinSplitData<P> {
69    fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
70        // Denoted as `nJoinSplit` and `vJoinSplit` in the spec.
71        let joinsplits: Vec<_> = self.joinsplits().cloned().collect();
72        joinsplits.zcash_serialize(&mut writer)?;
73
74        // Denoted as `joinSplitPubKey` in the spec.
75        writer.write_all(&<[u8; 32]>::from(self.pub_key)[..])?;
76
77        // Denoted as `joinSplitSig` in the spec.
78        writer.write_all(&<[u8; 64]>::from(self.sig)[..])?;
79        Ok(())
80    }
81}
82
83impl<P> ZcashDeserialize for Option<JoinSplitData<P>>
84where
85    P: ZkSnarkProof,
86    sprout::JoinSplit<P>: TrustedPreallocate,
87{
88    fn zcash_deserialize<R: io::Read>(mut reader: R) -> Result<Self, SerializationError> {
89        // Denoted as `nJoinSplit` and `vJoinSplit` in the spec.
90        let joinsplits: Vec<sprout::JoinSplit<P>> = (&mut reader).zcash_deserialize_into()?;
91        match joinsplits.split_first() {
92            None => Ok(None),
93            Some((first, rest)) => {
94                // Denoted as `joinSplitPubKey` in the spec.
95                let pub_key = reader.read_32_bytes()?.into();
96                // Denoted as `joinSplitSig` in the spec.
97                let sig = reader.read_64_bytes()?.into();
98                Ok(Some(JoinSplitData {
99                    first: first.clone(),
100                    rest: rest.to_vec(),
101                    pub_key,
102                    sig,
103                }))
104            }
105        }
106    }
107}
108
109// Transaction::V5 serializes sapling ShieldedData in a single continuous byte
110// range, so we can implement its serialization and deserialization separately.
111// (Unlike V4, where it must be serialized as part of the transaction.)
112
113impl ZcashSerialize for Option<sapling::ShieldedData<sapling::SharedAnchor>> {
114    fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
115        match self {
116            None => {
117                // Denoted as `nSpendsSapling` in the spec.
118                zcash_serialize_empty_list(&mut writer)?;
119                // Denoted as `nOutputsSapling` in the spec.
120                zcash_serialize_empty_list(&mut writer)?;
121            }
122            Some(sapling_shielded_data) => {
123                sapling_shielded_data.zcash_serialize(&mut writer)?;
124            }
125        }
126        Ok(())
127    }
128}
129
130impl ZcashSerialize for sapling::ShieldedData<sapling::SharedAnchor> {
131    fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
132        // Collect arrays for Spends
133        // There's no unzip3, so we have to unzip twice.
134        let (spend_prefixes, spend_proofs_sigs): (Vec<_>, Vec<_>) = self
135            .spends()
136            .cloned()
137            .map(sapling::Spend::<sapling::SharedAnchor>::into_v5_parts)
138            .map(|(prefix, proof, sig)| (prefix, (proof, sig)))
139            .unzip();
140        let (spend_proofs, spend_sigs) = spend_proofs_sigs.into_iter().unzip();
141
142        // Collect arrays for Outputs
143        let (output_prefixes, output_proofs): (Vec<_>, _) = self
144            .outputs()
145            .cloned()
146            .map(sapling::Output::into_v5_parts)
147            .unzip();
148
149        // Denoted as `nSpendsSapling` and `vSpendsSapling` in the spec.
150        spend_prefixes.zcash_serialize(&mut writer)?;
151        // Denoted as `nOutputsSapling` and `vOutputsSapling` in the spec.
152        output_prefixes.zcash_serialize(&mut writer)?;
153
154        // Denoted as `valueBalanceSapling` in the spec.
155        self.value_balance.zcash_serialize(&mut writer)?;
156
157        // Denoted as `anchorSapling` in the spec.
158        // `TransferData` ensures this field is only present when there is at
159        // least one spend.
160        if let Some(shared_anchor) = self.shared_anchor() {
161            writer.write_all(&<[u8; 32]>::from(shared_anchor)[..])?;
162        }
163
164        // Denoted as `vSpendProofsSapling` in the spec.
165        zcash_serialize_external_count(&spend_proofs, &mut writer)?;
166        // Denoted as `vSpendAuthSigsSapling` in the spec.
167        zcash_serialize_external_count(&spend_sigs, &mut writer)?;
168
169        // Denoted as `vOutputProofsSapling` in the spec.
170        zcash_serialize_external_count(&output_proofs, &mut writer)?;
171
172        // Denoted as `bindingSigSapling` in the spec.
173        writer.write_all(&<[u8; 64]>::from(self.binding_sig)[..])?;
174
175        Ok(())
176    }
177}
178
179// we can't split ShieldedData out of Option<ShieldedData> deserialization,
180// because the counts are read along with the arrays.
181impl ZcashDeserialize for Option<sapling::ShieldedData<sapling::SharedAnchor>> {
182    #[allow(clippy::unwrap_in_result)]
183    fn zcash_deserialize<R: io::Read>(mut reader: R) -> Result<Self, SerializationError> {
184        // Denoted as `nSpendsSapling` and `vSpendsSapling` in the spec.
185        let spend_prefixes: Vec<_> = (&mut reader).zcash_deserialize_into()?;
186
187        // Denoted as `nOutputsSapling` and `vOutputsSapling` in the spec.
188        let output_prefixes: Vec<_> = (&mut reader).zcash_deserialize_into()?;
189
190        // nSpendsSapling and nOutputsSapling as variables
191        let spends_count = spend_prefixes.len();
192        let outputs_count = output_prefixes.len();
193
194        // All the other fields depend on having spends or outputs
195        if spend_prefixes.is_empty() && output_prefixes.is_empty() {
196            return Ok(None);
197        }
198
199        // Denoted as `valueBalanceSapling` in the spec.
200        let value_balance = (&mut reader).zcash_deserialize_into()?;
201
202        // Denoted as `anchorSapling` in the spec.
203        //
204        // # Consensus
205        //
206        // > Elements of a Spend description MUST be valid encodings of the types given above.
207        //
208        // https://zips.z.cash/protocol/protocol.pdf#spenddesc
209        //
210        // Type is `B^{[ℓ_{Sapling}_{Merkle}]}`, i.e. 32 bytes
211        //
212        // > LEOS2IP_{256}(anchorSapling), if present, MUST be less than 𝑞_𝕁.
213        //
214        // https://zips.z.cash/protocol/protocol.pdf#spendencodingandconsensus
215        //
216        // Validated in [`crate::sapling::tree::Root::zcash_deserialize`].
217        let shared_anchor = if spends_count > 0 {
218            Some((&mut reader).zcash_deserialize_into()?)
219        } else {
220            None
221        };
222
223        // Denoted as `vSpendProofsSapling` in the spec.
224        //
225        // # Consensus
226        //
227        // > Elements of a Spend description MUST be valid encodings of the types given above.
228        //
229        // https://zips.z.cash/protocol/protocol.pdf#spenddesc
230        //
231        // Type is `ZKSpend.Proof`, described in
232        // https://zips.z.cash/protocol/protocol.pdf#grothencoding
233        // It is not enforced here; this just reads 192 bytes.
234        // The type is validated when validating the proof, see
235        // [`groth16::Item::try_from`]. In #3179 we plan to validate here instead.
236        let spend_proofs = zcash_deserialize_external_count(spends_count, &mut reader)?;
237
238        // Denoted as `vSpendAuthSigsSapling` in the spec.
239        //
240        // # Consensus
241        //
242        // > Elements of a Spend description MUST be valid encodings of the types given above.
243        //
244        // https://zips.z.cash/protocol/protocol.pdf#spenddesc
245        //
246        // Type is SpendAuthSig^{Sapling}.Signature, i.e.
247        // B^Y^{[ceiling(ℓ_G/8) + ceiling(bitlength(𝑟_G)/8)]} i.e. 64 bytes
248        // https://zips.z.cash/protocol/protocol.pdf#concretereddsa
249        // See [`redjubjub::Signature<SpendAuth>::zcash_deserialize`].
250        let spend_sigs = zcash_deserialize_external_count(spends_count, &mut reader)?;
251
252        // Denoted as `vOutputProofsSapling` in the spec.
253        //
254        // # Consensus
255        //
256        // > Elements of an Output description MUST be valid encodings of the types given above.
257        //
258        // https://zips.z.cash/protocol/protocol.pdf#outputdesc
259        //
260        // Type is `ZKOutput.Proof`, described in
261        // https://zips.z.cash/protocol/protocol.pdf#grothencoding
262        // It is not enforced here; this just reads 192 bytes.
263        // The type is validated when validating the proof, see
264        // [`groth16::Item::try_from`]. In #3179 we plan to validate here instead.
265        let output_proofs = zcash_deserialize_external_count(outputs_count, &mut reader)?;
266
267        // Denoted as `bindingSigSapling` in the spec.
268        let binding_sig = reader.read_64_bytes()?.into();
269
270        // Create shielded spends from deserialized parts
271        let spends: Vec<_> = spend_prefixes
272            .into_iter()
273            .zip(spend_proofs)
274            .zip(spend_sigs)
275            .map(|((prefix, proof), sig)| {
276                sapling::Spend::<sapling::SharedAnchor>::from_v5_parts(prefix, proof, sig)
277            })
278            .collect();
279
280        // Create shielded outputs from deserialized parts
281        let outputs = output_prefixes
282            .into_iter()
283            .zip(output_proofs)
284            .map(|(prefix, proof)| sapling::Output::from_v5_parts(prefix, proof))
285            .collect();
286
287        // Create transfers
288        //
289        // # Consensus
290        //
291        // > The anchor of each Spend description MUST refer to some earlier
292        // > block’s final Sapling treestate. The anchor is encoded separately
293        // > in each Spend description for v4 transactions, or encoded once and
294        // > shared between all Spend descriptions in a v5 transaction.
295        //
296        // <https://zips.z.cash/protocol/protocol.pdf#spendsandoutputs>
297        //
298        // This rule is also implemented in
299        // [`zebra_state::service::check::anchor`] and
300        // [`zebra_chain::sapling::spend`].
301        //
302        // The "anchor encoding for v5 transactions" is implemented here.
303        let transfers = match shared_anchor {
304            Some(shared_anchor) => sapling::TransferData::SpendsAndMaybeOutputs {
305                shared_anchor,
306                spends: spends
307                    .try_into()
308                    .expect("checked spends when parsing shared anchor"),
309                maybe_outputs: outputs,
310            },
311            None => sapling::TransferData::JustOutputs {
312                outputs: outputs
313                    .try_into()
314                    .expect("checked spends or outputs and returned early"),
315            },
316        };
317
318        Ok(Some(sapling::ShieldedData {
319            value_balance,
320            transfers,
321            binding_sig,
322        }))
323    }
324}
325
326impl ZcashSerialize for Option<orchard::ShieldedData> {
327    fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
328        match self {
329            None => {
330                // Denoted as `nActionsOrchard` in the spec.
331                zcash_serialize_empty_list(writer)?;
332
333                // We don't need to write anything else here.
334                // "The fields flagsOrchard, valueBalanceOrchard, anchorOrchard, sizeProofsOrchard,
335                // proofsOrchard , and bindingSigOrchard are present if and only if nActionsOrchard > 0."
336                // `§` note of the second table of https://zips.z.cash/protocol/protocol.pdf#txnencoding
337            }
338            Some(orchard_shielded_data) => {
339                orchard_shielded_data.zcash_serialize(&mut writer)?;
340            }
341        }
342        Ok(())
343    }
344}
345
346impl ZcashSerialize for orchard::ShieldedData {
347    fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
348        // Split the AuthorizedAction
349        let (actions, sigs): (Vec<orchard::Action>, Vec<Signature<SpendAuth>>) = self
350            .actions
351            .iter()
352            .cloned()
353            .map(orchard::AuthorizedAction::into_parts)
354            .unzip();
355
356        // Denoted as `nActionsOrchard` and `vActionsOrchard` in the spec.
357        actions.zcash_serialize(&mut writer)?;
358
359        // Denoted as `flagsOrchard` in the spec.
360        self.flags.zcash_serialize(&mut writer)?;
361
362        // Denoted as `valueBalanceOrchard` in the spec.
363        self.value_balance.zcash_serialize(&mut writer)?;
364
365        // Denoted as `anchorOrchard` in the spec.
366        self.shared_anchor.zcash_serialize(&mut writer)?;
367
368        // Denoted as `sizeProofsOrchard` and `proofsOrchard` in the spec.
369        self.proof.zcash_serialize(&mut writer)?;
370
371        // Denoted as `vSpendAuthSigsOrchard` in the spec.
372        zcash_serialize_external_count(&sigs, &mut writer)?;
373
374        // Denoted as `bindingSigOrchard` in the spec.
375        self.binding_sig.zcash_serialize(&mut writer)?;
376
377        Ok(())
378    }
379}
380
381// we can't split ShieldedData out of Option<ShieldedData> deserialization,
382// because the counts are read along with the arrays.
383impl ZcashDeserialize for Option<orchard::ShieldedData> {
384    fn zcash_deserialize<R: io::Read>(mut reader: R) -> Result<Self, SerializationError> {
385        // Denoted as `nActionsOrchard` and `vActionsOrchard` in the spec.
386        let actions: Vec<orchard::Action> = (&mut reader).zcash_deserialize_into()?;
387
388        // "The fields flagsOrchard, valueBalanceOrchard, anchorOrchard, sizeProofsOrchard,
389        // proofsOrchard , and bindingSigOrchard are present if and only if nActionsOrchard > 0."
390        // `§` note of the second table of https://zips.z.cash/protocol/protocol.pdf#txnencoding
391        if actions.is_empty() {
392            return Ok(None);
393        }
394
395        // # Consensus
396        //
397        // > Elements of an Action description MUST be canonical encodings of the types given above.
398        //
399        // https://zips.z.cash/protocol/protocol.pdf#actiondesc
400        //
401        // Some Action elements are validated in this function; they are described below.
402
403        // Denoted as `flagsOrchard` in the spec.
404        // Consensus: type of each flag is 𝔹, i.e. a bit. This is enforced implicitly
405        // in [`Flags::zcash_deserialized`].
406        let flags: orchard::Flags = (&mut reader).zcash_deserialize_into()?;
407
408        // Denoted as `valueBalanceOrchard` in the spec.
409        let value_balance: amount::Amount = (&mut reader).zcash_deserialize_into()?;
410
411        // Denoted as `anchorOrchard` in the spec.
412        // Consensus: type is `{0 .. 𝑞_ℙ − 1}`. See [`orchard::tree::Root::zcash_deserialize`].
413        let shared_anchor: orchard::tree::Root = (&mut reader).zcash_deserialize_into()?;
414
415        // Denoted as `sizeProofsOrchard` and `proofsOrchard` in the spec.
416        // Consensus: type is `ZKAction.Proof`, i.e. a byte sequence.
417        // https://zips.z.cash/protocol/protocol.pdf#halo2encoding
418        let proof: Halo2Proof = (&mut reader).zcash_deserialize_into()?;
419
420        // Denoted as `vSpendAuthSigsOrchard` in the spec.
421        // Consensus: this validates the `spendAuthSig` elements, whose type is
422        // SpendAuthSig^{Orchard}.Signature, i.e.
423        // B^Y^{[ceiling(ℓ_G/8) + ceiling(bitlength(𝑟_G)/8)]} i.e. 64 bytes
424        // See [`Signature::zcash_deserialize`].
425        let sigs: Vec<Signature<SpendAuth>> =
426            zcash_deserialize_external_count(actions.len(), &mut reader)?;
427
428        // Denoted as `bindingSigOrchard` in the spec.
429        let binding_sig: Signature<Binding> = (&mut reader).zcash_deserialize_into()?;
430
431        // Create the AuthorizedAction from deserialized parts
432        let authorized_actions: Vec<orchard::AuthorizedAction> = actions
433            .into_iter()
434            .zip(sigs)
435            .map(|(action, spend_auth_sig)| {
436                orchard::AuthorizedAction::from_parts(action, spend_auth_sig)
437            })
438            .collect();
439
440        let actions: AtLeastOne<orchard::AuthorizedAction> = authorized_actions.try_into()?;
441
442        Ok(Some(orchard::ShieldedData {
443            flags,
444            value_balance,
445            shared_anchor,
446            proof,
447            actions,
448            binding_sig,
449        }))
450    }
451}
452
453impl<T: reddsa::SigType> ZcashSerialize for reddsa::Signature<T> {
454    fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
455        writer.write_all(&<[u8; 64]>::from(*self)[..])?;
456        Ok(())
457    }
458}
459
460impl<T: reddsa::SigType> ZcashDeserialize for reddsa::Signature<T> {
461    fn zcash_deserialize<R: io::Read>(mut reader: R) -> Result<Self, SerializationError> {
462        Ok(reader.read_64_bytes()?.into())
463    }
464}
465
466impl ZcashSerialize for Transaction {
467    #[allow(clippy::unwrap_in_result)]
468    fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
469        // Post-Sapling, transaction size is limited to MAX_BLOCK_BYTES.
470        // (Strictly, the maximum transaction size is about 1.5 kB less,
471        // because blocks also include a block header.)
472        //
473        // Currently, all transaction structs are parsed as part of a
474        // block. So we don't need to check transaction size here, until
475        // we start parsing mempool transactions, or generating our own
476        // transactions (see #483).
477        //
478        // Since we checkpoint on Canopy activation, we won't ever need
479        // to check the smaller pre-Sapling transaction size limit.
480
481        // Denoted as `header` in the spec, contains the `fOverwintered` flag and the `version` field.
482        // Write `version` and set the `fOverwintered` bit if necessary
483        let overwintered_flag = if self.is_overwintered() { 1 << 31 } else { 0 };
484        let version = overwintered_flag | self.version();
485
486        writer.write_u32::<LittleEndian>(version)?;
487
488        match self {
489            Transaction::V1 {
490                inputs,
491                outputs,
492                lock_time,
493            } => {
494                // Denoted as `tx_in_count` and `tx_in` in the spec.
495                inputs.zcash_serialize(&mut writer)?;
496
497                // Denoted as `tx_out_count` and `tx_out` in the spec.
498                outputs.zcash_serialize(&mut writer)?;
499
500                // Denoted as `lock_time` in the spec.
501                lock_time.zcash_serialize(&mut writer)?;
502            }
503            Transaction::V2 {
504                inputs,
505                outputs,
506                lock_time,
507                joinsplit_data,
508            } => {
509                // Denoted as `tx_in_count` and `tx_in` in the spec.
510                inputs.zcash_serialize(&mut writer)?;
511
512                // Denoted as `tx_out_count` and `tx_out` in the spec.
513                outputs.zcash_serialize(&mut writer)?;
514
515                // Denoted as `lock_time` in the spec.
516                lock_time.zcash_serialize(&mut writer)?;
517
518                // A bundle of fields denoted in the spec as `nJoinSplit`, `vJoinSplit`,
519                // `joinSplitPubKey` and `joinSplitSig`.
520                match joinsplit_data {
521                    // Write 0 for nJoinSplits to signal no JoinSplitData.
522                    None => zcash_serialize_empty_list(writer)?,
523                    Some(jsd) => jsd.zcash_serialize(&mut writer)?,
524                }
525            }
526            Transaction::V3 {
527                inputs,
528                outputs,
529                lock_time,
530                expiry_height,
531                joinsplit_data,
532            } => {
533                // Denoted as `nVersionGroupId` in the spec.
534                writer.write_u32::<LittleEndian>(OVERWINTER_VERSION_GROUP_ID)?;
535
536                // Denoted as `tx_in_count` and `tx_in` in the spec.
537                inputs.zcash_serialize(&mut writer)?;
538
539                // Denoted as `tx_out_count` and `tx_out` in the spec.
540                outputs.zcash_serialize(&mut writer)?;
541
542                // Denoted as `lock_time` in the spec.
543                lock_time.zcash_serialize(&mut writer)?;
544
545                writer.write_u32::<LittleEndian>(expiry_height.0)?;
546
547                // A bundle of fields denoted in the spec as `nJoinSplit`, `vJoinSplit`,
548                // `joinSplitPubKey` and `joinSplitSig`.
549                match joinsplit_data {
550                    // Write 0 for nJoinSplits to signal no JoinSplitData.
551                    None => zcash_serialize_empty_list(writer)?,
552                    Some(jsd) => jsd.zcash_serialize(&mut writer)?,
553                }
554            }
555            Transaction::V4 {
556                inputs,
557                outputs,
558                lock_time,
559                expiry_height,
560                sapling_shielded_data,
561                joinsplit_data,
562            } => {
563                // Transaction V4 spec:
564                // https://zips.z.cash/protocol/protocol.pdf#txnencoding
565
566                // Denoted as `nVersionGroupId` in the spec.
567                writer.write_u32::<LittleEndian>(SAPLING_VERSION_GROUP_ID)?;
568
569                // Denoted as `tx_in_count` and `tx_in` in the spec.
570                inputs.zcash_serialize(&mut writer)?;
571
572                // Denoted as `tx_out_count` and `tx_out` in the spec.
573                outputs.zcash_serialize(&mut writer)?;
574
575                // Denoted as `lock_time` in the spec.
576                lock_time.zcash_serialize(&mut writer)?;
577
578                // Denoted as `nExpiryHeight` in the spec.
579                writer.write_u32::<LittleEndian>(expiry_height.0)?;
580
581                // The previous match arms serialize in one go, because the
582                // internal structure happens to nicely line up with the
583                // serialized structure. However, this is not possible for
584                // version 4 transactions, as the binding_sig for the
585                // ShieldedData is placed at the end of the transaction. So
586                // instead we have to interleave serialization of the
587                // ShieldedData and the JoinSplitData.
588
589                match sapling_shielded_data {
590                    None => {
591                        // Signal no value balance.
592                        writer.write_i64::<LittleEndian>(0)?;
593                        // Signal no shielded spends and no shielded outputs.
594                        zcash_serialize_empty_list(&mut writer)?;
595                        zcash_serialize_empty_list(&mut writer)?;
596                    }
597                    Some(sapling_shielded_data) => {
598                        // Denoted as `valueBalanceSapling` in the spec.
599                        sapling_shielded_data
600                            .value_balance
601                            .zcash_serialize(&mut writer)?;
602
603                        // Denoted as `nSpendsSapling` and `vSpendsSapling` in the spec.
604                        let spends: Vec<_> = sapling_shielded_data.spends().cloned().collect();
605                        spends.zcash_serialize(&mut writer)?;
606
607                        // Denoted as `nOutputsSapling` and `vOutputsSapling` in the spec.
608                        let outputs: Vec<_> = sapling_shielded_data
609                            .outputs()
610                            .cloned()
611                            .map(sapling::OutputInTransactionV4)
612                            .collect();
613                        outputs.zcash_serialize(&mut writer)?;
614                    }
615                }
616
617                // A bundle of fields denoted in the spec as `nJoinSplit`, `vJoinSplit`,
618                // `joinSplitPubKey` and `joinSplitSig`.
619                match joinsplit_data {
620                    None => zcash_serialize_empty_list(&mut writer)?,
621                    Some(jsd) => jsd.zcash_serialize(&mut writer)?,
622                }
623
624                // Denoted as `bindingSigSapling` in the spec.
625                if let Some(shielded_data) = sapling_shielded_data {
626                    writer.write_all(&<[u8; 64]>::from(shielded_data.binding_sig)[..])?;
627                }
628            }
629
630            Transaction::V5 {
631                network_upgrade,
632                lock_time,
633                expiry_height,
634                inputs,
635                outputs,
636                sapling_shielded_data,
637                orchard_shielded_data,
638            } => {
639                // Transaction V5 spec:
640                // https://zips.z.cash/protocol/protocol.pdf#txnencoding
641
642                // Denoted as `nVersionGroupId` in the spec.
643                writer.write_u32::<LittleEndian>(TX_V5_VERSION_GROUP_ID)?;
644
645                // Denoted as `nConsensusBranchId` in the spec.
646                writer.write_u32::<LittleEndian>(u32::from(
647                    network_upgrade
648                        .branch_id()
649                        .expect("valid transactions must have a network upgrade with a branch id"),
650                ))?;
651
652                // Denoted as `lock_time` in the spec.
653                lock_time.zcash_serialize(&mut writer)?;
654
655                // Denoted as `nExpiryHeight` in the spec.
656                writer.write_u32::<LittleEndian>(expiry_height.0)?;
657
658                // Denoted as `tx_in_count` and `tx_in` in the spec.
659                inputs.zcash_serialize(&mut writer)?;
660
661                // Denoted as `tx_out_count` and `tx_out` in the spec.
662                outputs.zcash_serialize(&mut writer)?;
663
664                // A bundle of fields denoted in the spec as `nSpendsSapling`, `vSpendsSapling`,
665                // `nOutputsSapling`,`vOutputsSapling`, `valueBalanceSapling`, `anchorSapling`,
666                // `vSpendProofsSapling`, `vSpendAuthSigsSapling`, `vOutputProofsSapling` and
667                // `bindingSigSapling`.
668                sapling_shielded_data.zcash_serialize(&mut writer)?;
669
670                // A bundle of fields denoted in the spec as `nActionsOrchard`, `vActionsOrchard`,
671                // `flagsOrchard`,`valueBalanceOrchard`, `anchorOrchard`, `sizeProofsOrchard`,
672                // `proofsOrchard`, `vSpendAuthSigsOrchard`, and `bindingSigOrchard`.
673                orchard_shielded_data.zcash_serialize(&mut writer)?;
674            }
675
676            #[cfg(feature = "tx_v6")]
677            Transaction::V6 {
678                network_upgrade,
679                lock_time,
680                expiry_height,
681                inputs,
682                outputs,
683                sapling_shielded_data,
684                orchard_shielded_data,
685            } => {
686                // Transaction V6 spec:
687                // https://zips.z.cash/zip-0230#specification
688
689                // Denoted as `nVersionGroupId` in the spec.
690                writer.write_u32::<LittleEndian>(TX_V5_VERSION_GROUP_ID)?;
691
692                // Denoted as `nConsensusBranchId` in the spec.
693                writer.write_u32::<LittleEndian>(u32::from(
694                    network_upgrade
695                        .branch_id()
696                        .expect("valid transactions must have a network upgrade with a branch id"),
697                ))?;
698
699                // Denoted as `lock_time` in the spec.
700                lock_time.zcash_serialize(&mut writer)?;
701
702                // Denoted as `nExpiryHeight` in the spec.
703                writer.write_u32::<LittleEndian>(expiry_height.0)?;
704
705                // Denoted as `tx_in_count` and `tx_in` in the spec.
706                inputs.zcash_serialize(&mut writer)?;
707
708                // Denoted as `tx_out_count` and `tx_out` in the spec.
709                outputs.zcash_serialize(&mut writer)?;
710
711                // A bundle of fields denoted in the spec as `nSpendsSapling`, `vSpendsSapling`,
712                // `nOutputsSapling`,`vOutputsSapling`, `valueBalanceSapling`, `anchorSapling`,
713                // `vSpendProofsSapling`, `vSpendAuthSigsSapling`, `vOutputProofsSapling` and
714                // `bindingSigSapling`.
715                sapling_shielded_data.zcash_serialize(&mut writer)?;
716
717                // A bundle of fields denoted in the spec as `nActionsOrchard`, `vActionsOrchard`,
718                // `flagsOrchard`,`valueBalanceOrchard`, `anchorOrchard`, `sizeProofsOrchard`,
719                // `proofsOrchard`, `vSpendAuthSigsOrchard`, and `bindingSigOrchard`.
720                orchard_shielded_data.zcash_serialize(&mut writer)?;
721
722                // TODO: Add the rest of v6 transaction fields.
723            }
724        }
725        Ok(())
726    }
727}
728
729impl ZcashDeserialize for Transaction {
730    #[allow(clippy::unwrap_in_result)]
731    fn zcash_deserialize<R: io::Read>(reader: R) -> Result<Self, SerializationError> {
732        // # Consensus
733        //
734        // > [Pre-Sapling] The encoded size of the transaction MUST be less than or
735        // > equal to 100000 bytes.
736        //
737        // https://zips.z.cash/protocol/protocol.pdf#txnconsensus
738        //
739        // Zebra does not verify this rule because we checkpoint up to Canopy blocks, but:
740        // Since transactions must get mined into a block to be useful,
741        // we reject transactions that are larger than blocks.
742        //
743        // If the limit is reached, we'll get an UnexpectedEof error.
744        let mut limited_reader = reader.take(MAX_BLOCK_BYTES);
745
746        let (version, overwintered) = {
747            const LOW_31_BITS: u32 = (1 << 31) - 1;
748            // Denoted as `header` in the spec, contains the `fOverwintered` flag and the `version` field.
749            let header = limited_reader.read_u32::<LittleEndian>()?;
750            (header & LOW_31_BITS, header >> 31 != 0)
751        };
752
753        // # Consensus
754        //
755        // The next rules apply for different transaction versions as follows:
756        //
757        // [Pre-Overwinter]: Transactions version 1 and 2.
758        // [Overwinter onward]: Transactions version 3 and above.
759        // [Overwinter only, pre-Sapling]: Transactions version 3.
760        // [Sapling to Canopy inclusive, pre-NU5]: Transactions version 4.
761        // [NU5 onward]: Transactions version 4 and above.
762        //
763        // > The transaction version number MUST be greater than or equal to 1.
764        //
765        // > [Pre-Overwinter] The fOverwintered fag MUST NOT be set.
766        //
767        // > [Overwinter onward] The version group ID MUST be recognized.
768        //
769        // > [Overwinter onward] The fOverwintered flag MUST be set.
770        //
771        // > [Overwinter only, pre-Sapling] The transaction version number MUST be 3,
772        // > and the version group ID MUST be 0x03C48270.
773        //
774        // > [Sapling to Canopy inclusive, pre-NU5] The transaction version number MUST be 4,
775        // > and the version group ID MUST be 0x892F2085.
776        //
777        // > [NU5 onward] The transaction version number MUST be 4 or 5.
778        // > If the transaction version number is 4 then the version group ID MUST be 0x892F2085.
779        // > If the transaction version number is 5 then the version group ID MUST be 0x26A7270A.
780        //
781        // Note: Zebra checkpoints until Canopy blocks, this means only transactions versions
782        // 4 and 5 get fully verified. This satisfies "The transaction version number MUST be 4"
783        // and "The transaction version number MUST be 4 or 5" from the last two rules above.
784        // This is done in the zebra-consensus crate, in the transactions checks.
785        //
786        // https://zips.z.cash/protocol/protocol.pdf#txnconsensus
787        match (version, overwintered) {
788            (1, false) => Ok(Transaction::V1 {
789                // Denoted as `tx_in_count` and `tx_in` in the spec.
790                inputs: Vec::zcash_deserialize(&mut limited_reader)?,
791                // Denoted as `tx_out_count` and `tx_out` in the spec.
792                outputs: Vec::zcash_deserialize(&mut limited_reader)?,
793                // Denoted as `lock_time` in the spec.
794                lock_time: LockTime::zcash_deserialize(&mut limited_reader)?,
795            }),
796            (2, false) => {
797                // Version 2 transactions use Sprout-on-BCTV14.
798                type OptV2Jsd = Option<JoinSplitData<Bctv14Proof>>;
799                Ok(Transaction::V2 {
800                    // Denoted as `tx_in_count` and `tx_in` in the spec.
801                    inputs: Vec::zcash_deserialize(&mut limited_reader)?,
802                    // Denoted as `tx_out_count` and `tx_out` in the spec.
803                    outputs: Vec::zcash_deserialize(&mut limited_reader)?,
804                    // Denoted as `lock_time` in the spec.
805                    lock_time: LockTime::zcash_deserialize(&mut limited_reader)?,
806                    // A bundle of fields denoted in the spec as `nJoinSplit`, `vJoinSplit`,
807                    // `joinSplitPubKey` and `joinSplitSig`.
808                    joinsplit_data: OptV2Jsd::zcash_deserialize(&mut limited_reader)?,
809                })
810            }
811            (3, true) => {
812                // Denoted as `nVersionGroupId` in the spec.
813                let id = limited_reader.read_u32::<LittleEndian>()?;
814                if id != OVERWINTER_VERSION_GROUP_ID {
815                    return Err(SerializationError::Parse(
816                        "expected OVERWINTER_VERSION_GROUP_ID",
817                    ));
818                }
819                // Version 3 transactions use Sprout-on-BCTV14.
820                type OptV3Jsd = Option<JoinSplitData<Bctv14Proof>>;
821                Ok(Transaction::V3 {
822                    // Denoted as `tx_in_count` and `tx_in` in the spec.
823                    inputs: Vec::zcash_deserialize(&mut limited_reader)?,
824                    // Denoted as `tx_out_count` and `tx_out` in the spec.
825                    outputs: Vec::zcash_deserialize(&mut limited_reader)?,
826                    // Denoted as `lock_time` in the spec.
827                    lock_time: LockTime::zcash_deserialize(&mut limited_reader)?,
828                    // Denoted as `nExpiryHeight` in the spec.
829                    expiry_height: block::Height(limited_reader.read_u32::<LittleEndian>()?),
830                    // A bundle of fields denoted in the spec as `nJoinSplit`, `vJoinSplit`,
831                    // `joinSplitPubKey` and `joinSplitSig`.
832                    joinsplit_data: OptV3Jsd::zcash_deserialize(&mut limited_reader)?,
833                })
834            }
835            (4, true) => {
836                // Transaction V4 spec:
837                // https://zips.z.cash/protocol/protocol.pdf#txnencoding
838
839                // Denoted as `nVersionGroupId` in the spec.
840                let id = limited_reader.read_u32::<LittleEndian>()?;
841                if id != SAPLING_VERSION_GROUP_ID {
842                    return Err(SerializationError::Parse(
843                        "expected SAPLING_VERSION_GROUP_ID",
844                    ));
845                }
846                // Version 4 transactions use Sprout-on-Groth16.
847                type OptV4Jsd = Option<JoinSplitData<Groth16Proof>>;
848
849                // The previous match arms deserialize in one go, because the
850                // internal structure happens to nicely line up with the
851                // serialized structure. However, this is not possible for
852                // version 4 transactions, as the binding_sig for the
853                // ShieldedData is placed at the end of the transaction. So
854                // instead we have to pull the component parts out manually and
855                // then assemble them.
856
857                // Denoted as `tx_in_count` and `tx_in` in the spec.
858                let inputs = Vec::zcash_deserialize(&mut limited_reader)?;
859
860                // Denoted as `tx_out_count` and `tx_out` in the spec.
861                let outputs = Vec::zcash_deserialize(&mut limited_reader)?;
862
863                // Denoted as `lock_time` in the spec.
864                let lock_time = LockTime::zcash_deserialize(&mut limited_reader)?;
865
866                // Denoted as `nExpiryHeight` in the spec.
867                let expiry_height = block::Height(limited_reader.read_u32::<LittleEndian>()?);
868
869                // Denoted as `valueBalanceSapling` in the spec.
870                let value_balance = (&mut limited_reader).zcash_deserialize_into()?;
871
872                // Denoted as `nSpendsSapling` and `vSpendsSapling` in the spec.
873                let shielded_spends = Vec::zcash_deserialize(&mut limited_reader)?;
874
875                // Denoted as `nOutputsSapling` and `vOutputsSapling` in the spec.
876                let shielded_outputs =
877                    Vec::<sapling::OutputInTransactionV4>::zcash_deserialize(&mut limited_reader)?
878                        .into_iter()
879                        .map(sapling::Output::from_v4)
880                        .collect();
881
882                // A bundle of fields denoted in the spec as `nJoinSplit`, `vJoinSplit`,
883                // `joinSplitPubKey` and `joinSplitSig`.
884                let joinsplit_data = OptV4Jsd::zcash_deserialize(&mut limited_reader)?;
885
886                let sapling_transfers = if !shielded_spends.is_empty() {
887                    Some(sapling::TransferData::SpendsAndMaybeOutputs {
888                        shared_anchor: FieldNotPresent,
889                        spends: shielded_spends.try_into().expect("checked for spends"),
890                        maybe_outputs: shielded_outputs,
891                    })
892                } else if !shielded_outputs.is_empty() {
893                    Some(sapling::TransferData::JustOutputs {
894                        outputs: shielded_outputs.try_into().expect("checked for outputs"),
895                    })
896                } else {
897                    // # Consensus
898                    //
899                    // > [Sapling onward] If effectiveVersion = 4 and there are no Spend
900                    // > descriptions or Output descriptions, then valueBalanceSapling MUST be 0.
901                    //
902                    // https://zips.z.cash/protocol/protocol.pdf#txnconsensus
903                    if value_balance != 0 {
904                        return Err(SerializationError::BadTransactionBalance);
905                    }
906                    None
907                };
908
909                let sapling_shielded_data = match sapling_transfers {
910                    Some(transfers) => Some(sapling::ShieldedData {
911                        value_balance,
912                        transfers,
913                        // Denoted as `bindingSigSapling` in the spec.
914                        binding_sig: limited_reader.read_64_bytes()?.into(),
915                    }),
916                    None => None,
917                };
918
919                Ok(Transaction::V4 {
920                    inputs,
921                    outputs,
922                    lock_time,
923                    expiry_height,
924                    sapling_shielded_data,
925                    joinsplit_data,
926                })
927            }
928            (5, true) => {
929                // Transaction V5 spec:
930                // https://zips.z.cash/protocol/protocol.pdf#txnencoding
931
932                // Denoted as `nVersionGroupId` in the spec.
933                let id = limited_reader.read_u32::<LittleEndian>()?;
934                if id != TX_V5_VERSION_GROUP_ID {
935                    return Err(SerializationError::Parse("expected TX_V5_VERSION_GROUP_ID"));
936                }
937                // Denoted as `nConsensusBranchId` in the spec.
938                // Convert it to a NetworkUpgrade
939                let network_upgrade =
940                    NetworkUpgrade::try_from(limited_reader.read_u32::<LittleEndian>()?)?;
941
942                // Denoted as `lock_time` in the spec.
943                let lock_time = LockTime::zcash_deserialize(&mut limited_reader)?;
944
945                // Denoted as `nExpiryHeight` in the spec.
946                let expiry_height = block::Height(limited_reader.read_u32::<LittleEndian>()?);
947
948                // Denoted as `tx_in_count` and `tx_in` in the spec.
949                let inputs = Vec::zcash_deserialize(&mut limited_reader)?;
950
951                // Denoted as `tx_out_count` and `tx_out` in the spec.
952                let outputs = Vec::zcash_deserialize(&mut limited_reader)?;
953
954                // A bundle of fields denoted in the spec as `nSpendsSapling`, `vSpendsSapling`,
955                // `nOutputsSapling`,`vOutputsSapling`, `valueBalanceSapling`, `anchorSapling`,
956                // `vSpendProofsSapling`, `vSpendAuthSigsSapling`, `vOutputProofsSapling` and
957                // `bindingSigSapling`.
958                let sapling_shielded_data = (&mut limited_reader).zcash_deserialize_into()?;
959
960                // A bundle of fields denoted in the spec as `nActionsOrchard`, `vActionsOrchard`,
961                // `flagsOrchard`,`valueBalanceOrchard`, `anchorOrchard`, `sizeProofsOrchard`,
962                // `proofsOrchard`, `vSpendAuthSigsOrchard`, and `bindingSigOrchard`.
963                let orchard_shielded_data = (&mut limited_reader).zcash_deserialize_into()?;
964
965                Ok(Transaction::V5 {
966                    network_upgrade,
967                    lock_time,
968                    expiry_height,
969                    inputs,
970                    outputs,
971                    sapling_shielded_data,
972                    orchard_shielded_data,
973                })
974            }
975            (_, _) => Err(SerializationError::Parse("bad tx header")),
976        }
977    }
978}
979
980impl<T> ZcashDeserialize for Arc<T>
981where
982    T: ZcashDeserialize,
983{
984    fn zcash_deserialize<R: io::Read>(reader: R) -> Result<Self, SerializationError> {
985        Ok(Arc::new(T::zcash_deserialize(reader)?))
986    }
987}
988
989impl<T> ZcashSerialize for Arc<T>
990where
991    T: ZcashSerialize,
992{
993    fn zcash_serialize<W: io::Write>(&self, writer: W) -> Result<(), io::Error> {
994        T::zcash_serialize(self, writer)
995    }
996}
997
998/// A Tx Input must have an Outpoint (32 byte hash + 4 byte index), a 4 byte sequence number,
999/// and a signature script, which always takes a min of 1 byte (for a length 0 script).
1000pub(crate) const MIN_TRANSPARENT_INPUT_SIZE: u64 = 32 + 4 + 4 + 1;
1001
1002/// A Transparent output has an 8 byte value and script which takes a min of 1 byte.
1003pub(crate) const MIN_TRANSPARENT_OUTPUT_SIZE: u64 = 8 + 1;
1004
1005/// All txs must have at least one input, a 4 byte locktime, and at least one output.
1006///
1007/// Shielded transfers are much larger than transparent transfers,
1008/// so this is the minimum transaction size.
1009pub const MIN_TRANSPARENT_TX_SIZE: u64 =
1010    MIN_TRANSPARENT_INPUT_SIZE + 4 + MIN_TRANSPARENT_OUTPUT_SIZE;
1011
1012/// The minimum transaction size for v4 transactions.
1013///
1014/// v4 transactions also have an expiry height.
1015pub const MIN_TRANSPARENT_TX_V4_SIZE: u64 = MIN_TRANSPARENT_TX_SIZE + 4;
1016
1017/// The minimum transaction size for v5 transactions.
1018///
1019/// v5 transactions also have an expiry height and a consensus branch ID.
1020pub const MIN_TRANSPARENT_TX_V5_SIZE: u64 = MIN_TRANSPARENT_TX_SIZE + 4 + 4;
1021
1022/// No valid Zcash message contains more transactions than can fit in a single block
1023///
1024/// `tx` messages contain a single transaction, and `block` messages are limited to the maximum
1025/// block size.
1026impl TrustedPreallocate for Transaction {
1027    fn max_allocation() -> u64 {
1028        // A transparent transaction is the smallest transaction variant
1029        MAX_BLOCK_BYTES / MIN_TRANSPARENT_TX_SIZE
1030    }
1031}
1032
1033/// The maximum number of inputs in a valid Zcash on-chain transaction.
1034///
1035/// If a transaction contains more inputs than can fit in maximally large block, it might be
1036/// valid on the network and in the mempool, but it can never be mined into a block. So
1037/// rejecting these large edge-case transactions can never break consensus.
1038impl TrustedPreallocate for transparent::Input {
1039    fn max_allocation() -> u64 {
1040        MAX_BLOCK_BYTES / MIN_TRANSPARENT_INPUT_SIZE
1041    }
1042}
1043
1044/// The maximum number of outputs in a valid Zcash on-chain transaction.
1045///
1046/// If a transaction contains more outputs than can fit in maximally large block, it might be
1047/// valid on the network and in the mempool, but it can never be mined into a block. So
1048/// rejecting these large edge-case transactions can never break consensus.
1049impl TrustedPreallocate for transparent::Output {
1050    fn max_allocation() -> u64 {
1051        MAX_BLOCK_BYTES / MIN_TRANSPARENT_OUTPUT_SIZE
1052    }
1053}
1054
1055/// A serialized transaction.
1056///
1057/// Stores bytes that are guaranteed to be deserializable into a [`Transaction`].
1058///
1059/// Sorts in lexicographic order of the transaction's serialized data.
1060#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
1061pub struct SerializedTransaction {
1062    bytes: Vec<u8>,
1063}
1064
1065impl fmt::Display for SerializedTransaction {
1066    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1067        f.write_str(&hex::encode(&self.bytes))
1068    }
1069}
1070
1071impl fmt::Debug for SerializedTransaction {
1072    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1073        // A transaction with a lot of transfers can be extremely long in logs.
1074        let mut data_truncated = hex::encode(&self.bytes);
1075        if data_truncated.len() > 1003 {
1076            let end = data_truncated.len() - 500;
1077            // Replace the middle bytes with "...", but leave 500 bytes on either side.
1078            // The data is hex, so this replacement won't panic.
1079            data_truncated.replace_range(500..=end, "...");
1080        }
1081
1082        f.debug_tuple("SerializedTransaction")
1083            .field(&data_truncated)
1084            .finish()
1085    }
1086}
1087
1088/// Build a [`SerializedTransaction`] by serializing a block.
1089impl<B: Borrow<Transaction>> From<B> for SerializedTransaction {
1090    fn from(tx: B) -> Self {
1091        SerializedTransaction {
1092            bytes: tx
1093                .borrow()
1094                .zcash_serialize_to_vec()
1095                .expect("Writing to a `Vec` should never fail"),
1096        }
1097    }
1098}
1099
1100/// Access the serialized bytes of a [`SerializedTransaction`].
1101impl AsRef<[u8]> for SerializedTransaction {
1102    fn as_ref(&self) -> &[u8] {
1103        self.bytes.as_ref()
1104    }
1105}
1106
1107impl From<Vec<u8>> for SerializedTransaction {
1108    fn from(bytes: Vec<u8>) -> Self {
1109        Self { bytes }
1110    }
1111}
1112
1113impl FromHex for SerializedTransaction {
1114    type Error = <Vec<u8> as FromHex>::Error;
1115
1116    fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, Self::Error> {
1117        let bytes = <Vec<u8>>::from_hex(hex)?;
1118
1119        Ok(bytes.into())
1120    }
1121}