From 19f19fdb16b86808e136b3bb26f38c7059d424f2 Mon Sep 17 00:00:00 2001 From: Boog900 <54e72d8a-345f-4599-bd90-c6b9bc7d0ec5@aleeas.com> Date: Thu, 3 Aug 2023 14:13:20 +0100 Subject: [PATCH] add new `LevinCommand` enum and clean up monero-wire message de/encoding --- net/monero-wire/src/messages.rs | 304 ++++++++++++++++++++++---------- 1 file changed, 210 insertions(+), 94 deletions(-) diff --git a/net/monero-wire/src/messages.rs b/net/monero-wire/src/messages.rs index f6557cd..7d1630b 100644 --- a/net/monero-wire/src/messages.rs +++ b/net/monero-wire/src/messages.rs @@ -16,7 +16,9 @@ //! This module defines a Monero `Message` enum which contains //! every possible Monero network message (levin body) -use levin_cuprate::{BucketBuilder, BucketError, LevinBody, MessageType}; +use levin_cuprate::{ + BucketBuilder, BucketError, LevinBody, LevinCommand as LevinCommandTrait, MessageType, +}; pub mod admin; pub mod common; @@ -32,6 +34,100 @@ pub use protocol::{ GetObjectsResponse, GetTxPoolCompliment, NewBlock, NewFluffyBlock, NewTransactions, }; +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +pub enum LevinCommand { + Handshake, + TimedSync, + Ping, + SupportFlags, + + NewBlock, + NewTransactions, + GetObjectsRequest, + GetObjectsResponse, + ChainRequest, + ChainResponse, + NewFluffyBlock, + FluffyMissingTxsRequest, + GetTxPoolCompliment, + + Unknown(u32), +} + +impl LevinCommandTrait for LevinCommand { + fn bucket_size_limit(&self) -> u64 { + // https://github.com/monero-project/monero/blob/00fd416a99686f0956361d1cd0337fe56e58d4a7/src/cryptonote_basic/connection_context.cpp#L37 + match self { + LevinCommand::Handshake => 65536, + LevinCommand::TimedSync => 65536, + LevinCommand::Ping => 4096, + LevinCommand::SupportFlags => 4096, + + LevinCommand::NewBlock => 1024 * 1024 * 128, // 128 MB (max packet is a bit less than 100 MB though) + LevinCommand::NewTransactions => 1024 * 1024 * 128, // 128 MB (max packet is a bit less than 100 MB though) + LevinCommand::GetObjectsRequest => 1024 * 1024 * 2, // 2 MB + LevinCommand::GetObjectsResponse => 1024 * 1024 * 128, // 128 MB (max packet is a bit less than 100 MB though) + LevinCommand::ChainRequest => 512 * 1024, // 512 kB + LevinCommand::ChainResponse => 1024 * 1024 * 4, // 4 MB + LevinCommand::NewFluffyBlock => 1024 * 1024 * 4, // 4 MB + LevinCommand::FluffyMissingTxsRequest => 1024 * 1024, // 1 MB + LevinCommand::GetTxPoolCompliment => 1024 * 1024 * 4, // 4 MB + + LevinCommand::Unknown(_) => usize::MAX.try_into().unwrap_or(u64::MAX), + } + } + + fn is_handshake(&self) -> bool { + matches!(self, LevinCommand::Handshake) + } +} + +impl From for LevinCommand { + fn from(value: u32) -> Self { + match value { + 1001 => LevinCommand::Handshake, + 1002 => LevinCommand::TimedSync, + 1003 => LevinCommand::Ping, + 1007 => LevinCommand::SupportFlags, + + 2001 => LevinCommand::NewBlock, + 2002 => LevinCommand::NewTransactions, + 2003 => LevinCommand::GetObjectsRequest, + 2004 => LevinCommand::GetObjectsResponse, + 2006 => LevinCommand::ChainRequest, + 2007 => LevinCommand::ChainResponse, + 2008 => LevinCommand::NewFluffyBlock, + 2009 => LevinCommand::FluffyMissingTxsRequest, + 2010 => LevinCommand::NewBlock, + + x => LevinCommand::Unknown(x), + } + } +} + +impl From for u32 { + fn from(value: LevinCommand) -> Self { + match value { + LevinCommand::Handshake => 1001, + LevinCommand::TimedSync => 1002, + LevinCommand::Ping => 1003, + LevinCommand::SupportFlags => 1007, + + LevinCommand::NewBlock => 2001, + LevinCommand::NewTransactions => 2002, + LevinCommand::GetObjectsRequest => 2003, + LevinCommand::GetObjectsResponse => 2004, + LevinCommand::ChainRequest => 2006, + LevinCommand::ChainResponse => 2007, + LevinCommand::NewFluffyBlock => 2008, + LevinCommand::FluffyMissingTxsRequest => 2009, + LevinCommand::GetTxPoolCompliment => 2010, + + LevinCommand::Unknown(x) => x, + } + } +} + pub enum ProtocolMessage { NewBlock(NewBlock), NewFluffyBlock(NewFluffyBlock), @@ -45,19 +141,33 @@ pub enum ProtocolMessage { } impl ProtocolMessage { - fn decode(buf: &[u8], command: u32) -> Result { + fn decode(buf: &[u8], command: LevinCommand) -> Result { Ok(match command { - 2001 => ProtocolMessage::NewBlock(epee_encoding::from_bytes(buf)?), - 2002 => ProtocolMessage::NewTransactions(epee_encoding::from_bytes(buf)?), - 2003 => ProtocolMessage::GetObjectsRequest(epee_encoding::from_bytes(buf)?), - 2004 => ProtocolMessage::GetObjectsResponse(epee_encoding::from_bytes(buf)?), - 2006 => ProtocolMessage::ChainRequest(epee_encoding::from_bytes(buf)?), - 2007 => ProtocolMessage::ChainEntryResponse(epee_encoding::from_bytes(buf)?), - 2008 => ProtocolMessage::NewFluffyBlock(epee_encoding::from_bytes(buf)?), - 2009 => { + LevinCommand::NewBlock => ProtocolMessage::NewBlock(epee_encoding::from_bytes(buf)?), + LevinCommand::NewTransactions => { + ProtocolMessage::NewTransactions(epee_encoding::from_bytes(buf)?) + } + LevinCommand::GetObjectsRequest => { + ProtocolMessage::GetObjectsRequest(epee_encoding::from_bytes(buf)?) + } + LevinCommand::GetObjectsResponse => { + ProtocolMessage::GetObjectsResponse(epee_encoding::from_bytes(buf)?) + } + LevinCommand::ChainRequest => { + ProtocolMessage::ChainRequest(epee_encoding::from_bytes(buf)?) + } + LevinCommand::ChainResponse => { + ProtocolMessage::ChainEntryResponse(epee_encoding::from_bytes(buf)?) + } + LevinCommand::NewFluffyBlock => { + ProtocolMessage::NewFluffyBlock(epee_encoding::from_bytes(buf)?) + } + LevinCommand::FluffyMissingTxsRequest => { ProtocolMessage::FluffyMissingTransactionsRequest(epee_encoding::from_bytes(buf)?) } - 2010 => ProtocolMessage::GetTxPoolCompliment(epee_encoding::from_bytes(buf)?), + LevinCommand::GetTxPoolCompliment => { + ProtocolMessage::GetTxPoolCompliment(epee_encoding::from_bytes(buf)?) + } _ => { return Err(epee_encoding::Error::Value( "Failed to decode message, unknown command", @@ -66,45 +176,39 @@ impl ProtocolMessage { }) } - fn build(&self, builder: &mut BucketBuilder) -> Result<(), epee_encoding::Error> { + fn encode(&self) -> Result, epee_encoding::Error> { match self { - ProtocolMessage::NewBlock(nb) => { - builder.set_command(2001); - builder.set_body(epee_encoding::to_bytes(nb)?); - } - ProtocolMessage::NewTransactions(nt) => { - builder.set_command(2002); - builder.set_body(epee_encoding::to_bytes(nt)?); - } - ProtocolMessage::GetObjectsRequest(gt) => { - builder.set_command(2003); - builder.set_body(epee_encoding::to_bytes(gt)?); - } - ProtocolMessage::GetObjectsResponse(ge) => { - builder.set_command(2004); - builder.set_body(epee_encoding::to_bytes(ge)?); - } - ProtocolMessage::ChainRequest(ct) => { - builder.set_command(2006); - builder.set_body(epee_encoding::to_bytes(ct)?); - } - ProtocolMessage::ChainEntryResponse(ce) => { - builder.set_command(2007); - builder.set_body(epee_encoding::to_bytes(ce)?); - } - ProtocolMessage::NewFluffyBlock(fb) => { - builder.set_command(2008); - builder.set_body(epee_encoding::to_bytes(fb)?); - } - ProtocolMessage::FluffyMissingTransactionsRequest(ft) => { - builder.set_command(2009); - builder.set_body(epee_encoding::to_bytes(ft)?); - } - ProtocolMessage::GetTxPoolCompliment(tp) => { - builder.set_command(2010); - builder.set_body(epee_encoding::to_bytes(tp)?); - } + ProtocolMessage::NewBlock(nb) => epee_encoding::to_bytes(nb), + ProtocolMessage::NewTransactions(nt) => epee_encoding::to_bytes(nt), + ProtocolMessage::GetObjectsRequest(gt) => epee_encoding::to_bytes(gt), + ProtocolMessage::GetObjectsResponse(ge) => epee_encoding::to_bytes(ge), + ProtocolMessage::ChainRequest(ct) => epee_encoding::to_bytes(ct), + ProtocolMessage::ChainEntryResponse(ce) => epee_encoding::to_bytes(ce), + ProtocolMessage::NewFluffyBlock(fb) => epee_encoding::to_bytes(fb), + ProtocolMessage::FluffyMissingTransactionsRequest(ft) => epee_encoding::to_bytes(ft), + ProtocolMessage::GetTxPoolCompliment(tp) => epee_encoding::to_bytes(tp), } + } + + fn command(&self) -> LevinCommand { + match self { + ProtocolMessage::NewBlock(_) => LevinCommand::NewBlock, + ProtocolMessage::NewTransactions(_) => LevinCommand::NewTransactions, + ProtocolMessage::GetObjectsRequest(_) => LevinCommand::GetObjectsRequest, + ProtocolMessage::GetObjectsResponse(_) => LevinCommand::GetObjectsResponse, + ProtocolMessage::ChainRequest(_) => LevinCommand::ChainRequest, + ProtocolMessage::ChainEntryResponse(_) => LevinCommand::ChainResponse, + ProtocolMessage::NewFluffyBlock(_) => LevinCommand::NewFluffyBlock, + ProtocolMessage::FluffyMissingTransactionsRequest(_) => { + LevinCommand::FluffyMissingTxsRequest + } + ProtocolMessage::GetTxPoolCompliment(_) => LevinCommand::GetTxPoolCompliment, + } + } + + fn build(&self, builder: &mut BucketBuilder) -> Result<(), epee_encoding::Error> { + builder.set_command(self.command()); + builder.set_body(self.encode()?); Ok(()) } } @@ -117,12 +221,12 @@ pub enum RequestMessage { } impl RequestMessage { - fn decode(buf: &[u8], command: u32) -> Result { + fn decode(buf: &[u8], command: LevinCommand) -> Result { Ok(match command { - 1001 => RequestMessage::Handshake(epee_encoding::from_bytes(buf)?), - 1002 => RequestMessage::TimedSync(epee_encoding::from_bytes(buf)?), - 1003 => RequestMessage::Ping, - 1007 => RequestMessage::SupportFlags, + LevinCommand::Handshake => RequestMessage::Handshake(epee_encoding::from_bytes(buf)?), + LevinCommand::TimedSync => RequestMessage::TimedSync(epee_encoding::from_bytes(buf)?), + LevinCommand::Ping => RequestMessage::Ping, + LevinCommand::SupportFlags => RequestMessage::SupportFlags, _ => { return Err(epee_encoding::Error::Value( "Failed to decode message, unknown command", @@ -131,25 +235,27 @@ impl RequestMessage { }) } - fn build(&self, builder: &mut BucketBuilder) -> Result<(), epee_encoding::Error> { + fn command(&self) -> LevinCommand { match self { - RequestMessage::Handshake(hs) => { - builder.set_command(1001); - builder.set_body(epee_encoding::to_bytes(hs)?); - } - RequestMessage::TimedSync(ts) => { - builder.set_command(1002); - builder.set_body(epee_encoding::to_bytes(ts)?); - } - RequestMessage::Ping => { - builder.set_command(1003); - builder.set_body(Vec::new()); - } - RequestMessage::SupportFlags => { - builder.set_command(1007); - builder.set_body(Vec::new()); - } + RequestMessage::Handshake(_) => LevinCommand::Handshake, + RequestMessage::TimedSync(_) => LevinCommand::TimedSync, + RequestMessage::Ping => LevinCommand::Ping, + RequestMessage::SupportFlags => LevinCommand::SupportFlags, } + } + + fn encode(&self) -> Result, epee_encoding::Error> { + match self { + RequestMessage::Handshake(x) => epee_encoding::to_bytes(x), + RequestMessage::TimedSync(x) => epee_encoding::to_bytes(x), + RequestMessage::Ping => Ok(vec![]), + RequestMessage::SupportFlags => Ok(vec![]), + } + } + + fn build(&self, builder: &mut BucketBuilder) -> Result<(), epee_encoding::Error> { + builder.set_command(self.command()); + builder.set_body(self.encode()?); Ok(()) } } @@ -162,12 +268,14 @@ pub enum ResponseMessage { } impl ResponseMessage { - fn decode(buf: &[u8], command: u32) -> Result { + fn decode(buf: &[u8], command: LevinCommand) -> Result { Ok(match command { - 1001 => ResponseMessage::Handshake(epee_encoding::from_bytes(buf)?), - 1002 => ResponseMessage::TimedSync(epee_encoding::from_bytes(buf)?), - 1003 => ResponseMessage::Ping(epee_encoding::from_bytes(buf)?), - 1007 => ResponseMessage::SupportFlags(epee_encoding::from_bytes(buf)?), + LevinCommand::Handshake => ResponseMessage::Handshake(epee_encoding::from_bytes(buf)?), + LevinCommand::TimedSync => ResponseMessage::TimedSync(epee_encoding::from_bytes(buf)?), + LevinCommand::Ping => ResponseMessage::Ping(epee_encoding::from_bytes(buf)?), + LevinCommand::SupportFlags => { + ResponseMessage::SupportFlags(epee_encoding::from_bytes(buf)?) + } _ => { return Err(epee_encoding::Error::Value( "Failed to decode message, unknown command", @@ -176,25 +284,27 @@ impl ResponseMessage { }) } - fn build(&self, builder: &mut BucketBuilder) -> Result<(), epee_encoding::Error> { + fn command(&self) -> LevinCommand { match self { - ResponseMessage::Handshake(hs) => { - builder.set_command(1001); - builder.set_body(epee_encoding::to_bytes(hs)?); - } - ResponseMessage::TimedSync(ts) => { - builder.set_command(1002); - builder.set_body(epee_encoding::to_bytes(ts)?); - } - ResponseMessage::Ping(pg) => { - builder.set_command(1003); - builder.set_body(epee_encoding::to_bytes(pg)?); - } - ResponseMessage::SupportFlags(sf) => { - builder.set_command(1007); - builder.set_body(epee_encoding::to_bytes(sf)?); - } + ResponseMessage::Handshake(_) => LevinCommand::Handshake, + ResponseMessage::TimedSync(_) => LevinCommand::TimedSync, + ResponseMessage::Ping(_) => LevinCommand::Ping, + ResponseMessage::SupportFlags(_) => LevinCommand::SupportFlags, } + } + + fn encode(&self) -> Result, epee_encoding::Error> { + match self { + ResponseMessage::Handshake(x) => epee_encoding::to_bytes(x), + ResponseMessage::TimedSync(x) => epee_encoding::to_bytes(x), + ResponseMessage::Ping(x) => epee_encoding::to_bytes(x), + ResponseMessage::SupportFlags(x) => epee_encoding::to_bytes(x), + } + } + + fn build(&self, builder: &mut BucketBuilder) -> Result<(), epee_encoding::Error> { + builder.set_command(self.command()); + builder.set_body(self.encode()?); Ok(()) } } @@ -206,7 +316,13 @@ pub enum Message { } impl LevinBody for Message { - fn decode_message(body: &[u8], typ: MessageType, command: u32) -> Result { + type Command = LevinCommand; + + fn decode_message( + body: &[u8], + typ: MessageType, + command: LevinCommand, + ) -> Result { Ok(match typ { MessageType::Request => Message::Request( RequestMessage::decode(body, command) @@ -223,7 +339,7 @@ impl LevinBody for Message { }) } - fn encode(&self, builder: &mut BucketBuilder) -> Result<(), BucketError> { + fn encode(&self, builder: &mut BucketBuilder) -> Result<(), BucketError> { match self { Message::Protocol(pro) => { builder.set_message_type(MessageType::Notification);