diff --git a/Cargo.toml b/Cargo.toml index 09c47601..0a4d131c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,16 +23,15 @@ secp-lowmemory = ["secp256k1/lowmemory"] secp-recovery = ["secp256k1/recovery"] [dependencies] -base64-compat = { version = "1.0.0", optional = true } bech32 = "0.7.2" bitcoin_hashes = "0.9.1" secp256k1 = { version = "0.19.0", features = [ "recovery" ] } +base64-compat = { version = "1.0.0", optional = true } bitcoinconsensus = { version = "0.19.0-1", optional = true } -serde = { version = "1", optional = true } +serde = { version = "1", features = [ "derive" ], optional = true } [dev-dependencies] -serde_derive = "<1.0.99" serde_json = "<1.0.45" serde_test = "1" secp256k1 = { version = "0.19.0", features = [ "recovery", "rand-std" ] } diff --git a/README.md b/README.md index 36a3c96e..56a12282 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,13 @@ compile with 1.29.0 you will need to run the following version-pinning command: cargo update -p cc --precise "1.0.41" --verbose ``` +In order to use the `use-serde` feature or to build the unit tests with 1.29.0, +the following version-pinning commands are also needed: +``` +cargo update --package "serde" --precise "1.0.98" +cargo update --package "serde_derive" --precise "1.0.98" +``` + ## Installing Rust Rust can be installed using your package manager of choice or [rustup.rs](https://rustup.rs). The former way is considered more secure since diff --git a/src/blockdata/block.rs b/src/blockdata/block.rs index f85fab9c..8b69c8f4 100644 --- a/src/blockdata/block.rs +++ b/src/blockdata/block.rs @@ -38,6 +38,7 @@ use VarInt; /// A block header, which contains all the block's information except /// the actual transactions #[derive(Copy, PartialEq, Eq, Clone, Debug)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct BlockHeader { /// The protocol version. Should always be 1. pub version: i32, @@ -55,7 +56,6 @@ pub struct BlockHeader { } impl_consensus_encoding!(BlockHeader, version, prev_blockhash, merkle_root, time, bits, nonce); -serde_struct_impl!(BlockHeader, version, prev_blockhash, merkle_root, time, bits, nonce); impl BlockHeader { /// Return the block hash. @@ -156,6 +156,7 @@ impl BlockHeader { /// A Bitcoin block, which is a collection of transactions with an attached /// proof of work. #[derive(PartialEq, Eq, Clone, Debug)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct Block { /// The block header pub header: BlockHeader, @@ -164,7 +165,6 @@ pub struct Block { } impl_consensus_encoding!(Block, header, txdata); -serde_struct_impl!(Block, header, txdata); impl Block { /// Return the block hash. diff --git a/src/blockdata/transaction.rs b/src/blockdata/transaction.rs index b7829ac6..bcfefa5f 100644 --- a/src/blockdata/transaction.rs +++ b/src/blockdata/transaction.rs @@ -174,6 +174,7 @@ impl ::std::str::FromStr for OutPoint { /// A transaction input, which defines old coins to be consumed #[derive(Clone, PartialEq, Eq, Debug, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct TxIn { /// The reference to the previous output that is being used an an input pub previous_output: OutPoint, @@ -192,7 +193,6 @@ pub struct TxIn { /// (de)serialization routines. pub witness: Vec> } -serde_struct_impl!(TxIn, previous_output, script_sig, sequence, witness); impl Default for TxIn { fn default() -> TxIn { @@ -207,13 +207,13 @@ impl Default for TxIn { /// A transaction output, which defines new coins to be created from old ones. #[derive(Clone, PartialEq, Eq, Debug, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct TxOut { /// The value of the output, in satoshis pub value: u64, /// The script which must satisfy for the output to be spent pub script_pubkey: Script } -serde_struct_impl!(TxOut, value, script_pubkey); // This is used as a "null txout" in consensus signing code impl Default for TxOut { @@ -253,6 +253,7 @@ impl Default for TxOut { /// We therefore deviate from the spec by always using the Segwit witness encoding /// for 0-input transactions, which results in unambiguously parseable transactions. #[derive(Clone, PartialEq, Eq, Debug, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct Transaction { /// The protocol version, is currently expected to be 1 or 2 (BIP 68). pub version: i32, @@ -264,7 +265,6 @@ pub struct Transaction { /// List of outputs pub output: Vec, } -serde_struct_impl!(Transaction, version, lock_time, input, output); impl Transaction { /// Computes a "normalized TXID" which does not include any signatures. diff --git a/src/internal_macros.rs b/src/internal_macros.rs index 88a39705..52fd78a1 100644 --- a/src/internal_macros.rs +++ b/src/internal_macros.rs @@ -163,148 +163,6 @@ macro_rules! hex_script (($s:expr) => ($crate::blockdata::script::Script::from(< #[cfg(test)] macro_rules! hex_hash (($h:ident, $s:expr) => ($h::from_slice(& as $crate::hashes::hex::FromHex>::from_hex($s).unwrap()).unwrap())); -macro_rules! serde_struct_impl { - ($name:ident, $($fe:ident),*) => ( - #[cfg(feature = "serde")] - impl<'de> $crate::serde::Deserialize<'de> for $name { - fn deserialize(deserializer: D) -> Result<$name, D::Error> - where - D: $crate::serde::de::Deserializer<'de>, - { - use ::std::fmt::{self, Formatter}; - use $crate::serde::de::IgnoredAny; - - #[allow(non_camel_case_types)] - enum Enum { Unknown__Field, $($fe),* } - - struct EnumVisitor; - impl<'de> $crate::serde::de::Visitor<'de> for EnumVisitor { - type Value = Enum; - - fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { - formatter.write_str("a field name") - } - - fn visit_str(self, v: &str) -> Result - where - E: $crate::serde::de::Error, - { - match v { - $( - stringify!($fe) => Ok(Enum::$fe) - ),*, - _ => Ok(Enum::Unknown__Field) - } - } - } - - impl<'de> $crate::serde::Deserialize<'de> for Enum { - fn deserialize(deserializer: D) -> Result - where - D: $crate::serde::de::Deserializer<'de>, - { - deserializer.deserialize_str(EnumVisitor) - } - } - - struct Visitor; - - impl<'de> $crate::serde::de::Visitor<'de> for Visitor { - type Value = $name; - - fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { - formatter.write_str("a struct") - } - - fn visit_seq(self, mut seq: V) -> Result - where - V: $crate::serde::de::SeqAccess<'de>, - { - use $crate::serde::de::Error; - - let length = 0; - $( - let $fe = seq.next_element()?.ok_or_else(|| { - Error::invalid_length(length, &self) - })?; - #[allow(unused_variables)] - let length = length + 1; - )* - - let ret = $name { - $($fe: $fe),* - }; - - Ok(ret) - } - - fn visit_map(self, mut map: A) -> Result - where - A: $crate::serde::de::MapAccess<'de>, - { - use $crate::serde::de::Error; - - $(let mut $fe = None;)* - - loop { - match map.next_key::()? { - Some(Enum::Unknown__Field) => { - map.next_value::()?; - } - $( - Some(Enum::$fe) => { - $fe = Some(map.next_value()?); - } - )* - None => { break; } - } - } - - $( - let $fe = match $fe { - Some(x) => x, - None => return Err(A::Error::missing_field(stringify!($fe))), - }; - )* - - let ret = $name { - $($fe: $fe),* - }; - - Ok(ret) - } - } - // end type defs - - static FIELDS: &'static [&'static str] = &[$(stringify!($fe)),*]; - - deserializer.deserialize_struct(stringify!($name), FIELDS, Visitor) - } - } - - #[cfg(feature = "serde")] - impl<'de> $crate::serde::Serialize for $name { - fn serialize(&self, serializer: S) -> Result - where - S: $crate::serde::Serializer, - { - use $crate::serde::ser::SerializeStruct; - - // Only used to get the struct length. - static FIELDS: &'static [&'static str] = &[$(stringify!($fe)),*]; - - let mut st = serializer.serialize_struct(stringify!($name), FIELDS.len())?; - - $( - st.serialize_field(stringify!($fe), &self.$fe)?; - )* - - st.end() - } - } - ) -} - macro_rules! serde_string_impl { ($name:ident, $expecting:expr) => { #[cfg(feature = "serde")] @@ -362,9 +220,8 @@ macro_rules! serde_string_impl { }; } -/// A combination of serde_struct_impl and serde_string_impl where string is -/// used for human-readable serialization and struct is used for -/// non-human-readable serialization. +/// A combination macro where the human-readable serialization is done like +/// serde_string_impl and the non-human-readable impl is done as a struct. macro_rules! serde_struct_human_string_impl { ($name:ident, $expecting:expr, $($fe:ident),*) => ( #[cfg(feature = "serde")] diff --git a/src/lib.rs b/src/lib.rs index 790b6182..5f61648e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -44,8 +44,7 @@ pub extern crate bech32; #[cfg(feature = "base64")] pub extern crate base64; #[cfg(feature="bitcoinconsensus")] extern crate bitcoinconsensus; -#[cfg(feature = "serde")] extern crate serde; -#[cfg(all(test, feature = "serde"))] #[macro_use] extern crate serde_derive; // for 1.22.0 compat +#[cfg(feature = "serde")] #[macro_use] extern crate serde; #[cfg(all(test, feature = "serde"))] extern crate serde_json; #[cfg(all(test, feature = "serde"))] extern crate serde_test; #[cfg(all(test, feature = "unstable"))] extern crate test; diff --git a/src/util/psbt/map/global.rs b/src/util/psbt/map/global.rs index 729fc91c..1897e49b 100644 --- a/src/util/psbt/map/global.rs +++ b/src/util/psbt/map/global.rs @@ -37,6 +37,7 @@ const PSBT_GLOBAL_PROPRIETARY: u8 = 0xFC; /// A key-value map for global data. #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct Global { /// The unsigned transaction, scriptSigs and witnesses for each input must be /// empty. @@ -51,7 +52,6 @@ pub struct Global { /// Unknown global key-value pairs. pub unknown: BTreeMap>, } -serde_struct_impl!(Global, unsigned_tx, version, xpub, proprietary, unknown); impl Global { /// Create a Global from an unsigned transaction, error if not unsigned diff --git a/src/util/psbt/map/input.rs b/src/util/psbt/map/input.rs index b10641ed..0e79fc2c 100644 --- a/src/util/psbt/map/input.rs +++ b/src/util/psbt/map/input.rs @@ -58,6 +58,7 @@ const PSBT_IN_PROPRIETARY: u8 = 0xFC; /// A key-value map for an input of the corresponding index in the unsigned /// transaction. #[derive(Clone, Default, Debug, PartialEq)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct Input { /// The non-witness transaction this input spends from. Should only be /// [std::option::Option::Some] for inputs which spend non-segwit outputs or @@ -100,13 +101,6 @@ pub struct Input { /// Unknown key-value pairs for this input. pub unknown: BTreeMap>, } -serde_struct_impl!( - Input, non_witness_utxo, witness_utxo, partial_sigs, - sighash_type, redeem_script, witness_script, bip32_derivation, - final_script_sig, final_script_witness, - ripemd160_preimages, sha256_preimages, hash160_preimages, hash256_preimages, - proprietary, unknown -); impl Map for Input { fn insert_pair(&mut self, pair: raw::Pair) -> Result<(), encode::Error> { diff --git a/src/util/psbt/map/output.rs b/src/util/psbt/map/output.rs index 71e1d2ac..2577ed87 100644 --- a/src/util/psbt/map/output.rs +++ b/src/util/psbt/map/output.rs @@ -36,6 +36,7 @@ const PSBT_OUT_PROPRIETARY: u8 = 0xFC; /// A key-value map for an output of the corresponding index in the unsigned /// transaction. #[derive(Clone, Default, Debug, PartialEq)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct Output { /// The redeem script for this output. pub redeem_script: Option