From 9151382bd0e3a86ddc6a40a1770bc1d5a000cbb3 Mon Sep 17 00:00:00 2001 From: Nick Johnson Date: Fri, 10 May 2024 11:27:43 -0700 Subject: [PATCH] WIP serde --- protocol/src/v2.rs | 290 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 231 insertions(+), 59 deletions(-) diff --git a/protocol/src/v2.rs b/protocol/src/v2.rs index fe7e276..8fb224f 100644 --- a/protocol/src/v2.rs +++ b/protocol/src/v2.rs @@ -1,10 +1,13 @@ -use core::fmt; +//! A subset of commands are represented with a single byte in V2 instead of the 12-byte ASCII encoding like V1. +//! +//! ID mappings defined in [BIP324](https://github.com/bitcoin/bips/blob/master/bip-0324.mediawiki#user-content-v2_Bitcoin_P2P_message_structure). -use alloc::string::String; -use bitcoin::{consensus::Encodable, p2p::message::NetworkMessage}; +use core::fmt; -/// A subset of commands are represented with a single byte -/// in V2 instead of the 12-byte ASCII encoding like V1. +use bitcoin::{ + consensus::{Decodable, Encodable}, + p2p::message::{CommandString, NetworkMessage}, +}; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum Error { @@ -33,69 +36,238 @@ impl std::error::Error for Error { /// Serialize message in v2 format to buffer. pub fn serialize(msg: NetworkMessage, buffer: &mut [u8]) -> Result<(), Error> { - let mut b = [0u8; 20]; - let mut buf2 = &mut b[1..]; - msg.consensus_encode(&mut buffer); match msg { - NetworkMessage::Version(_) => {} - NetworkMessage::Verack => todo!(), NetworkMessage::Addr(_) => { buffer[0] = 1u8; + let mut payload_buffer = &mut buffer[1..]; + msg.consensus_encode(&mut payload_buffer) + .map_err(|_| Error::Serialize)?; + } + NetworkMessage::Inv(_) => { + buffer[0] = 14u8; + let mut payload_buffer = &mut buffer[1..]; + msg.consensus_encode(&mut payload_buffer) + .map_err(|_| Error::Serialize)?; + } + NetworkMessage::GetData(_) => { + buffer[0] = 11u8; + let mut payload_buffer = &mut buffer[1..]; + msg.consensus_encode(&mut payload_buffer) + .map_err(|_| Error::Serialize)?; + } + NetworkMessage::NotFound(_) => { + buffer[0] = 17u8; + let mut payload_buffer = &mut buffer[1..]; + msg.consensus_encode(&mut payload_buffer) + .map_err(|_| Error::Serialize)?; + } + NetworkMessage::GetBlocks(_) => { + buffer[0] = 9u8; + let mut payload_buffer = &mut buffer[1..]; + msg.consensus_encode(&mut payload_buffer) + .map_err(|_| Error::Serialize)?; + } + NetworkMessage::GetHeaders(_) => { + buffer[0] = 12u8; + let mut payload_buffer = &mut buffer[1..]; + msg.consensus_encode(&mut payload_buffer) + .map_err(|_| Error::Serialize)?; + } + NetworkMessage::MemPool => { + buffer[0] = 15u8; + let mut payload_buffer = &mut buffer[1..]; + msg.consensus_encode(&mut payload_buffer) + .map_err(|_| Error::Serialize)?; + } + NetworkMessage::Tx(_) => { + buffer[0] = 21u8; + let mut payload_buffer = &mut buffer[1..]; + msg.consensus_encode(&mut payload_buffer) + .map_err(|_| Error::Serialize)?; + } + NetworkMessage::Block(_) => { + buffer[0] = 2u8; + let mut payload_buffer = &mut buffer[1..]; + msg.consensus_encode(&mut payload_buffer) + .map_err(|_| Error::Serialize)?; + } + NetworkMessage::Headers(_) => { + buffer[0] = 13u8; + let mut payload_buffer = &mut buffer[1..]; + msg.consensus_encode(&mut payload_buffer) + .map_err(|_| Error::Serialize)?; + } + NetworkMessage::Ping(_) => { + buffer[0] = 18u8; + let mut payload_buffer = &mut buffer[1..]; + msg.consensus_encode(&mut payload_buffer) + .map_err(|_| Error::Serialize)?; + } + NetworkMessage::Pong(_) => { + buffer[0] = 19u8; + let mut payload_buffer = &mut buffer[1..]; + msg.consensus_encode(&mut payload_buffer) + .map_err(|_| Error::Serialize)?; + } + NetworkMessage::MerkleBlock(_) => { + buffer[0] = 16u8; + let mut payload_buffer = &mut buffer[1..]; + msg.consensus_encode(&mut payload_buffer) + .map_err(|_| Error::Serialize)?; + } + NetworkMessage::FilterLoad(_) => { + buffer[0] = 8u8; + let mut payload_buffer = &mut buffer[1..]; + msg.consensus_encode(&mut payload_buffer) + .map_err(|_| Error::Serialize)?; + } + NetworkMessage::FilterAdd(_) => { + buffer[0] = 6u8; + let mut payload_buffer = &mut buffer[1..]; + msg.consensus_encode(&mut payload_buffer) + .map_err(|_| Error::Serialize)?; + } + NetworkMessage::FilterClear => { + buffer[0] = 7u8; + let mut payload_buffer = &mut buffer[1..]; + msg.consensus_encode(&mut payload_buffer) + .map_err(|_| Error::Serialize)?; + } + NetworkMessage::GetCFilters(_) => { + buffer[0] = 22u8; + let mut payload_buffer = &mut buffer[1..]; + msg.consensus_encode(&mut payload_buffer) + .map_err(|_| Error::Serialize)?; + } + NetworkMessage::CFilter(_) => { + buffer[0] = 23u8; + let mut payload_buffer = &mut buffer[1..]; + msg.consensus_encode(&mut payload_buffer) + .map_err(|_| Error::Serialize)?; + } + NetworkMessage::GetCFHeaders(_) => { + buffer[0] = 24u8; + let mut payload_buffer = &mut buffer[1..]; + msg.consensus_encode(&mut payload_buffer) + .map_err(|_| Error::Serialize)?; + } + NetworkMessage::CFHeaders(_) => { + buffer[0] = 25u8; + let mut payload_buffer = &mut buffer[1..]; + msg.consensus_encode(&mut payload_buffer) + .map_err(|_| Error::Serialize)?; + } + NetworkMessage::GetCFCheckpt(_) => { + buffer[0] = 25u8; + let mut payload_buffer = &mut buffer[1..]; + msg.consensus_encode(&mut payload_buffer) + .map_err(|_| Error::Serialize)?; + } + NetworkMessage::CFCheckpt(_) => { + buffer[0] = 26u8; + let mut payload_buffer = &mut buffer[1..]; + msg.consensus_encode(&mut payload_buffer) + .map_err(|_| Error::Serialize)?; + } + NetworkMessage::SendCmpct(_) => { + buffer[0] = 20u8; + let mut payload_buffer = &mut buffer[1..]; + msg.consensus_encode(&mut payload_buffer) + .map_err(|_| Error::Serialize)?; + } + NetworkMessage::CmpctBlock(_) => { + buffer[0] = 4u8; + let mut payload_buffer = &mut buffer[1..]; + msg.consensus_encode(&mut payload_buffer) + .map_err(|_| Error::Serialize)?; + } + NetworkMessage::GetBlockTxn(_) => { + buffer[0] = 10u8; + let mut payload_buffer = &mut buffer[1..]; + msg.consensus_encode(&mut payload_buffer) + .map_err(|_| Error::Serialize)?; + } + NetworkMessage::BlockTxn(_) => { + buffer[0] = 3u8; + let mut payload_buffer = &mut buffer[1..]; + msg.consensus_encode(&mut payload_buffer) + .map_err(|_| Error::Serialize)?; + } + NetworkMessage::FeeFilter(_) => { + buffer[0] = 5u8; + let mut payload_buffer = &mut buffer[1..]; + msg.consensus_encode(&mut payload_buffer) + .map_err(|_| Error::Serialize)?; + } + NetworkMessage::AddrV2(_) => { + buffer[0] = 28u8; + let mut payload_buffer = &mut buffer[1..]; + msg.consensus_encode(&mut payload_buffer) + .map_err(|_| Error::Serialize)?; + } + // Messages which are not optimized and use the zero-byte + 12 following bytes to encode command in ascii. + NetworkMessage::Version(_) + | NetworkMessage::Verack + | NetworkMessage::SendHeaders + | NetworkMessage::GetAddr + | NetworkMessage::WtxidRelay + | NetworkMessage::SendAddrV2 + | NetworkMessage::Alert(_) + | NetworkMessage::Reject(_) => { + buffer[0] = 0u8; + let mut command_buffer = &mut buffer[1..13]; + msg.command() + .consensus_encode(&mut command_buffer) + .map_err(|_| Error::Serialize)?; + let mut payload_buffer = &mut buffer[13..]; + msg.consensus_encode(&mut payload_buffer) + .map_err(|_| Error::Serialize)?; + } + NetworkMessage::Unknown { command, payload } => { + buffer[0] = 0u8; + let mut command_buffer = &mut buffer[1..13]; + command + .consensus_encode(&mut command_buffer) + .map_err(|_| Error::Serialize)?; + buffer[13..].copy_from_slice(&payload[..]); } - NetworkMessage::Inv(_) => todo!(), - NetworkMessage::GetData(_) => todo!(), - NetworkMessage::NotFound(_) => todo!(), - NetworkMessage::GetBlocks(_) => todo!(), - NetworkMessage::GetHeaders(_) => todo!(), - NetworkMessage::MemPool => todo!(), - NetworkMessage::Tx(_) => todo!(), - NetworkMessage::Block(_) => todo!(), - NetworkMessage::Headers(_) => todo!(), - NetworkMessage::SendHeaders => todo!(), - NetworkMessage::GetAddr => todo!(), - NetworkMessage::Ping(_) => todo!(), - NetworkMessage::Pong(_) => todo!(), - NetworkMessage::MerkleBlock(_) => todo!(), - NetworkMessage::FilterLoad(_) => todo!(), - NetworkMessage::FilterAdd(_) => todo!(), - NetworkMessage::FilterClear => todo!(), - NetworkMessage::GetCFilters(_) => todo!(), - NetworkMessage::CFilter(_) => todo!(), - NetworkMessage::GetCFHeaders(_) => todo!(), - NetworkMessage::CFHeaders(_) => todo!(), - NetworkMessage::GetCFCheckpt(_) => todo!(), - NetworkMessage::CFCheckpt(_) => todo!(), - NetworkMessage::SendCmpct(_) => todo!(), - NetworkMessage::CmpctBlock(_) => todo!(), - NetworkMessage::GetBlockTxn(_) => todo!(), - NetworkMessage::BlockTxn(_) => todo!(), - NetworkMessage::Alert(_) => todo!(), - NetworkMessage::Reject(_) => todo!(), - NetworkMessage::FeeFilter(_) => todo!(), - NetworkMessage::WtxidRelay => todo!(), - NetworkMessage::AddrV2(_) => todo!(), - NetworkMessage::SendAddrV2 => todo!(), - NetworkMessage::Unknown { command, payload } => todo!(), } Ok(()) } -/// Deserialize v2 message into NetworkMessage. -pub fn deserialize(buffer: &[u8]) -> Result { - Ok(()) -} - -fn to_ascii(bytes: [u8; 12]) -> String { - String::from_utf8(bytes.to_vec()) - .expect("ascii") - .trim_end_matches("00") - .to_string() +#[cfg(feature = "alloc")] +pub fn serialize_with_alloc(msg: NetworkMessage) -> Result, Error> { + let mut buffer = alloc::vec![]; + serialize(msg, &mut buffer)?; + Ok(buffer) } -fn from_ascii(ascii: String) -> [u8; 12] { - let mut output_bytes = [0u8; 12]; - let cmd_bytes = ascii.as_bytes(); - output_bytes[0..cmd_bytes.len()].copy_from_slice(cmd_bytes); - output_bytes +/// Deserialize v2 message into NetworkMessage. +#[cfg(feature = "alloc")] +pub fn deserialize(buffer: &[u8]) -> Result { + let short_id = buffer[0]; + match short_id { + // zero-byte means the command is encoded in the next 12 bytes. + 0u8 => { + let mut command_buffer = &buffer[1..13]; + let command = CommandString::consensus_decode(&mut command_buffer) + .map_err(|_| Error::Deserialize)?; + match command { + "verack" => {} + _ => Ok(NetworkMessage::Unknown { + command, + payload: buffer[13..].to_vec(), + }), + } + } + // The following 27 IDs are command short IDs. + 1u8 => { + let mut payload_buffer = &buffer[1..]; + Ok(NetworkMessage::Addr( + Decodable::consensus_decode(&mut payload_buffer).map_err(|_| Error::Deserialize)?, + )) + } + _ => Err(Error::Deserialize), + } }