p2p: Remove legacy encoding in `message`
What changed, and why it matters
This commit removes old-style Bitcoin P2P message encoding and decoding code from the rust-bitcoin library and replaces it with a newer encoding system. It is a cleanup/refactoring change, not a fix for an active security bug. The deleted code included checksum verification and message-length limits that now live in the new encoder, so the security of the library depends on whether the new code provides equivalent protections. The commit itself does not describe any security issue.
Treat as a routine refactoring commit. Verify through tests and code review that the new `encoding::Encode`/`Decode` implementations enforce the same checksum validation, message length limits, and finite-reader bounds as the removed legacy code. No immediate security patch is indicated.
Security signals we found
Large deletion of consensus encoding code without explicit security rationale
Removal of checksum-bearing type CheckedData from public API
Replacement of finite-reader length limits with new encoder; equivalence must be assumed from existing tests
No mention of vulnerability, CVE, or security fix in commit message
Evidence from the diff
The diff deletes legacy bitcoin::consensus::encode::{Encodable, Decodable} implementations for P2P types (CommandString, V1MessageHeader, NetworkMessage, V1NetworkMessage, V2NetworkMessage, NetworkHeader, HeadersMessage, FeeFilter, CheckedData, and several vec wrappers) and removes the public re-export of message::CheckedData. The same types already have new encoding::Encode/Decode implementations elsewhere in the file, so this is a removal of duplicated/deprecated code paths. No vulnerability is mentioned in the commit message or diff, and no CVE or advisory is referenced.
Changed components
p2p/src/message.rsp2p/src/lib.rsCommandStringV1MessageHeaderV1NetworkMessageV2NetworkMessageNetworkHeaderHeadersMessageFeeFilterCheckedDataInspect captured patch +2 / −442
diff --git a/p2p/src/lib.rs b/p2p/src/lib.rs
index b8db442e..161b1194 100644
--- a/p2p/src/lib.rs
+++ b/p2p/src/lib.rs
@@ -60,7 +60,7 @@ pub use self::{
#[cfg(feature = "std")]
#[rustfmt::skip]
#[doc(inline)]
-pub use self::{address::Address, message::CheckedData};
+pub use self::address::Address;
#[rustfmt::skip] // Keep public re-exports separate.
#[doc(no_inline)]
diff --git a/p2p/src/message.rs b/p2p/src/message.rs
index 92ca09d0..d853ec40 100644
--- a/p2p/src/message.rs
+++ b/p2p/src/message.rs
@@ -8,27 +8,22 @@
use alloc::borrow::{Cow, ToOwned};
use alloc::boxed::Box;
use alloc::string::String;
-use alloc::vec;
use alloc::vec::Vec;
-use core::{cmp, fmt, mem};
+use core::{fmt, mem};
#[cfg(feature = "arbitrary")]
use arbitrary::{Arbitrary, Unstructured};
-use bitcoin::consensus::encode::{self, Decodable, Encodable, ReadExt, WriteExt};
use encoding::{
self, ArrayDecoder, ArrayEncoder, BytesEncoder, CompactSizeEncoder, Decoder2, Encoder2,
SliceEncoder, VecDecoder,
};
use hashes::{sha256d, HashEngine};
-use internals::ToU64 as _;
-use io::{self, BufRead, Read, Write};
use primitives::block::{self, HeaderDecoder, HeaderEncoder};
use primitives::transaction;
use units::FeeRate;
use self::error::V1NetworkMessageDecoderErrorInner;
use crate::address::{AddrV1Message, AddrV2Message};
-use crate::consensus::{impl_consensus_encoding, impl_vec_wrapper};
use crate::merkle_tree::MerkleBlock;
use crate::{
bip152, message_blockdata, message_bloom, message_compact_blocks, message_filter,
@@ -120,33 +115,6 @@ impl AsRef<str> for CommandString {
fn as_ref(&self) -> &str { self.0.as_ref() }
}
-impl Encodable for CommandString {
- #[inline]
- fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
- let mut rawbytes = [0u8; 12];
- let strbytes = self.0.as_bytes();
- debug_assert!(strbytes.len() <= 12);
- rawbytes[..strbytes.len()].copy_from_slice(strbytes);
- rawbytes.consensus_encode(w)
- }
-}
-
-impl Decodable for CommandString {
- #[inline]
- fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
- let rawbytes: [u8; 12] = Decodable::consensus_decode(r)?;
-
- // Find the last non-null byte and trim null padding from the end
- let trimmed = &rawbytes[..rawbytes.iter().rposition(|&b| b != 0).map_or(0, |i| i + 1)];
-
- if !trimmed.is_ascii() {
- return Err(crate::consensus::parse_failed_error("Command string must be ASCII"));
- }
-
- Ok(Self(Cow::Owned(unsafe { String::from_utf8_unchecked(trimmed.to_vec()) })))
- }
-}
-
impl encoding::Encode for CommandString {
type Encoder<'e> = CommandStringEncoder;
@@ -322,8 +290,6 @@ impl encoding::Decode for V1MessageHeader {
}
}
-impl_consensus_encoding!(V1MessageHeader, magic, command, length, checksum);
-
/// A Network message using the v2 p2p protocol defined in BIP-0324.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct V2NetworkMessage {
@@ -488,10 +454,6 @@ impl encoding::Decode for AddrV2Payload {
fn decoder() -> Self::Decoder { AddrV2PayloadDecoder(VecDecoder::new()) }
}
-impl_vec_wrapper!(InventoryPayload, message_blockdata::Inventory);
-impl_vec_wrapper!(AddrPayload, AddrV1Message);
-impl_vec_wrapper!(AddrV2Payload, AddrV2Message);
-
/// The `feefilter` message, wrapper around [`FeeRate`] for P2P wire format encoding.
///
/// This message is used to inform peers about the minimum fee rate for transactions
@@ -517,48 +479,6 @@ impl From<FeeFilter> for FeeRate {
fn from(filter: FeeFilter) -> Self { filter.0 }
}
-impl bitcoin::consensus::encode::Encodable for FeeFilter {
- fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
- use encoding::Encoder;
- let mut encoder = encoding::Encode::encoder(self);
- loop {
- w.write_all(encoder.current_chunk())?;
- if !encoder.advance() {
- break;
- }
- }
- Ok(8)
- }
-}
-
-impl bitcoin::consensus::encode::Decodable for FeeFilter {
- fn consensus_decode<R: BufRead + ?Sized>(
- r: &mut R,
- ) -> Result<Self, bitcoin::consensus::encode::Error> {
- use encoding::Decoder;
-
- let mut decoder = <Self as encoding::Decode>::decoder();
- let mut buffer = [0u8; 8];
-
- r.read_exact(&mut buffer)?;
-
- let mut slice = &buffer[..];
- decoder.push_bytes(&mut slice).map_err(|_| {
- bitcoin::consensus::encode::Error::Io(io::Error::new(
- io::ErrorKind::UnexpectedEof,
- "insufficient data for FeeFilter",
- ))
- })?;
-
- decoder.end().map_err(|_| {
- bitcoin::consensus::encode::Error::Io(io::Error::new(
- io::ErrorKind::UnexpectedEof,
- "insufficient data for FeeFilter",
- ))
- })
- }
-}
-
encoding::encoder_newtype_exact! {
/// Encoder for [`FeeFilter`] type.
#[derive(Debug, Clone)]
@@ -940,51 +860,6 @@ impl V2NetworkMessage {
pub fn command(&self) -> CommandString { self.payload.command() }
}
-impl Encodable for NetworkMessage {
- fn consensus_encode<W: Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
- match self {
- Self::Version(ref dat) => dat.consensus_encode(writer),
- Self::Addr(ref dat) => dat.consensus_encode(writer),
- Self::Inv(ref dat) => dat.consensus_encode(writer),
- Self::GetData(ref dat) => dat.consensus_encode(writer),
- Self::NotFound(ref dat) => dat.consensus_encode(writer),
- Self::GetBlocks(ref dat) => dat.consensus_encode(writer),
- Self::GetHeaders(ref dat) => dat.consensus_encode(writer),
- Self::Tx(ref dat) => dat.consensus_encode(writer),
- Self::Block(ref dat) => dat.consensus_encode(writer),
- Self::Headers(ref dat) => dat.consensus_encode(writer),
- Self::Ping(ref dat) => dat.0.consensus_encode(writer),
- Self::Pong(ref dat) => dat.0.consensus_encode(writer),
- Self::MerkleBlock(ref dat) => dat.consensus_encode(writer),
- Self::FilterLoad(ref dat) => dat.consensus_encode(writer),
- Self::FilterAdd(ref dat) => dat.consensus_encode(writer),
- Self::GetCFilters(ref dat) => dat.consensus_encode(writer),
- Self::CFilter(ref dat) => dat.consensus_encode(writer),
- Self::GetCFHeaders(ref dat) => dat.consensus_encode(writer),
- Self::CFHeaders(ref dat) => dat.consensus_encode(writer),
- Self::GetCFCheckpt(ref dat) => dat.consensus_encode(writer),
- Self::CFCheckpt(ref dat) => dat.consensus_encode(writer),
- Self::SendCmpct(ref dat) => dat.consensus_encode(writer),
- Self::CmpctBlock(ref dat) => dat.consensus_encode(writer),
- Self::GetBlockTxn(ref dat) => dat.consensus_encode(writer),
- Self::BlockTxn(ref dat) => dat.consensus_encode(writer),
- Self::Alert(ref dat) => dat.consensus_encode(writer),
- Self::Reject(ref dat) => dat.consensus_encode(writer),
- Self::FeeFilter(ref dat) => dat.consensus_encode(writer),
- Self::AddrV2(ref dat) => dat.consensus_encode(writer),
- Self::Verack
- | Self::SendHeaders
- | Self::MemPool
- | Self::GetAddr
- | Self::WtxidRelay
- | Self::FilterClear
- | Self::SendAddrV2 => Ok(0),
- // Don't use consensus_encode so as not to add a length suffix.
- Self::Unknown { payload: ref data, .. } => writer.write(data),
- }
- }
-}
-
impl encoding::Encode for NetworkMessage {
type Encoder<'e> = NetworkMessageEncoder<'e>;
@@ -992,18 +867,6 @@ impl encoding::Encode for NetworkMessage {
fn encoder(&self) -> Self::Encoder<'_> { NetworkMessageEncoder::new(self) }
}
-impl Encodable for V1NetworkMessage {
- fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
- let mut len = 0;
- len += self.magic.consensus_encode(w)?;
- len += self.command().consensus_encode(w)?;
- len += self.payload_len.consensus_encode(w)?;
- len += self.checksum.consensus_encode(w)?;
- len += self.payload().consensus_encode(w)?;
- Ok(len)
- }
-}
-
/// Encoder for [`NetworkMessage`]
#[derive(Debug, Clone)]
pub enum NetworkMessageEncoder<'e> {
@@ -1682,24 +1545,6 @@ fn v2_command_byte(payload: &NetworkMessage) -> (u8, Option<CommandString>) {
}
}
-impl Encodable for V2NetworkMessage {
- fn consensus_encode<W: Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
- // A subset of message types are optimized to only use one byte to encode the command.
- // Non-optimized message types use the zero-byte flag and the following twelve bytes to encode the command.
- let (command_byte, full_command) = v2_command_byte(&self.payload);
-
- let mut len = command_byte.consensus_encode(writer)?;
- if let Some(cmd) = full_command {
- len += cmd.consensus_encode(writer)?;
- }
-
- // Encode the payload.
- len += self.payload.consensus_encode(writer)?;
-
- Ok(len)
- }
-}
-
/// Network encoded [`Header`](primitives::block::Header) with associated byte for the length of
/// transactions that follow, which is currently always zero.
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -1765,20 +1610,6 @@ impl encoding::Decode for NetworkHeader {
}
}
-impl Decodable for NetworkHeader {
- fn consensus_decode<R: BufRead + ?Sized>(reader: &mut R) -> Result<Self, encode::Error> {
- Ok(Self { header: Decodable::consensus_decode(reader)?, length: reader.read_u8()? })
- }
-}
-
-impl Encodable for NetworkHeader {
- fn consensus_encode<W: Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
- let mut size = self.header.consensus_encode(writer)?;
- size += self.length.consensus_encode(writer)?;
- Ok(size)
- }
-}
-
/// A list of bitcoin block headers.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct HeadersMessage(pub Vec<NetworkHeader>);
@@ -1798,8 +1629,6 @@ impl HeadersMessage {
}
}
-impl_vec_wrapper!(HeadersMessage, NetworkHeader);
-
encoding::encoder_newtype! {
/// The encoder type for a [`HeadersMessage`].
#[derive(Debug, Clone)]
@@ -1848,185 +1677,6 @@ impl encoding::Decode for HeadersMessage {
fn decoder() -> Self::Decoder { HeadersMessageDecoder(VecDecoder::new()) }
}
-impl Decodable for V1NetworkMessage {
- fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(
- r: &mut R,
- ) -> Result<Self, encode::Error> {
- let magic = Decodable::consensus_decode_from_finite_reader(r)?;
- let cmd = CommandString::consensus_decode_from_finite_reader(r)?;
- let checked_data = CheckedData::consensus_decode_from_finite_reader(r)?;
- let checksum = checked_data.checksum();
- let raw_payload = checked_data.into_data();
- let payload_len = raw_payload.len() as u32;
-
- let mut mem_d = raw_payload.as_slice();
- let payload = match &cmd.0[..] {
- "version" =>
- NetworkMessage::Version(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
- "verack" => NetworkMessage::Verack,
- "addr" =>
- NetworkMessage::Addr(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
- "inv" =>
- NetworkMessage::Inv(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
- "getdata" =>
- NetworkMessage::GetData(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
- "notfound" => NetworkMessage::NotFound(Decodable::consensus_decode_from_finite_reader(
- &mut mem_d,
- )?),
- "getblocks" => NetworkMessage::GetBlocks(
- Decodable::consensus_decode_from_finite_reader(&mut mem_d)?,
- ),
- "getheaders" => NetworkMessage::GetHeaders(
- Decodable::consensus_decode_from_finite_reader(&mut mem_d)?,
- ),
- "mempool" => NetworkMessage::MemPool,
- "block" =>
- NetworkMessage::Block(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
- "headers" => NetworkMessage::Headers(
- HeadersMessage::consensus_decode_from_finite_reader(&mut mem_d)?,
- ),
- "sendheaders" => NetworkMessage::SendHeaders,
- "getaddr" => NetworkMessage::GetAddr,
- "ping" => NetworkMessage::Ping(Ping(Decodable::consensus_decode_from_finite_reader(
- &mut mem_d,
- )?)),
- "pong" => NetworkMessage::Pong(Pong(Decodable::consensus_decode_from_finite_reader(
- &mut mem_d,
- )?)),
- "merkleblock" => NetworkMessage::MerkleBlock(
- Decodable::consensus_decode_from_finite_reader(&mut mem_d)?,
- ),
- "filterload" => NetworkMessage::FilterLoad(
- Decodable::consensus_decode_from_finite_reader(&mut mem_d)?,
- ),
- "filteradd" => NetworkMessage::FilterAdd(
- Decodable::consensus_decode_from_finite_reader(&mut mem_d)?,
- ),
- "filterclear" => NetworkMessage::FilterClear,
- "tx" => NetworkMessage::Tx(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
- "getcfilters" => NetworkMessage::GetCFilters(
- Decodable::consensus_decode_from_finite_reader(&mut mem_d)?,
- ),
- "cfilter" =>
- NetworkMessage::CFilter(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
- "getcfheaders" => NetworkMessage::GetCFHeaders(
- Decodable::consensus_decode_from_finite_reader(&mut mem_d)?,
- ),
- "cfheaders" => NetworkMessage::CFHeaders(
- Decodable::consensus_decode_from_finite_reader(&mut mem_d)?,
- ),
- "getcfcheckpt" => NetworkMessage::GetCFCheckpt(
- Decodable::consensus_decode_from_finite_reader(&mut mem_d)?,
- ),
- "cfcheckpt" => NetworkMessage::CFCheckpt(
- Decodable::consensus_decode_from_finite_reader(&mut mem_d)?,
- ),
- "reject" =>
- NetworkMessage::Reject(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
- "alert" =>
- NetworkMessage::Alert(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
- "feefilter" => NetworkMessage::FeeFilter(
- FeeFilter::consensus_decode_from_finite_reader(&mut mem_d)?,
- ),
- "sendcmpct" => NetworkMessage::SendCmpct(
- Decodable::consensus_decode_from_finite_reader(&mut mem_d)?,
- ),
- "cmpctblock" => NetworkMessage::CmpctBlock(
- Decodable::consensus_decode_from_finite_reader(&mut mem_d)?,
- ),
- "getblocktxn" => NetworkMessage::GetBlockTxn(
- Decodable::consensus_decode_from_finite_reader(&mut mem_d)?,
- ),
- "blocktxn" => NetworkMessage::BlockTxn(Decodable::consensus_decode_from_finite_reader(
- &mut mem_d,
- )?),
- "wtxidrelay" => NetworkMessage::WtxidRelay,
- "addrv2" =>
- NetworkMessage::AddrV2(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
- "sendaddrv2" => NetworkMessage::SendAddrV2,
- _ => NetworkMessage::Unknown { command: cmd, payload: raw_payload },
- };
- Ok(Self { magic, payload, payload_len, checksum })
- }
-
- #[inline]
- fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
- Self::consensus_decode_from_finite_reader(&mut r.take(MAX_MSG_SIZE.to_u64()))
- }
-}
-
-impl Decodable for V2NetworkMessage {
- fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(
- r: &mut R,
- ) -> Result<Self, encode::Error> {
- let short_id: u8 = Decodable::consensus_decode_from_finite_reader(r)?;
- let payload = match short_id {
- 0u8 => {
- // Full command encoding.
- let cmd = CommandString::consensus_decode_from_finite_reader(r)?;
- match &cmd.0[..] {
- "version" =>
- NetworkMessage::Version(Decodable::consensus_decode_from_finite_reader(r)?),
- "verack" => NetworkMessage::Verack,
- "sendheaders" => NetworkMessage::SendHeaders,
- "getaddr" => NetworkMessage::GetAddr,
- "wtxidrelay" => NetworkMessage::WtxidRelay,
- "sendaddrv2" => NetworkMessage::SendAddrV2,
- "alert" =>
- NetworkMessage::Alert(Decodable::consensus_decode_from_finite_reader(r)?),
- "reject" =>
- NetworkMessage::Reject(Decodable::consensus_decode_from_finite_reader(r)?),
- _ => NetworkMessage::Unknown {
- command: cmd,
- payload: Vec::consensus_decode_from_finite_reader(r)?,
- },
- }
- }
- 1u8 => NetworkMessage::Addr(Decodable::consensus_decode_from_finite_reader(r)?),
- 2u8 => NetworkMessage::Block(Decodable::consensus_decode_from_finite_reader(r)?),
- 3u8 => NetworkMessage::BlockTxn(Decodable::consensus_decode_from_finite_reader(r)?),
- 4u8 => NetworkMessage::CmpctBlock(Decodable::consensus_decode_from_finite_reader(r)?),
- 5u8 => NetworkMessage::FeeFilter(FeeFilter::consensus_decode_from_finite_reader(r)?),
- 6u8 => NetworkMessage::FilterAdd(Decodable::consensus_decode_from_finite_reader(r)?),
- 7u8 => NetworkMessage::FilterClear,
- 8u8 => NetworkMessage::FilterLoad(Decodable::consensus_decode_from_finite_reader(r)?),
- 9u8 => NetworkMessage::GetBlocks(Decodable::consensus_decode_from_finite_reader(r)?),
- 10u8 => NetworkMessage::GetBlockTxn(Decodable::consensus_decode_from_finite_reader(r)?),
- 11u8 => NetworkMessage::GetData(Decodable::consensus_decode_from_finite_reader(r)?),
- 12u8 => NetworkMessage::GetHeaders(Decodable::consensus_decode_from_finite_reader(r)?),
- 13u8 =>
- NetworkMessage::Headers(HeadersMessage::consensus_decode_from_finite_reader(r)?),
- 14u8 => NetworkMessage::Inv(Decodable::consensus_decode_from_finite_reader(r)?),
- 15u8 => NetworkMessage::MemPool,
- 16u8 => NetworkMessage::MerkleBlock(Decodable::consensus_decode_from_finite_reader(r)?),
- 17u8 => NetworkMessage::NotFound(Decodable::consensus_decode_from_finite_reader(r)?),
- 18u8 => NetworkMessage::Ping(Ping(Decodable::consensus_decode_from_finite_reader(r)?)),
- 19u8 => NetworkMessage::Pong(Pong(Decodable::consensus_decode_from_finite_reader(r)?)),
- 20u8 => NetworkMessage::SendCmpct(Decodable::consensus_decode_from_finite_reader(r)?),
- 21u8 => NetworkMessage::Tx(Decodable::consensus_decode_from_finite_reader(r)?),
- 22u8 => NetworkMessage::GetCFilters(Decodable::consensus_decode_from_finite_reader(r)?),
- 23u8 => NetworkMessage::CFilter(Decodable::consensus_decode_from_finite_reader(r)?),
- 24u8 =>
- NetworkMessage::GetCFHeaders(Decodable::consensus_decode_from_finite_reader(r)?),
- 25u8 => NetworkMessage::CFHeaders(Decodable::consensus_decode_from_finite_reader(r)?),
- 26u8 =>
- NetworkMessage::GetCFCheckpt(Decodable::consensus_decode_from_finite_reader(r)?),
- 27u8 => NetworkMessage::CFCheckpt(Decodable::consensus_decode_from_finite_reader(r)?),
- 28u8 => NetworkMessage::AddrV2(Decodable::consensus_decode_from_finite_reader(r)?),
- _ =>
- return Err(encode::Error::Parse(encode::ParseError::ParseFailed(
- "Unknown short ID",
- ))),
- };
- Ok(Self { payload })
- }
-
- #[inline]
- fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
- Self::consensus_decode_from_finite_reader(&mut r.take(MAX_MSG_SIZE.to_u64()))
- }
-}
-
// State machine for decoding a [`V2NetworkMessage`].
#[derive(Clone, Debug)]
#[allow(clippy::large_enum_variant)]
@@ -2235,96 +1885,6 @@ impl encoding::Decode for V2NetworkMessage {
}
}
-/// Data and a 4-byte checksum.
-#[derive(PartialEq, Eq, Clone, Debug)]
-pub struct CheckedData {
- data: Vec<u8>,
- checksum: [u8; 4],
-}
-
-impl CheckedData {
- /// Constructs a new `CheckedData` computing the checksum of given data.
- pub fn new(data: Vec<u8>) -> Self {
- let hash = sha256d::hash(data.as_slice()).to_byte_array();
- let checksum = [hash[0], hash[1], hash[2], hash[3]];
- Self { data, checksum }
- }
-
- /// Returns a reference to the raw data without the checksum.
- pub fn data(&self) -> &[u8] { &self.data }
-
- /// Returns the raw data without the checksum.
- pub fn into_data(self) -> Vec<u8> { self.data }
-
- /// Returns the checksum of the data.
- pub fn checksum(&self) -> [u8; 4] { self.checksum }
-}
-
-impl Encodable for CheckedData {
- #[inline]
- fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
- u32::try_from(self.data.len())
- .expect("network message use u32 as length")
- .consensus_encode(w)?;
- self.checksum().consensus_encode(w)?;
- Ok(8 + w.emit_slice(&self.data)?)
- }
-}
-
-impl Decodable for CheckedData {
- #[inline]
- fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(
- r: &mut R,
- ) -> Result<Self, encode::Error> {
- let len = u32::consensus_decode_from_finite_reader(r)? as usize;
-
- let checksum = <[u8; 4]>::consensus_decode_from_finite_reader(r)?;
- let opts = ReadBytesFromFiniteReaderOpts { len, chunk_size: encode::MAX_VEC_SIZE };
- let data = read_bytes_from_finite_reader(r, opts)?;
- let hash = sha256d::hash(data.as_slice()).to_byte_array();
- let expected_checksum = [hash[0], hash[1], hash[2], hash[3]];
- if expected_checksum == checksum {
- Ok(Self { data, checksum })
- } else {
- Err(encode::ParseError::InvalidChecksum {
- expected: expected_checksum,
- actual: checksum,
- }
- .into())
- }
- }
-}
-
-struct ReadBytesFromFiniteReaderOpts {
- len: usize,
- chunk_size: usize,
-}
-
-/// Read `opts.len` bytes from reader, where `opts.len` could potentially be malicious.
-///
-/// This function relies on reader being bound in amount of data
-/// it returns for OOM protection. See [`Decodable::consensus_decode_from_finite_reader`].
-#[inline]
-fn read_bytes_from_finite_reader<D: Read + ?Sized>(
- d: &mut D,
- mut opts: ReadBytesFromFiniteReaderOpts,
-) -> Result<Vec<u8>, encode::Error> {
- let mut ret = vec![];
-
- assert_ne!(opts.chunk_size, 0);
-
- while opts.len > 0 {
- let chunk_start = ret.len();
- let chunk_size = cmp::min(opts.len, opts.chunk_size);
- let chunk_end = chunk_start + chunk_size;
- ret.resize(chunk_end, 0u8);
- d.read_slice(&mut ret[chunk_start..chunk_end])?;
- opts.len -= chunk_size;
- }
-
- Ok(ret)
-}
-
/// Does a double-SHA256 on `data` and returns the first 4 bytes.
fn sha2_checksum(data: &impl encoding::Encode) -> (u64, [u8; 4]) {
let mut engine = sha256d::HashEngine::new();
Why this scored 18/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.