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        Ok(())
677    }
678}
679
680impl ZcashDeserialize for Transaction {
681    #[allow(clippy::unwrap_in_result)]
682    fn zcash_deserialize<R: io::Read>(reader: R) -> Result<Self, SerializationError> {
683        // # Consensus
684        //
685        // > [Pre-Sapling] The encoded size of the transaction MUST be less than or
686        // > equal to 100000 bytes.
687        //
688        // https://zips.z.cash/protocol/protocol.pdf#txnconsensus
689        //
690        // Zebra does not verify this rule because we checkpoint up to Canopy blocks, but:
691        // Since transactions must get mined into a block to be useful,
692        // we reject transactions that are larger than blocks.
693        //
694        // If the limit is reached, we'll get an UnexpectedEof error.
695        let mut limited_reader = reader.take(MAX_BLOCK_BYTES);
696
697        let (version, overwintered) = {
698            const LOW_31_BITS: u32 = (1 << 31) - 1;
699            // Denoted as `header` in the spec, contains the `fOverwintered` flag and the `version` field.
700            let header = limited_reader.read_u32::<LittleEndian>()?;
701            (header & LOW_31_BITS, header >> 31 != 0)
702        };
703
704        // # Consensus
705        //
706        // The next rules apply for different transaction versions as follows:
707        //
708        // [Pre-Overwinter]: Transactions version 1 and 2.
709        // [Overwinter onward]: Transactions version 3 and above.
710        // [Overwinter only, pre-Sapling]: Transactions version 3.
711        // [Sapling to Canopy inclusive, pre-NU5]: Transactions version 4.
712        // [NU5 onward]: Transactions version 4 and above.
713        //
714        // > The transaction version number MUST be greater than or equal to 1.
715        //
716        // > [Pre-Overwinter] The fOverwintered fag MUST NOT be set.
717        //
718        // > [Overwinter onward] The version group ID MUST be recognized.
719        //
720        // > [Overwinter onward] The fOverwintered flag MUST be set.
721        //
722        // > [Overwinter only, pre-Sapling] The transaction version number MUST be 3,
723        // > and the version group ID MUST be 0x03C48270.
724        //
725        // > [Sapling to Canopy inclusive, pre-NU5] The transaction version number MUST be 4,
726        // > and the version group ID MUST be 0x892F2085.
727        //
728        // > [NU5 onward] The transaction version number MUST be 4 or 5.
729        // > If the transaction version number is 4 then the version group ID MUST be 0x892F2085.
730        // > If the transaction version number is 5 then the version group ID MUST be 0x26A7270A.
731        //
732        // Note: Zebra checkpoints until Canopy blocks, this means only transactions versions
733        // 4 and 5 get fully verified. This satisfies "The transaction version number MUST be 4"
734        // and "The transaction version number MUST be 4 or 5" from the last two rules above.
735        // This is done in the zebra-consensus crate, in the transactions checks.
736        //
737        // https://zips.z.cash/protocol/protocol.pdf#txnconsensus
738        match (version, overwintered) {
739            (1, false) => Ok(Transaction::V1 {
740                // Denoted as `tx_in_count` and `tx_in` in the spec.
741                inputs: Vec::zcash_deserialize(&mut limited_reader)?,
742                // Denoted as `tx_out_count` and `tx_out` in the spec.
743                outputs: Vec::zcash_deserialize(&mut limited_reader)?,
744                // Denoted as `lock_time` in the spec.
745                lock_time: LockTime::zcash_deserialize(&mut limited_reader)?,
746            }),
747            (2, false) => {
748                // Version 2 transactions use Sprout-on-BCTV14.
749                type OptV2Jsd = Option<JoinSplitData<Bctv14Proof>>;
750                Ok(Transaction::V2 {
751                    // Denoted as `tx_in_count` and `tx_in` in the spec.
752                    inputs: Vec::zcash_deserialize(&mut limited_reader)?,
753                    // Denoted as `tx_out_count` and `tx_out` in the spec.
754                    outputs: Vec::zcash_deserialize(&mut limited_reader)?,
755                    // Denoted as `lock_time` in the spec.
756                    lock_time: LockTime::zcash_deserialize(&mut limited_reader)?,
757                    // A bundle of fields denoted in the spec as `nJoinSplit`, `vJoinSplit`,
758                    // `joinSplitPubKey` and `joinSplitSig`.
759                    joinsplit_data: OptV2Jsd::zcash_deserialize(&mut limited_reader)?,
760                })
761            }
762            (3, true) => {
763                // Denoted as `nVersionGroupId` in the spec.
764                let id = limited_reader.read_u32::<LittleEndian>()?;
765                if id != OVERWINTER_VERSION_GROUP_ID {
766                    return Err(SerializationError::Parse(
767                        "expected OVERWINTER_VERSION_GROUP_ID",
768                    ));
769                }
770                // Version 3 transactions use Sprout-on-BCTV14.
771                type OptV3Jsd = Option<JoinSplitData<Bctv14Proof>>;
772                Ok(Transaction::V3 {
773                    // Denoted as `tx_in_count` and `tx_in` in the spec.
774                    inputs: Vec::zcash_deserialize(&mut limited_reader)?,
775                    // Denoted as `tx_out_count` and `tx_out` in the spec.
776                    outputs: Vec::zcash_deserialize(&mut limited_reader)?,
777                    // Denoted as `lock_time` in the spec.
778                    lock_time: LockTime::zcash_deserialize(&mut limited_reader)?,
779                    // Denoted as `nExpiryHeight` in the spec.
780                    expiry_height: block::Height(limited_reader.read_u32::<LittleEndian>()?),
781                    // A bundle of fields denoted in the spec as `nJoinSplit`, `vJoinSplit`,
782                    // `joinSplitPubKey` and `joinSplitSig`.
783                    joinsplit_data: OptV3Jsd::zcash_deserialize(&mut limited_reader)?,
784                })
785            }
786            (4, true) => {
787                // Transaction V4 spec:
788                // https://zips.z.cash/protocol/protocol.pdf#txnencoding
789
790                // Denoted as `nVersionGroupId` in the spec.
791                let id = limited_reader.read_u32::<LittleEndian>()?;
792                if id != SAPLING_VERSION_GROUP_ID {
793                    return Err(SerializationError::Parse(
794                        "expected SAPLING_VERSION_GROUP_ID",
795                    ));
796                }
797                // Version 4 transactions use Sprout-on-Groth16.
798                type OptV4Jsd = Option<JoinSplitData<Groth16Proof>>;
799
800                // The previous match arms deserialize in one go, because the
801                // internal structure happens to nicely line up with the
802                // serialized structure. However, this is not possible for
803                // version 4 transactions, as the binding_sig for the
804                // ShieldedData is placed at the end of the transaction. So
805                // instead we have to pull the component parts out manually and
806                // then assemble them.
807
808                // Denoted as `tx_in_count` and `tx_in` in the spec.
809                let inputs = Vec::zcash_deserialize(&mut limited_reader)?;
810
811                // Denoted as `tx_out_count` and `tx_out` in the spec.
812                let outputs = Vec::zcash_deserialize(&mut limited_reader)?;
813
814                // Denoted as `lock_time` in the spec.
815                let lock_time = LockTime::zcash_deserialize(&mut limited_reader)?;
816
817                // Denoted as `nExpiryHeight` in the spec.
818                let expiry_height = block::Height(limited_reader.read_u32::<LittleEndian>()?);
819
820                // Denoted as `valueBalanceSapling` in the spec.
821                let value_balance = (&mut limited_reader).zcash_deserialize_into()?;
822
823                // Denoted as `nSpendsSapling` and `vSpendsSapling` in the spec.
824                let shielded_spends = Vec::zcash_deserialize(&mut limited_reader)?;
825
826                // Denoted as `nOutputsSapling` and `vOutputsSapling` in the spec.
827                let shielded_outputs =
828                    Vec::<sapling::OutputInTransactionV4>::zcash_deserialize(&mut limited_reader)?
829                        .into_iter()
830                        .map(sapling::Output::from_v4)
831                        .collect();
832
833                // A bundle of fields denoted in the spec as `nJoinSplit`, `vJoinSplit`,
834                // `joinSplitPubKey` and `joinSplitSig`.
835                let joinsplit_data = OptV4Jsd::zcash_deserialize(&mut limited_reader)?;
836
837                let sapling_transfers = if !shielded_spends.is_empty() {
838                    Some(sapling::TransferData::SpendsAndMaybeOutputs {
839                        shared_anchor: FieldNotPresent,
840                        spends: shielded_spends.try_into().expect("checked for spends"),
841                        maybe_outputs: shielded_outputs,
842                    })
843                } else if !shielded_outputs.is_empty() {
844                    Some(sapling::TransferData::JustOutputs {
845                        outputs: shielded_outputs.try_into().expect("checked for outputs"),
846                    })
847                } else {
848                    // # Consensus
849                    //
850                    // > [Sapling onward] If effectiveVersion = 4 and there are no Spend
851                    // > descriptions or Output descriptions, then valueBalanceSapling MUST be 0.
852                    //
853                    // https://zips.z.cash/protocol/protocol.pdf#txnconsensus
854                    if value_balance != 0 {
855                        return Err(SerializationError::BadTransactionBalance);
856                    }
857                    None
858                };
859
860                let sapling_shielded_data = match sapling_transfers {
861                    Some(transfers) => Some(sapling::ShieldedData {
862                        value_balance,
863                        transfers,
864                        // Denoted as `bindingSigSapling` in the spec.
865                        binding_sig: limited_reader.read_64_bytes()?.into(),
866                    }),
867                    None => None,
868                };
869
870                Ok(Transaction::V4 {
871                    inputs,
872                    outputs,
873                    lock_time,
874                    expiry_height,
875                    sapling_shielded_data,
876                    joinsplit_data,
877                })
878            }
879            (5, true) => {
880                // Transaction V5 spec:
881                // https://zips.z.cash/protocol/protocol.pdf#txnencoding
882
883                // Denoted as `nVersionGroupId` in the spec.
884                let id = limited_reader.read_u32::<LittleEndian>()?;
885                if id != TX_V5_VERSION_GROUP_ID {
886                    return Err(SerializationError::Parse("expected TX_V5_VERSION_GROUP_ID"));
887                }
888                // Denoted as `nConsensusBranchId` in the spec.
889                // Convert it to a NetworkUpgrade
890                let network_upgrade =
891                    NetworkUpgrade::try_from(limited_reader.read_u32::<LittleEndian>()?)?;
892
893                // Denoted as `lock_time` in the spec.
894                let lock_time = LockTime::zcash_deserialize(&mut limited_reader)?;
895
896                // Denoted as `nExpiryHeight` in the spec.
897                let expiry_height = block::Height(limited_reader.read_u32::<LittleEndian>()?);
898
899                // Denoted as `tx_in_count` and `tx_in` in the spec.
900                let inputs = Vec::zcash_deserialize(&mut limited_reader)?;
901
902                // Denoted as `tx_out_count` and `tx_out` in the spec.
903                let outputs = Vec::zcash_deserialize(&mut limited_reader)?;
904
905                // A bundle of fields denoted in the spec as `nSpendsSapling`, `vSpendsSapling`,
906                // `nOutputsSapling`,`vOutputsSapling`, `valueBalanceSapling`, `anchorSapling`,
907                // `vSpendProofsSapling`, `vSpendAuthSigsSapling`, `vOutputProofsSapling` and
908                // `bindingSigSapling`.
909                let sapling_shielded_data = (&mut limited_reader).zcash_deserialize_into()?;
910
911                // A bundle of fields denoted in the spec as `nActionsOrchard`, `vActionsOrchard`,
912                // `flagsOrchard`,`valueBalanceOrchard`, `anchorOrchard`, `sizeProofsOrchard`,
913                // `proofsOrchard`, `vSpendAuthSigsOrchard`, and `bindingSigOrchard`.
914                let orchard_shielded_data = (&mut limited_reader).zcash_deserialize_into()?;
915
916                Ok(Transaction::V5 {
917                    network_upgrade,
918                    lock_time,
919                    expiry_height,
920                    inputs,
921                    outputs,
922                    sapling_shielded_data,
923                    orchard_shielded_data,
924                })
925            }
926            (_, _) => Err(SerializationError::Parse("bad tx header")),
927        }
928    }
929}
930
931impl<T> ZcashDeserialize for Arc<T>
932where
933    T: ZcashDeserialize,
934{
935    fn zcash_deserialize<R: io::Read>(reader: R) -> Result<Self, SerializationError> {
936        Ok(Arc::new(T::zcash_deserialize(reader)?))
937    }
938}
939
940impl<T> ZcashSerialize for Arc<T>
941where
942    T: ZcashSerialize,
943{
944    fn zcash_serialize<W: io::Write>(&self, writer: W) -> Result<(), io::Error> {
945        T::zcash_serialize(self, writer)
946    }
947}
948
949/// A Tx Input must have an Outpoint (32 byte hash + 4 byte index), a 4 byte sequence number,
950/// and a signature script, which always takes a min of 1 byte (for a length 0 script).
951pub(crate) const MIN_TRANSPARENT_INPUT_SIZE: u64 = 32 + 4 + 4 + 1;
952
953/// A Transparent output has an 8 byte value and script which takes a min of 1 byte.
954pub(crate) const MIN_TRANSPARENT_OUTPUT_SIZE: u64 = 8 + 1;
955
956/// All txs must have at least one input, a 4 byte locktime, and at least one output.
957///
958/// Shielded transfers are much larger than transparent transfers,
959/// so this is the minimum transaction size.
960pub const MIN_TRANSPARENT_TX_SIZE: u64 =
961    MIN_TRANSPARENT_INPUT_SIZE + 4 + MIN_TRANSPARENT_OUTPUT_SIZE;
962
963/// The minimum transaction size for v4 transactions.
964///
965/// v4 transactions also have an expiry height.
966pub const MIN_TRANSPARENT_TX_V4_SIZE: u64 = MIN_TRANSPARENT_TX_SIZE + 4;
967
968/// The minimum transaction size for v5 transactions.
969///
970/// v5 transactions also have an expiry height and a consensus branch ID.
971pub const MIN_TRANSPARENT_TX_V5_SIZE: u64 = MIN_TRANSPARENT_TX_SIZE + 4 + 4;
972
973/// No valid Zcash message contains more transactions than can fit in a single block
974///
975/// `tx` messages contain a single transaction, and `block` messages are limited to the maximum
976/// block size.
977impl TrustedPreallocate for Transaction {
978    fn max_allocation() -> u64 {
979        // A transparent transaction is the smallest transaction variant
980        MAX_BLOCK_BYTES / MIN_TRANSPARENT_TX_SIZE
981    }
982}
983
984/// The maximum number of inputs in a valid Zcash on-chain transaction.
985///
986/// If a transaction contains more inputs than can fit in maximally large block, it might be
987/// valid on the network and in the mempool, but it can never be mined into a block. So
988/// rejecting these large edge-case transactions can never break consensus.
989impl TrustedPreallocate for transparent::Input {
990    fn max_allocation() -> u64 {
991        MAX_BLOCK_BYTES / MIN_TRANSPARENT_INPUT_SIZE
992    }
993}
994
995/// The maximum number of outputs in a valid Zcash on-chain transaction.
996///
997/// If a transaction contains more outputs than can fit in maximally large block, it might be
998/// valid on the network and in the mempool, but it can never be mined into a block. So
999/// rejecting these large edge-case transactions can never break consensus.
1000impl TrustedPreallocate for transparent::Output {
1001    fn max_allocation() -> u64 {
1002        MAX_BLOCK_BYTES / MIN_TRANSPARENT_OUTPUT_SIZE
1003    }
1004}
1005
1006/// A serialized transaction.
1007///
1008/// Stores bytes that are guaranteed to be deserializable into a [`Transaction`].
1009///
1010/// Sorts in lexicographic order of the transaction's serialized data.
1011#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
1012pub struct SerializedTransaction {
1013    bytes: Vec<u8>,
1014}
1015
1016impl fmt::Display for SerializedTransaction {
1017    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1018        f.write_str(&hex::encode(&self.bytes))
1019    }
1020}
1021
1022impl fmt::Debug for SerializedTransaction {
1023    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1024        // A transaction with a lot of transfers can be extremely long in logs.
1025        let mut data_truncated = hex::encode(&self.bytes);
1026        if data_truncated.len() > 1003 {
1027            let end = data_truncated.len() - 500;
1028            // Replace the middle bytes with "...", but leave 500 bytes on either side.
1029            // The data is hex, so this replacement won't panic.
1030            data_truncated.replace_range(500..=end, "...");
1031        }
1032
1033        f.debug_tuple("SerializedTransaction")
1034            .field(&data_truncated)
1035            .finish()
1036    }
1037}
1038
1039/// Build a [`SerializedTransaction`] by serializing a block.
1040impl<B: Borrow<Transaction>> From<B> for SerializedTransaction {
1041    fn from(tx: B) -> Self {
1042        SerializedTransaction {
1043            bytes: tx
1044                .borrow()
1045                .zcash_serialize_to_vec()
1046                .expect("Writing to a `Vec` should never fail"),
1047        }
1048    }
1049}
1050
1051/// Access the serialized bytes of a [`SerializedTransaction`].
1052impl AsRef<[u8]> for SerializedTransaction {
1053    fn as_ref(&self) -> &[u8] {
1054        self.bytes.as_ref()
1055    }
1056}
1057
1058impl From<Vec<u8>> for SerializedTransaction {
1059    fn from(bytes: Vec<u8>) -> Self {
1060        Self { bytes }
1061    }
1062}
1063
1064impl FromHex for SerializedTransaction {
1065    type Error = <Vec<u8> as FromHex>::Error;
1066
1067    fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, Self::Error> {
1068        let bytes = <Vec<u8>>::from_hex(hex)?;
1069
1070        Ok(bytes.into())
1071    }
1072}