From 77085a1fa1f39e7358202e49189282e48a965747 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Wed, 27 Nov 2024 14:09:56 +1100 Subject: [PATCH] units: Remove serde from amounts The `Amount` and `SignedAmount` were not supposed to implement `serde` traits by design because doing so implicitly uses sats. We provide two modules `as_sat` and `as_btc` to allow users to explicitly serialize in their preferred format. In commit: `d57ec019d5 Use Amount type for TxOut value field` derives were added for `serde` and we did not notice it during review. --- bitcoin/src/crypto/sighash.rs | 1 + primitives/src/transaction.rs | 1 + units/src/amount/signed.rs | 21 ++++++++++++++++++--- units/src/amount/unsigned.rs | 24 ++++++++++++++++++------ 4 files changed, 38 insertions(+), 9 deletions(-) diff --git a/bitcoin/src/crypto/sighash.rs b/bitcoin/src/crypto/sighash.rs index d5651de35..ccbac973e 100644 --- a/bitcoin/src/crypto/sighash.rs +++ b/bitcoin/src/crypto/sighash.rs @@ -1862,6 +1862,7 @@ mod tests { #[serde(rename = "scriptPubKey")] script_pubkey: ScriptBuf, #[serde(rename = "amountSats")] + #[serde(with = "crate::amount::serde::as_sat")] value: Amount, } diff --git a/primitives/src/transaction.rs b/primitives/src/transaction.rs index 639f0c52a..4a4c6f668 100644 --- a/primitives/src/transaction.rs +++ b/primitives/src/transaction.rs @@ -343,6 +343,7 @@ impl TxIn { #[cfg(feature = "alloc")] pub struct TxOut { /// The value of the output, in satoshis. + #[cfg_attr(feature = "serde", serde(with = "crate::amount::serde::as_sat"))] pub value: Amount, /// The script which must be satisfied for the output to be spent. pub script_pubkey: ScriptBuf, diff --git a/units/src/amount/signed.rs b/units/src/amount/signed.rs index b90fdd5e7..266a5d32a 100644 --- a/units/src/amount/signed.rs +++ b/units/src/amount/signed.rs @@ -17,9 +17,9 @@ use super::{ /// A signed amount. /// -/// The [`SignedAmount`] type can be used to express Bitcoin amounts that support -/// arithmetic and conversion to various denominations. -/// +/// The [`SignedAmount`] type can be used to express Bitcoin amounts that support arithmetic and +/// conversion to various denominations. The `Amount` type does not implement `serde` traits but we +/// do provide modules for serializing as satoshis or bitcoin. /// /// Warning! /// @@ -29,6 +29,21 @@ use super::{ /// start with `checked_`. The operations from [`core::ops`] that [`Amount`] /// implements will panic when overflow or underflow occurs. /// +/// # Examples +/// +/// ``` +/// # #[cfg(feature = "serde")] { +/// use serde::{Serialize, Deserialize}; +/// use bitcoin_units::SignedAmount; +/// +/// #[derive(Serialize, Deserialize)] +/// struct Foo { +/// // If you are using `rust-bitcoin` then `bitcoin::amount::serde::as_sat` also works. +/// #[serde(with = "bitcoin_units::amount::serde::as_sat")] // Also `serde::as_btc`. +/// amount: SignedAmount, +/// } +/// # } +/// ``` #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct SignedAmount(i64); diff --git a/units/src/amount/unsigned.rs b/units/src/amount/unsigned.rs index a68262385..c2e6de9a9 100644 --- a/units/src/amount/unsigned.rs +++ b/units/src/amount/unsigned.rs @@ -7,8 +7,6 @@ use alloc::string::{String, ToString}; use core::str::FromStr; use core::{default, fmt, ops}; -#[cfg(feature = "serde")] -use ::serde::{Deserialize, Serialize}; #[cfg(feature = "arbitrary")] use arbitrary::{Arbitrary, Unstructured}; @@ -21,9 +19,9 @@ use crate::{FeeRate, Weight}; /// An amount. /// -/// The [`Amount`] type can be used to express Bitcoin amounts that support -/// arithmetic and conversion to various denominations. -/// +/// The [`Amount`] type can be used to express Bitcoin amounts that support arithmetic and +/// conversion to various denominations. The `Amount` type does not implement `serde` traits but we +/// do provide modules for serializing as satoshis or bitcoin. /// /// Warning! /// @@ -36,8 +34,22 @@ use crate::{FeeRate, Weight}; /// zero is considered an underflow and will cause a panic if you're not using /// the checked arithmetic methods. /// +/// # Examples +/// +/// ``` +/// # #[cfg(feature = "serde")] { +/// use serde::{Serialize, Deserialize}; +/// use bitcoin_units::Amount; +/// +/// #[derive(Serialize, Deserialize)] +/// struct Foo { +/// // If you are using `rust-bitcoin` then `bitcoin::amount::serde::as_sat` also works. +/// #[serde(with = "bitcoin_units::amount::serde::as_sat")] // Also `serde::as_btc`. +/// amount: Amount, +/// } +/// # } +/// ``` #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct Amount(u64); impl Amount {