p2p: Implement `encoding` traits for `MerkleBlock`
What changed, and why it matters
This commit adds new encoding and decoding machinery for a data structure called MerkleBlock in the library's peer-to-peer networking code. It is a routine feature addition that mirrors a similar change already made for PartialMerkleTree. There is no indication in the commit that this fixes a security bug or introduces a vulnerability.
No security action required. Review as normal code-quality change.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch implements the project’s newer encoding::Encodable/Decodable traits for MerkleBlock, alongside the existing legacy consensus::encode::Encodable/Decodable traits. It introduces MerkleBlockEncoder, MerkleBlockDecoder, and MerkleBlockDecoderError, wiring them to the previously added PartialMerkleTree encoder/decoder and the block header encoder/decoder. The change is additive and self-contained.
Changed components
p2p/src/merkle_tree.rsMerkleBlock encoding/decodingInspect captured patch +67 / −2
diff --git a/p2p/src/merkle_tree.rs b/p2p/src/merkle_tree.rs
index 22306d02..3e69b541 100644
--- a/p2p/src/merkle_tree.rs
+++ b/p2p/src/merkle_tree.rs
@@ -17,11 +17,11 @@ use core::fmt;
#[cfg(feature = "arbitrary")]
use arbitrary::{Arbitrary, Unstructured};
use bitcoin::consensus::encode::{self, Decodable, Encodable, ReadExt, WriteExt, MAX_VEC_SIZE};
-use encoding::{ArrayDecoder, ArrayEncoder, ByteVecDecoder, CompactSizeEncoder, Decoder3, Encoder2, Encoder3, SliceEncoder, VecDecoder};
+use encoding::{ArrayDecoder, ArrayEncoder, ByteVecDecoder, CompactSizeEncoder, Decoder2, Decoder3, Encoder2, Encoder3, SliceEncoder, VecDecoder};
use internals::ToU64 as _;
use internals::write_err;
use io::{BufRead, Write};
-use primitives::block::{self, Block, Checked};
+use primitives::block::{self, Block, Checked, HeaderDecoder, HeaderEncoder};
use primitives::merkle_tree::TxMerkleNode;
use primitives::transaction::{Transaction, Txid};
use primitives::Weight;
@@ -125,6 +125,71 @@ impl MerkleBlock {
}
}
+encoding::encoder_newtype! {
+ /// The encoder type for a [`MerkleBlock`].
+ pub struct MerkleBlockEncoder<'e>(Encoder2<HeaderEncoder<'e>, PartialMerkleTreeEncoder<'e>>);
+}
+
+impl encoding::Encodable for MerkleBlock {
+ type Encoder<'e> = MerkleBlockEncoder<'e>;
+
+ fn encoder(&self) -> Self::Encoder<'_> {
+ MerkleBlockEncoder::new(
+ Encoder2::new(self.header.encoder(), self.txn.encoder())
+ )
+ }
+}
+
+type MerkleBlockInnerDecoder = Decoder2<HeaderDecoder, PartialMerkleTreeDecoder>;
+
+/// The decoder for a [`MerkleBlock`].
+pub struct MerkleBlockDecoder(MerkleBlockInnerDecoder);
+
+impl encoding::Decoder for MerkleBlockDecoder {
+ type Output = MerkleBlock;
+ type Error = MerkleBlockDecoderError;
+
+ #[inline]
+ fn push_bytes(&mut self, bytes: &mut &[u8]) -> Result<bool, Self::Error> {
+ self.0.push_bytes(bytes).map_err(MerkleBlockDecoderError)
+ }
+
+ #[inline]
+ fn end(self) -> Result<Self::Output, Self::Error> {
+ let (header, txn) = self.0.end().map_err(MerkleBlockDecoderError)?;
+ Ok(MerkleBlock { header, txn })
+ }
+
+ #[inline]
+ fn read_limit(&self) -> usize { self.0.read_limit() }
+}
+
+impl encoding::Decodable for MerkleBlock {
+ type Decoder = MerkleBlockDecoder;
+ fn decoder() -> Self::Decoder {
+ MerkleBlockDecoder(Decoder2::new(block::Header::decoder(), PartialMerkleTree::decoder()))
+ }
+}
+
+/// An error occuring when decoding a [`MerkleBlock`].
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct MerkleBlockDecoderError(<MerkleBlockInnerDecoder as encoding::Decoder>::Error);
+
+impl From<Infallible> for MerkleBlockDecoderError {
+ fn from(never: Infallible) -> Self { match never {} }
+}
+
+impl fmt::Display for MerkleBlockDecoderError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write_err!(f, "merkleblock error"; self.0)
+ }
+}
+
+#[cfg(feature = "std")]
+impl std::error::Error for MerkleBlockDecoderError {
+ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { Some(&self.0) }
+}
+
impl Encodable for MerkleBlock {
fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
let len = self.header.consensus_encode(w)? + self.txn.consensus_encode(w)?;
Why this scored 15/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.