Remove Encodable and Decodable impls for crate types
What changed, and why it matters
This commit removes old serialization/deserialization trait implementations (called Encodable and Decodable) from many Bitcoin data types in the rust-bitcoin library. It is described by the project as a cleanup step toward replacing the old consensus encoding code. There is no indication in the commit or supplied references that this fixes a security vulnerability; it appears to be a routine internal refactor.
No immediate security action required. Treat as a normal API-breaking refactor. Downstream users relying on Encodable/Decodable for these types should verify the new encoding APIs and ensure consensus-critical serialization behavior is preserved in the replacement code. Monitor subsequent commits for the full migration and any restored tests.
Security signals we found
Large deletion of serialization code (535 lines removed)
Removal of consensus encoding traits from core Bitcoin types
Removal of transaction deserialization tests including extreme-size witness/scriptSig tests
No explicit security claim in commit message or diff
Evidence from the diff
The commit deletes Encodable/Decodable implementations for BlockHash, Header, Version, BlockTime, Block, LockTime, Script, ScriptBuf, Txid, Wtxid, Version, TxOut, OutPoint, TxIn, Sequence, Transaction, Witness, Amount, CompactTarget, TxMerkleNode, WitnessMerkleNode, Annex, BlockHeight, and BlockHeightInterval. It also removes related tests and a serde adapter example. The code is moving toward a new encoding system (primitives-based encoders/decoders). No replacement implementations are added in this commit, so this is a partial removal/refactor rather than a complete migration.
Changed components
bitcoin/src/blockdata/block.rsbitcoin/src/blockdata/mod.rsbitcoin/src/blockdata/script/mod.rsbitcoin/src/blockdata/script/tests.rsbitcoin/src/blockdata/transaction.rsbitcoin/src/blockdata/witness.rsbitcoin/src/consensus/encode.rsbitcoin/src/consensus/serde.rsbitcoin/src/crypto/sighash.rsbitcoin/src/lib.rsbitcoin/src/merkle_tree/mod.rsbitcoin/src/pow.rsInspect captured patch +8 / −535
diff --git a/bitcoin/src/blockdata/block.rs b/bitcoin/src/blockdata/block.rs
index 987f4f13..b1529d31 100644
--- a/bitcoin/src/blockdata/block.rs
+++ b/bitcoin/src/blockdata/block.rs
@@ -8,16 +8,14 @@
//! these blocks and the blockchain.
use encoding::CompactSizeEncoder;
-use io::{BufRead, Write};
-use crate::consensus::encode::{self, Decodable, Encodable, WriteExt as _};
use crate::merkle_tree::{TxMerkleNode, WitnessMerkleNode};
use crate::network::Params;
use crate::pow::TargetExt as _;
use crate::prelude::Vec;
use crate::script::{PushBytesExt as _, ScriptExt as _};
use crate::transaction::{Coinbase, Transaction, TransactionExt as _};
-use crate::{internal_macros, BlockTime, Target, ToU64, Weight, Work};
+use crate::{internal_macros, Target, ToU64, Weight, Work};
#[rustfmt::skip] // Keep public re-exports separate.
#[doc(inline)]
@@ -43,21 +41,6 @@ pub use self::error::{
#[doc(hidden)]
pub type BlockInterval = BlockHeightInterval;
-impl Encodable for BlockHash {
- fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
- self.to_byte_array().consensus_encode(w)
- }
-}
-
-impl Decodable for BlockHash {
- fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
- Ok(Self::from_byte_array(<[u8; 32]>::consensus_decode(r)?))
- }
-}
-
-#[rustfmt::skip]
-internal_macros::impl_consensus_encoding!(Header, version, prev_blockhash, merkle_root, time, bits, nonce);
-
internal_macros::define_extension_trait! {
/// Extension functionality for the [`Header`] type.
pub trait HeaderExt impl for Header {
@@ -96,30 +79,6 @@ internal_macros::define_extension_trait! {
}
}
-impl Encodable for Version {
- fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
- self.to_consensus().consensus_encode(w)
- }
-}
-
-impl Decodable for Version {
- fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
- Decodable::consensus_decode(r).map(Self::from_consensus)
- }
-}
-
-impl Encodable for BlockTime {
- fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
- self.to_u32().consensus_encode(w)
- }
-}
-
-impl Decodable for BlockTime {
- fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
- Decodable::consensus_decode(r).map(Self::from_u32)
- }
-}
-
/// Extension functionality for the [`Block<Checked>`] type.
pub trait BlockCheckedExt: sealed::Sealed {
/// Constructs a new [`Block`].
@@ -239,57 +198,6 @@ fn block_base_size(transactions: &[Transaction]) -> usize {
size
}
-impl Encodable for Block<Unchecked> {
- #[inline]
- fn consensus_encode<W: io::Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
- let (header, transactions) = self.as_parts();
- let mut len = 0;
- len += header.consensus_encode(w)?;
- len += w.emit_compact_size(transactions.len())?;
- for tx in transactions.iter() {
- len += tx.consensus_encode(w)?;
- }
- Ok(len)
- }
-}
-
-impl Encodable for Block<Checked> {
- #[inline]
- fn consensus_encode<W: io::Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
- let mut len = 0;
- len += self.header().consensus_encode(w)?;
-
- let transactions = self.transactions();
- len += w.emit_compact_size(transactions.len())?;
- for c in transactions.iter() {
- len += c.consensus_encode(w)?;
- }
-
- Ok(len)
- }
-}
-
-impl Decodable for Block<Unchecked> {
- #[inline]
- fn consensus_decode_from_finite_reader<R: io::BufRead + ?Sized>(
- r: &mut R,
- ) -> Result<Self, encode::Error> {
- let header = Decodable::consensus_decode_from_finite_reader(r)?;
- let transactions = Decodable::consensus_decode_from_finite_reader(r)?;
-
- Ok(Self::new_unchecked(header, transactions))
- }
-
- #[inline]
- fn consensus_decode<R: io::BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
- let mut r = io::Read::take(r, crate::ToU64::to_u64(encode::MAX_VEC_SIZE));
- let header = Decodable::consensus_decode(&mut r)?;
- let transactions = Decodable::consensus_decode(&mut r)?;
-
- Ok(Self::new_unchecked(header, transactions))
- }
-}
-
mod sealed {
/// Seals the extension traits.
pub trait Sealed {}
@@ -416,7 +324,9 @@ mod tests {
use crate::pow::test_utils::{u128_to_work, u64_to_work};
use crate::script::{ScriptPubKeyBuf, ScriptSigBuf};
use crate::transaction::{OutPoint, Transaction, TxIn, TxOut, Txid};
- use crate::{block, Amount, CompactTarget, Network, Sequence, TestnetVersion, Witness, Wtxid};
+ use crate::{
+ block, Amount, BlockTime, CompactTarget, Network, Sequence, TestnetVersion, Witness, Wtxid,
+ };
#[test]
fn coinbase_and_bip34() {
diff --git a/bitcoin/src/blockdata/mod.rs b/bitcoin/src/blockdata/mod.rs
index 5bec3c13..769ff0fe 100644
--- a/bitcoin/src/blockdata/mod.rs
+++ b/bitcoin/src/blockdata/mod.rs
@@ -37,10 +37,6 @@ pub mod locktime {
//! There are two types of lock time: lock-by-height and lock-by-time, distinguished by
//! whether `LockTime < LOCKTIME_THRESHOLD`.
- use io::{BufRead, Write};
-
- use crate::consensus::encode::{self, Decodable, Encodable};
-
// Re-export everything from the `units::locktime::absolute` module.
#[rustfmt::skip] // Keep public re-exports separate.
#[doc(inline)]
@@ -56,21 +52,6 @@ pub mod locktime {
#[deprecated(since = "TBD", note = "use `MedianTimePast` instead")]
#[doc(hidden)]
pub type Time = MedianTimePast;
-
- impl Encodable for LockTime {
- #[inline]
- fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
- let v = self.to_consensus_u32();
- v.consensus_encode(w)
- }
- }
-
- impl Decodable for LockTime {
- #[inline]
- fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
- u32::consensus_decode(r).map(Self::from_consensus)
- }
- }
}
pub mod relative {
diff --git a/bitcoin/src/blockdata/script/mod.rs b/bitcoin/src/blockdata/script/mod.rs
index be9ff3dd..3a8f1f82 100644
--- a/bitcoin/src/blockdata/script/mod.rs
+++ b/bitcoin/src/blockdata/script/mod.rs
@@ -55,14 +55,10 @@ mod tests;
pub mod witness_program;
pub mod witness_version;
-use io::{BufRead, Write};
-
use self::witness_version::WitnessVersion;
-use crate::consensus::{encode, Decodable, Encodable};
use crate::key::WPubkeyHash;
use crate::opcodes::all::*;
use crate::opcodes::Opcode;
-use crate::prelude::Vec;
#[rustfmt::skip] // Keep public re-exports separate.
#[doc(inline)]
@@ -215,30 +211,6 @@ pub(crate) fn new_witness_program_unchecked<T: AsRef<PushBytes>, Tg>(
Builder::new().push_opcode(version.into()).push_slice(program).into_script()
}
-impl<T> Encodable for Script<T> {
- #[inline]
- fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
- crate::consensus::encode::consensus_encode_with_size(self.as_bytes(), w)
- }
-}
-
-impl<T> Encodable for ScriptBuf<T> {
- #[inline]
- fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
- self.as_script().consensus_encode(w)
- }
-}
-
-impl<T> Decodable for ScriptBuf<T> {
- #[inline]
- fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(
- r: &mut R,
- ) -> Result<Self, encode::Error> {
- let v: Vec<u8> = Decodable::consensus_decode_from_finite_reader(r)?;
- Ok(Self::from_bytes(v))
- }
-}
-
/// Error types for Bitcoin scripts.
pub mod error {
use core::convert::Infallible;
diff --git a/bitcoin/src/blockdata/script/tests.rs b/bitcoin/src/blockdata/script/tests.rs
index d5bef119..55a44361 100644
--- a/bitcoin/src/blockdata/script/tests.rs
+++ b/bitcoin/src/blockdata/script/tests.rs
@@ -12,6 +12,7 @@ use crate::script::owned::ScriptSigBufExt as _;
use crate::script::witness_program::WitnessProgram;
use crate::script::witness_version::WitnessVersion;
use crate::{opcodes, Amount, FeeRate};
+use crate::prelude::Vec;
// Tests should compile and pass no matter what these are.
type Tag = primitives::script::ScriptSigTag;
diff --git a/bitcoin/src/blockdata/transaction.rs b/bitcoin/src/blockdata/transaction.rs
index 0c18ffbd..9314da01 100644
--- a/bitcoin/src/blockdata/transaction.rs
+++ b/bitcoin/src/blockdata/transaction.rs
@@ -14,12 +14,12 @@
use arbitrary::{Arbitrary, Unstructured};
use encoding::CompactSizeEncoder;
use internals::const_casts;
-use io::{BufRead, Write};
use super::Weight;
-use crate::consensus::{self, encode, Decodable, Encodable};
use crate::locktime::absolute::{self, Height, MedianTimePast};
-use crate::prelude::{Borrow, Vec};
+use crate::prelude::Borrow;
+#[cfg(feature = "arbitrary")]
+use crate::prelude::Vec;
use crate::script::{
RedeemScript, ScriptExt as _, ScriptExtPriv as _, ScriptPubKey, ScriptPubKeyBuf,
ScriptPubKeyExt as _, WitnessScript,
@@ -46,30 +46,6 @@ pub use self::error::{
VersionDecoderError,
};
-impl Encodable for Txid {
- fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
- self.to_byte_array().consensus_encode(w)
- }
-}
-
-impl Decodable for Txid {
- fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
- Ok(Self::from_byte_array(<[u8; 32]>::consensus_decode(r)?))
- }
-}
-
-impl Encodable for Wtxid {
- fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
- self.to_byte_array().consensus_encode(w)
- }
-}
-
-impl Decodable for Wtxid {
- fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
- Ok(Self::from_byte_array(<[u8; 32]>::consensus_decode(r)?))
- }
-}
-
internal_macros::define_extension_trait! {
/// Extension functionality for the [`Txid`] type.
pub trait TxidExt impl for Txid {
@@ -611,136 +587,6 @@ impl TransactionExtPriv for Transaction {
}
}
-impl Encodable for Version {
- fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
- self.to_u32().consensus_encode(w)
- }
-}
-
-impl Decodable for Version {
- fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
- Decodable::consensus_decode(r).map(Self::maybe_non_standard)
- }
-}
-
-internal_macros::impl_consensus_encoding!(TxOut, amount, script_pubkey);
-
-impl Encodable for OutPoint {
- fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
- let len = self.txid.consensus_encode(w)?;
- Ok(len + self.vout.consensus_encode(w)?)
- }
-}
-impl Decodable for OutPoint {
- fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
- Ok(Self { txid: Decodable::consensus_decode(r)?, vout: Decodable::consensus_decode(r)? })
- }
-}
-
-impl Encodable for TxIn {
- fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
- let mut len = 0;
- len += self.previous_output.consensus_encode(w)?;
- len += self.script_sig.consensus_encode(w)?;
- len += self.sequence.consensus_encode(w)?;
- Ok(len)
- }
-}
-impl Decodable for TxIn {
- #[inline]
- fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(
- r: &mut R,
- ) -> Result<Self, encode::Error> {
- Ok(Self {
- previous_output: Decodable::consensus_decode_from_finite_reader(r)?,
- script_sig: Decodable::consensus_decode_from_finite_reader(r)?,
- sequence: Decodable::consensus_decode_from_finite_reader(r)?,
- witness: Witness::default(),
- })
- }
-}
-
-impl Encodable for Sequence {
- fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
- self.0.consensus_encode(w)
- }
-}
-
-impl Decodable for Sequence {
- fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
- Decodable::consensus_decode(r).map(Sequence)
- }
-}
-
-impl Encodable for Transaction {
- fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
- let mut len = 0;
- len += self.version.consensus_encode(w)?;
-
- // Legacy transaction serialization format only includes inputs and outputs.
- if !self.uses_segwit_serialization() {
- len += self.inputs.consensus_encode(w)?;
- len += self.outputs.consensus_encode(w)?;
- } else {
- // BIP-0141 (SegWit) transaction serialization also includes marker, flag, and witness data.
- len += SEGWIT_MARKER.consensus_encode(w)?;
- len += SEGWIT_FLAG.consensus_encode(w)?;
- len += self.inputs.consensus_encode(w)?;
- len += self.outputs.consensus_encode(w)?;
- for input in &self.inputs {
- len += input.witness.consensus_encode(w)?;
- }
- }
- len += self.lock_time.consensus_encode(w)?;
- Ok(len)
- }
-}
-
-impl Decodable for Transaction {
- fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(
- r: &mut R,
- ) -> Result<Self, encode::Error> {
- let version = Version::consensus_decode_from_finite_reader(r)?;
- let inputs = Vec::<TxIn>::consensus_decode_from_finite_reader(r)?;
- // SegWit
- if inputs.is_empty() {
- let segwit_flag = u8::consensus_decode_from_finite_reader(r)?;
- match segwit_flag {
- // BIP-0144 input witnesses
- 1 => {
- let mut inputs = Vec::<TxIn>::consensus_decode_from_finite_reader(r)?;
- let outputs = Vec::<TxOut>::consensus_decode_from_finite_reader(r)?;
- for txin in inputs.iter_mut() {
- txin.witness = Decodable::consensus_decode_from_finite_reader(r)?;
- }
- if !inputs.is_empty() && inputs.iter().all(|input| input.witness.is_empty()) {
- Err(consensus::parse_failed_error(
- "witness flag set but no witnesses present",
- ))
- } else {
- Ok(Self {
- version,
- inputs,
- outputs,
- lock_time: Decodable::consensus_decode_from_finite_reader(r)?,
- })
- }
- }
- // We don't support anything else
- x => Err(encode::ParseError::UnsupportedSegwitFlag(x).into()),
- }
- // non-SegWit
- } else {
- Ok(Self {
- version,
- inputs,
- outputs: Decodable::consensus_decode_from_finite_reader(r)?,
- lock_time: Decodable::consensus_decode_from_finite_reader(r)?,
- })
- }
- }
-}
-
/// Computes the value of an output accounting for the cost of spending it.
///
/// The effective value is the value of an output value minus the amount to spend it. That is, the
@@ -1418,25 +1264,6 @@ mod tests {
assert_eq!(tx_without_witness.total_size(), expected_strippedsize);
}
- // We temporarily abuse `Transaction` for testing consensus serde adapter.
- #[test]
- #[cfg(feature = "serde")]
- fn consensus_serde() {
- use crate::consensus::serde as con_serde;
- let json = "\"010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff3603da1b0e00045503bd5704c7dd8a0d0ced13bb5785010800000000000a636b706f6f6c122f4e696e6a61506f6f6c2f5345475749542fffffffff02b4e5a212000000001976a914876fbb82ec05caa6af7a3b5e5a983aae6c6cc6d688ac0000000000000000266a24aa21a9edf91c46b49eb8a29089980f02ee6b57e7d63d33b18b4fddac2bcd7db2a39837040120000000000000000000000000000000000000000000000000000000000000000000000000\"";
- let mut deserializer = serde_json::Deserializer::from_str(json);
- let tx =
- con_serde::With::<con_serde::Hex>::deserialize::<'_, Transaction, _>(&mut deserializer)
- .unwrap();
- let tx_bytes = hex::decode_to_vec(&json[1..(json.len() - 1)]).unwrap();
- let expected = decode_from_slice::<Transaction>(&tx_bytes).unwrap();
- assert_eq!(tx, expected);
- let mut bytes = Vec::new();
- let mut serializer = serde_json::Serializer::new(&mut bytes);
- con_serde::With::<con_serde::Hex>::serialize(&tx, &mut serializer).unwrap();
- assert_eq!(bytes, json.as_bytes())
- }
-
#[test]
fn txid() {
// SegWit tx from Liquid integration tests, txid/hash from Core decoderawtransaction
diff --git a/bitcoin/src/blockdata/witness.rs b/bitcoin/src/blockdata/witness.rs
index 0a82f2f8..940aa5cc 100644
--- a/bitcoin/src/blockdata/witness.rs
+++ b/bitcoin/src/blockdata/witness.rs
@@ -4,10 +4,6 @@
//!
//! This module contains the [`Witness`] struct and related methods to operate on it
-use io::{BufRead, Write};
-
-use crate::consensus::encode::{self, Error, ParseError, WriteExt};
-use crate::consensus::{Decodable, Encodable};
use crate::crypto::ecdsa;
use crate::crypto::key::{FullPublicKey, SerializedXOnlyPublicKey};
use crate::taproot::{self, ControlBlock, LeafScript, TaprootMerkleBranch, TAPROOT_ANNEX_PREFIX};
@@ -21,25 +17,6 @@ pub use primitives::witness::{error, Iter, Witness, WitnessDecoder, WitnessEncod
#[doc(no_inline)]
pub use primitives::witness::{UnexpectedEofError, WitnessDecoderError};
-impl Decodable for Witness {
- fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
- io::decode_from_read(r).map_err(|e| Error::Parse(ParseError::Witness(e)))
- }
-}
-
-impl Encodable for Witness {
- // `self.content` includes the varints so encoding here includes them, as expected.
- fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
- let mut written = w.emit_compact_size(self.len())?;
-
- for element in self.iter() {
- written += encode::consensus_encode_with_size(element, w)?
- }
-
- Ok(written)
- }
-}
-
internal_macros::define_extension_trait! {
/// Extension functionality for the [`Witness`] type.
pub trait WitnessExt impl for Witness {
diff --git a/bitcoin/src/consensus/encode.rs b/bitcoin/src/consensus/encode.rs
index 15450d03..ca95e6a1 100644
--- a/bitcoin/src/consensus/encode.rs
+++ b/bitcoin/src/consensus/encode.rs
@@ -712,10 +712,7 @@ mod tests {
use core::mem::discriminant;
use super::*;
- use crate::block::BlockHash;
- use crate::merkle_tree::TxMerkleNode;
use crate::prelude::{Cow, Vec};
- use crate::transaction::{Transaction, TxIn, TxOut};
#[test]
fn serialize_int() {
@@ -1048,17 +1045,7 @@ mod tests {
])
.is_err());
- // Check serialization that `if len > MAX_VEC_SIZE {return err}` isn't inclusive,
- // by making sure it fails with `MissingData` and not an `OversizedVectorAllocation` Error.
- let err = deserialize::<BlockHash>(&serialize(&(super::MAX_VEC_SIZE as u32))).unwrap_err();
- assert!(matches!(err, DeserializeError::Parse(ParseError::MissingData)));
-
test_len_is_max_vec::<u8>();
- test_len_is_max_vec::<BlockHash>();
- test_len_is_max_vec::<TxMerkleNode>();
- test_len_is_max_vec::<Transaction>();
- test_len_is_max_vec::<TxOut>();
- test_len_is_max_vec::<TxIn>();
test_len_is_max_vec::<Vec<u8>>();
test_len_is_max_vec::<u64>();
}
@@ -1151,63 +1138,4 @@ mod tests {
);
}
}
-
- #[test]
- fn deserialize_tx_hex() {
- let hex = include_str!("../../tests/data/previous_tx_0_hex"); // An arbitrary transaction.
- assert!(deserialize_hex::<Transaction>(hex).is_ok())
- }
-
- #[test]
- fn deserialize_tx_hex_too_many_bytes() {
- use crate::consensus::DecodeError;
-
- let mut hex = include_str!("../../tests/data/previous_tx_0_hex").to_string(); // An arbitrary transaction.
- hex.push_str("abcdef");
- assert!(matches!(
- deserialize_hex::<Transaction>(&hex).unwrap_err(),
- FromHexError::Decode(DecodeError::Unconsumed)
- ));
- }
-
- #[test]
- fn deserialize_extreme_tx() {
- use crate::{ScriptSigBuf, Witness};
-
- // Start with transaction from `deserialize_tx_hex`
- let hex = include_str!("../../tests/data/previous_tx_0_hex"); // An arbitrary transaction.
- let tx = deserialize_hex::<Transaction>(hex).unwrap();
-
- assert_eq!(tx.inputs.len(), 1);
- assert_eq!(tx.outputs.len(), 2);
- assert_eq!(tx.inputs[0].witness.len(), 2);
-
- // 1. Test with 4 million witnesses.
- let mut tx_copy = tx.clone();
- tx_copy.inputs[0].witness = Witness::from_slice(&vec![vec![]; 4_000_000]);
- let roundtrip = deserialize(&serialize(&tx_copy)).unwrap();
- assert_eq!(tx_copy, roundtrip);
-
- // 2. Test with a single large witness. (Size of 4 megs, including length prefix)
- let mut tx_copy = tx.clone();
- tx_copy.inputs[0].witness = Witness::from_slice(&vec![vec![0; 4_000_000 - 9]; 1]);
- let roundtrip = deserialize(&serialize(&tx_copy)).unwrap();
- assert_eq!(tx_copy, roundtrip);
-
- // 3. Combine these; with the witness stack we can exceed a total size of 4M but
- // only by a tiny bit. (It is not part of our API guarantee that such things
- // will round-trip, but we unit test them anyway to help notice changes.)
- let mut tx_copy = tx.clone();
- tx_copy.inputs[0].witness = Witness::from_slice(&vec![vec![0; 997]; 4_000]);
- let roundtrip = deserialize(&serialize(&tx_copy)).unwrap();
- assert_eq!(tx_copy, roundtrip);
-
- // 4. Test with a large script sig. With scriptsigs there is no limit on how large
- // an object we can parse, which is inconsistent with witnesses. Also not an
- // API guarantee.
- let mut tx_copy = tx;
- tx_copy.inputs[0].script_sig = ScriptSigBuf::from(vec![0; 8_000_001]);
- let roundtrip = deserialize(&serialize(&tx_copy)).unwrap();
- assert_eq!(tx_copy, roundtrip);
- }
}
diff --git a/bitcoin/src/consensus/serde.rs b/bitcoin/src/consensus/serde.rs
index ba447ea3..08f5cead 100644
--- a/bitcoin/src/consensus/serde.rs
+++ b/bitcoin/src/consensus/serde.rs
@@ -400,20 +400,6 @@ where
}
/// Helper for `#[serde(with = "")]`.
-///
-/// To (de)serialize a field using consensus encoding you can write e.g.:
-///
-/// ```
-/// # use serde::{Serialize, Deserialize};
-/// use bitcoin::Transaction;
-/// use bitcoin::consensus;
-///
-/// #[derive(Serialize, Deserialize)]
-/// pub struct MyStruct {
-/// #[serde(with = "consensus::serde::With::<consensus::serde::Hex>")]
-/// tx: Transaction,
-/// }
-/// ```
pub struct With<E>(PhantomData<E>);
impl<E> With<E> {
diff --git a/bitcoin/src/crypto/sighash.rs b/bitcoin/src/crypto/sighash.rs
index c2db1a38..46a93a08 100644
--- a/bitcoin/src/crypto/sighash.rs
+++ b/bitcoin/src/crypto/sighash.rs
@@ -22,7 +22,6 @@ use encoding::CompactSizeEncoder;
use hashes::{hash_newtype, sha256, sha256d, sha256t, sha256t_tag};
use io::Write;
-use crate::consensus::{encode, Encodable};
use crate::prelude::{Borrow, BorrowMut};
use crate::script::{ScriptExt as _, ScriptHashableTag};
use crate::taproot::{LeafVersion, TapLeafHash, TapLeafTag, TAPROOT_ANNEX_PREFIX};
@@ -938,12 +937,6 @@ impl<'a> Annex<'a> {
pub fn as_bytes(&self) -> &[u8] { self.0 }
}
-impl Encodable for Annex<'_> {
- fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
- encode::consensus_encode_with_size(self.0, w)
- }
-}
-
fn is_invalid_use_of_sighash_single(sighash: u32, input_index: usize, outputs_len: usize) -> bool {
let ty = EcdsaSighashType::from_consensus(sighash);
ty.is_single() && input_index >= outputs_len
diff --git a/bitcoin/src/lib.rs b/bitcoin/src/lib.rs
index 0aa6ae55..56e8811a 100644
--- a/bitcoin/src/lib.rs
+++ b/bitcoin/src/lib.rs
@@ -237,9 +237,6 @@ pub mod amount {
//! This module mainly introduces the [`Amount`] and [`SignedAmount`] types.
//! We refer to the documentation on the types for more information.
- use crate::consensus::{self, encode, Decodable, Encodable};
- use crate::io::{BufRead, Write};
-
#[rustfmt::skip] // Keep public re-exports separate.
#[cfg(feature = "serde")]
pub use units::amount::serde;
@@ -265,60 +262,6 @@ pub mod amount {
TooPreciseError, UnknownDenominationError,
};
}
-
- impl Decodable for Amount {
- #[inline]
- fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
- Self::from_sat(Decodable::consensus_decode(r)?).map_err(|_| {
- consensus::parse_failed_error("amount is greater than Amount::MAX_MONEY")
- })
- }
- }
-
- impl Encodable for Amount {
- #[inline]
- fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
- self.to_sat().consensus_encode(w)
- }
- }
-}
-
-mod encode_impls {
- //! Encodable/Decodable implementations.
- // While we are deprecating, re-exporting, and generally moving things around just put these here.
-
- use crate::consensus::{encode, Decodable, Encodable};
- use crate::io::{BufRead, Write};
- use crate::{BlockHeight, BlockHeightInterval};
-
- /// Implements Encodable and Decodable for a simple wrapper type.
- ///
- /// Wrapper type is required to implement `to_u32()` and `From<u32>`.
- macro_rules! impl_encodable_for_u32_wrapper {
- ($ty:ident) => {
- impl Decodable for $ty {
- #[inline]
- fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
- let inner = u32::consensus_decode(r)?;
- Ok($ty::from(inner))
- }
- }
-
- impl Encodable for $ty {
- #[inline]
- fn consensus_encode<W: Write + ?Sized>(
- &self,
- w: &mut W,
- ) -> Result<usize, io::Error> {
- let inner = self.to_u32();
- inner.consensus_encode(w)
- }
- }
- };
- }
-
- impl_encodable_for_u32_wrapper!(BlockHeight);
- impl_encodable_for_u32_wrapper!(BlockHeightInterval);
}
/// A conversion trait for unsigned integer types smaller than or equal to 64-bits.
diff --git a/bitcoin/src/merkle_tree/mod.rs b/bitcoin/src/merkle_tree/mod.rs
index bac1bb5d..121e0931 100644
--- a/bitcoin/src/merkle_tree/mod.rs
+++ b/bitcoin/src/merkle_tree/mod.rs
@@ -14,36 +14,8 @@
//! assert!(root.is_some());
//! ```
-use io::{BufRead, Write};
-
#[rustfmt::skip]
#[doc(inline)]
pub use primitives::merkle_tree::{TxMerkleNodeDecoder, TxMerkleNodeEncoder, TxMerkleNode, WitnessMerkleNode};
#[doc(no_inline)]
pub use primitives::merkle_tree::TxMerkleNodeDecoderError;
-
-use crate::consensus::{encode, Decodable, Encodable};
-
-impl Encodable for TxMerkleNode {
- fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
- self.to_byte_array().consensus_encode(w)
- }
-}
-
-impl Decodable for TxMerkleNode {
- fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
- Ok(Self::from_byte_array(<[u8; 32]>::consensus_decode(r)?))
- }
-}
-
-impl Encodable for WitnessMerkleNode {
- fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
- self.to_byte_array().consensus_encode(w)
- }
-}
-
-impl Decodable for WitnessMerkleNode {
- fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
- Ok(Self::from_byte_array(<[u8; 32]>::consensus_decode(r)?))
- }
-}
diff --git a/bitcoin/src/pow.rs b/bitcoin/src/pow.rs
index 37131892..c1489067 100644
--- a/bitcoin/src/pow.rs
+++ b/bitcoin/src/pow.rs
@@ -9,10 +9,7 @@ use alloc::string::String;
use core::ops::{Add, Div, Mul, Not, Rem, Shl, Shr, Sub};
use core::{cmp, fmt};
-use io::{BufRead, Write};
-
use crate::block::{BlockHash, BlockHeight, BlockHeightInterval, Header};
-use crate::consensus::encode::{self, Decodable, Encodable};
use crate::internal_macros;
use crate::network::Params;
@@ -377,20 +374,6 @@ mod sealed {
impl Sealed for super::Work {}
}
-impl Encodable for CompactTarget {
- #[inline]
- fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
- self.to_consensus().consensus_encode(w)
- }
-}
-
-impl Decodable for CompactTarget {
- #[inline]
- fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
- u32::consensus_decode(r).map(Self::from_consensus)
- }
-}
-
/// A trait for types that can convert to and from a [`U256`]
///
/// This just provides short-hand functions for the conversions going via byte arrays.
Why this scored 11/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.