add new LevinCommand enum and clean up monero-wire message de/encoding

This commit is contained in:
Boog900 2023-08-03 14:13:20 +01:00
parent 6a75b90fe7
commit 19f19fdb16
No known key found for this signature in database
GPG key ID: 5401367FB7302004

View file

@ -16,7 +16,9 @@
//! This module defines a Monero `Message` enum which contains //! This module defines a Monero `Message` enum which contains
//! every possible Monero network message (levin body) //! 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 admin;
pub mod common; pub mod common;
@ -32,6 +34,100 @@ pub use protocol::{
GetObjectsResponse, GetTxPoolCompliment, NewBlock, NewFluffyBlock, NewTransactions, 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<u32> 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<LevinCommand> 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 { pub enum ProtocolMessage {
NewBlock(NewBlock), NewBlock(NewBlock),
NewFluffyBlock(NewFluffyBlock), NewFluffyBlock(NewFluffyBlock),
@ -45,19 +141,33 @@ pub enum ProtocolMessage {
} }
impl ProtocolMessage { impl ProtocolMessage {
fn decode(buf: &[u8], command: u32) -> Result<Self, epee_encoding::Error> { fn decode(buf: &[u8], command: LevinCommand) -> Result<Self, epee_encoding::Error> {
Ok(match command { Ok(match command {
2001 => ProtocolMessage::NewBlock(epee_encoding::from_bytes(buf)?), LevinCommand::NewBlock => ProtocolMessage::NewBlock(epee_encoding::from_bytes(buf)?),
2002 => ProtocolMessage::NewTransactions(epee_encoding::from_bytes(buf)?), LevinCommand::NewTransactions => {
2003 => ProtocolMessage::GetObjectsRequest(epee_encoding::from_bytes(buf)?), ProtocolMessage::NewTransactions(epee_encoding::from_bytes(buf)?)
2004 => ProtocolMessage::GetObjectsResponse(epee_encoding::from_bytes(buf)?), }
2006 => ProtocolMessage::ChainRequest(epee_encoding::from_bytes(buf)?), LevinCommand::GetObjectsRequest => {
2007 => ProtocolMessage::ChainEntryResponse(epee_encoding::from_bytes(buf)?), ProtocolMessage::GetObjectsRequest(epee_encoding::from_bytes(buf)?)
2008 => ProtocolMessage::NewFluffyBlock(epee_encoding::from_bytes(buf)?), }
2009 => { 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)?) 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( return Err(epee_encoding::Error::Value(
"Failed to decode message, unknown command", "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<Vec<u8>, epee_encoding::Error> {
match self { match self {
ProtocolMessage::NewBlock(nb) => { ProtocolMessage::NewBlock(nb) => epee_encoding::to_bytes(nb),
builder.set_command(2001); ProtocolMessage::NewTransactions(nt) => epee_encoding::to_bytes(nt),
builder.set_body(epee_encoding::to_bytes(nb)?); ProtocolMessage::GetObjectsRequest(gt) => epee_encoding::to_bytes(gt),
} ProtocolMessage::GetObjectsResponse(ge) => epee_encoding::to_bytes(ge),
ProtocolMessage::NewTransactions(nt) => { ProtocolMessage::ChainRequest(ct) => epee_encoding::to_bytes(ct),
builder.set_command(2002); ProtocolMessage::ChainEntryResponse(ce) => epee_encoding::to_bytes(ce),
builder.set_body(epee_encoding::to_bytes(nt)?); ProtocolMessage::NewFluffyBlock(fb) => epee_encoding::to_bytes(fb),
} ProtocolMessage::FluffyMissingTransactionsRequest(ft) => epee_encoding::to_bytes(ft),
ProtocolMessage::GetObjectsRequest(gt) => { ProtocolMessage::GetTxPoolCompliment(tp) => epee_encoding::to_bytes(tp),
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)?);
}
} }
}
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<LevinCommand>) -> Result<(), epee_encoding::Error> {
builder.set_command(self.command());
builder.set_body(self.encode()?);
Ok(()) Ok(())
} }
} }
@ -117,12 +221,12 @@ pub enum RequestMessage {
} }
impl RequestMessage { impl RequestMessage {
fn decode(buf: &[u8], command: u32) -> Result<Self, epee_encoding::Error> { fn decode(buf: &[u8], command: LevinCommand) -> Result<Self, epee_encoding::Error> {
Ok(match command { Ok(match command {
1001 => RequestMessage::Handshake(epee_encoding::from_bytes(buf)?), LevinCommand::Handshake => RequestMessage::Handshake(epee_encoding::from_bytes(buf)?),
1002 => RequestMessage::TimedSync(epee_encoding::from_bytes(buf)?), LevinCommand::TimedSync => RequestMessage::TimedSync(epee_encoding::from_bytes(buf)?),
1003 => RequestMessage::Ping, LevinCommand::Ping => RequestMessage::Ping,
1007 => RequestMessage::SupportFlags, LevinCommand::SupportFlags => RequestMessage::SupportFlags,
_ => { _ => {
return Err(epee_encoding::Error::Value( return Err(epee_encoding::Error::Value(
"Failed to decode message, unknown command", "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 { match self {
RequestMessage::Handshake(hs) => { RequestMessage::Handshake(_) => LevinCommand::Handshake,
builder.set_command(1001); RequestMessage::TimedSync(_) => LevinCommand::TimedSync,
builder.set_body(epee_encoding::to_bytes(hs)?); RequestMessage::Ping => LevinCommand::Ping,
} RequestMessage::SupportFlags => LevinCommand::SupportFlags,
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());
}
} }
}
fn encode(&self) -> Result<Vec<u8>, 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<LevinCommand>) -> Result<(), epee_encoding::Error> {
builder.set_command(self.command());
builder.set_body(self.encode()?);
Ok(()) Ok(())
} }
} }
@ -162,12 +268,14 @@ pub enum ResponseMessage {
} }
impl ResponseMessage { impl ResponseMessage {
fn decode(buf: &[u8], command: u32) -> Result<Self, epee_encoding::Error> { fn decode(buf: &[u8], command: LevinCommand) -> Result<Self, epee_encoding::Error> {
Ok(match command { Ok(match command {
1001 => ResponseMessage::Handshake(epee_encoding::from_bytes(buf)?), LevinCommand::Handshake => ResponseMessage::Handshake(epee_encoding::from_bytes(buf)?),
1002 => ResponseMessage::TimedSync(epee_encoding::from_bytes(buf)?), LevinCommand::TimedSync => ResponseMessage::TimedSync(epee_encoding::from_bytes(buf)?),
1003 => ResponseMessage::Ping(epee_encoding::from_bytes(buf)?), LevinCommand::Ping => ResponseMessage::Ping(epee_encoding::from_bytes(buf)?),
1007 => ResponseMessage::SupportFlags(epee_encoding::from_bytes(buf)?), LevinCommand::SupportFlags => {
ResponseMessage::SupportFlags(epee_encoding::from_bytes(buf)?)
}
_ => { _ => {
return Err(epee_encoding::Error::Value( return Err(epee_encoding::Error::Value(
"Failed to decode message, unknown command", "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 { match self {
ResponseMessage::Handshake(hs) => { ResponseMessage::Handshake(_) => LevinCommand::Handshake,
builder.set_command(1001); ResponseMessage::TimedSync(_) => LevinCommand::TimedSync,
builder.set_body(epee_encoding::to_bytes(hs)?); ResponseMessage::Ping(_) => LevinCommand::Ping,
} ResponseMessage::SupportFlags(_) => LevinCommand::SupportFlags,
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)?);
}
} }
}
fn encode(&self) -> Result<Vec<u8>, 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<LevinCommand>) -> Result<(), epee_encoding::Error> {
builder.set_command(self.command());
builder.set_body(self.encode()?);
Ok(()) Ok(())
} }
} }
@ -206,7 +316,13 @@ pub enum Message {
} }
impl LevinBody for Message { impl LevinBody for Message {
fn decode_message(body: &[u8], typ: MessageType, command: u32) -> Result<Self, BucketError> { type Command = LevinCommand;
fn decode_message(
body: &[u8],
typ: MessageType,
command: LevinCommand,
) -> Result<Self, BucketError> {
Ok(match typ { Ok(match typ {
MessageType::Request => Message::Request( MessageType::Request => Message::Request(
RequestMessage::decode(body, command) 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<LevinCommand>) -> Result<(), BucketError> {
match self { match self {
Message::Protocol(pro) => { Message::Protocol(pro) => {
builder.set_message_type(MessageType::Notification); builder.set_message_type(MessageType::Notification);