From bea86871de949712d12ae14d993a76e56403ad14 Mon Sep 17 00:00:00 2001 From: cloudhead Date: Thu, 16 Nov 2023 13:20:00 +0100 Subject: [PATCH] node: Test that message encoding doesn't panic Previously, it was possible for the `wire::serialize` function to panic due to large ref announcements. Now that ref announcements are properly bounded in size, this shouldn't happen anymore. --- radicle-node/src/wire.rs | 13 +++++--- radicle-node/src/wire/message.rs | 53 ++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 4 deletions(-) diff --git a/radicle-node/src/wire.rs b/radicle-node/src/wire.rs index 5632bb4b..268b4a67 100644 --- a/radicle-node/src/wire.rs +++ b/radicle-node/src/wire.rs @@ -82,12 +82,17 @@ pub trait Decode: Sized { fn decode(reader: &mut R) -> Result; } -/// Encode an object into a vector. +/// Encode an object into a byte vector. +/// +/// # Panics +/// +/// If the encoded object exceeds [`Size::MAX`]. pub fn serialize(data: &T) -> Vec { let mut buffer = Vec::new(); - let len = data - .encode(&mut buffer) - .expect("in-memory writes don't error"); + // SAFETY: We expect this to panic if the user passes + // in data that exceeds the maximum allowed size. + #[allow(clippy::unwrap_used)] + let len = data.encode(&mut buffer).unwrap(); debug_assert_eq!(len, buffer.len()); diff --git a/radicle-node/src/wire/message.rs b/radicle-node/src/wire/message.rs index ec0ec499..6160fedd 100644 --- a/radicle-node/src/wire/message.rs +++ b/radicle-node/src/wire/message.rs @@ -371,10 +371,63 @@ impl wire::Decode for ZeroBytes { mod tests { use super::*; use qcheck_macros::quickcheck; + use radicle::storage::refs::RefsAt; + use radicle_crypto::test::signer::MockSigner; use crate::deserializer::Deserializer; + use crate::test::arbitrary; use crate::wire::{self, Encode}; + #[test] + fn test_refs_ann_max_size() { + let signer = MockSigner::default(); + let refs: [RefsAt; REF_REMOTE_LIMIT] = arbitrary::gen(1); + let ann = AnnouncementMessage::Refs(RefsAnnouncement { + rid: arbitrary::gen(1), + refs: BoundedVec::collect_from(&mut refs.into_iter()), + timestamp: arbitrary::gen(1), + }); + let ann = ann.signed(&signer); + let msg = Message::Announcement(ann); + let data = wire::serialize(&msg); + + assert!(data.len() < wire::Size::MAX as usize); + } + + #[test] + fn test_inv_ann_max_size() { + let signer = MockSigner::default(); + let inv: [Id; INVENTORY_LIMIT] = arbitrary::gen(1); + let ann = AnnouncementMessage::Inventory(InventoryAnnouncement { + inventory: BoundedVec::collect_from(&mut inv.into_iter()), + timestamp: arbitrary::gen(1), + }); + let ann = ann.signed(&signer); + let msg = Message::Announcement(ann); + let data = wire::serialize(&msg); + + assert!(data.len() < wire::Size::MAX as usize); + } + + #[test] + fn test_node_ann_max_size() { + let signer = MockSigner::default(); + let addrs: [Address; ADDRESS_LIMIT] = arbitrary::gen(1); + let alias = ['@'; radicle::node::MAX_ALIAS_LENGTH]; + let ann = AnnouncementMessage::Node(NodeAnnouncement { + features: Default::default(), + alias: radicle::node::Alias::new(String::from_iter(alias)), + addresses: BoundedVec::collect_from(&mut addrs.into_iter()), + timestamp: arbitrary::gen(1), + nonce: u64::MAX, + }); + let ann = ann.signed(&signer); + let msg = Message::Announcement(ann); + let data = wire::serialize(&msg); + + assert!(data.len() < wire::Size::MAX as usize); + } + #[test] fn test_pingpong_encode_max_size() { let mut buf = Vec::new();