Add a hash value to Inventory's Error variant

While the hash value of the Error variant is meaningless, the variant
still conforms to all other Inventory messages and requires a 32
byte hash to be sent over the wire. This is how bitcoin core operates.

This patch adds the 32 byte array to the Error variant in order to make
its Encoding and Decoding paths symmetrical. This also allows a reader
to discard the 32 bytes when decoding a message. The hash is still not
exposed to the caller.

This was never a problem before because the top level RawNetworkPackage
pulls all the required bytes off a reader before decoding. But this is
not as easy to do with the v2 p2p network messages.
This commit is contained in:
Nick Johnson 2024-12-18 19:24:26 -08:00
parent ebe43b6f87
commit 72e97c637f
2 changed files with 8 additions and 7 deletions

View File

@ -583,7 +583,7 @@ mod test {
)]),
NetworkMessage::Inv(vec![Inventory::Block(hash([8u8; 32]).into())]),
NetworkMessage::GetData(vec![Inventory::Transaction(hash([45u8; 32]).into())]),
NetworkMessage::NotFound(vec![Inventory::Error]),
NetworkMessage::NotFound(vec![Inventory::Error([0u8; 32])]),
NetworkMessage::GetBlocks(GetBlocksMessage::new(
vec![hash([1u8; 32]).into(), hash([4u8; 32]).into()],
hash([5u8; 32]).into(),

View File

@ -16,8 +16,9 @@ use crate::transaction::{Txid, Wtxid};
/// An inventory item.
#[derive(PartialEq, Eq, Clone, Debug, Copy, Hash, PartialOrd, Ord)]
pub enum Inventory {
/// Error --- these inventories can be ignored
Error,
/// Error --- these inventories can be ignored.
/// While a 32 byte hash is expected over the wire, the value is meaningless.
Error([u8; 32]),
/// Transaction
Transaction(Txid),
/// Block
@ -42,10 +43,10 @@ pub enum Inventory {
impl Inventory {
/// Return the item value represented as a SHA256-d hash.
///
/// Returns [None] only for [Inventory::Error].
/// Returns [None] only for [Inventory::Error] who's hash value is meaningless.
pub fn network_hash(&self) -> Option<[u8; 32]> {
match self {
Inventory::Error => None,
Inventory::Error(_) => None,
Inventory::Transaction(t) => Some(t.to_byte_array()),
Inventory::Block(b) => Some(b.to_byte_array()),
Inventory::CompactBlock(b) => Some(b.to_byte_array()),
@ -66,7 +67,7 @@ impl Encodable for Inventory {
};
}
Ok(match *self {
Inventory::Error => encode_inv!(0, [0; 32]),
Inventory::Error(_) => encode_inv!(0, [0; 32]),
Inventory::Transaction(ref t) => encode_inv!(1, t),
Inventory::Block(ref b) => encode_inv!(2, b),
Inventory::CompactBlock(ref b) => encode_inv!(4, b),
@ -83,7 +84,7 @@ impl Decodable for Inventory {
fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
let inv_type: u32 = Decodable::consensus_decode(r)?;
Ok(match inv_type {
0 => Inventory::Error,
0 => Inventory::Error(Decodable::consensus_decode(r)?),
1 => Inventory::Transaction(Decodable::consensus_decode(r)?),
2 => Inventory::Block(Decodable::consensus_decode(r)?),
4 => Inventory::CompactBlock(Decodable::consensus_decode(r)?),