diff --git a/Cargo.toml b/Cargo.toml index f6b8444a..2b3b32a1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,23 +15,22 @@ default = ["json-contract"] json-contract = ["serde_json"] "serde" = [ "bitcoin/serde", - "bitcoin/serde", + "bitcoin-units/serde", "secp256k1-zkp/serde", - "actual-serde", + "dep:serde", ] base64 = ["bitcoin/base64"] [dependencies] bech32 = "0.11.0" bitcoin = "0.32.2" +bitcoin-units = { version = "1.0.0-rc.0", default-features = false, features = [ "std" ] } secp256k1-zkp = { version = "0.11.0", features = ["global-context", "hashes"] } # Used for ContractHash::from_json_contract. serde_json = { version = "1.0", optional = true } -actual-serde = { package = "serde", version = "1.0.103", features = [ - "derive", -], optional = true } +serde = { version = "1.0.103", features = ["derive"], optional = true } [target.wasm32-unknown-unknown.dev-dependencies] diff --git a/fuzz/fuzz_targets/deserialize_block.rs b/fuzz/fuzz_targets/deserialize_block.rs index 061fec7e..9cf79206 100644 --- a/fuzz/fuzz_targets/deserialize_block.rs +++ b/fuzz/fuzz_targets/deserialize_block.rs @@ -39,9 +39,9 @@ mod tests { for (idx, c) in hex.as_bytes().iter().enumerate() { b <<= 4; match *c { - b'A'...b'F' => b |= c - b'A' + 10, - b'a'...b'f' => b |= c - b'a' + 10, - b'0'...b'9' => b |= c - b'0', + b'A'..=b'F' => b |= c - b'A' + 10, + b'a'..=b'f' => b |= c - b'a' + 10, + b'0'..=b'9' => b |= c - b'0', _ => panic!("Bad hex"), } if (idx & 1) == 1 { diff --git a/fuzz/fuzz_targets/deserialize_output.rs b/fuzz/fuzz_targets/deserialize_output.rs index 22bc06d9..f8964056 100644 --- a/fuzz/fuzz_targets/deserialize_output.rs +++ b/fuzz/fuzz_targets/deserialize_output.rs @@ -45,9 +45,9 @@ mod tests { for (idx, c) in hex.as_bytes().iter().enumerate() { b <<= 4; match *c { - b'A'...b'F' => b |= c - b'A' + 10, - b'a'...b'f' => b |= c - b'a' + 10, - b'0'...b'9' => b |= c - b'0', + b'A'..=b'F' => b |= c - b'A' + 10, + b'a'..=b'f' => b |= c - b'a' + 10, + b'0'..=b'9' => b |= c - b'0', _ => panic!("Bad hex"), } if (idx & 1) == 1 { diff --git a/fuzz/fuzz_targets/deserialize_pset.rs b/fuzz/fuzz_targets/deserialize_pset.rs index bf1576a5..9c03c087 100644 --- a/fuzz/fuzz_targets/deserialize_pset.rs +++ b/fuzz/fuzz_targets/deserialize_pset.rs @@ -41,9 +41,9 @@ mod tests { for (idx, c) in hex.as_bytes().iter().enumerate() { b <<= 4; match *c { - b'A'...b'F' => b |= c - b'A' + 10, - b'a'...b'f' => b |= c - b'a' + 10, - b'0'...b'9' => b |= c - b'0', + b'A'..=b'F' => b |= c - b'A' + 10, + b'a'..=b'f' => b |= c - b'a' + 10, + b'0'..=b'9' => b |= c - b'0', _ => panic!("Bad hex"), } if (idx & 1) == 1 { diff --git a/fuzz/fuzz_targets/deserialize_transaction.rs b/fuzz/fuzz_targets/deserialize_transaction.rs index 25148086..d5af7fa4 100644 --- a/fuzz/fuzz_targets/deserialize_transaction.rs +++ b/fuzz/fuzz_targets/deserialize_transaction.rs @@ -9,7 +9,7 @@ fn do_test(data: &[u8]) { let reser = elements::encode::serialize(&tx); assert_eq!(data, &reser[..]); let len = reser.len(); - let calculated_weight = tx.get_weight(); + let calculated_weight = tx.weight(); for input in &mut tx.input { input.witness = elements::TxInWitness::default(); } @@ -18,7 +18,7 @@ fn do_test(data: &[u8]) { } assert_eq!(tx.has_witness(), false); let no_witness_len = elements::encode::serialize(&tx).len(); - assert_eq!(no_witness_len * 3 + len, calculated_weight); + assert_eq!(no_witness_len * 3 + len, calculated_weight.to_wu() as usize); for output in &tx.output { output.is_null_data(); @@ -58,9 +58,9 @@ mod tests { for (idx, c) in hex.as_bytes().iter().enumerate() { b <<= 4; match *c { - b'A'...b'F' => b |= c - b'A' + 10, - b'a'...b'f' => b |= c - b'a' + 10, - b'0'...b'9' => b |= c - b'0', + b'A'..=b'F' => b |= c - b'A' + 10, + b'a'..=b'f' => b |= c - b'a' + 10, + b'0'..=b'9' => b |= c - b'0', _ => panic!("Bad hex"), } if (idx & 1) == 1 { diff --git a/src/blind.rs b/src/blind.rs index 340e62c5..c293d05a 100644 --- a/src/blind.rs +++ b/src/blind.rs @@ -229,11 +229,7 @@ impl RangeProofMessage { } /// Information about Transaction Input Asset -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "actual_serde") -)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] pub struct TxOutSecrets { /// Asset diff --git a/src/block.rs b/src/block.rs index f16f790f..89353198 100644 --- a/src/block.rs +++ b/src/block.rs @@ -24,7 +24,8 @@ use crate::dynafed; use crate::hashes::{Hash, sha256}; use crate::Transaction; use crate::encode::{self, serialize, Decodable, Encodable, VarInt}; -use crate::{BlockHash, Script, TxMerkleNode}; +use crate::{BlockHash, Script, TxMerkleNode, Weight}; +use crate::Len64 as _; /// Data related to block signatures #[derive(Clone, Debug, Eq, Hash, PartialEq)] @@ -365,29 +366,19 @@ impl Block { } /// Get the size of the block - #[deprecated(since = "0.19.1", note = "Please use `Block::size` instead.")] - pub fn get_size(&self) -> usize { - self.size() - } - - /// Get the size of the block + #[deprecated(since = "0.26.0", note = "use Self::weight or Self::encoded_length instead")] pub fn size(&self) -> usize { // The size of the header + the size of the varint with the tx count + the txs themselves - let base_size = serialize(&self.header).len() + VarInt(self.txdata.len() as u64).size(); - let txs_size: usize = self.txdata.iter().map(Transaction::size).sum(); + let base_size = serialize(&self.header).len() + VarInt(self.txdata.len64()).size(); + let txs_size = self.txdata.iter().map(Transaction::encoded_length).sum::(); base_size + txs_size } /// Get the weight of the block - #[deprecated(since = "0.19.1", note = "Please use `Block::weight` instead.")] - pub fn get_weight(&self) -> usize { - self.weight() - } - - /// Get the weight of the block - pub fn weight(&self) -> usize { - let base_weight = 4 * (serialize(&self.header).len() + VarInt(self.txdata.len() as u64).size()); - let txs_weight: usize = self.txdata.iter().map(Transaction::weight).sum(); + pub fn weight(&self) -> Weight { + let base_weight = Weight::from_vb(self.header.encoded_len64() + VarInt(self.txdata.len64()).len64()) + .expect("base weight does not overflow the Weight type"); + let txs_weight = self.txdata.iter().map(Transaction::weight).sum::(); base_weight + txs_weight } } @@ -466,8 +457,8 @@ mod tests { assert_eq!(block.header.version, 0x2000_0000); assert_eq!(block.header.height, 2); assert_eq!(block.txdata.len(), 1); - assert_eq!(block.size(), serialize(&block).len()); - assert_eq!(block.weight(), 1089); + assert_eq!(block.encoded_length(), serialize(&block).len()); + assert_eq!(block.weight().to_wu(), 1089); // Block with 3 transactions ... the rangeproofs are very large :) let block: Block = hex_deserialize!( @@ -678,7 +669,7 @@ mod tests { assert_eq!(block.header.version, 0x2000_0000); assert_eq!(block.header.height, 1); assert_eq!(block.txdata.len(), 3); - assert_eq!(block.size(), serialize(&block).len()); + assert_eq!(block.encoded_length(), serialize(&block).len()); // 2-of-3 signed block from Liquid integration tests let block: Block = hex_deserialize!( diff --git a/src/confidential.rs b/src/confidential.rs index 34f1a564..2319dced 100644 --- a/src/confidential.rs +++ b/src/confidential.rs @@ -70,15 +70,6 @@ impl Value { Value::Confidential(comm) } - /// Serialized length, in bytes - pub fn encoded_length(&self) -> usize { - match *self { - Value::Null => 1, - Value::Explicit(..) => 9, - Value::Confidential(..) => 33, - } - } - /// Create from commitment. pub fn from_commitment(bytes: &[u8]) -> Result { Ok(Value::Confidential(PedersenCommitment::from_slice(bytes)?)) @@ -145,6 +136,14 @@ impl Encodable for Value { Value::Confidential(commitment) => commitment.consensus_encode(&mut s), } } + + fn encoded_length(&self) -> usize { + match *self { + Self::Null => 1, + Self::Explicit(..) => 9, + Self::Confidential(..) => 33, + } + } } impl Encodable for PedersenCommitment { @@ -152,6 +151,8 @@ impl Encodable for PedersenCommitment { e.write_all(&self.serialize())?; Ok(33) } + + fn encoded_length(&self) -> usize { 33 } } impl Decodable for Value { @@ -272,15 +273,6 @@ impl Asset { )) } - /// Serialized length, in bytes - pub fn encoded_length(&self) -> usize { - match *self { - Asset::Null => 1, - Asset::Explicit(..) => 33, - Asset::Confidential(..) => 33, - } - } - /// Create from commitment. pub fn from_commitment(bytes: &[u8]) -> Result { Ok(Asset::Confidential(Generator::from_slice(bytes)?)) @@ -367,6 +359,14 @@ impl Encodable for Asset { Asset::Confidential(generator) => generator.consensus_encode(&mut s) } } + + fn encoded_length(&self) -> usize { + match *self { + Self::Null => 1, + Self::Explicit(..) => 33, + Self::Confidential(..) => 33, + } + } } impl Encodable for Generator { @@ -374,6 +374,8 @@ impl Encodable for Generator { e.write_all(&self.serialize())?; Ok(33) } + + fn encoded_length(&self) -> usize { 33 } } impl Decodable for Asset { @@ -537,15 +539,6 @@ impl Nonce { SecretKey::from_slice(&shared_secret[..32]).expect("always has exactly 32 bytes") } - /// Serialized length, in bytes - pub fn encoded_length(&self) -> usize { - match *self { - Nonce::Null => 1, - Nonce::Explicit(..) => 33, - Nonce::Confidential(..) => 33, - } - } - /// Create from commitment. pub fn from_commitment(bytes: &[u8]) -> Result { Ok(Nonce::Confidential( @@ -619,6 +612,14 @@ impl Encodable for Nonce { Nonce::Confidential(commitment) => commitment.consensus_encode(&mut s), } } + + fn encoded_length(&self) -> usize { + match *self { + Self::Null => 1, + Self::Explicit(..) => 33, + Self::Confidential(..) => 33, + } + } } impl Encodable for PublicKey { @@ -626,6 +627,8 @@ impl Encodable for PublicKey { e.write_all(&self.serialize())?; Ok(33) } + + fn encoded_length(&self) -> usize { 33 } } impl Decodable for Nonce { diff --git a/src/encode.rs b/src/encode.rs index 6868cee2..10744731 100644 --- a/src/encode.rs +++ b/src/encode.rs @@ -24,6 +24,7 @@ use secp256k1_zkp::{self, RangeProof, SurjectionProof, Tweak}; use crate::hashes::{sha256, Hash}; use crate::pset; use crate::transaction::{Transaction, TxIn, TxOut}; +use crate::Len64 as _; pub use bitcoin::{self, consensus::encode::MAX_VEC_SIZE}; @@ -147,6 +148,22 @@ pub trait Encodable { /// the underlying `Write` errors. Returns the number of bytes written on /// success fn consensus_encode(&self, e: W) -> Result; + + /// The length of the object, in bytes, when encoded. + #[inline] + fn encoded_length(&self) -> usize { + self.consensus_encode(io::sink()).expect("no errors on sink") + } + + /// The length of the object, in bytes, when encoded. + /// + /// Convenience function to minimize the amount of explicit casting that + /// users need to do. No object in Bitcoin or Elements will ever approach + /// [`u64::MAX`] in encoded size, regardless of the range of `usize`. + #[inline] + fn encoded_len64(&self) -> u64 { + self.encoded_length() as u64 + } } /// Data which can be encoded in a consensus-consistent way @@ -208,7 +225,7 @@ pub(crate) fn consensus_encode_with_size( data: &[u8], mut s: S, ) -> Result { - let vi_len = VarInt(data.len() as u64).consensus_encode(&mut s)?; + let vi_len = VarInt(data.len64()).consensus_encode(&mut s)?; s.emit_slice(data)?; Ok(vi_len + data.len()) } @@ -320,7 +337,7 @@ macro_rules! impl_vec { #[inline] fn consensus_encode(&self, mut s: S) -> Result { let mut len = 0; - len += VarInt(self.len() as u64).consensus_encode(&mut s)?; + len += VarInt(self.len64()).consensus_encode(&mut s)?; for c in self.iter() { len += c.consensus_encode(&mut s)?; } diff --git a/src/lib.rs b/src/lib.rs index b54fc1f5..57df6dac 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,8 +32,7 @@ pub extern crate bitcoin; pub extern crate secp256k1_zkp; /// Re-export of serde crate #[cfg(feature = "serde")] -#[macro_use] -pub extern crate actual_serde as serde; +pub extern crate serde; #[cfg(all(test, feature = "serde"))] extern crate serde_test; @@ -65,8 +64,6 @@ mod parse; pub mod pset; pub mod schnorr; pub mod script; -#[cfg(feature = "serde")] -mod serde_utils; pub mod sighash; pub mod taproot; mod transaction; @@ -74,6 +71,12 @@ mod transaction; mod endian; // re-export bitcoin deps which we re-use pub use bitcoin::hashes; +// Re-export units which are identical in Bitcoin and Elements +pub use bitcoin_units::{ + BlockHeight, BlockHeightInterval, BlockMtp, BlockMtpInterval, BlockTime, + MathOp, NumOpError, NumOpResult, + Weight, +}; // export everything at the top level so it can be used as `elements::Transaction` etc. pub use crate::address::{Address, AddressError, AddressParams}; pub use crate::blind::{ @@ -95,3 +98,39 @@ pub use crate::transaction::{ AssetIssuance, EcdsaSighashType, OutPoint, PeginData, PegoutData, Transaction, TxIn, TxInWitness, TxOut, TxOutWitness, }; + +/// Utility trait for producing lengths in u64, for use in weight computations. +trait Len64 { + fn len64(&self) -> u64; +} + +impl Len64 for [T] { + fn len64(&self) -> u64 { self.len() as u64 } +} +impl Len64 for &[T] { + fn len64(&self) -> u64 { (*self).len64() } +} +impl Len64 for Vec { + fn len64(&self) -> u64 { self[..].len64() } +} +impl Len64 for crate::script::Script { + fn len64(&self) -> u64 { self[..].len64() } +} +impl Len64 for secp256k1_zkp::RangeProof { + fn len64(&self) -> u64 { self.serialize().len64() } +} +impl Len64 for secp256k1_zkp::SurjectionProof { + fn len64(&self) -> u64 { self.serialize().len64() } +} +impl Len64 for bitcoin::VarInt { + fn len64(&self) -> u64 { self.size() as u64 } +} +impl Len64 for crate::encode::VarInt { + fn len64(&self) -> u64 { self.size() as u64 } +} +impl Len64 for Option { + fn len64(&self) -> u64 { self.as_ref().map_or(0, T::len64) } +} +impl Len64 for Box { + fn len64(&self) -> u64 { (**self).len64() } +} diff --git a/src/locktime.rs b/src/locktime.rs index e93f10b6..90b5a834 100644 --- a/src/locktime.rs +++ b/src/locktime.rs @@ -19,28 +19,14 @@ use std::{mem, fmt}; use std::cmp::{PartialOrd, Ordering}; -use std::convert::TryFrom; -use std::str::FromStr; use std::io::{Read, Write}; -use crate::error::ParseIntError; -use crate::parse; use crate::encode::{self, Decodable, Encodable}; -use crate::error::write_err; use crate::parse::impl_parse_str_through_int; -/// The Threshold for deciding whether a lock time value is a height or a time (see [Bitcoin Core]). -/// -/// `LockTime` values _below_ the threshold are interpreted as block heights, values _above_ (or -/// equal to) the threshold are interpreted as block times (UNIX timestamp, seconds since epoch). -/// -/// Elements is able to safely use this value because a block height greater than 500,000,000 would -/// never occur because it would represent a height in approximately 950 years. Conversely, block -/// times under 500,000,000 will never happen because they would represent times before 1986 which -/// are, for obvious reasons, not useful within any Elements network. -/// -/// [Bitcoin Core]: https://github.com/bitcoin/bitcoin/blob/9ccaee1d5e2e4b79b0a7c29aadb41b97e4741332/src/script/script.h#L39 -pub const LOCK_TIME_THRESHOLD: u32 = 500_000_000; +pub use bitcoin_units::locktime::absolute::{Height, Time}; +pub use bitcoin_units::locktime::absolute::ConversionError; +pub use bitcoin_units::locktime::absolute::LOCK_TIME_THRESHOLD; /// A lock time value, representing either a block height or a UNIX timestamp (seconds since epoch). /// @@ -66,8 +52,6 @@ pub const LOCK_TIME_THRESHOLD: u32 = 500_000_000; /// ``` #[allow(clippy::derive_ord_xor_partial_ord)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[cfg_attr(feature = "serde", serde(crate = "actual_serde"))] pub enum LockTime { /// A block height lock time value. /// @@ -98,7 +82,7 @@ pub enum LockTime { impl LockTime { /// If [`crate::Transaction::lock_time`] is set to zero it is ignored, in other words a /// transaction with nLocktime==0 is able to be included immediately in any block. - pub const ZERO: LockTime = LockTime::Blocks(Height(0)); + pub const ZERO: LockTime = LockTime::Blocks(Height::ZERO); /// Constructs a `LockTime` from an nLockTime value or the argument to `OP_CHEKCLOCKTIMEVERIFY`. /// @@ -132,7 +116,7 @@ impl LockTime { /// assert!(LockTime::from_height(1653195600).is_err()); /// ``` #[inline] - pub fn from_height(n: u32) -> Result { + pub fn from_height(n: u32) -> Result { let height = Height::from_consensus(n)?; Ok(LockTime::Blocks(height)) } @@ -148,7 +132,7 @@ impl LockTime { /// assert!(LockTime::from_time(741521).is_err()); /// ``` #[inline] - pub fn from_time(n: u32) -> Result { + pub fn from_time(n: u32) -> Result { let time = Time::from_consensus(n)?; Ok(LockTime::Seconds(time)) } @@ -276,6 +260,24 @@ impl fmt::Display for LockTime { } } +#[cfg(feature = "serde")] +impl serde::Serialize for LockTime { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer { + self.to_consensus_u32().serialize(serializer) + } +} + +#[cfg(feature = "serde")] +impl<'de> serde::Deserialize<'de> for LockTime { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de> { + u32::deserialize(deserializer).map(Self::from_consensus) + } +} + impl Encodable for LockTime { #[inline] fn consensus_encode(&self, w: W) -> Result { @@ -291,302 +293,11 @@ impl Decodable for LockTime { } } -/// An absolute block height, guaranteed to always contain a valid height value. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[cfg_attr(feature = "serde", serde(crate = "actual_serde"))] -pub struct Height(u32); - -impl Height { - /// Height zero - pub const ZERO: Self = Height(0); - - /// Constructs a new block height. - /// - /// # Errors - /// - /// If `n` does not represent a block height value (see documentation on [`LockTime`]). - /// - /// # Examples - /// ```rust - /// use elements::locktime::Height; - /// - /// let h: u32 = 741521; - /// let height = Height::from_consensus(h).expect("invalid height value"); - /// assert_eq!(height.to_consensus_u32(), h); - /// ``` - #[inline] - pub fn from_consensus(n: u32) -> Result { - if is_block_height(n) { - Ok(Self(n)) - } else { - Err(ConversionError::invalid_height(n).into()) - } - } - - /// Converts this `Height` to its inner `u32` value. - /// - /// # Examples - /// ```rust - /// use elements::LockTime; - /// - /// let n_lock_time: u32 = 741521; - /// let lock_time = LockTime::from_consensus(n_lock_time); - /// assert!(lock_time.is_block_height()); - /// assert_eq!(lock_time.to_consensus_u32(), n_lock_time); - #[inline] - pub fn to_consensus_u32(self) -> u32 { - self.0 - } -} - -impl fmt::Display for Height { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(&self.0, f) - } -} - -impl FromStr for Height { - type Err = Error; - - fn from_str(s: &str) -> Result { - let n = parse::int(s)?; - Height::from_consensus(n) - } -} - -impl TryFrom<&str> for Height { - type Error = Error; - - fn try_from(s: &str) -> Result { - let n = parse::int(s)?; - Height::from_consensus(n) - } -} - -impl TryFrom for Height { - type Error = Error; - - fn try_from(s: String) -> Result { - let n = parse::int(s)?; - Height::from_consensus(n) - } -} - -/// A UNIX timestamp, seconds since epoch, guaranteed to always contain a valid time value. -/// -/// Note that there is no manipulation of the inner value during construction or when using -/// `to_consensus_u32()`. Said another way, `Time(x)` means 'x seconds since epoch' _not_ '(x - -/// threshold) seconds since epoch'. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[cfg_attr(feature = "serde", serde(crate = "actual_serde"))] -pub struct Time(u32); - -impl Time { - /// Constructs a new block time. - /// - /// # Errors - /// - /// If `n` does not encode a UNIX time stamp (see documentation on [`LockTime`]). - /// - /// # Examples - /// ```rust - /// use elements::locktime::Time; - /// - /// let t: u32 = 1653195600; // May 22nd, 5am UTC. - /// let time = Time::from_consensus(t).expect("invalid time value"); - /// assert_eq!(time.to_consensus_u32(), t); - /// ``` - #[inline] - pub fn from_consensus(n: u32) -> Result { - if is_block_time(n) { - Ok(Self(n)) - } else { - Err(ConversionError::invalid_time(n).into()) - } - } - - /// Converts this `Time` to its inner `u32` value. - /// - /// # Examples - /// ```rust - /// use elements::LockTime; - /// - /// let n_lock_time: u32 = 1653195600; // May 22nd, 5am UTC. - /// let lock_time = LockTime::from_consensus(n_lock_time); - /// assert_eq!(lock_time.to_consensus_u32(), n_lock_time); - /// ``` - #[inline] - pub fn to_consensus_u32(self) -> u32 { - self.0 - } -} - -impl fmt::Display for Time { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(&self.0, f) - } -} - -impl FromStr for Time { - type Err = Error; - - fn from_str(s: &str) -> Result { - let n = parse::int(s)?; - Time::from_consensus(n) - } -} - -impl TryFrom<&str> for Time { - type Error = Error; - - fn try_from(s: &str) -> Result { - let n = parse::int(s)?; - Time::from_consensus(n) - } -} - -impl TryFrom for Time { - type Error = Error; - - fn try_from(s: String) -> Result { - let n = parse::int(s)?; - Time::from_consensus(n) - } -} - /// Returns true if `n` is a block height i.e., less than 500,000,000. fn is_block_height(n: u32) -> bool { n < LOCK_TIME_THRESHOLD } -/// Returns true if `n` is a UNIX timestamp i.e., greater than or equal to 500,000,000. -fn is_block_time(n: u32) -> bool { - n >= LOCK_TIME_THRESHOLD -} - -/// Catchall type for errors that relate to time locks. -#[derive(Debug, Clone, PartialEq, Eq)] -#[non_exhaustive] -pub enum Error { - /// An error occurred while converting a `u32` to a lock time variant. - Conversion(ConversionError), - /// An error occurred while operating on lock times. - Operation(OperationError), - /// An error occurred while parsing a string into an `u32`. - Parse(ParseIntError), -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Self::Conversion(ref e) => write_err!(f, "error converting lock time value"; e), - Self::Operation(ref e) => write_err!(f, "error during lock time operation"; e), - Self::Parse(ref e) => write_err!(f, "failed to parse lock time from string"; e), - } - } -} - -impl std::error::Error for Error { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - match *self { - Self::Conversion(ref e) => Some(e), - Self::Operation(ref e) => Some(e), - Self::Parse(ref e) => Some(e), - } - } -} - -impl From for Error { - fn from(e: ConversionError) -> Self { - Error::Conversion(e) - } -} - -impl From for Error { - fn from(e: OperationError) -> Self { - Error::Operation(e) - } -} - -impl From for Error { - fn from(e: ParseIntError) -> Self { - Error::Parse(e) - } -} - -/// An error that occurs when converting a `u32` to a lock time variant. -#[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub struct ConversionError { - /// The expected timelock unit, height (blocks) or time (seconds). - unit: LockTimeUnit, - /// The invalid input value. - input: u32, -} - -impl ConversionError { - /// Constructs a `ConversionError` from an invalid `n` when expecting a height value. - fn invalid_height(n: u32) -> Self { - Self { - unit: LockTimeUnit::Blocks, - input: n, - } - } - - /// Constructs a `ConversionError` from an invalid `n` when expecting a time value. - fn invalid_time(n: u32) -> Self { - Self { - unit: LockTimeUnit::Seconds, - input: n, - } - } -} - -impl fmt::Display for ConversionError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "invalid lock time value {}, {}", self.input, self.unit) - } -} - -impl std::error::Error for ConversionError {} - -/// Describes the two types of locking, lock-by-blockheight and lock-by-blocktime. -#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] -enum LockTimeUnit { - /// Lock by blockheight. - Blocks, - /// Lock by blocktime. - Seconds, -} - -impl fmt::Display for LockTimeUnit { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Self::Blocks => write!(f, "expected lock-by-blockheight (must be < {})", LOCK_TIME_THRESHOLD), - Self::Seconds => write!(f, "expected lock-by-blocktime (must be >= {})", LOCK_TIME_THRESHOLD), - } - } -} - -/// Errors than occur when operating on lock times. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[non_exhaustive] -pub enum OperationError { - /// Cannot compare different lock time units (height vs time). - InvalidComparison, -} - -impl fmt::Display for OperationError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Self::InvalidComparison => f.write_str("cannot compare different lock units (height vs time)"), - } - } -} - -impl std::error::Error for OperationError {} - #[cfg(test)] mod tests { use super::*; diff --git a/src/pset/map/global.rs b/src/pset/map/global.rs index 4f9b0e24..24b94d56 100644 --- a/src/pset/map/global.rs +++ b/src/pset/map/global.rs @@ -58,7 +58,6 @@ const PSBT_ELEMENTS_GLOBAL_TX_MODIFIABLE: u8 = 0x01; /// Global transaction data #[derive(Debug, Clone, PartialEq)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(crate = "actual_serde"))] pub struct TxData { /// Transaction version. Must be 2. pub version: u32, @@ -93,10 +92,8 @@ impl Default for TxData { /// A key-value map for global data. #[derive(Clone, Debug, PartialEq)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(crate = "actual_serde"))] pub struct Global { /// Global transaction data - #[cfg_attr(feature = "serde", serde(flatten))] pub tx_data: TxData, /// The version number of this PSET. Must be present. pub version: u32, @@ -109,16 +106,8 @@ pub struct Global { /// Elements tx modifiable flag pub elements_tx_modifiable_flag: Option, /// Other Proprietary fields - #[cfg_attr( - feature = "serde", - serde(with = "crate::serde_utils::btreemap_as_seq_byte_values") - )] pub proprietary: BTreeMap>, /// Unknown global key-value pairs. - #[cfg_attr( - feature = "serde", - serde(with = "crate::serde_utils::btreemap_as_seq_byte_values") - )] pub unknown: BTreeMap>, } diff --git a/src/pset/map/input.rs b/src/pset/map/input.rs index 72702525..e3324718 100644 --- a/src/pset/map/input.rs +++ b/src/pset/map/input.rs @@ -171,7 +171,6 @@ const PSBT_ELEMENTS_IN_BLINDED_ISSUANCE: u8 = 0x15; /// A key-value map for an input of the corresponding index in the unsigned /// transaction. #[derive(Clone, Debug, PartialEq)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(crate = "actual_serde"))] 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 @@ -183,10 +182,6 @@ pub struct Input { pub witness_utxo: Option, /// A map from public keys to their corresponding signature as would be /// pushed to the stack from a scriptSig or witness. - #[cfg_attr( - feature = "serde", - serde(with = "crate::serde_utils::btreemap_byte_values") - )] pub partial_sigs: BTreeMap>, /// The sighash type to be used for this input. Signatures for this input /// must use the sighash type. @@ -197,7 +192,6 @@ pub struct Input { pub witness_script: Option