Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Derive Serialize/Deserialize for certain simple structs #1565

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ hex = "0.4"
percent-encoding = "2.1.0"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
serde_with = "3.9"

# HTTP
hyper = "1"
Expand Down
3 changes: 3 additions & 0 deletions components/zcash_protocol/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ proptest = { workspace = true, optional = true }
incrementalmerkletree = { workspace = true, optional = true }
incrementalmerkletree-testing = { workspace = true, optional = true }

serde.workspace = true
serde_with.workspace = true

[dev-dependencies]
proptest.workspace = true

Expand Down
3 changes: 2 additions & 1 deletion components/zcash_protocol/src/consensus.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! Consensus logic and parameters.

use memuse::DynamicUsage;
use serde::{Deserialize, Serialize};
use std::cmp::{Ord, Ordering};
use std::convert::TryFrom;
use std::fmt;
Expand All @@ -13,7 +14,7 @@ use crate::constants::{mainnet, regtest, testnet};
/// Safe conversion from various integer types, as well as addition and subtraction, are
/// provided.
#[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct BlockHeight(u32);

memuse::impl_no_dynamic_usage!(BlockHeight);
Expand Down
6 changes: 4 additions & 2 deletions components/zcash_protocol/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

use core::fmt;

use serde::{Deserialize, Serialize};

pub mod consensus;
pub mod constants;
#[cfg(feature = "local-consensus")]
Expand All @@ -25,7 +27,7 @@ pub mod memo;
pub mod value;

/// A Zcash shielded transfer protocol.
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum ShieldedProtocol {
/// The Sapling protocol
Sapling,
Expand All @@ -34,7 +36,7 @@ pub enum ShieldedProtocol {
}

/// A value pool in the Zcash protocol.
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum PoolType {
/// The transparent value pool
Transparent,
Expand Down
8 changes: 6 additions & 2 deletions components/zcash_protocol/src/memo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ use std::fmt;
use std::ops::Deref;
use std::str;

use serde::{Deserialize, Serialize};
use serde_with::serde_as;

/// Format a byte array as a colon-delimited hex string.
///
/// - Source: <https://github.com/tendermint/signatory>
Expand Down Expand Up @@ -46,8 +49,9 @@ impl fmt::Display for Error {
impl error::Error for Error {}

/// The unencrypted memo bytes received alongside a shielded note in a Zcash transaction.
#[derive(Clone)]
pub struct MemoBytes(pub(crate) Box<[u8; 512]>);
#[serde_as]
#[derive(Clone, Serialize, Deserialize)]
pub struct MemoBytes(#[serde_as(as = "Box<[_; 512]>")] pub(crate) Box<[u8; 512]>);

impl fmt::Debug for MemoBytes {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Expand Down
7 changes: 5 additions & 2 deletions components/zcash_protocol/src/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use std::iter::Sum;
use std::ops::{Add, Mul, Neg, Sub};

use memuse::DynamicUsage;
use serde::{Deserialize, Serialize};

pub const COIN: u64 = 1_0000_0000;
pub const MAX_MONEY: u64 = 21_000_000 * COIN;
Expand All @@ -17,7 +18,8 @@ pub const MAX_BALANCE: i64 = MAX_MONEY as i64;
/// invalid ZatBalances would also be rejected by the network consensus rules.)
///
/// [`Transaction`]: https://docs.rs/zcash_primitives/latest/zcash_primitives/transaction/struct.Transaction.html
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Eq, Ord)]
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Eq, Ord, Serialize, Deserialize)]
#[serde(try_from = "i64", into = "i64")]
pub struct ZatBalance(i64);

memuse::impl_no_dynamic_usage!(ZatBalance);
Expand Down Expand Up @@ -226,7 +228,8 @@ impl Mul<usize> for ZatBalance {
///
/// A Zatoshis can only be constructed from an integer that is within the valid monetary
/// range of `{0..MAX_MONEY}` (where `MAX_MONEY` = 21,000,000 × 10⁸ zatoshis).
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Eq, Ord)]
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Eq, Ord, Serialize, Deserialize)]
#[serde(try_from = "u64", into = "u64")]
pub struct Zatoshis(u64);

impl Zatoshis {
Expand Down
3 changes: 1 addition & 2 deletions zcash_client_backend/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ rand_core.workspace = true
base64.workspace = true
bech32.workspace = true
bs58.workspace = true
serde.workspace = true

# - Errors
bip32 = { workspace = true, optional = true }
Expand Down Expand Up @@ -123,7 +124,6 @@ tower = { workspace = true, optional = true }
http-body-util = { workspace = true, optional = true }
hyper-util = { workspace = true, optional = true }
rand = { workspace = true, optional = true }
serde = { workspace = true, optional = true }
tokio-rustls = { workspace = true, optional = true }
webpki-roots = { workspace = true, optional = true }

Expand Down Expand Up @@ -186,7 +186,6 @@ tor = [
"dep:hyper-util",
"dep:rand",
"dep:rust_decimal",
"dep:serde",
"dep:serde_json",
"dep:tokio",
"dep:tokio-rustls",
Expand Down
7 changes: 4 additions & 3 deletions zcash_client_backend/src/fees.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::fmt;

use serde::{Deserialize, Serialize};
use zcash_primitives::{
consensus::{self, BlockHeight},
memo::MemoBytes,
Expand All @@ -24,10 +25,10 @@ pub mod zip317;
/// `ChangeValue` represents either a proposed change output to a shielded pool
/// (with an optional change memo), or if the "transparent-inputs" feature is
/// enabled, an ephemeral output to the transparent pool.
#[derive(Clone, Debug, PartialEq, Eq)]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct ChangeValue(ChangeValueInner);

#[derive(Clone, Debug, PartialEq, Eq)]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
ec2 marked this conversation as resolved.
Show resolved Hide resolved
enum ChangeValueInner {
Shielded {
protocol: ShieldedProtocol,
Expand Down Expand Up @@ -114,7 +115,7 @@ impl ChangeValue {
/// The amount of change and fees required to make a transaction's inputs and
/// outputs balance under a specific fee rule, as computed by a particular
/// [`ChangeStrategy`] that is aware of that rule.
#[derive(Clone, Debug, PartialEq, Eq)]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
ec2 marked this conversation as resolved.
Show resolved Hide resolved
pub struct TransactionBalance {
proposed_change: Vec<ChangeValue>,
fee_required: NonNegativeAmount,
Expand Down
5 changes: 3 additions & 2 deletions zcash_client_backend/src/proposal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use std::{
};

use nonempty::NonEmpty;
use serde::{Deserialize, Serialize};
use zcash_primitives::{
consensus::BlockHeight,
transaction::{components::amount::NonNegativeAmount, TxId},
Expand Down Expand Up @@ -330,14 +331,14 @@ impl<FeeRuleT: Debug, NoteRef> Debug for Proposal<FeeRuleT, NoteRef> {
}

/// A reference to either a payment or change output within a step.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
ec2 marked this conversation as resolved.
Show resolved Hide resolved
pub enum StepOutputIndex {
Payment(usize),
Change(usize),
}

/// A reference to the output of a step in a proposal.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct StepOutput {
step_index: usize,
output_index: StepOutputIndex,
Expand Down
6 changes: 5 additions & 1 deletion zcash_client_backend/src/wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
//! light client.

use incrementalmerkletree::Position;
use serde::{Deserialize, Serialize};
use zcash_address::ZcashAddress;
use zcash_note_encryption::EphemeralKeyBytes;
use zcash_primitives::{
Expand All @@ -28,7 +29,7 @@ use crate::fees::orchard as orchard_fees;
use zcash_primitives::legacy::keys::{NonHardenedChildIndex, TransparentKeyScope};

/// A unique identifier for a shielded transaction output
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct NoteId {
txid: TxId,
protocol: ShieldedProtocol,
Expand Down Expand Up @@ -171,6 +172,7 @@ impl<AccountId, N, O> Recipient<AccountId, Option<N>, O> {
/// The shielded subset of a [`Transaction`]'s data that is relevant to a particular wallet.
///
/// [`Transaction`]: zcash_primitives::transaction::Transaction
#[derive(Clone)]
pub struct WalletTx<AccountId> {
txid: TxId,
block_index: usize,
Expand Down Expand Up @@ -300,6 +302,7 @@ impl transparent_fees::InputView for WalletTransparentOutput {
}

/// A reference to a spent note belonging to the wallet within a transaction.
#[derive(Clone)]
pub struct WalletSpend<Nf, AccountId> {
index: usize,
nf: Nf,
Expand Down Expand Up @@ -339,6 +342,7 @@ pub type WalletSaplingSpend<AccountId> = WalletSpend<sapling::Nullifier, Account
pub type WalletOrchardSpend<AccountId> = WalletSpend<orchard::note::Nullifier, AccountId>;

/// An output that was successfully decrypted in the process of wallet scanning.
#[derive(Clone)]
pub struct WalletOutput<Note, Nullifier, AccountId> {
index: usize,
ephemeral_key: EphemeralKeyBytes,
Expand Down
1 change: 1 addition & 0 deletions zcash_primitives/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ document-features.workspace = true
bs58.workspace = true
byteorder.workspace = true
hex.workspace = true
serde.workspace = true

# - Shielded protocols
redjubjub = "0.7"
Expand Down
3 changes: 2 additions & 1 deletion zcash_primitives/src/legacy.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! Support for legacy transparent addresses and scripts.

use byteorder::{ReadBytesExt, WriteBytesExt};
use serde::{Deserialize, Serialize};
use zcash_address::TryFromRawAddress;

use std::fmt;
Expand Down Expand Up @@ -272,7 +273,7 @@ impl OpCode {
}

/// A serialized script, used inside transparent inputs and outputs of a transaction.
#[derive(Clone, Default, PartialEq, Eq)]
#[derive(Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct Script(pub Vec<u8>);

impl fmt::Debug for Script {
Expand Down
5 changes: 3 additions & 2 deletions zcash_primitives/src/transaction/components/transparent.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! Structs representing the components within Zcash transactions.

use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use serde::{Deserialize, Serialize};

use std::fmt::Debug;
use std::io::{self, Read, Write};
Expand Down Expand Up @@ -92,7 +93,7 @@ impl<A: Authorization> Bundle<A> {
}
}

#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct OutPoint {
hash: TxId,
n: u32,
Expand Down Expand Up @@ -180,7 +181,7 @@ impl TxIn<Authorized> {
}
}

#[derive(Clone, Debug, PartialEq, Eq)]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct TxOut {
pub value: NonNegativeAmount,
pub script_pubkey: Script,
Expand Down
4 changes: 3 additions & 1 deletion zcash_primitives/src/transaction/fees.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
//! Abstractions and types related to fee calculations.

use serde::{Deserialize, Serialize};

use crate::{
consensus::{self, BlockHeight},
transaction::{components::amount::NonNegativeAmount, fees::transparent::InputSize},
Expand Down Expand Up @@ -60,7 +62,7 @@ pub trait FutureFeeRule: FeeRule {
}

/// An enumeration of the standard fee rules supported by the wallet.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
ec2 marked this conversation as resolved.
Show resolved Hide resolved
pub enum StandardFeeRule {
#[deprecated(
note = "Using this fee rule violates ZIP 317, and might cause transactions built with it to fail. Use `StandardFeeRule::Zip317` instead."
Expand Down
4 changes: 3 additions & 1 deletion zcash_primitives/src/transaction/fees/zip317.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
//! [ZIP 317]: https//zips.z.cash/zip-0317
use core::cmp::max;

use serde::{Deserialize, Serialize};

use crate::{
consensus::{self, BlockHeight},
transaction::{
Expand Down Expand Up @@ -53,7 +55,7 @@ pub const MINIMUM_FEE: NonNegativeAmount = NonNegativeAmount::const_from_u64(10_
///
/// [`FeeRule`]: crate::transaction::fees::FeeRule
/// [ZIP 317]: https//zips.z.cash/zip-0317
#[derive(Clone, Debug)]
#[derive(Clone, Debug, Serialize, Deserialize)]
ec2 marked this conversation as resolved.
Show resolved Hide resolved
pub struct FeeRule {
marginal_fee: NonNegativeAmount,
grace_actions: usize,
Expand Down
3 changes: 2 additions & 1 deletion zcash_primitives/src/transaction/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ mod tests;
use blake2b_simd::Hash as Blake2bHash;
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use memuse::DynamicUsage;
use serde::{Deserialize, Serialize};
use std::convert::TryFrom;
use std::fmt;
use std::fmt::Debug;
Expand Down Expand Up @@ -67,7 +68,7 @@ const ZFUTURE_TX_VERSION: u32 = 0x0000FFFF;
/// that have been mined.
/// - For v5 transactions onwards, this identifier is derived only from "effecting" data,
/// and is non-malleable in all contexts.
#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash)]
#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash, Serialize, Deserialize)]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should use hand-written Serialize and Deserialize impls that serialize to the canonical txid text string representation.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why? Also I dont see the definition for the canonical string rep - could you point me to it? I do see Display implemented so maybe that is it? Is there a FromStr for TxId anywhere?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We haven't needed to implement parsing, but yes the string representation used in the Display impl is canonical.

pub struct TxId([u8; 32]);

memuse::impl_no_dynamic_usage!(TxId);
Expand Down