From 418575458ecc16e0216d56add9d086473dd1fb61 Mon Sep 17 00:00:00 2001 From: teor Date: Wed, 7 Apr 2021 22:34:58 +1000 Subject: [PATCH] Rename the () placeholder to FieldNotPresent (#1987) * Rename the () placeholder to FieldNotPresent * Use a unit struct * Update the RFC --- book/src/dev/rfcs/0010-v5-transaction.md | 7 +++++-- zebra-chain/src/sapling.rs | 4 +++- zebra-chain/src/sapling/arbitrary.rs | 5 +++-- zebra-chain/src/sapling/shielded_data.rs | 15 +++++++-------- zebra-chain/src/sapling/spend.rs | 9 ++++----- zebra-chain/src/transaction.rs | 1 + zebra-chain/src/transaction/arbitrary.rs | 4 ++-- zebra-chain/src/transaction/serialize.rs | 4 ++-- 8 files changed, 27 insertions(+), 22 deletions(-) diff --git a/book/src/dev/rfcs/0010-v5-transaction.md b/book/src/dev/rfcs/0010-v5-transaction.md index 0a0c9a5c27d..3c6751363b2 100644 --- a/book/src/dev/rfcs/0010-v5-transaction.md +++ b/book/src/dev/rfcs/0010-v5-transaction.md @@ -95,14 +95,17 @@ We add an `AnchorVariant` generic type trait, because V4 transactions have a per struct PerSpendAnchor {} struct SharedAnchor {} +/// This field is not present in this transaction version. +struct FieldNotPresent; + impl AnchorVariant for PerSpendAnchor { - type Shared = (); + type Shared = FieldNotPresent; type PerSpend = tree::Root; } impl AnchorVariant for SharedAnchor { type Shared = tree::Root; - type PerSpend = (); + type PerSpend = FieldNotPresent; } trait AnchorVariant { diff --git a/zebra-chain/src/sapling.rs b/zebra-chain/src/sapling.rs index d62e8206b78..5c7aabf0b59 100644 --- a/zebra-chain/src/sapling.rs +++ b/zebra-chain/src/sapling.rs @@ -21,5 +21,7 @@ pub use commitment::{CommitmentRandomness, NoteCommitment, ValueCommitment}; pub use keys::Diversifier; pub use note::{EncryptedNote, Note, Nullifier, WrappedNoteKey}; pub use output::Output; -pub use shielded_data::{AnchorVariant, PerSpendAnchor, SharedAnchor, ShieldedData}; +pub use shielded_data::{ + AnchorVariant, FieldNotPresent, PerSpendAnchor, SharedAnchor, ShieldedData, +}; pub use spend::Spend; diff --git a/zebra-chain/src/sapling/arbitrary.rs b/zebra-chain/src/sapling/arbitrary.rs index 7f3faebcdfe..60237e3d95d 100644 --- a/zebra-chain/src/sapling/arbitrary.rs +++ b/zebra-chain/src/sapling/arbitrary.rs @@ -4,7 +4,8 @@ use proptest::{arbitrary::any, array, collection::vec, prelude::*}; use crate::primitives::Groth16Proof; use super::{ - keys, note, tree, NoteCommitment, Output, PerSpendAnchor, SharedAnchor, Spend, ValueCommitment, + keys, note, tree, FieldNotPresent, NoteCommitment, Output, PerSpendAnchor, SharedAnchor, Spend, + ValueCommitment, }; impl Arbitrary for Spend { @@ -49,7 +50,7 @@ impl Arbitrary for Spend { vec(any::(), 64), ) .prop_map(|(nullifier, rpk_bytes, proof, sig_bytes)| Self { - per_spend_anchor: (), + per_spend_anchor: FieldNotPresent, cv: ValueCommitment(AffinePoint::identity()), nullifier, rk: redjubjub::VerificationKeyBytes::from(rpk_bytes), diff --git a/zebra-chain/src/sapling/shielded_data.rs b/zebra-chain/src/sapling/shielded_data.rs index 86341227256..88a6add6f79 100644 --- a/zebra-chain/src/sapling/shielded_data.rs +++ b/zebra-chain/src/sapling/shielded_data.rs @@ -28,14 +28,18 @@ pub struct PerSpendAnchor {} #[derive(Copy, Clone, Debug, Deserialize, Serialize, PartialEq, Eq)] pub struct SharedAnchor {} +/// This field is not present in this transaction version. +#[derive(Copy, Clone, Debug, Deserialize, Serialize, PartialEq, Eq)] +pub struct FieldNotPresent; + impl AnchorVariant for PerSpendAnchor { - type Shared = (); + type Shared = FieldNotPresent; type PerSpend = tree::Root; } impl AnchorVariant for SharedAnchor { type Shared = tree::Root; - type PerSpend = (); + type PerSpend = FieldNotPresent; } /// A type trait to handle structural differences between V4 and V5 Sapling @@ -45,13 +49,9 @@ impl AnchorVariant for SharedAnchor { /// single transaction anchor for all Spends in a transaction. pub trait AnchorVariant { /// The type of the shared anchor. - /// - /// `()` means "not present in this transaction version". type Shared: Clone + Debug + DeserializeOwned + Serialize + Eq + PartialEq; /// The type of the per-spend anchor. - /// - /// `()` means "not present in this transaction version". type PerSpend: Clone + Debug + DeserializeOwned + Serialize + Eq + PartialEq; } @@ -74,7 +74,6 @@ pub trait AnchorVariant { /// In `Transaction::V4`, each `Spend` has its own anchor. In `Transaction::V5`, /// there is a single `shared_anchor` for the entire transaction. This /// structural difference is modeled using the `AnchorVariant` type trait. -/// A type of `()` means "not present in this transaction version". #[derive(Clone, Debug, Serialize, Deserialize)] pub struct ShieldedData where @@ -84,7 +83,7 @@ where pub value_balance: Amount, /// The shared anchor for all `Spend`s in this transaction. /// - /// A type of `()` means "not present in this transaction version". + /// Some transaction versions do not have this field. pub shared_anchor: AnchorV::Shared, /// Either a spend or output description. /// diff --git a/zebra-chain/src/sapling/spend.rs b/zebra-chain/src/sapling/spend.rs index c8c5e5221a7..6fb504b8bd3 100644 --- a/zebra-chain/src/sapling/spend.rs +++ b/zebra-chain/src/sapling/spend.rs @@ -17,7 +17,7 @@ use crate::{ }, }; -use super::{commitment, note, tree, AnchorVariant, PerSpendAnchor, SharedAnchor}; +use super::{commitment, note, tree, AnchorVariant, FieldNotPresent, PerSpendAnchor, SharedAnchor}; /// A _Spend Description_, as described in [protocol specification ยง7.3][ps]. /// @@ -26,7 +26,6 @@ use super::{commitment, note, tree, AnchorVariant, PerSpendAnchor, SharedAnchor} /// In `Transaction::V4`, each `Spend` has its own anchor. In `Transaction::V5`, /// there is a single `shared_anchor` for the entire transaction. This /// structural difference is modeled using the `AnchorVariant` type trait. -/// A type of `()` means "not present in this transaction version". /// /// [ps]: https://zips.z.cash/protocol/protocol.pdf#spendencoding #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] @@ -35,7 +34,7 @@ pub struct Spend { pub cv: commitment::ValueCommitment, /// A root of the Sapling note commitment tree at some block height in the past. /// - /// A type of `()` means "not present in this transaction version". + /// Some transaction versions do not have this field. pub per_spend_anchor: AnchorV::PerSpend, /// The nullifier of the input note. pub nullifier: note::Nullifier, @@ -62,9 +61,9 @@ impl From<(Spend, tree::Root)> for Spend { } } -impl From<(Spend, ())> for Spend { +impl From<(Spend, FieldNotPresent)> for Spend { /// Take the `Spend` from a spend + anchor tuple. - fn from(per_spend: (Spend, ())) -> Self { + fn from(per_spend: (Spend, FieldNotPresent)) -> Self { per_spend.0 } } diff --git a/zebra-chain/src/transaction.rs b/zebra-chain/src/transaction.rs index d924ee3765b..835cdbc06ac 100644 --- a/zebra-chain/src/transaction.rs +++ b/zebra-chain/src/transaction.rs @@ -18,6 +18,7 @@ pub use hash::Hash; pub use joinsplit::JoinSplitData; pub use lock_time::LockTime; pub use memo::Memo; +pub use sapling::FieldNotPresent; pub use sighash::HashType; use crate::{ diff --git a/zebra-chain/src/transaction/arbitrary.rs b/zebra-chain/src/transaction/arbitrary.rs index 9afb0558a9c..38316ace8d1 100644 --- a/zebra-chain/src/transaction/arbitrary.rs +++ b/zebra-chain/src/transaction/arbitrary.rs @@ -13,7 +13,7 @@ use crate::{ sapling, sprout, transparent, }; -use super::{JoinSplitData, LockTime, Memo, Transaction}; +use super::{FieldNotPresent, JoinSplitData, LockTime, Memo, Transaction}; impl Transaction { /// Generate a proptest strategy for V1 Transactions @@ -219,7 +219,7 @@ impl Arbitrary for sapling::ShieldedData { .prop_map( |(value_balance, first, rest_spends, rest_outputs, sig_bytes)| Self { value_balance, - shared_anchor: (), + shared_anchor: FieldNotPresent, first, rest_spends, rest_outputs, diff --git a/zebra-chain/src/transaction/serialize.rs b/zebra-chain/src/transaction/serialize.rs index 2b412a5e7a3..498d9b69da9 100644 --- a/zebra-chain/src/transaction/serialize.rs +++ b/zebra-chain/src/transaction/serialize.rs @@ -281,7 +281,7 @@ impl ZcashDeserialize for Transaction { let sapling_shielded_data = if !shielded_spends.is_empty() { Some(sapling::ShieldedData { value_balance, - shared_anchor: (), + shared_anchor: FieldNotPresent, first: Left(shielded_spends.remove(0)), rest_spends: shielded_spends, rest_outputs: shielded_outputs, @@ -290,7 +290,7 @@ impl ZcashDeserialize for Transaction { } else if !shielded_outputs.is_empty() { Some(sapling::ShieldedData { value_balance, - shared_anchor: (), + shared_anchor: FieldNotPresent, first: Right(shielded_outputs.remove(0)), // the spends are actually empty here, but we use the // vec for consistency and readability