From 5cbdd669f225c810c3d6442649bab7e93affad41 Mon Sep 17 00:00:00 2001 From: sanghren Date: Thu, 7 Sep 2023 17:29:45 +0200 Subject: [PATCH 01/53] feat: add gossipable trait --- core/network/src/lib.rs | 1 + core/network/src/p2p/mod.rs | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 core/network/src/p2p/mod.rs diff --git a/core/network/src/lib.rs b/core/network/src/lib.rs index 2e7ce1a..02219a4 100644 --- a/core/network/src/lib.rs +++ b/core/network/src/lib.rs @@ -1,2 +1,3 @@ //! A library for building p2p inbound and outbound connections. pub mod peer; +pub mod p2p; diff --git a/core/network/src/p2p/mod.rs b/core/network/src/p2p/mod.rs new file mode 100644 index 0000000..df62623 --- /dev/null +++ b/core/network/src/p2p/mod.rs @@ -0,0 +1,18 @@ +pub mod gossip; + +use avalanche_types::ids::Id; + +/// Represent the mempool of an avalanche-rs node. +/// ref. + +pub trait Gossipable { + fn get_id(&self) -> Id; + fn marshal(&self) -> Result, Box>; + fn unmarshal(&mut self, bytes: &[u8]) -> Result<(), Box>; +} + +pub trait Set { + fn add(&mut self, gossipable: T) -> Result<(), Box>; + fn iterate(&self, f: impl Fn(&T) -> bool); + fn get_filter(&self) -> Result<(Vec, Vec), Box>; +} \ No newline at end of file From a0e662afcb0e5f0851cefaffb77aa509289486aa Mon Sep 17 00:00:00 2001 From: sanghren Date: Thu, 7 Sep 2023 21:45:41 +0200 Subject: [PATCH 02/53] feat: add gossip --- core/network/src/p2p/client.rs | 4 + core/network/src/p2p/gossip/gossip.rs | 121 ++++++++++++++++++++++++++ core/network/src/p2p/gossip/mod.rs | 18 ++++ core/network/src/p2p/mod.rs | 18 +--- 4 files changed, 144 insertions(+), 17 deletions(-) create mode 100644 core/network/src/p2p/client.rs create mode 100644 core/network/src/p2p/gossip/gossip.rs create mode 100644 core/network/src/p2p/gossip/mod.rs diff --git a/core/network/src/p2p/client.rs b/core/network/src/p2p/client.rs new file mode 100644 index 0000000..e390c0c --- /dev/null +++ b/core/network/src/p2p/client.rs @@ -0,0 +1,4 @@ + +pub trait Client: Send + Sync { + // ToDo Implement this +} \ No newline at end of file diff --git a/core/network/src/p2p/gossip/gossip.rs b/core/network/src/p2p/gossip/gossip.rs new file mode 100644 index 0000000..d016688 --- /dev/null +++ b/core/network/src/p2p/gossip/gossip.rs @@ -0,0 +1,121 @@ +use std::error::Error; +use std::sync::Arc; +use std::time::Duration; +use log::{debug, error}; +use tokio::time::interval; +use avalanche_types::ids::Id; +use crate::p2p::gossip::{Gossipable, Set}; +use crate::p2p::client::Client; + +pub struct Config { + pub frequency: std::time::Duration, + pub poll_size: usize, +} + +pub struct Gossiper + ?Sized> { + config: Config, + set: Arc>, + client: Arc, +} + +impl> Gossiper { + pub fn new( + config: Config, + set: Arc>, + client: Arc, + ) -> Self { + Self { + config, + set, + client, + } + } + + pub async fn gossip(&self) { + let mut gossip_ticker = interval(self.config.frequency); + + loop { + gossip_ticker.tick().await; + // This will pause the loop for `self.config.frequency` + if let Err(e) = self.single_gossip().await { + error!("Failed to Gossip : {:?}", e) + } + } + } + + async fn single_gossip(&self) -> Result<(), Box> { + let (bloom, salt) = self.set.get_filter()?; + // ... Perform the gossip operation, involving self.client, and return a Result + // (Left as an exercise for the reader) + debug!("In single_gossip"); + Ok(()) + } +} + +// Mock implementation for the Set trait +struct MockSet; + +impl> Set for MockSet { + fn add(&mut self, _gossipable: T) -> Result<(), Box> { + Ok(()) + } + + fn iterate(&self, _f: &dyn Fn(&T) -> bool) { + // Do nothing + } + + fn get_filter(&self) -> Result<(Vec, Vec), Box> { + Ok((vec![], vec![])) + } +} + +// Mock implementation for the Client trait +struct MockClient; + +impl Client for MockClient { + // Implement the methods of the Client trait here... +} + +struct TestGossipableType; + +impl Gossipable for TestGossipableType { + fn get_id(&self) -> Id { + todo!() + } + + fn marshal(&self) -> Result, Box> { + todo!() + } + + fn unmarshal(&mut self, bytes: &[u8]) -> Result<(), Box> { + todo!() + } + // ... your methods here +} + + +/// RUST_LOG=debug cargo test --package network --lib -- p2p::gossip::test_gossip --exact --show-output +#[tokio::test] +async fn test_gossip() { + let _ = env_logger::builder() + .filter_level(log::LevelFilter::Debug) + .is_test(true) + .try_init() + .unwrap(); + + let gossiper: Gossiper = Gossiper::new( + Config { frequency: Duration::from_millis(200), poll_size: 0 }, + Arc::new(MockSet), // Replace with your real Set implementation + Arc::new(MockClient), // Replace with your real Client implementation + ); + + // Spawn the gossiping task + let gossip_task = tokio::spawn(async move { + gossiper.gossip().await; + }); + + // Wait some time to let a few cycles of gossiping happen + tokio::time::sleep(Duration::from_secs(5)).await; + + gossip_task.abort(); +} diff --git a/core/network/src/p2p/gossip/mod.rs b/core/network/src/p2p/gossip/mod.rs new file mode 100644 index 0000000..a56ec02 --- /dev/null +++ b/core/network/src/p2p/gossip/mod.rs @@ -0,0 +1,18 @@ +pub mod gossip; + +use avalanche_types::ids::Id; + +/// Represent the mempool of an avalanche-rs node. +/// ref. + +pub trait Gossipable { + fn get_id(&self) -> Id; + fn marshal(&self) -> Result, Box>; + fn unmarshal(&mut self, bytes: &[u8]) -> Result<(), Box>; +} + +pub trait Set + ?Sized>: Send + Sync { + fn add(&mut self, gossipable: T) -> Result<(), Box>; + fn iterate(&self, f: &dyn Fn(&T) -> bool); + fn get_filter(&self) -> Result<(Vec, Vec), Box>; +} \ No newline at end of file diff --git a/core/network/src/p2p/mod.rs b/core/network/src/p2p/mod.rs index df62623..ced53b7 100644 --- a/core/network/src/p2p/mod.rs +++ b/core/network/src/p2p/mod.rs @@ -1,18 +1,2 @@ pub mod gossip; - -use avalanche_types::ids::Id; - -/// Represent the mempool of an avalanche-rs node. -/// ref. - -pub trait Gossipable { - fn get_id(&self) -> Id; - fn marshal(&self) -> Result, Box>; - fn unmarshal(&mut self, bytes: &[u8]) -> Result<(), Box>; -} - -pub trait Set { - fn add(&mut self, gossipable: T) -> Result<(), Box>; - fn iterate(&self, f: impl Fn(&T) -> bool); - fn get_filter(&self) -> Result<(Vec, Vec), Box>; -} \ No newline at end of file +pub mod client; \ No newline at end of file From aa7f63c7b9484d819d6bcb38addbe1c92914ee71 Mon Sep 17 00:00:00 2001 From: sanghren Date: Thu, 7 Sep 2023 22:08:13 +0200 Subject: [PATCH 03/53] feat: add channel to gossiper --- core/network/src/p2p/gossip/gossip.rs | 31 +++++++++++++++++++++------ 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/core/network/src/p2p/gossip/gossip.rs b/core/network/src/p2p/gossip/gossip.rs index d016688..d5dfd37 100644 --- a/core/network/src/p2p/gossip/gossip.rs +++ b/core/network/src/p2p/gossip/gossip.rs @@ -2,6 +2,8 @@ use std::error::Error; use std::sync::Arc; use std::time::Duration; use log::{debug, error}; +use tokio::select; +use tokio::sync::mpsc::{channel, Receiver}; use tokio::time::interval; use avalanche_types::ids::Id; use crate::p2p::gossip::{Gossipable, Set}; @@ -16,6 +18,7 @@ pub struct Gossiper + ?Sized> { config: Config, set: Arc>, client: Arc, + stop_rx: Receiver<()>, // Receiver to get the stop signal } impl> Gossiper { @@ -23,22 +26,31 @@ impl> Gossiper { config: Config, set: Arc>, client: Arc, + stop_rx: Receiver<()>, ) -> Self { Self { config, set, client, + stop_rx, } } - pub async fn gossip(&self) { + pub async fn gossip(&mut self) { let mut gossip_ticker = interval(self.config.frequency); loop { - gossip_ticker.tick().await; - // This will pause the loop for `self.config.frequency` - if let Err(e) = self.single_gossip().await { - error!("Failed to Gossip : {:?}", e) + select! { + _ = gossip_ticker.tick() => { + debug!("Tick!"); + if let Err(e) = self.single_gossip().await { + error!("Failed to Gossip : {:?}", e); + } + } + _ = self.stop_rx.recv() => { + debug!("Shutting down gossip"); + break; + } } } } @@ -103,10 +115,13 @@ async fn test_gossip() { .try_init() .unwrap(); - let gossiper: Gossiper = Gossiper::new( + let (stop_tx, stop_rx) = channel(1); // Create a new channel + + let mut gossiper: Gossiper = Gossiper::new( Config { frequency: Duration::from_millis(200), poll_size: 0 }, Arc::new(MockSet), // Replace with your real Set implementation Arc::new(MockClient), // Replace with your real Client implementation + stop_rx ); // Spawn the gossiping task @@ -117,5 +132,7 @@ async fn test_gossip() { // Wait some time to let a few cycles of gossiping happen tokio::time::sleep(Duration::from_secs(5)).await; - gossip_task.abort(); + stop_tx.send(()).await.expect("Failed to send stop signal"); + + gossip_task.await.expect("Gossip task failed"); } From ed23c1eb460e753e2c4d0d89ba0a3e268709eb9a Mon Sep 17 00:00:00 2001 From: sanghren Date: Thu, 7 Sep 2023 17:29:45 +0200 Subject: [PATCH 04/53] feat: add gossipable trait --- core/network/src/lib.rs | 1 + core/network/src/p2p/mod.rs | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 core/network/src/p2p/mod.rs diff --git a/core/network/src/lib.rs b/core/network/src/lib.rs index 2e7ce1a..02219a4 100644 --- a/core/network/src/lib.rs +++ b/core/network/src/lib.rs @@ -1,2 +1,3 @@ //! A library for building p2p inbound and outbound connections. pub mod peer; +pub mod p2p; diff --git a/core/network/src/p2p/mod.rs b/core/network/src/p2p/mod.rs new file mode 100644 index 0000000..df62623 --- /dev/null +++ b/core/network/src/p2p/mod.rs @@ -0,0 +1,18 @@ +pub mod gossip; + +use avalanche_types::ids::Id; + +/// Represent the mempool of an avalanche-rs node. +/// ref. + +pub trait Gossipable { + fn get_id(&self) -> Id; + fn marshal(&self) -> Result, Box>; + fn unmarshal(&mut self, bytes: &[u8]) -> Result<(), Box>; +} + +pub trait Set { + fn add(&mut self, gossipable: T) -> Result<(), Box>; + fn iterate(&self, f: impl Fn(&T) -> bool); + fn get_filter(&self) -> Result<(Vec, Vec), Box>; +} \ No newline at end of file From 0c35d214ad241b5809deee6e9fda528c6e88cc94 Mon Sep 17 00:00:00 2001 From: sanghren Date: Thu, 7 Sep 2023 21:45:41 +0200 Subject: [PATCH 05/53] feat: add gossip --- core/network/src/p2p/client.rs | 4 + core/network/src/p2p/gossip/gossip.rs | 121 ++++++++++++++++++++++++++ core/network/src/p2p/gossip/mod.rs | 18 ++++ core/network/src/p2p/mod.rs | 18 +--- 4 files changed, 144 insertions(+), 17 deletions(-) create mode 100644 core/network/src/p2p/client.rs create mode 100644 core/network/src/p2p/gossip/gossip.rs create mode 100644 core/network/src/p2p/gossip/mod.rs diff --git a/core/network/src/p2p/client.rs b/core/network/src/p2p/client.rs new file mode 100644 index 0000000..e390c0c --- /dev/null +++ b/core/network/src/p2p/client.rs @@ -0,0 +1,4 @@ + +pub trait Client: Send + Sync { + // ToDo Implement this +} \ No newline at end of file diff --git a/core/network/src/p2p/gossip/gossip.rs b/core/network/src/p2p/gossip/gossip.rs new file mode 100644 index 0000000..d016688 --- /dev/null +++ b/core/network/src/p2p/gossip/gossip.rs @@ -0,0 +1,121 @@ +use std::error::Error; +use std::sync::Arc; +use std::time::Duration; +use log::{debug, error}; +use tokio::time::interval; +use avalanche_types::ids::Id; +use crate::p2p::gossip::{Gossipable, Set}; +use crate::p2p::client::Client; + +pub struct Config { + pub frequency: std::time::Duration, + pub poll_size: usize, +} + +pub struct Gossiper + ?Sized> { + config: Config, + set: Arc>, + client: Arc, +} + +impl> Gossiper { + pub fn new( + config: Config, + set: Arc>, + client: Arc, + ) -> Self { + Self { + config, + set, + client, + } + } + + pub async fn gossip(&self) { + let mut gossip_ticker = interval(self.config.frequency); + + loop { + gossip_ticker.tick().await; + // This will pause the loop for `self.config.frequency` + if let Err(e) = self.single_gossip().await { + error!("Failed to Gossip : {:?}", e) + } + } + } + + async fn single_gossip(&self) -> Result<(), Box> { + let (bloom, salt) = self.set.get_filter()?; + // ... Perform the gossip operation, involving self.client, and return a Result + // (Left as an exercise for the reader) + debug!("In single_gossip"); + Ok(()) + } +} + +// Mock implementation for the Set trait +struct MockSet; + +impl> Set for MockSet { + fn add(&mut self, _gossipable: T) -> Result<(), Box> { + Ok(()) + } + + fn iterate(&self, _f: &dyn Fn(&T) -> bool) { + // Do nothing + } + + fn get_filter(&self) -> Result<(Vec, Vec), Box> { + Ok((vec![], vec![])) + } +} + +// Mock implementation for the Client trait +struct MockClient; + +impl Client for MockClient { + // Implement the methods of the Client trait here... +} + +struct TestGossipableType; + +impl Gossipable for TestGossipableType { + fn get_id(&self) -> Id { + todo!() + } + + fn marshal(&self) -> Result, Box> { + todo!() + } + + fn unmarshal(&mut self, bytes: &[u8]) -> Result<(), Box> { + todo!() + } + // ... your methods here +} + + +/// RUST_LOG=debug cargo test --package network --lib -- p2p::gossip::test_gossip --exact --show-output +#[tokio::test] +async fn test_gossip() { + let _ = env_logger::builder() + .filter_level(log::LevelFilter::Debug) + .is_test(true) + .try_init() + .unwrap(); + + let gossiper: Gossiper = Gossiper::new( + Config { frequency: Duration::from_millis(200), poll_size: 0 }, + Arc::new(MockSet), // Replace with your real Set implementation + Arc::new(MockClient), // Replace with your real Client implementation + ); + + // Spawn the gossiping task + let gossip_task = tokio::spawn(async move { + gossiper.gossip().await; + }); + + // Wait some time to let a few cycles of gossiping happen + tokio::time::sleep(Duration::from_secs(5)).await; + + gossip_task.abort(); +} diff --git a/core/network/src/p2p/gossip/mod.rs b/core/network/src/p2p/gossip/mod.rs new file mode 100644 index 0000000..a56ec02 --- /dev/null +++ b/core/network/src/p2p/gossip/mod.rs @@ -0,0 +1,18 @@ +pub mod gossip; + +use avalanche_types::ids::Id; + +/// Represent the mempool of an avalanche-rs node. +/// ref. + +pub trait Gossipable { + fn get_id(&self) -> Id; + fn marshal(&self) -> Result, Box>; + fn unmarshal(&mut self, bytes: &[u8]) -> Result<(), Box>; +} + +pub trait Set + ?Sized>: Send + Sync { + fn add(&mut self, gossipable: T) -> Result<(), Box>; + fn iterate(&self, f: &dyn Fn(&T) -> bool); + fn get_filter(&self) -> Result<(Vec, Vec), Box>; +} \ No newline at end of file diff --git a/core/network/src/p2p/mod.rs b/core/network/src/p2p/mod.rs index df62623..ced53b7 100644 --- a/core/network/src/p2p/mod.rs +++ b/core/network/src/p2p/mod.rs @@ -1,18 +1,2 @@ pub mod gossip; - -use avalanche_types::ids::Id; - -/// Represent the mempool of an avalanche-rs node. -/// ref. - -pub trait Gossipable { - fn get_id(&self) -> Id; - fn marshal(&self) -> Result, Box>; - fn unmarshal(&mut self, bytes: &[u8]) -> Result<(), Box>; -} - -pub trait Set { - fn add(&mut self, gossipable: T) -> Result<(), Box>; - fn iterate(&self, f: impl Fn(&T) -> bool); - fn get_filter(&self) -> Result<(Vec, Vec), Box>; -} \ No newline at end of file +pub mod client; \ No newline at end of file From 86580a63c2805b5fc21a40ba8fe6d6927582f5f5 Mon Sep 17 00:00:00 2001 From: sanghren Date: Thu, 7 Sep 2023 22:08:13 +0200 Subject: [PATCH 06/53] feat: add channel to gossiper --- core/network/src/p2p/gossip/gossip.rs | 31 +++++++++++++++++++++------ 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/core/network/src/p2p/gossip/gossip.rs b/core/network/src/p2p/gossip/gossip.rs index d016688..d5dfd37 100644 --- a/core/network/src/p2p/gossip/gossip.rs +++ b/core/network/src/p2p/gossip/gossip.rs @@ -2,6 +2,8 @@ use std::error::Error; use std::sync::Arc; use std::time::Duration; use log::{debug, error}; +use tokio::select; +use tokio::sync::mpsc::{channel, Receiver}; use tokio::time::interval; use avalanche_types::ids::Id; use crate::p2p::gossip::{Gossipable, Set}; @@ -16,6 +18,7 @@ pub struct Gossiper + ?Sized> { config: Config, set: Arc>, client: Arc, + stop_rx: Receiver<()>, // Receiver to get the stop signal } impl> Gossiper { @@ -23,22 +26,31 @@ impl> Gossiper { config: Config, set: Arc>, client: Arc, + stop_rx: Receiver<()>, ) -> Self { Self { config, set, client, + stop_rx, } } - pub async fn gossip(&self) { + pub async fn gossip(&mut self) { let mut gossip_ticker = interval(self.config.frequency); loop { - gossip_ticker.tick().await; - // This will pause the loop for `self.config.frequency` - if let Err(e) = self.single_gossip().await { - error!("Failed to Gossip : {:?}", e) + select! { + _ = gossip_ticker.tick() => { + debug!("Tick!"); + if let Err(e) = self.single_gossip().await { + error!("Failed to Gossip : {:?}", e); + } + } + _ = self.stop_rx.recv() => { + debug!("Shutting down gossip"); + break; + } } } } @@ -103,10 +115,13 @@ async fn test_gossip() { .try_init() .unwrap(); - let gossiper: Gossiper = Gossiper::new( + let (stop_tx, stop_rx) = channel(1); // Create a new channel + + let mut gossiper: Gossiper = Gossiper::new( Config { frequency: Duration::from_millis(200), poll_size: 0 }, Arc::new(MockSet), // Replace with your real Set implementation Arc::new(MockClient), // Replace with your real Client implementation + stop_rx ); // Spawn the gossiping task @@ -117,5 +132,7 @@ async fn test_gossip() { // Wait some time to let a few cycles of gossiping happen tokio::time::sleep(Duration::from_secs(5)).await; - gossip_task.abort(); + stop_tx.send(()).await.expect("Failed to send stop signal"); + + gossip_task.await.expect("Gossip task failed"); } From 10657e080ca41fb39530c6d98867516eaa0e9ff8 Mon Sep 17 00:00:00 2001 From: sanghren Date: Sat, 9 Sep 2023 11:09:15 +0200 Subject: [PATCH 07/53] feat: add bloom --- core/network/src/p2p/gossip/bloom.rs | 113 ++++++++++++++++++++++++++ core/network/src/p2p/gossip/gossip.rs | 52 +++++++----- core/network/src/p2p/gossip/mod.rs | 5 +- core/network/src/p2p/mod.rs | 2 +- 4 files changed, 149 insertions(+), 23 deletions(-) create mode 100644 core/network/src/p2p/gossip/bloom.rs diff --git a/core/network/src/p2p/gossip/bloom.rs b/core/network/src/p2p/gossip/bloom.rs new file mode 100644 index 0000000..6bc92c2 --- /dev/null +++ b/core/network/src/p2p/gossip/bloom.rs @@ -0,0 +1,113 @@ +use probabilistic_collections::bloom::BloomFilter; +use avalanche_types::ids::{Id, LEN}; +use crate::p2p::gossip::Gossipable; +use byteorder::{BigEndian, ByteOrder}; + +pub struct Bloom { + bloom: BloomFilter::, + // ToDo Which type here ? + salt: Id, +} + +#[derive(Hash)] +pub struct Hasher { + hash: Vec, + // ToDo Which type here ? + salt: Id, +} + + +impl Bloom { + pub fn new_bloom_filter( + max_expected_elements: usize, + false_positive_probability: f64, + ) -> Self { + let salt = random_salt(); + + Bloom { + bloom: BloomFilter::new(max_expected_elements, false_positive_probability), + salt, + } + } + + + pub fn add(&mut self, gossipable: impl Gossipable) { + let id = gossipable.get_id(); + + let salted = Hasher { + hash: id.to_vec(), + salt: self.salt, + }; + + //ToDo Is this what we want here ? + self.bloom.insert(&salted) + } + + pub fn has(&self, gossipable: impl Gossipable) -> bool { + let id = gossipable.get_id(); + + let salted = Hasher { + hash: id.to_vec(), + salt: self.salt, + }; + + //ToDo Is this what we want here ? + self.bloom.contains(&salted) + } +} + +pub fn reset_bloom_filter_if_needed( + bloom_filter: &mut Bloom, + false_positive_probability: f64, +) -> bool { + if bloom_filter.bloom.estimated_fpp() < false_positive_probability { + return false; + } + + let new_bloom_filter = BloomFilter::new(bloom_filter.bloom.len(), false_positive_probability); + let salt = random_salt(); + + bloom_filter.bloom = new_bloom_filter; + bloom_filter.salt = salt; + true +} + +fn random_salt() -> Id { + let random_32_bytes = random_manager::secure_bytes(32).unwrap(); + let salt: Id = Id::from_slice(random_32_bytes.as_slice()); + salt +} + +impl Hasher { + pub fn write(&mut self, p: &[u8]) -> Result { + self.hash.extend_from_slice(p); + Ok(p.len()) + } + + pub fn sum(&mut self, b: &[u8]) -> Vec { + self.hash.extend_from_slice(b); + self.hash.clone() + } + + pub fn reset(&mut self) { + self.hash = vec![0; LEN]; + } + + pub fn block_size() -> usize { + LEN + } + + pub fn sum64(&self) -> u64 { + let mut salted = [0u8; LEN]; + + for i in 0..std::cmp::min(self.hash.len(), LEN) { + salted[i] = self.hash[i] ^ self.salt.to_vec().get(i).unwrap(); + } + + BigEndian::read_u64(&salted[0..8]) + } + + pub fn size(&self) -> usize { + self.hash.len() + } +} diff --git a/core/network/src/p2p/gossip/gossip.rs b/core/network/src/p2p/gossip/gossip.rs index d5dfd37..d2908ca 100644 --- a/core/network/src/p2p/gossip/gossip.rs +++ b/core/network/src/p2p/gossip/gossip.rs @@ -10,18 +10,18 @@ use crate::p2p::gossip::{Gossipable, Set}; use crate::p2p::client::Client; pub struct Config { - pub frequency: std::time::Duration, + pub frequency: Duration, pub poll_size: usize, } -pub struct Gossiper + ?Sized> { +pub struct Gossiper { config: Config, set: Arc>, client: Arc, - stop_rx: Receiver<()>, // Receiver to get the stop signal + stop_rx: Receiver<()>, } -impl> Gossiper { +impl Gossiper { pub fn new( config: Config, set: Arc>, @@ -43,8 +43,10 @@ impl> Gossiper { select! { _ = gossip_ticker.tick() => { debug!("Tick!"); - if let Err(e) = self.single_gossip().await { + if let Err(e) = self.execute_gossip().await { error!("Failed to Gossip : {:?}", e); + //ToDo + } } _ = self.stop_rx.recv() => { @@ -55,11 +57,21 @@ impl> Gossiper { } } - async fn single_gossip(&self) -> Result<(), Box> { + // ToDo Maybe there is a better name here + async fn execute_gossip(&self) -> Result<(), Box> { let (bloom, salt) = self.set.get_filter()?; - // ... Perform the gossip operation, involving self.client, and return a Result - // (Left as an exercise for the reader) + debug!("In single_gossip"); + // ToDo Implement logic + Ok(()) + } + + async fn handle_response(&self, node_id: Id, response_bytes: Vec) -> Result<(), Box> { + let (bloom, salt) = self.set.get_filter()?; + + debug!("In handle_response"); + // ToDo Implement logic + Ok(()) } } @@ -67,7 +79,7 @@ impl> Gossiper { // Mock implementation for the Set trait struct MockSet; -impl> Set for MockSet { +impl Set for MockSet { fn add(&mut self, _gossipable: T) -> Result<(), Box> { Ok(()) } @@ -81,16 +93,13 @@ impl> Set for MockSet { } } -// Mock implementation for the Client trait struct MockClient; -impl Client for MockClient { - // Implement the methods of the Client trait here... -} +impl Client for MockClient {} struct TestGossipableType; -impl Gossipable for TestGossipableType { +impl Gossipable for TestGossipableType { fn get_id(&self) -> Id { todo!() } @@ -102,7 +111,6 @@ impl Gossipable for TestGossipableType { fn unmarshal(&mut self, bytes: &[u8]) -> Result<(), Box> { todo!() } - // ... your methods here } @@ -119,9 +127,9 @@ async fn test_gossip() { let mut gossiper: Gossiper = Gossiper::new( Config { frequency: Duration::from_millis(200), poll_size: 0 }, - Arc::new(MockSet), // Replace with your real Set implementation - Arc::new(MockClient), // Replace with your real Client implementation - stop_rx + Arc::new(MockSet), + Arc::new(MockClient), + stop_rx, ); // Spawn the gossiping task @@ -132,7 +140,11 @@ async fn test_gossip() { // Wait some time to let a few cycles of gossiping happen tokio::time::sleep(Duration::from_secs(5)).await; - stop_tx.send(()).await.expect("Failed to send stop signal"); + // Send the stop signal before awaiting the task. + if stop_tx.send(()).await.is_err() { + panic!("Failed to send stop signal"); + } - gossip_task.await.expect("Gossip task failed"); + // Await the gossip task. + let _ = gossip_task.await.expect("Gossip task failed"); } diff --git a/core/network/src/p2p/gossip/mod.rs b/core/network/src/p2p/gossip/mod.rs index a56ec02..82aa2cc 100644 --- a/core/network/src/p2p/gossip/mod.rs +++ b/core/network/src/p2p/gossip/mod.rs @@ -1,17 +1,18 @@ pub mod gossip; +pub mod bloom; use avalanche_types::ids::Id; /// Represent the mempool of an avalanche-rs node. /// ref. -pub trait Gossipable { +pub trait Gossipable { fn get_id(&self) -> Id; fn marshal(&self) -> Result, Box>; fn unmarshal(&mut self, bytes: &[u8]) -> Result<(), Box>; } -pub trait Set + ?Sized>: Send + Sync { +pub trait Set: Send + Sync { fn add(&mut self, gossipable: T) -> Result<(), Box>; fn iterate(&self, f: &dyn Fn(&T) -> bool); fn get_filter(&self) -> Result<(Vec, Vec), Box>; diff --git a/core/network/src/p2p/mod.rs b/core/network/src/p2p/mod.rs index ced53b7..6979ea8 100644 --- a/core/network/src/p2p/mod.rs +++ b/core/network/src/p2p/mod.rs @@ -1,2 +1,2 @@ pub mod gossip; -pub mod client; \ No newline at end of file +pub mod client; From baf2923dcb38d5e3fd81ef92450737bb2b008fd0 Mon Sep 17 00:00:00 2001 From: sanghren Date: Sat, 9 Sep 2023 16:39:28 +0200 Subject: [PATCH 08/53] feat: add test for bloom --- core/network/src/p2p/gossip/bloom.rs | 59 +++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 2 deletions(-) diff --git a/core/network/src/p2p/gossip/bloom.rs b/core/network/src/p2p/gossip/bloom.rs index 6bc92c2..bd7e668 100644 --- a/core/network/src/p2p/gossip/bloom.rs +++ b/core/network/src/p2p/gossip/bloom.rs @@ -1,15 +1,19 @@ +use std::error::Error; use probabilistic_collections::bloom::BloomFilter; use avalanche_types::ids::{Id, LEN}; use crate::p2p::gossip::Gossipable; use byteorder::{BigEndian, ByteOrder}; +use proptest::proptest; +use proptest::prelude::*; +#[derive(Debug)] pub struct Bloom { bloom: BloomFilter::, // ToDo Which type here ? salt: Id, } -#[derive(Hash)] +#[derive(Debug, Hash)] pub struct Hasher { hash: Vec, // ToDo Which type here ? @@ -43,7 +47,7 @@ impl Bloom { self.bloom.insert(&salted) } - pub fn has(&self, gossipable: impl Gossipable) -> bool { + pub fn has(&self, gossipable: &impl Gossipable) -> bool { let id = gossipable.get_id(); let salted = Hasher { @@ -111,3 +115,54 @@ impl Hasher { self.hash.len() } } + +#[derive(Debug, Clone)] +struct TestTx { + pub id: Id, +} + +impl Gossipable for TestTx { + fn get_id(&self) -> Id { + self.id + } + + fn marshal(&self) -> Result, Box> { + todo!() + } + + fn unmarshal(&mut self, bytes: &[u8]) -> Result<(), Box> { + todo!() + } +} + +proptest! { + #![proptest_config(ProptestConfig { + cases: 100, + .. ProptestConfig::default() + })] + + #[test] + fn test_bloom_filter_refresh( + false_positive_probability in 0.0..1.0f64, + txs in proptest::collection::vec(any::<[u8; 32]>(), 0..100) + ) { + let mut bloom_filter = Bloom::new_bloom_filter(10, 0.01); + let mut expected = vec![]; + + for tx in txs { + let should_reset = reset_bloom_filter_if_needed(&mut bloom_filter, false_positive_probability); + let test_tx = TestTx { id: Id::from_slice(&tx) }; + if should_reset { + expected.clear(); + } + + bloom_filter.add(test_tx.clone()); + expected.push(test_tx.clone()); + + for expected_tx in &expected { + assert!(bloom_filter.has(expected_tx)) + } + } + } + } + From 1fea689966c30693c8f27025f1fe2f1d26ec3e60 Mon Sep 17 00:00:00 2001 From: sanghren Date: Sat, 9 Sep 2023 17:24:02 +0200 Subject: [PATCH 09/53] feat: add test for bloom --- core/network/src/p2p/gossip/bloom.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/network/src/p2p/gossip/bloom.rs b/core/network/src/p2p/gossip/bloom.rs index bd7e668..c2b91b6 100644 --- a/core/network/src/p2p/gossip/bloom.rs +++ b/core/network/src/p2p/gossip/bloom.rs @@ -137,14 +137,14 @@ impl Gossipable for TestTx { proptest! { #![proptest_config(ProptestConfig { - cases: 100, + cases: 100, // Need 100 successful test cases .. ProptestConfig::default() })] #[test] fn test_bloom_filter_refresh( false_positive_probability in 0.0..1.0f64, - txs in proptest::collection::vec(any::<[u8; 32]>(), 0..100) + txs in proptest::collection::vec(any::<[u8; 32]>(), 0..100) // Will populate txs with 0 to 100 [u8; 32] ) { let mut bloom_filter = Bloom::new_bloom_filter(10, 0.01); let mut expected = vec![]; From 7ba33ea8ae7166c29cb68aa58a33331787008baf Mon Sep 17 00:00:00 2001 From: sanghren Date: Mon, 11 Sep 2023 18:09:03 +0200 Subject: [PATCH 10/53] feat: add proto --- core/network/build.rs | 16 +++++ core/network/src/p2p/client.rs | 10 +++- core/network/src/p2p/gossip/gossip.rs | 86 ++++++++++++++++++++------- core/network/src/p2p/gossip/sdk.proto | 12 ++++ core/network/src/p2p/mod.rs | 1 + 5 files changed, 103 insertions(+), 22 deletions(-) create mode 100644 core/network/build.rs create mode 100644 core/network/src/p2p/gossip/sdk.proto diff --git a/core/network/build.rs b/core/network/build.rs new file mode 100644 index 0000000..d665b75 --- /dev/null +++ b/core/network/build.rs @@ -0,0 +1,16 @@ +/// ref. +fn main() { + tonic_build::configure() + .out_dir("./src/p2p") + .build_server(true) + .build_client(true) + .compile( + &[ + "./src/p2p/gossip/sdk.proto", + ], + &["./src/p2p/gossip/"] + ) + .unwrap(); + + println!("cargo:warning={:?}", std::env::var("OUT_DIR")); +} diff --git a/core/network/src/p2p/client.rs b/core/network/src/p2p/client.rs index e390c0c..13fd73a 100644 --- a/core/network/src/p2p/client.rs +++ b/core/network/src/p2p/client.rs @@ -1,4 +1,10 @@ +pub struct Client {} -pub trait Client: Send + Sync { - // ToDo Implement this +impl Client { + pub async fn app_request_any(&self) {} + pub async fn app_request(&self) {} + pub async fn app_gossip(&self) {} + pub async fn app_gossip_specific(&self) {} + pub async fn cross_chain_app_request(&self) {} + pub async fn prefix_message(&self) {} } \ No newline at end of file diff --git a/core/network/src/p2p/gossip/gossip.rs b/core/network/src/p2p/gossip/gossip.rs index d2908ca..277f952 100644 --- a/core/network/src/p2p/gossip/gossip.rs +++ b/core/network/src/p2p/gossip/gossip.rs @@ -1,31 +1,39 @@ use std::error::Error; -use std::sync::Arc; +use std::sync::{Arc, Mutex}; +use std::thread::sleep; use std::time::Duration; use log::{debug, error}; +use prost::Message; use tokio::select; use tokio::sync::mpsc::{channel, Receiver}; use tokio::time::interval; -use avalanche_types::ids::Id; +use avalanche_types::ids::{Id, Ids}; use crate::p2p::gossip::{Gossipable, Set}; use crate::p2p::client::Client; +use crate::p2p::sdk::{PullGossipRequest, PullGossipResponse}; pub struct Config { pub frequency: Duration, pub poll_size: usize, } -pub struct Gossiper { + +pub struct Gossiper + where + T: Gossipable, +{ config: Config, - set: Arc>, - client: Arc, + set: Arc>>, + client: Arc, stop_rx: Receiver<()>, } -impl Gossiper { +impl Gossiper where + T: Gossipable + Default { pub fn new( config: Config, - set: Arc>, - client: Arc, + set: Arc>>, // Mutex or RWLock here ? + client: Arc, stop_rx: Receiver<()>, ) -> Self { Self { @@ -58,21 +66,55 @@ impl Gossiper { } // ToDo Maybe there is a better name here - async fn execute_gossip(&self) -> Result<(), Box> { - let (bloom, salt) = self.set.get_filter()?; + async fn execute_gossip(&self) -> Result<(), Box> { + let read_guard = self.set.lock().unwrap(); + let (bloom, salt) = read_guard.get_filter()?; + let request = PullGossipRequest { filter: bloom, salt }; + + let mut msg_bytes = vec![]; + request + .encode(&mut msg_bytes)?; + + for i in 0..self.config.poll_size { + self.client.app_request_any(); //ToDo + } debug!("In single_gossip"); - // ToDo Implement logic Ok(()) } - async fn handle_response(&self, node_id: Id, response_bytes: Vec) -> Result<(), Box> { - let (bloom, salt) = self.set.get_filter()?; + async fn handle_response(& mut self, node_id: Id, response_bytes: Vec, err: Option>) { + if let Some(e) = err { + debug!("failed gossip request, nodeID: {:?}, error: {:?}", node_id, e); + return; + } + + let mut response = PullGossipResponse::default(); + match PullGossipResponse::decode(response_bytes.as_slice()) { + Ok(res) => response = res, + Err(e) => { + debug!("failed to unmarshal gossip response, error: {:?}", e); + return; + } + } - debug!("In handle_response"); - // ToDo Implement logic + for bytes in response.gossip.iter() { + let mut gossipable: T = T::default(); + if let Err(e) = gossipable.unmarshal(bytes) { + debug!("failed to unmarshal gossip, nodeID: {:?}, error: {:?}", node_id, e); + continue; + } - Ok(()) + let hash = gossipable.get_id(); + debug!("received gossip, nodeID: {:?}, id: {:?}", node_id, hash); + + + let mut set_guard = self.set.lock().unwrap(); + if let Err(e) = set_guard.add(gossipable) { + debug!("failed to add gossip to the known set, nodeID: {:?}, id: {:?}, error: {:?}", node_id, hash, e); + continue; + } + } } } @@ -95,10 +137,14 @@ impl Set for MockSet { struct MockClient; -impl Client for MockClient {} - struct TestGossipableType; +impl Default for TestGossipableType { + fn default() -> Self { + todo!() + } +} + impl Gossipable for TestGossipableType { fn get_id(&self) -> Id { todo!() @@ -127,8 +173,8 @@ async fn test_gossip() { let mut gossiper: Gossiper = Gossiper::new( Config { frequency: Duration::from_millis(200), poll_size: 0 }, - Arc::new(MockSet), - Arc::new(MockClient), + Arc::new(Mutex::new(MockSet)), + Arc::new(Client {}), stop_rx, ); diff --git a/core/network/src/p2p/gossip/sdk.proto b/core/network/src/p2p/gossip/sdk.proto new file mode 100644 index 0000000..1f9759b --- /dev/null +++ b/core/network/src/p2p/gossip/sdk.proto @@ -0,0 +1,12 @@ +syntax = "proto3"; + +package sdk; + +message PullGossipRequest { + bytes filter = 1; + bytes salt = 2; +} + +message PullGossipResponse { + repeated bytes gossip = 1; +} diff --git a/core/network/src/p2p/mod.rs b/core/network/src/p2p/mod.rs index 6979ea8..8d2a289 100644 --- a/core/network/src/p2p/mod.rs +++ b/core/network/src/p2p/mod.rs @@ -1,2 +1,3 @@ pub mod gossip; pub mod client; +pub mod sdk; From cc7edebda426bf65ff2e07c1eb7fc1ec62ddafc2 Mon Sep 17 00:00:00 2001 From: sanghren Date: Mon, 11 Sep 2023 18:44:41 +0200 Subject: [PATCH 11/53] feat: add proto generated file --- core/network/src/p2p/sdk.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 core/network/src/p2p/sdk.rs diff --git a/core/network/src/p2p/sdk.rs b/core/network/src/p2p/sdk.rs new file mode 100644 index 0000000..595cb70 --- /dev/null +++ b/core/network/src/p2p/sdk.rs @@ -0,0 +1,14 @@ +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PullGossipRequest { + #[prost(bytes = "vec", tag = "1")] + pub filter: ::prost::alloc::vec::Vec, + #[prost(bytes = "vec", tag = "2")] + pub salt: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PullGossipResponse { + #[prost(bytes = "vec", repeated, tag = "1")] + pub gossip: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec>, +} From 231d93bfeeae3ec24148423c7e18b91d62fbdb7e Mon Sep 17 00:00:00 2001 From: sanghren Date: Tue, 12 Sep 2023 08:23:16 +0200 Subject: [PATCH 12/53] feat: some cleanup --- core/network/src/p2p/gossip/bloom.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/core/network/src/p2p/gossip/bloom.rs b/core/network/src/p2p/gossip/bloom.rs index c2b91b6..11561d1 100644 --- a/core/network/src/p2p/gossip/bloom.rs +++ b/core/network/src/p2p/gossip/bloom.rs @@ -9,18 +9,15 @@ use proptest::prelude::*; #[derive(Debug)] pub struct Bloom { bloom: BloomFilter::, - // ToDo Which type here ? salt: Id, } #[derive(Debug, Hash)] pub struct Hasher { hash: Vec, - // ToDo Which type here ? salt: Id, } - impl Bloom { pub fn new_bloom_filter( max_expected_elements: usize, @@ -43,7 +40,6 @@ impl Bloom { salt: self.salt, }; - //ToDo Is this what we want here ? self.bloom.insert(&salted) } @@ -55,7 +51,6 @@ impl Bloom { salt: self.salt, }; - //ToDo Is this what we want here ? self.bloom.contains(&salted) } } @@ -164,5 +159,4 @@ proptest! { } } } - } - + } \ No newline at end of file From c1b42c2f926d9198c6b01dac7d995ac75bc23bf2 Mon Sep 17 00:00:00 2001 From: sanghren Date: Tue, 12 Sep 2023 08:23:55 +0200 Subject: [PATCH 13/53] feat: some cleanup --- core/network/src/p2p/gossip/mod.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/core/network/src/p2p/gossip/mod.rs b/core/network/src/p2p/gossip/mod.rs index 82aa2cc..3007319 100644 --- a/core/network/src/p2p/gossip/mod.rs +++ b/core/network/src/p2p/gossip/mod.rs @@ -3,9 +3,6 @@ pub mod bloom; use avalanche_types::ids::Id; -/// Represent the mempool of an avalanche-rs node. -/// ref. - pub trait Gossipable { fn get_id(&self) -> Id; fn marshal(&self) -> Result, Box>; From 1f57923b854234f5c06a1d39f15712bb8f003e77 Mon Sep 17 00:00:00 2001 From: sanghren Date: Tue, 12 Sep 2023 08:30:09 +0200 Subject: [PATCH 14/53] feat: add Namespace to Config --- core/network/src/p2p/gossip/gossip.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/core/network/src/p2p/gossip/gossip.rs b/core/network/src/p2p/gossip/gossip.rs index 277f952..42373e7 100644 --- a/core/network/src/p2p/gossip/gossip.rs +++ b/core/network/src/p2p/gossip/gossip.rs @@ -1,18 +1,18 @@ use std::error::Error; use std::sync::{Arc, Mutex}; -use std::thread::sleep; use std::time::Duration; use log::{debug, error}; use prost::Message; use tokio::select; use tokio::sync::mpsc::{channel, Receiver}; use tokio::time::interval; -use avalanche_types::ids::{Id, Ids}; +use avalanche_types::ids::{Id}; use crate::p2p::gossip::{Gossipable, Set}; use crate::p2p::client::Client; use crate::p2p::sdk::{PullGossipRequest, PullGossipResponse}; pub struct Config { + pub namespace: String, pub frequency: Duration, pub poll_size: usize, } @@ -50,7 +50,6 @@ impl Gossiper where loop { select! { _ = gossip_ticker.tick() => { - debug!("Tick!"); if let Err(e) = self.execute_gossip().await { error!("Failed to Gossip : {:?}", e); //ToDo @@ -79,13 +78,12 @@ impl Gossiper where self.client.app_request_any(); //ToDo } - debug!("In single_gossip"); Ok(()) } async fn handle_response(& mut self, node_id: Id, response_bytes: Vec, err: Option>) { if let Some(e) = err { - debug!("failed gossip request, nodeID: {:?}, error: {:?}", node_id, e); + error!("failed gossip request, nodeID: {:?}, error: {:?}", node_id, e); return; } @@ -93,7 +91,7 @@ impl Gossiper where match PullGossipResponse::decode(response_bytes.as_slice()) { Ok(res) => response = res, Err(e) => { - debug!("failed to unmarshal gossip response, error: {:?}", e); + error!("failed to unmarshal gossip response, error: {:?}", e); return; } } @@ -101,7 +99,7 @@ impl Gossiper where for bytes in response.gossip.iter() { let mut gossipable: T = T::default(); if let Err(e) = gossipable.unmarshal(bytes) { - debug!("failed to unmarshal gossip, nodeID: {:?}, error: {:?}", node_id, e); + error!("failed to unmarshal gossip, nodeID: {:?}, error: {:?}", node_id, e); continue; } @@ -172,7 +170,7 @@ async fn test_gossip() { let (stop_tx, stop_rx) = channel(1); // Create a new channel let mut gossiper: Gossiper = Gossiper::new( - Config { frequency: Duration::from_millis(200), poll_size: 0 }, + Config { namespace: "test".to_string(), frequency: Duration::from_millis(200), poll_size: 0 }, Arc::new(Mutex::new(MockSet)), Arc::new(Client {}), stop_rx, From db4cf30d1c9dce7de994d2aa1d0ffcd8228f6a8c Mon Sep 17 00:00:00 2001 From: sanghren Date: Tue, 12 Sep 2023 12:54:19 +0200 Subject: [PATCH 15/53] feat: add test --- core/network/src/p2p/gossip/gossip.rs | 78 +++++++++++++++++++++++---- 1 file changed, 67 insertions(+), 11 deletions(-) diff --git a/core/network/src/p2p/gossip/gossip.rs b/core/network/src/p2p/gossip/gossip.rs index 42373e7..1f54125 100644 --- a/core/network/src/p2p/gossip/gossip.rs +++ b/core/network/src/p2p/gossip/gossip.rs @@ -1,3 +1,4 @@ +use std::collections::HashSet; use std::error::Error; use std::sync::{Arc, Mutex}; use std::time::Duration; @@ -18,9 +19,7 @@ pub struct Config { } -pub struct Gossiper - where - T: Gossipable, +pub struct Gossiper { config: Config, set: Arc>>, @@ -66,7 +65,7 @@ impl Gossiper where // ToDo Maybe there is a better name here async fn execute_gossip(&self) -> Result<(), Box> { - let read_guard = self.set.lock().unwrap(); + let read_guard = self.set.lock().expect("Failed to acquire lock"); let (bloom, salt) = read_guard.get_filter()?; let request = PullGossipRequest { filter: bloom, salt }; @@ -75,13 +74,13 @@ impl Gossiper where .encode(&mut msg_bytes)?; for i in 0..self.config.poll_size { - self.client.app_request_any(); //ToDo + self.client.app_request_any(); //ToDo out of scope of my PR } Ok(()) } - async fn handle_response(& mut self, node_id: Id, response_bytes: Vec, err: Option>) { + async fn handle_response(&mut self, node_id: Id, response_bytes: Vec, err: Option>) { if let Some(e) = err { error!("failed gossip request, nodeID: {:?}, error: {:?}", node_id, e); return; @@ -107,7 +106,7 @@ impl Gossiper where debug!("received gossip, nodeID: {:?}, id: {:?}", node_id, hash); - let mut set_guard = self.set.lock().unwrap(); + let mut set_guard = self.set.lock().expect("Failed to acquire lock"); if let Err(e) = set_guard.add(gossipable) { debug!("failed to add gossip to the known set, nodeID: {:?}, id: {:?}, error: {:?}", node_id, hash, e); continue; @@ -117,10 +116,11 @@ impl Gossiper where } // Mock implementation for the Set trait +//ToDo Should we move all tests to a new file ? struct MockSet; impl Set for MockSet { - fn add(&mut self, _gossipable: T) -> Result<(), Box> { + fn add(&mut self, _gossipable: T) -> Result<(), Box> { Ok(()) } @@ -128,7 +128,7 @@ impl Set for MockSet { // Do nothing } - fn get_filter(&self) -> Result<(Vec, Vec), Box> { + fn get_filter(&self) -> Result<(Vec, Vec), Box> { Ok((vec![], vec![])) } } @@ -158,9 +158,9 @@ impl Gossipable for TestGossipableType { } -/// RUST_LOG=debug cargo test --package network --lib -- p2p::gossip::test_gossip --exact --show-output +/// RUST_LOG=debug cargo test --package network --lib -- p2p::gossip::test_gossip_shutdown --exact --show-output #[tokio::test] -async fn test_gossip() { +async fn test_gossip_shutdown() { let _ = env_logger::builder() .filter_level(log::LevelFilter::Debug) .is_test(true) @@ -192,3 +192,59 @@ async fn test_gossip() { // Await the gossip task. let _ = gossip_task.await.expect("Gossip task failed"); } + +#[cfg(test)] +mod tests { + use super::*; + use std::collections::HashSet; + use testing_logger; + + #[tokio::test] + async fn test_handle_response_with_empty_response_bytes() { + // Initialize logging capture + testing_logger::setup(); + + let mut set = Arc::new(Mutex::new(HashSet::::new())); + + let (stop_tx, stop_rx) = channel(1); // Create a new channel + + let mut gossiper: Gossiper = Gossiper::new( + Config { namespace: "test".to_string(), frequency: Duration::from_millis(200), poll_size: 0 }, + Arc::new(Mutex::new(MockSet)), + Arc::new(Client {}), + stop_rx, + ); + + gossiper.handle_response(Id::default(), vec![0u8; 16], None).await; + + testing_logger::validate(|captured_logs| { + assert_eq!(captured_logs.len(), 1); + assert_eq!(captured_logs[0].body, "failed to unmarshal gossip response, error: DecodeError { description: \"invalid tag value: 0\", stack: [] }"); + }) + } + + + #[tokio::test] + async fn test_handle_response_with_empty_response_bytes() { + // Initialize logging capture + testing_logger::setup(); + + let mut set = Arc::new(Mutex::new(HashSet::::new())); + + let (stop_tx, stop_rx) = channel(1); // Create a new channel + + let mut gossiper: Gossiper = Gossiper::new( + Config { namespace: "test".to_string(), frequency: Duration::from_millis(200), poll_size: 0 }, + Arc::new(Mutex::new(MockSet)), + Arc::new(Client {}), + stop_rx, + ); + + gossiper.handle_response(Id::default(), vec![0u8; 16], None).await; + + testing_logger::validate(|captured_logs| { + assert_eq!(captured_logs.len(), 1); + assert_eq!(captured_logs[0].body, "failed to unmarshal gossip response, error: DecodeError { description: \"invalid tag value: 0\", stack: [] }"); + }) + } +} From e52b0a1407532d3aeaa032af99b3608a2a605998 Mon Sep 17 00:00:00 2001 From: sanghren Date: Tue, 12 Sep 2023 18:01:45 +0200 Subject: [PATCH 16/53] feat: add test --- core/network/build.rs | 7 +- core/network/src/lib.rs | 2 +- core/network/src/p2p/client.rs | 2 +- core/network/src/p2p/gossip/bloom.rs | 70 +++++---- core/network/src/p2p/gossip/gossip.rs | 199 +++++++++++++++++--------- core/network/src/p2p/gossip/mod.rs | 4 +- core/network/src/p2p/mod.rs | 2 +- 7 files changed, 171 insertions(+), 115 deletions(-) diff --git a/core/network/build.rs b/core/network/build.rs index d665b75..d66f9a0 100644 --- a/core/network/build.rs +++ b/core/network/build.rs @@ -4,12 +4,7 @@ fn main() { .out_dir("./src/p2p") .build_server(true) .build_client(true) - .compile( - &[ - "./src/p2p/gossip/sdk.proto", - ], - &["./src/p2p/gossip/"] - ) + .compile(&["./src/p2p/gossip/sdk.proto"], &["./src/p2p/gossip/"]) .unwrap(); println!("cargo:warning={:?}", std::env::var("OUT_DIR")); diff --git a/core/network/src/lib.rs b/core/network/src/lib.rs index 02219a4..084d95b 100644 --- a/core/network/src/lib.rs +++ b/core/network/src/lib.rs @@ -1,3 +1,3 @@ //! A library for building p2p inbound and outbound connections. -pub mod peer; pub mod p2p; +pub mod peer; diff --git a/core/network/src/p2p/client.rs b/core/network/src/p2p/client.rs index 13fd73a..9aed8fc 100644 --- a/core/network/src/p2p/client.rs +++ b/core/network/src/p2p/client.rs @@ -7,4 +7,4 @@ impl Client { pub async fn app_gossip_specific(&self) {} pub async fn cross_chain_app_request(&self) {} pub async fn prefix_message(&self) {} -} \ No newline at end of file +} diff --git a/core/network/src/p2p/gossip/bloom.rs b/core/network/src/p2p/gossip/bloom.rs index 11561d1..2c03df8 100644 --- a/core/network/src/p2p/gossip/bloom.rs +++ b/core/network/src/p2p/gossip/bloom.rs @@ -1,14 +1,14 @@ -use std::error::Error; -use probabilistic_collections::bloom::BloomFilter; -use avalanche_types::ids::{Id, LEN}; use crate::p2p::gossip::Gossipable; +use avalanche_types::ids::{Id, LEN}; use byteorder::{BigEndian, ByteOrder}; -use proptest::proptest; +use probabilistic_collections::bloom::BloomFilter; use proptest::prelude::*; +use proptest::proptest; +use std::error::Error; #[derive(Debug)] pub struct Bloom { - bloom: BloomFilter::, + bloom: BloomFilter, salt: Id, } @@ -19,10 +19,7 @@ pub struct Hasher { } impl Bloom { - pub fn new_bloom_filter( - max_expected_elements: usize, - false_positive_probability: f64, - ) -> Self { + pub fn new_bloom_filter(max_expected_elements: usize, false_positive_probability: f64) -> Self { let salt = random_salt(); Bloom { @@ -31,7 +28,6 @@ impl Bloom { } } - pub fn add(&mut self, gossipable: impl Gossipable) { let id = gossipable.get_id(); @@ -131,32 +127,32 @@ impl Gossipable for TestTx { } proptest! { - #![proptest_config(ProptestConfig { - cases: 100, // Need 100 successful test cases - .. ProptestConfig::default() - })] - - #[test] - fn test_bloom_filter_refresh( - false_positive_probability in 0.0..1.0f64, - txs in proptest::collection::vec(any::<[u8; 32]>(), 0..100) // Will populate txs with 0 to 100 [u8; 32] - ) { - let mut bloom_filter = Bloom::new_bloom_filter(10, 0.01); - let mut expected = vec![]; - - for tx in txs { - let should_reset = reset_bloom_filter_if_needed(&mut bloom_filter, false_positive_probability); - let test_tx = TestTx { id: Id::from_slice(&tx) }; - if should_reset { - expected.clear(); - } - - bloom_filter.add(test_tx.clone()); - expected.push(test_tx.clone()); - - for expected_tx in &expected { - assert!(bloom_filter.has(expected_tx)) - } + #![proptest_config(ProptestConfig { + cases: 100, // Need 100 successful test cases + .. ProptestConfig::default() + })] + + #[test] + fn test_bloom_filter_refresh( + false_positive_probability in 0.0..1.0f64, + txs in proptest::collection::vec(any::<[u8; 32]>(), 0..100) // Will populate txs with 0 to 100 [u8; 32] + ) { + let mut bloom_filter = Bloom::new_bloom_filter(10, 0.01); + let mut expected = vec![]; + + for tx in txs { + let should_reset = reset_bloom_filter_if_needed(&mut bloom_filter, false_positive_probability); + let test_tx = TestTx { id: Id::from_slice(&tx) }; + if should_reset { + expected.clear(); + } + + bloom_filter.add(test_tx.clone()); + expected.push(test_tx.clone()); + + for expected_tx in &expected { + assert!(bloom_filter.has(expected_tx)) } } - } \ No newline at end of file + } +} diff --git a/core/network/src/p2p/gossip/gossip.rs b/core/network/src/p2p/gossip/gossip.rs index 1f54125..de99d93 100644 --- a/core/network/src/p2p/gossip/gossip.rs +++ b/core/network/src/p2p/gossip/gossip.rs @@ -1,16 +1,18 @@ -use std::collections::HashSet; +use crate::p2p::client::Client; +use crate::p2p::gossip::{Gossipable, Set}; +use crate::p2p::sdk::{PullGossipRequest, PullGossipResponse}; +use avalanche_types::ids::Id; +use log::{debug, error}; +use probabilistic_collections::bloom::BloomFilter; +use prost::Message; use std::error::Error; +use std::hash::Hash; +use std::marker::PhantomData; use std::sync::{Arc, Mutex}; use std::time::Duration; -use log::{debug, error}; -use prost::Message; use tokio::select; use tokio::sync::mpsc::{channel, Receiver}; use tokio::time::interval; -use avalanche_types::ids::{Id}; -use crate::p2p::gossip::{Gossipable, Set}; -use crate::p2p::client::Client; -use crate::p2p::sdk::{PullGossipRequest, PullGossipResponse}; pub struct Config { pub namespace: String, @@ -18,20 +20,22 @@ pub struct Config { pub poll_size: usize, } - -pub struct Gossiper -{ +pub struct Gossiper> { config: Config, - set: Arc>>, + set: Arc>, client: Arc, stop_rx: Receiver<()>, + phantom: PhantomData, // Had to use this to please the compiler about T not being used. } -impl Gossiper where - T: Gossipable + Default { +impl Gossiper +where + T: Gossipable + Default, + S: Set, +{ pub fn new( config: Config, - set: Arc>>, // Mutex or RWLock here ? + set: Arc>, // Mutex or RWLock here ? client: Arc, stop_rx: Receiver<()>, ) -> Self { @@ -40,6 +44,7 @@ impl Gossiper where set, client, stop_rx, + phantom: PhantomData, } } @@ -67,11 +72,13 @@ impl Gossiper where async fn execute_gossip(&self) -> Result<(), Box> { let read_guard = self.set.lock().expect("Failed to acquire lock"); let (bloom, salt) = read_guard.get_filter()?; - let request = PullGossipRequest { filter: bloom, salt }; + let request = PullGossipRequest { + filter: bloom, + salt, + }; let mut msg_bytes = vec![]; - request - .encode(&mut msg_bytes)?; + request.encode(&mut msg_bytes)?; for i in 0..self.config.poll_size { self.client.app_request_any(); //ToDo out of scope of my PR @@ -80,9 +87,17 @@ impl Gossiper where Ok(()) } - async fn handle_response(&mut self, node_id: Id, response_bytes: Vec, err: Option>) { + async fn handle_response( + &mut self, + node_id: Id, + response_bytes: Vec, + err: Option>, + ) { if let Some(e) = err { - error!("failed gossip request, nodeID: {:?}, error: {:?}", node_id, e); + error!( + "failed gossip request, nodeID: {:?}, error: {:?}", + node_id, e + ); return; } @@ -98,65 +113,87 @@ impl Gossiper where for bytes in response.gossip.iter() { let mut gossipable: T = T::default(); if let Err(e) = gossipable.unmarshal(bytes) { - error!("failed to unmarshal gossip, nodeID: {:?}, error: {:?}", node_id, e); + error!( + "failed to unmarshal gossip, nodeID: {:?}, error: {:?}", + node_id, e + ); continue; } let hash = gossipable.get_id(); debug!("received gossip, nodeID: {:?}, id: {:?}", node_id, hash); - let mut set_guard = self.set.lock().expect("Failed to acquire lock"); if let Err(e) = set_guard.add(gossipable) { - debug!("failed to add gossip to the known set, nodeID: {:?}, id: {:?}, error: {:?}", node_id, hash, e); + debug!( + "failed to add gossip to the known set, nodeID: {:?}, id: {:?}, error: {:?}", + node_id, hash, e + ); continue; } } } } -// Mock implementation for the Set trait -//ToDo Should we move all tests to a new file ? -struct MockSet; - -impl Set for MockSet { - fn add(&mut self, _gossipable: T) -> Result<(), Box> { - Ok(()) - } - - fn iterate(&self, _f: &dyn Fn(&T) -> bool) { - // Do nothing - } - - fn get_filter(&self) -> Result<(Vec, Vec), Box> { - Ok((vec![], vec![])) - } -} - struct MockClient; -struct TestGossipableType; +#[derive(Clone, Hash)] +struct TestGossipableType { + pub id: Id, +} impl Default for TestGossipableType { fn default() -> Self { - todo!() + TestGossipableType { + id: Default::default(), + } } } impl Gossipable for TestGossipableType { fn get_id(&self) -> Id { - todo!() + self.id } fn marshal(&self) -> Result, Box> { - todo!() + Ok(self.id.to_vec()) } fn unmarshal(&mut self, bytes: &[u8]) -> Result<(), Box> { - todo!() + self.id = Id::from_slice(bytes); + Ok(()) + } +} + +// Mock implementation for the Set trait +//ToDo Should we move all tests to a new file ? +struct MockSet { + pub set: Vec, + pub bloom: BloomFilter, +} + +impl MockSet { + pub fn len(&self) -> usize { + println!("{}", self.set.len()); + self.set.len() } } +impl Set for MockSet { + fn add(&mut self, _gossipable: T) -> Result<(), Box> { + self.set.push(_gossipable.clone()); + self.bloom.insert(&_gossipable.clone()); + Ok(()) + } + + fn iterate(&self, _f: &dyn Fn(&T) -> bool) { + // Do nothing + } + + fn get_filter(&self) -> Result<(Vec, Vec), Box> { + Ok((vec![], vec![])) + } +} /// RUST_LOG=debug cargo test --package network --lib -- p2p::gossip::test_gossip_shutdown --exact --show-output #[tokio::test] @@ -169,9 +206,16 @@ async fn test_gossip_shutdown() { let (stop_tx, stop_rx) = channel(1); // Create a new channel - let mut gossiper: Gossiper = Gossiper::new( - Config { namespace: "test".to_string(), frequency: Duration::from_millis(200), poll_size: 0 }, - Arc::new(Mutex::new(MockSet)), + let mut gossiper: Gossiper> = Gossiper::new( + Config { + namespace: "test".to_string(), + frequency: Duration::from_millis(200), + poll_size: 0, + }, + Arc::new(Mutex::new(MockSet { + set: Vec::new(), + bloom: BloomFilter::new(100, 0.5), + })), Arc::new(Client {}), stop_rx, ); @@ -196,7 +240,6 @@ async fn test_gossip_shutdown() { #[cfg(test)] mod tests { use super::*; - use std::collections::HashSet; use testing_logger; #[tokio::test] @@ -204,18 +247,25 @@ mod tests { // Initialize logging capture testing_logger::setup(); - let mut set = Arc::new(Mutex::new(HashSet::::new())); - let (stop_tx, stop_rx) = channel(1); // Create a new channel - let mut gossiper: Gossiper = Gossiper::new( - Config { namespace: "test".to_string(), frequency: Duration::from_millis(200), poll_size: 0 }, - Arc::new(Mutex::new(MockSet)), + let mut gossiper: Gossiper> = Gossiper::new( + Config { + namespace: "test".to_string(), + frequency: Duration::from_millis(200), + poll_size: 0, + }, + Arc::new(Mutex::new(MockSet { + set: Vec::new(), + bloom: BloomFilter::new(100, 0.5), + })), Arc::new(Client {}), stop_rx, ); - gossiper.handle_response(Id::default(), vec![0u8; 16], None).await; + gossiper + .handle_response(Id::default(), vec![0u8; 16], None) + .await; testing_logger::validate(|captured_logs| { assert_eq!(captured_logs.len(), 1); @@ -223,28 +273,43 @@ mod tests { }) } - #[tokio::test] - async fn test_handle_response_with_empty_response_bytes() { + async fn test_handle_response_with_non_empty_response_bytes() { // Initialize logging capture testing_logger::setup(); - let mut set = Arc::new(Mutex::new(HashSet::::new())); - let (stop_tx, stop_rx) = channel(1); // Create a new channel - let mut gossiper: Gossiper = Gossiper::new( - Config { namespace: "test".to_string(), frequency: Duration::from_millis(200), poll_size: 0 }, - Arc::new(Mutex::new(MockSet)), + let mut gossiper: Gossiper> = Gossiper::new( + Config { + namespace: "test".to_string(), + frequency: Duration::from_millis(200), + poll_size: 0, + }, + Arc::new(Mutex::new(MockSet { + set: Vec::new(), + bloom: BloomFilter::new(100, 0.5), + })), Arc::new(Client {}), stop_rx, ); - gossiper.handle_response(Id::default(), vec![0u8; 16], None).await; + let mut pull_gossip_response = PullGossipResponse::default(); + let gossip_data: Vec = vec![1, 2, 3, 4, 5]; + let another_gossip_data: Vec = vec![6, 7, 8, 9, 10]; + pull_gossip_response.gossip.push(gossip_data); + pull_gossip_response.gossip.push(another_gossip_data); + let mut response_bytes: Vec = vec![]; + pull_gossip_response + .encode(&mut response_bytes) + .expect("Encoding failed"); - testing_logger::validate(|captured_logs| { - assert_eq!(captured_logs.len(), 1); - assert_eq!(captured_logs[0].body, "failed to unmarshal gossip response, error: DecodeError { description: \"invalid tag value: 0\", stack: [] }"); - }) + gossiper + .handle_response(Id::default(), response_bytes, None) + .await; + + let read_guard = gossiper.set.lock().expect("Failed to acquire lock"); + + assert!(read_guard.len() == 2); } } diff --git a/core/network/src/p2p/gossip/mod.rs b/core/network/src/p2p/gossip/mod.rs index 3007319..5d90d6e 100644 --- a/core/network/src/p2p/gossip/mod.rs +++ b/core/network/src/p2p/gossip/mod.rs @@ -1,5 +1,5 @@ -pub mod gossip; pub mod bloom; +pub mod gossip; use avalanche_types::ids::Id; @@ -13,4 +13,4 @@ pub trait Set: Send + Sync { fn add(&mut self, gossipable: T) -> Result<(), Box>; fn iterate(&self, f: &dyn Fn(&T) -> bool); fn get_filter(&self) -> Result<(Vec, Vec), Box>; -} \ No newline at end of file +} diff --git a/core/network/src/p2p/mod.rs b/core/network/src/p2p/mod.rs index 8d2a289..ea471ec 100644 --- a/core/network/src/p2p/mod.rs +++ b/core/network/src/p2p/mod.rs @@ -1,3 +1,3 @@ -pub mod gossip; pub mod client; +pub mod gossip; pub mod sdk; From 3c3e13821f27b7bdfc21f9952f9c942fbe316f70 Mon Sep 17 00:00:00 2001 From: sanghren Date: Tue, 12 Sep 2023 18:44:39 +0200 Subject: [PATCH 17/53] feat: remove warning debug print --- core/network/build.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/core/network/build.rs b/core/network/build.rs index d66f9a0..4c06fdc 100644 --- a/core/network/build.rs +++ b/core/network/build.rs @@ -7,5 +7,4 @@ fn main() { .compile(&["./src/p2p/gossip/sdk.proto"], &["./src/p2p/gossip/"]) .unwrap(); - println!("cargo:warning={:?}", std::env::var("OUT_DIR")); } From c63269cadd9d4ec126e78bd317ca47ccc3b8064e Mon Sep 17 00:00:00 2001 From: sanghren Date: Wed, 13 Sep 2023 19:04:41 +0200 Subject: [PATCH 18/53] feat: add handler.rs --- core/network/src/p2p/gossip/bloom.rs | 16 +++-- core/network/src/p2p/gossip/gossip.rs | 2 +- core/network/src/p2p/gossip/handler.rs | 89 ++++++++++++++++++++++++++ core/network/src/p2p/gossip/mod.rs | 3 +- core/network/src/p2p/handler.rs | 45 +++++++++++++ core/network/src/p2p/mod.rs | 1 + 6 files changed, 150 insertions(+), 6 deletions(-) create mode 100644 core/network/src/p2p/gossip/handler.rs create mode 100644 core/network/src/p2p/handler.rs diff --git a/core/network/src/p2p/gossip/bloom.rs b/core/network/src/p2p/gossip/bloom.rs index 2c03df8..b05f5a4 100644 --- a/core/network/src/p2p/gossip/bloom.rs +++ b/core/network/src/p2p/gossip/bloom.rs @@ -5,14 +5,15 @@ use probabilistic_collections::bloom::BloomFilter; use proptest::prelude::*; use proptest::proptest; use std::error::Error; +use serde::Deserialize; #[derive(Debug)] pub struct Bloom { - bloom: BloomFilter, - salt: Id, + pub bloom: BloomFilter, + pub salt: Id, } -#[derive(Debug, Hash)] +#[derive(Debug, Hash, Deserialize)] pub struct Hasher { hash: Vec, salt: Id, @@ -27,6 +28,13 @@ impl Bloom { salt, } } + pub fn new_bloom_filter_with_salt(max_expected_elements: usize, false_positive_probability: f64, salt: Id) -> Self { + + Bloom { + bloom: BloomFilter::new(max_expected_elements, false_positive_probability), + salt, + } + } pub fn add(&mut self, gossipable: impl Gossipable) { let id = gossipable.get_id(); @@ -39,7 +47,7 @@ impl Bloom { self.bloom.insert(&salted) } - pub fn has(&self, gossipable: &impl Gossipable) -> bool { + pub fn has(&self, gossipable: &(impl Gossipable + ?Sized)) -> bool { let id = gossipable.get_id(); let salted = Hasher { diff --git a/core/network/src/p2p/gossip/gossip.rs b/core/network/src/p2p/gossip/gossip.rs index de99d93..c9b9a5a 100644 --- a/core/network/src/p2p/gossip/gossip.rs +++ b/core/network/src/p2p/gossip/gossip.rs @@ -186,7 +186,7 @@ impl Set for MockSet { Ok(()) } - fn iterate(&self, _f: &dyn Fn(&T) -> bool) { + fn iterate(&self, _f: &dyn FnMut(&T) -> bool) { // Do nothing } diff --git a/core/network/src/p2p/gossip/handler.rs b/core/network/src/p2p/gossip/handler.rs new file mode 100644 index 0000000..8d60393 --- /dev/null +++ b/core/network/src/p2p/gossip/handler.rs @@ -0,0 +1,89 @@ +use std::error::Error; +use std::marker::PhantomData; +use std::sync::{Arc, Mutex}; +use std::time::Duration; +use probabilistic_collections::bloom::BloomFilter; +use prost::Message; +use avalanche_types::ids::node::Id; +use crate::p2p; +use crate::p2p::gossip::{Gossipable, Set}; +use crate::p2p::gossip::bloom::{Bloom, Hasher}; +use crate::p2p::sdk::PullGossipRequest; + +pub struct HandlerConfig { + pub namespace: String, + pub target_response_size: usize, +} + +pub struct Handler> { + pub handler: Arc, + set: Arc>, + target_response_size: usize, + phantom: PhantomData, +} + +pub fn new>( + config: HandlerConfig, + set: Arc>, +) -> Handler { + Handler { + handler: Arc::new(p2p::handler::NoOpHandler {}), + set, + target_response_size: config.target_response_size, + phantom: PhantomData::default(), + } +} + +impl p2p::handler::Handler for Handler + where + T: Gossipable + Default, + S: Set, +{ + fn app_gossip(&self, node_id: Id, gossip_bytes: Vec) -> Result<(), Box> { + todo!() + } + + fn app_request( + &self, + node_id: Id, + deadline: Duration, + request_bytes: Vec, + ) -> Result, Box> { + let mut request = PullGossipRequest::default(); + request = PullGossipRequest::decode(request_bytes.as_slice()).expect("Failed to decode request_bytes"); + + let salt = avalanche_types::ids::Id::from_slice(request.salt.as_slice()); + + //ToDo not sure about this ? + let mut filter = Bloom::new_bloom_filter_with_salt(100, 0.5, salt); + + //ToDo Am not sure this does exactly what the equivalent gocode does. + let de_filter: BloomFilter = bincode::deserialize(&request_bytes).unwrap(); + + filter.bloom = de_filter; + + let mut response_size = 0_usize; + let mut gossip_bytes: Vec> = Vec::new(); + + self.set.lock().expect("Failed to lock").iterate(&|gossipable| { + if filter.has(gossipable) { return true; } + + let bytes = match gossipable.marshal() { + Ok(b) => b, + Err(_) => return false, + }; + + gossip_bytes.push(bytes.clone()); + response_size += bytes.len(); + + response_size <= self.target_response_size + }); + + + todo!() + } + + fn cross_chain_app_request(&self, chain_id: Id, deadline: Duration, request_bytes: Vec) -> Result, Box> { + todo!() + } +} \ No newline at end of file diff --git a/core/network/src/p2p/gossip/mod.rs b/core/network/src/p2p/gossip/mod.rs index 5d90d6e..79b99d2 100644 --- a/core/network/src/p2p/gossip/mod.rs +++ b/core/network/src/p2p/gossip/mod.rs @@ -1,5 +1,6 @@ pub mod bloom; pub mod gossip; +pub mod handler; use avalanche_types::ids::Id; @@ -11,6 +12,6 @@ pub trait Gossipable { pub trait Set: Send + Sync { fn add(&mut self, gossipable: T) -> Result<(), Box>; - fn iterate(&self, f: &dyn Fn(&T) -> bool); + fn iterate(&self, f: &dyn FnMut(&T) -> bool); fn get_filter(&self) -> Result<(Vec, Vec), Box>; } diff --git a/core/network/src/p2p/handler.rs b/core/network/src/p2p/handler.rs new file mode 100644 index 0000000..15d1f6c --- /dev/null +++ b/core/network/src/p2p/handler.rs @@ -0,0 +1,45 @@ +use std::error::Error; +use std::time::Duration; +use avalanche_types::ids::node::Id; + +pub trait Handler { + // AppGossip is called when handling an AppGossip message. + fn app_gossip( + &self, + node_id: Id, + gossip_bytes: Vec, + ) -> Result<(), Box>; + + // AppRequest is called when handling an AppRequest message. + // Returns the bytes for the response corresponding to request_bytes + fn app_request( + &self, + node_id: Id, + deadline: Duration, + request_bytes: Vec, + ) -> Result, Box>; + + // CrossChainAppRequest is called when handling a CrossChainAppRequest message. + // Returns the bytes for the response corresponding to request_bytes + fn cross_chain_app_request( + &self, + chain_id: Id, + deadline: Duration, + request_bytes: Vec, + ) -> Result, Box>; +} + +// NoOpHandler struct +pub struct NoOpHandler; + +impl Handler for NoOpHandler { + fn app_gossip(&self, _: Id, _: Vec) -> Result<(), Box> { + Ok(()) + } + fn app_request(&self, _: Id, _: Duration, _: Vec) -> Result, Box> { + Ok(vec![]) + } + fn cross_chain_app_request(&self, _: Id, _: Duration, _: Vec) -> Result, Box> { + Ok(vec![]) + } +} diff --git a/core/network/src/p2p/mod.rs b/core/network/src/p2p/mod.rs index ea471ec..eef23d2 100644 --- a/core/network/src/p2p/mod.rs +++ b/core/network/src/p2p/mod.rs @@ -1,3 +1,4 @@ pub mod client; pub mod gossip; pub mod sdk; +pub mod handler; From 476016a4efc0334c8e9eba1cf5cb527ff659112a Mon Sep 17 00:00:00 2001 From: sanghren Date: Wed, 13 Sep 2023 19:06:55 +0200 Subject: [PATCH 19/53] feat: cargo.toml dep --- core/network/Cargo.toml | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/core/network/Cargo.toml b/core/network/Cargo.toml index 11fb402..4515e26 100644 --- a/core/network/Cargo.toml +++ b/core/network/Cargo.toml @@ -12,25 +12,42 @@ readme = "README.md" [dependencies] avalanche-types = { path = "../../crates/avalanche-types", features = ["message"] } +byteorder = "1.4.3" cert-manager = "0.0.10" # https://github.com/gyuho/cert-manager log = "0.4.20" -rustls = { version = "0.21.5", features = ["logging", "dangerous_configuration"]} # https://github.com/rustls/rustls/tags +rustls = { version = "0.21.5", features = ["logging", "dangerous_configuration"] } # https://github.com/rustls/rustls/tags rcgen = "0.10.0" hyper-rustls = "0.24.1" +random-manager = "0.0.5" rustls-native-certs = "0.6.3" +probabilistic-collections = { version = "0.7.0", features = ["serde"] } hyper = { version = "0.14.27", features = ["full"], optional = true } tokio-rustls = { version = "0.24.1", optional = true } +tokio = { version = "1.32.0", features = ["full"] } +prost = "0.12.0" +prost-types = "0.12.0" +prost-build = "0.12.0" +bincode = "1.3.3" +serde = { version = "1.0.188", features = ["derive"] } # for feature "pem" pem = { version = "3.0.0", optional = true } # https://github.com/jcreekmore/pem-rs + [dev-dependencies] env_logger = "0.10.0" -random-manager = "0.0.5" +mockall = "0.11.4" +proptest = "1.2.0" +testing_logger = "0.1.1" tokio = { version = "1.32.0", features = ["full"] } tracing = "0.1.37" tracing-subscriber = "0.3.17" +[build-dependencies] +# ref. https://github.com/hyperium/tonic/tags +# ref. https://github.com/hyperium/tonic/tree/master/tonic-build +tonic-build = "0.9.2" + [features] default = ["rustls", "pem_encoding"] rustls = ["hyper", "tokio-rustls"] From 139dacb8b1c66d65f60fb3c1adcabc26c2697e33 Mon Sep 17 00:00:00 2001 From: sanghren Date: Thu, 14 Sep 2023 08:18:18 +0200 Subject: [PATCH 20/53] feat: cargo.toml dep --- core/network/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/network/Cargo.toml b/core/network/Cargo.toml index 4515e26..f24a6a7 100644 --- a/core/network/Cargo.toml +++ b/core/network/Cargo.toml @@ -18,7 +18,6 @@ log = "0.4.20" rustls = { version = "0.21.5", features = ["logging", "dangerous_configuration"] } # https://github.com/rustls/rustls/tags rcgen = "0.10.0" hyper-rustls = "0.24.1" -random-manager = "0.0.5" rustls-native-certs = "0.6.3" probabilistic-collections = { version = "0.7.0", features = ["serde"] } hyper = { version = "0.14.27", features = ["full"], optional = true } @@ -38,6 +37,7 @@ pem = { version = "3.0.0", optional = true } # https://github.com/jcreekmore/pem env_logger = "0.10.0" mockall = "0.11.4" proptest = "1.2.0" +random-manager = "0.0.5" testing_logger = "0.1.1" tokio = { version = "1.32.0", features = ["full"] } tracing = "0.1.37" From b9fc9eca27114529971e9a5a0354aa51767ca755 Mon Sep 17 00:00:00 2001 From: sanghren Date: Thu, 14 Sep 2023 08:19:27 +0200 Subject: [PATCH 21/53] feat: lint --- core/network/src/p2p/gossip/bloom.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/core/network/src/p2p/gossip/bloom.rs b/core/network/src/p2p/gossip/bloom.rs index b05f5a4..9494543 100644 --- a/core/network/src/p2p/gossip/bloom.rs +++ b/core/network/src/p2p/gossip/bloom.rs @@ -28,6 +28,7 @@ impl Bloom { salt, } } + pub fn new_bloom_filter_with_salt(max_expected_elements: usize, false_positive_probability: f64, salt: Id) -> Self { Bloom { From a6063518cea30f5df200bd24035cb532b0282819 Mon Sep 17 00:00:00 2001 From: sanghren Date: Thu, 14 Sep 2023 08:33:20 +0200 Subject: [PATCH 22/53] feat: finish handler accept_request --- core/network/src/p2p/gossip/handler.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/core/network/src/p2p/gossip/handler.rs b/core/network/src/p2p/gossip/handler.rs index 8d60393..94938fb 100644 --- a/core/network/src/p2p/gossip/handler.rs +++ b/core/network/src/p2p/gossip/handler.rs @@ -3,13 +3,14 @@ use std::marker::PhantomData; use std::sync::{Arc, Mutex}; use std::time::Duration; use probabilistic_collections::bloom::BloomFilter; -use prost::Message; +// use prost::bytes::BufMut; +use prost::{bytes, Message}; use avalanche_types::ids::node::Id; use crate::p2p; use crate::p2p::gossip::{Gossipable, Set}; use crate::p2p::gossip::bloom::{Bloom, Hasher}; -use crate::p2p::sdk::PullGossipRequest; - +use crate::p2p::sdk::{PullGossipRequest, PullGossipResponse}; +use bytes::BufMut; pub struct HandlerConfig { pub namespace: String, pub target_response_size: usize, @@ -79,8 +80,13 @@ impl p2p::handler::Handler for Handler response_size <= self.target_response_size }); + let mut response = PullGossipResponse::default(); + response.gossip = gossip_bytes; - todo!() + let mut response_bytes = vec![]; + response.encode(&mut response_bytes).expect("s"); + + Ok(response_bytes) } fn cross_chain_app_request(&self, chain_id: Id, deadline: Duration, request_bytes: Vec) -> Result, Box> { From 573db1175f0a274eb4cfa6738e6d1a50f475df34 Mon Sep 17 00:00:00 2001 From: sanghren Date: Thu, 14 Sep 2023 08:41:55 +0200 Subject: [PATCH 23/53] feat: unused app-request param --- core/network/src/p2p/gossip/handler.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/network/src/p2p/gossip/handler.rs b/core/network/src/p2p/gossip/handler.rs index 94938fb..ccb4ad7 100644 --- a/core/network/src/p2p/gossip/handler.rs +++ b/core/network/src/p2p/gossip/handler.rs @@ -46,8 +46,8 @@ impl p2p::handler::Handler for Handler fn app_request( &self, - node_id: Id, - deadline: Duration, + _: Id, + _: Duration, request_bytes: Vec, ) -> Result, Box> { let mut request = PullGossipRequest::default(); From f1b752a7a5a9aae3e06ad2e8312fc5834da9ac77 Mon Sep 17 00:00:00 2001 From: sanghren Date: Thu, 14 Sep 2023 09:05:54 +0200 Subject: [PATCH 24/53] feat: put tests under mod test --- core/network/src/p2p/gossip/bloom.rs | 42 +++--- core/network/src/p2p/gossip/gossip.rs | 189 ++++++++++++++------------ 2 files changed, 124 insertions(+), 107 deletions(-) diff --git a/core/network/src/p2p/gossip/bloom.rs b/core/network/src/p2p/gossip/bloom.rs index 9494543..999a3cf 100644 --- a/core/network/src/p2p/gossip/bloom.rs +++ b/core/network/src/p2p/gossip/bloom.rs @@ -3,7 +3,6 @@ use avalanche_types::ids::{Id, LEN}; use byteorder::{BigEndian, ByteOrder}; use probabilistic_collections::bloom::BloomFilter; use proptest::prelude::*; -use proptest::proptest; use std::error::Error; use serde::Deserialize; @@ -30,7 +29,6 @@ impl Bloom { } pub fn new_bloom_filter_with_salt(max_expected_elements: usize, false_positive_probability: f64, salt: Id) -> Self { - Bloom { bloom: BloomFilter::new(max_expected_elements, false_positive_probability), salt, @@ -116,26 +114,35 @@ impl Hasher { } } -#[derive(Debug, Clone)] -struct TestTx { - pub id: Id, -} - -impl Gossipable for TestTx { - fn get_id(&self) -> Id { - self.id +#[cfg(test)] +mod test { + use std::error::Error; + use proptest::proptest; + use avalanche_types::ids::Id; + use crate::p2p::gossip::Gossipable; + use proptest::prelude::*; + use crate::p2p::gossip::bloom::*; + + #[derive(Debug, Clone)] + struct TestTx { + pub id: Id, } - fn marshal(&self) -> Result, Box> { - todo!() - } + impl Gossipable for TestTx { + fn get_id(&self) -> Id { + self.id + } - fn unmarshal(&mut self, bytes: &[u8]) -> Result<(), Box> { - todo!() + fn marshal(&self) -> Result, Box> { + todo!() + } + + fn unmarshal(&mut self, bytes: &[u8]) -> Result<(), Box> { + todo!() + } } -} -proptest! { + proptest! { #![proptest_config(ProptestConfig { cases: 100, // Need 100 successful test cases .. ProptestConfig::default() @@ -165,3 +172,4 @@ proptest! { } } } +} diff --git a/core/network/src/p2p/gossip/gossip.rs b/core/network/src/p2p/gossip/gossip.rs index c9b9a5a..f37f79d 100644 --- a/core/network/src/p2p/gossip/gossip.rs +++ b/core/network/src/p2p/gossip/gossip.rs @@ -29,9 +29,9 @@ pub struct Gossiper> { } impl Gossiper -where - T: Gossipable + Default, - S: Set, + where + T: Gossipable + Default, + S: Set, { pub fn new( config: Config, @@ -135,112 +135,121 @@ where } } -struct MockClient; -#[derive(Clone, Hash)] -struct TestGossipableType { - pub id: Id, -} +#[cfg(test)] +mod test { + use std::sync::{Arc, Mutex}; + use tokio::sync::mpsc::{channel}; + use std::time::Duration; + use probabilistic_collections::bloom::BloomFilter; + use super::*; + use testing_logger; + use avalanche_types::ids::Id; + use crate::p2p::client::Client; + use crate::p2p::gossip::gossip::{Config, Gossiper}; + use crate::p2p::sdk::PullGossipResponse; -impl Default for TestGossipableType { - fn default() -> Self { - TestGossipableType { - id: Default::default(), - } - } -} + struct MockClient; -impl Gossipable for TestGossipableType { - fn get_id(&self) -> Id { - self.id + #[derive(Clone, Hash)] + struct TestGossipableType { + pub id: Id, } - fn marshal(&self) -> Result, Box> { - Ok(self.id.to_vec()) + impl Default for TestGossipableType { + fn default() -> Self { + TestGossipableType { + id: Default::default(), + } + } } - fn unmarshal(&mut self, bytes: &[u8]) -> Result<(), Box> { - self.id = Id::from_slice(bytes); - Ok(()) - } -} + impl Gossipable for TestGossipableType { + fn get_id(&self) -> Id { + self.id + } -// Mock implementation for the Set trait -//ToDo Should we move all tests to a new file ? -struct MockSet { - pub set: Vec, - pub bloom: BloomFilter, -} + fn marshal(&self) -> Result, Box> { + Ok(self.id.to_vec()) + } -impl MockSet { - pub fn len(&self) -> usize { - println!("{}", self.set.len()); - self.set.len() + fn unmarshal(&mut self, bytes: &[u8]) -> Result<(), Box> { + self.id = Id::from_slice(bytes); + Ok(()) + } } -} -impl Set for MockSet { - fn add(&mut self, _gossipable: T) -> Result<(), Box> { - self.set.push(_gossipable.clone()); - self.bloom.insert(&_gossipable.clone()); - Ok(()) + // Mock implementation for the Set trait +//ToDo Should we move all tests to a new file ? + struct MockSet { + pub set: Vec, + pub bloom: BloomFilter, } - fn iterate(&self, _f: &dyn FnMut(&T) -> bool) { - // Do nothing + impl MockSet { + pub fn len(&self) -> usize { + println!("{}", self.set.len()); + self.set.len() + } } - fn get_filter(&self) -> Result<(Vec, Vec), Box> { - Ok((vec![], vec![])) - } -} + impl Set for MockSet { + fn add(&mut self, _gossipable: T) -> Result<(), Box> { + self.set.push(_gossipable.clone()); + self.bloom.insert(&_gossipable.clone()); + Ok(()) + } -/// RUST_LOG=debug cargo test --package network --lib -- p2p::gossip::test_gossip_shutdown --exact --show-output -#[tokio::test] -async fn test_gossip_shutdown() { - let _ = env_logger::builder() - .filter_level(log::LevelFilter::Debug) - .is_test(true) - .try_init() - .unwrap(); - - let (stop_tx, stop_rx) = channel(1); // Create a new channel - - let mut gossiper: Gossiper> = Gossiper::new( - Config { - namespace: "test".to_string(), - frequency: Duration::from_millis(200), - poll_size: 0, - }, - Arc::new(Mutex::new(MockSet { - set: Vec::new(), - bloom: BloomFilter::new(100, 0.5), - })), - Arc::new(Client {}), - stop_rx, - ); - - // Spawn the gossiping task - let gossip_task = tokio::spawn(async move { - gossiper.gossip().await; - }); - - // Wait some time to let a few cycles of gossiping happen - tokio::time::sleep(Duration::from_secs(5)).await; - - // Send the stop signal before awaiting the task. - if stop_tx.send(()).await.is_err() { - panic!("Failed to send stop signal"); + fn iterate(&self, _f: &dyn FnMut(&T) -> bool) { + // Do nothing + } + + fn get_filter(&self) -> Result<(Vec, Vec), Box> { + Ok((vec![], vec![])) + } } - // Await the gossip task. - let _ = gossip_task.await.expect("Gossip task failed"); -} + /// RUST_LOG=debug cargo test --package network --lib -- p2p::gossip::test_gossip_shutdown --exact --show-output + #[tokio::test] + async fn test_gossip_shutdown() { + let _ = env_logger::builder() + .filter_level(log::LevelFilter::Debug) + .is_test(true) + .try_init() + .unwrap(); -#[cfg(test)] -mod tests { - use super::*; - use testing_logger; + let (stop_tx, stop_rx) = channel(1); // Create a new channel + + let mut gossiper: Gossiper> = Gossiper::new( + Config { + namespace: "test".to_string(), + frequency: Duration::from_millis(200), + poll_size: 0, + }, + Arc::new(Mutex::new(MockSet { + set: Vec::new(), + bloom: BloomFilter::new(100, 0.5), + })), + Arc::new(Client {}), + stop_rx, + ); + + // Spawn the gossiping task + let gossip_task = tokio::spawn(async move { + gossiper.gossip().await; + }); + + // Wait some time to let a few cycles of gossiping happen + tokio::time::sleep(Duration::from_secs(5)).await; + + // Send the stop signal before awaiting the task. + if stop_tx.send(()).await.is_err() { + panic!("Failed to send stop signal"); + } + + // Await the gossip task. + let _ = gossip_task.await.expect("Gossip task failed"); + } #[tokio::test] async fn test_handle_response_with_empty_response_bytes() { From bbf1488ea1ca58e75f3d420225f7dd0cafdd7cdc Mon Sep 17 00:00:00 2001 From: sanghren Date: Fri, 15 Sep 2023 09:31:59 +0200 Subject: [PATCH 25/53] feat: clean up --- core/network/src/p2p/gossip/bloom.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/network/src/p2p/gossip/bloom.rs b/core/network/src/p2p/gossip/bloom.rs index 999a3cf..a2067f4 100644 --- a/core/network/src/p2p/gossip/bloom.rs +++ b/core/network/src/p2p/gossip/bloom.rs @@ -46,7 +46,7 @@ impl Bloom { self.bloom.insert(&salted) } - pub fn has(&self, gossipable: &(impl Gossipable + ?Sized)) -> bool { + pub fn has(&self, gossipable: &(impl Gossipable)) -> bool { let id = gossipable.get_id(); let salted = Hasher { From 5654fb1222075b2d7280d068dfb2169882fa838c Mon Sep 17 00:00:00 2001 From: sanghren Date: Fri, 15 Sep 2023 09:34:31 +0200 Subject: [PATCH 26/53] feat: pass reference to bloom.has --- core/network/src/p2p/gossip/bloom.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/network/src/p2p/gossip/bloom.rs b/core/network/src/p2p/gossip/bloom.rs index a2067f4..5c1bace 100644 --- a/core/network/src/p2p/gossip/bloom.rs +++ b/core/network/src/p2p/gossip/bloom.rs @@ -46,7 +46,7 @@ impl Bloom { self.bloom.insert(&salted) } - pub fn has(&self, gossipable: &(impl Gossipable)) -> bool { + pub fn has(&self, gossipable: &T) -> bool { let id = gossipable.get_id(); let salted = Hasher { From 20db9328c2f6542926348a90bfa762db7fc2f95a Mon Sep 17 00:00:00 2001 From: sanghren Date: Fri, 15 Sep 2023 09:36:22 +0200 Subject: [PATCH 27/53] feat: clean up --- core/network/src/p2p/gossip/bloom.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/network/src/p2p/gossip/bloom.rs b/core/network/src/p2p/gossip/bloom.rs index 5c1bace..bcc153c 100644 --- a/core/network/src/p2p/gossip/bloom.rs +++ b/core/network/src/p2p/gossip/bloom.rs @@ -35,7 +35,7 @@ impl Bloom { } } - pub fn add(&mut self, gossipable: impl Gossipable) { + pub fn add(&mut self, gossipable: T) { let id = gossipable.get_id(); let salted = Hasher { From 27df6681b3361c8375e413beb458a749c87810ef Mon Sep 17 00:00:00 2001 From: sanghren Date: Fri, 15 Sep 2023 20:39:27 +0200 Subject: [PATCH 28/53] feat: address comments --- core/network/src/p2p/gossip/bloom.rs | 4 ++-- core/network/src/p2p/gossip/gossip.rs | 11 +++++------ core/network/src/p2p/gossip/handler.rs | 2 +- core/network/src/p2p/gossip/mod.rs | 4 ++-- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/core/network/src/p2p/gossip/bloom.rs b/core/network/src/p2p/gossip/bloom.rs index bcc153c..4d4a79e 100644 --- a/core/network/src/p2p/gossip/bloom.rs +++ b/core/network/src/p2p/gossip/bloom.rs @@ -133,11 +133,11 @@ mod test { self.id } - fn marshal(&self) -> Result, Box> { + fn serialize(&self) -> Result, Box> { todo!() } - fn unmarshal(&mut self, bytes: &[u8]) -> Result<(), Box> { + fn deserialize(&mut self, bytes: &[u8]) -> Result<(), Box> { todo!() } } diff --git a/core/network/src/p2p/gossip/gossip.rs b/core/network/src/p2p/gossip/gossip.rs index f37f79d..d6cc99f 100644 --- a/core/network/src/p2p/gossip/gossip.rs +++ b/core/network/src/p2p/gossip/gossip.rs @@ -54,7 +54,7 @@ impl Gossiper loop { select! { _ = gossip_ticker.tick() => { - if let Err(e) = self.execute_gossip().await { + if let Err(e) = self.execute().await { error!("Failed to Gossip : {:?}", e); //ToDo @@ -68,8 +68,7 @@ impl Gossiper } } - // ToDo Maybe there is a better name here - async fn execute_gossip(&self) -> Result<(), Box> { + async fn execute(&self) -> Result<(), Box> { let read_guard = self.set.lock().expect("Failed to acquire lock"); let (bloom, salt) = read_guard.get_filter()?; let request = PullGossipRequest { @@ -112,7 +111,7 @@ impl Gossiper for bytes in response.gossip.iter() { let mut gossipable: T = T::default(); - if let Err(e) = gossipable.unmarshal(bytes) { + if let Err(e) = gossipable.deserialize(bytes) { error!( "failed to unmarshal gossip, nodeID: {:?}, error: {:?}", node_id, e @@ -169,11 +168,11 @@ mod test { self.id } - fn marshal(&self) -> Result, Box> { + fn serialize(&self) -> Result, Box> { Ok(self.id.to_vec()) } - fn unmarshal(&mut self, bytes: &[u8]) -> Result<(), Box> { + fn deserialize(&mut self, bytes: &[u8]) -> Result<(), Box> { self.id = Id::from_slice(bytes); Ok(()) } diff --git a/core/network/src/p2p/gossip/handler.rs b/core/network/src/p2p/gossip/handler.rs index ccb4ad7..aefcadb 100644 --- a/core/network/src/p2p/gossip/handler.rs +++ b/core/network/src/p2p/gossip/handler.rs @@ -69,7 +69,7 @@ impl p2p::handler::Handler for Handler self.set.lock().expect("Failed to lock").iterate(&|gossipable| { if filter.has(gossipable) { return true; } - let bytes = match gossipable.marshal() { + let bytes = match gossipable.serialize() { Ok(b) => b, Err(_) => return false, }; diff --git a/core/network/src/p2p/gossip/mod.rs b/core/network/src/p2p/gossip/mod.rs index 79b99d2..d731b5a 100644 --- a/core/network/src/p2p/gossip/mod.rs +++ b/core/network/src/p2p/gossip/mod.rs @@ -6,8 +6,8 @@ use avalanche_types::ids::Id; pub trait Gossipable { fn get_id(&self) -> Id; - fn marshal(&self) -> Result, Box>; - fn unmarshal(&mut self, bytes: &[u8]) -> Result<(), Box>; + fn serialize(&self) -> Result, Box>; + fn deserialize(&mut self, bytes: &[u8]) -> Result<(), Box>; } pub trait Set: Send + Sync { From 0c446e9271ca0e83bb88a36331d79bbabf4d1788 Mon Sep 17 00:00:00 2001 From: sanghren Date: Fri, 15 Sep 2023 22:37:56 +0200 Subject: [PATCH 29/53] feat: address comments --- core/network/src/p2p/gossip/bloom.rs | 175 ------------------------- core/network/src/p2p/gossip/gossip.rs | 84 ++---------- core/network/src/p2p/gossip/handler.rs | 49 ++----- core/network/src/p2p/gossip/mod.rs | 9 +- 4 files changed, 21 insertions(+), 296 deletions(-) delete mode 100644 core/network/src/p2p/gossip/bloom.rs diff --git a/core/network/src/p2p/gossip/bloom.rs b/core/network/src/p2p/gossip/bloom.rs deleted file mode 100644 index 4d4a79e..0000000 --- a/core/network/src/p2p/gossip/bloom.rs +++ /dev/null @@ -1,175 +0,0 @@ -use crate::p2p::gossip::Gossipable; -use avalanche_types::ids::{Id, LEN}; -use byteorder::{BigEndian, ByteOrder}; -use probabilistic_collections::bloom::BloomFilter; -use proptest::prelude::*; -use std::error::Error; -use serde::Deserialize; - -#[derive(Debug)] -pub struct Bloom { - pub bloom: BloomFilter, - pub salt: Id, -} - -#[derive(Debug, Hash, Deserialize)] -pub struct Hasher { - hash: Vec, - salt: Id, -} - -impl Bloom { - pub fn new_bloom_filter(max_expected_elements: usize, false_positive_probability: f64) -> Self { - let salt = random_salt(); - - Bloom { - bloom: BloomFilter::new(max_expected_elements, false_positive_probability), - salt, - } - } - - pub fn new_bloom_filter_with_salt(max_expected_elements: usize, false_positive_probability: f64, salt: Id) -> Self { - Bloom { - bloom: BloomFilter::new(max_expected_elements, false_positive_probability), - salt, - } - } - - pub fn add(&mut self, gossipable: T) { - let id = gossipable.get_id(); - - let salted = Hasher { - hash: id.to_vec(), - salt: self.salt, - }; - - self.bloom.insert(&salted) - } - - pub fn has(&self, gossipable: &T) -> bool { - let id = gossipable.get_id(); - - let salted = Hasher { - hash: id.to_vec(), - salt: self.salt, - }; - - self.bloom.contains(&salted) - } -} - -pub fn reset_bloom_filter_if_needed( - bloom_filter: &mut Bloom, - false_positive_probability: f64, -) -> bool { - if bloom_filter.bloom.estimated_fpp() < false_positive_probability { - return false; - } - - let new_bloom_filter = BloomFilter::new(bloom_filter.bloom.len(), false_positive_probability); - let salt = random_salt(); - - bloom_filter.bloom = new_bloom_filter; - bloom_filter.salt = salt; - true -} - -fn random_salt() -> Id { - let random_32_bytes = random_manager::secure_bytes(32).unwrap(); - let salt: Id = Id::from_slice(random_32_bytes.as_slice()); - salt -} - -impl Hasher { - pub fn write(&mut self, p: &[u8]) -> Result { - self.hash.extend_from_slice(p); - Ok(p.len()) - } - - pub fn sum(&mut self, b: &[u8]) -> Vec { - self.hash.extend_from_slice(b); - self.hash.clone() - } - - pub fn reset(&mut self) { - self.hash = vec![0; LEN]; - } - - pub fn block_size() -> usize { - LEN - } - - pub fn sum64(&self) -> u64 { - let mut salted = [0u8; LEN]; - - for i in 0..std::cmp::min(self.hash.len(), LEN) { - salted[i] = self.hash[i] ^ self.salt.to_vec().get(i).unwrap(); - } - - BigEndian::read_u64(&salted[0..8]) - } - - pub fn size(&self) -> usize { - self.hash.len() - } -} - -#[cfg(test)] -mod test { - use std::error::Error; - use proptest::proptest; - use avalanche_types::ids::Id; - use crate::p2p::gossip::Gossipable; - use proptest::prelude::*; - use crate::p2p::gossip::bloom::*; - - #[derive(Debug, Clone)] - struct TestTx { - pub id: Id, - } - - impl Gossipable for TestTx { - fn get_id(&self) -> Id { - self.id - } - - fn serialize(&self) -> Result, Box> { - todo!() - } - - fn deserialize(&mut self, bytes: &[u8]) -> Result<(), Box> { - todo!() - } - } - - proptest! { - #![proptest_config(ProptestConfig { - cases: 100, // Need 100 successful test cases - .. ProptestConfig::default() - })] - - #[test] - fn test_bloom_filter_refresh( - false_positive_probability in 0.0..1.0f64, - txs in proptest::collection::vec(any::<[u8; 32]>(), 0..100) // Will populate txs with 0 to 100 [u8; 32] - ) { - let mut bloom_filter = Bloom::new_bloom_filter(10, 0.01); - let mut expected = vec![]; - - for tx in txs { - let should_reset = reset_bloom_filter_if_needed(&mut bloom_filter, false_positive_probability); - let test_tx = TestTx { id: Id::from_slice(&tx) }; - if should_reset { - expected.clear(); - } - - bloom_filter.add(test_tx.clone()); - expected.push(test_tx.clone()); - - for expected_tx in &expected { - assert!(bloom_filter.has(expected_tx)) - } - } - } -} -} diff --git a/core/network/src/p2p/gossip/gossip.rs b/core/network/src/p2p/gossip/gossip.rs index d6cc99f..d2bd16f 100644 --- a/core/network/src/p2p/gossip/gossip.rs +++ b/core/network/src/p2p/gossip/gossip.rs @@ -1,14 +1,13 @@ use crate::p2p::client::Client; -use crate::p2p::gossip::{Gossipable, Set}; +use crate::p2p::gossip::Gossipable; use crate::p2p::sdk::{PullGossipRequest, PullGossipResponse}; use avalanche_types::ids::Id; use log::{debug, error}; -use probabilistic_collections::bloom::BloomFilter; use prost::Message; use std::error::Error; use std::hash::Hash; use std::marker::PhantomData; -use std::sync::{Arc, Mutex}; +use std::sync::Arc; use std::time::Duration; use tokio::select; use tokio::sync::mpsc::{channel, Receiver}; @@ -20,28 +19,24 @@ pub struct Config { pub poll_size: usize, } -pub struct Gossiper> { +pub struct Gossiper { config: Config, - set: Arc>, client: Arc, stop_rx: Receiver<()>, phantom: PhantomData, // Had to use this to please the compiler about T not being used. } -impl Gossiper +impl Gossiper where T: Gossipable + Default, - S: Set, { pub fn new( config: Config, - set: Arc>, // Mutex or RWLock here ? client: Arc, stop_rx: Receiver<()>, ) -> Self { Self { config, - set, client, stop_rx, phantom: PhantomData, @@ -69,11 +64,12 @@ impl Gossiper } async fn execute(&self) -> Result<(), Box> { - let read_guard = self.set.lock().expect("Failed to acquire lock"); - let (bloom, salt) = read_guard.get_filter()?; + //ToDo Dummy vec for now. + let bloom = Vec::new(); + let request = PullGossipRequest { filter: bloom, - salt, + salt: Id::default().to_vec(), //ToDo Use default for now }; let mut msg_bytes = vec![]; @@ -121,15 +117,6 @@ impl Gossiper let hash = gossipable.get_id(); debug!("received gossip, nodeID: {:?}, id: {:?}", node_id, hash); - - let mut set_guard = self.set.lock().expect("Failed to acquire lock"); - if let Err(e) = set_guard.add(gossipable) { - debug!( - "failed to add gossip to the known set, nodeID: {:?}, id: {:?}, error: {:?}", - node_id, hash, e - ); - continue; - } } } } @@ -137,10 +124,9 @@ impl Gossiper #[cfg(test)] mod test { - use std::sync::{Arc, Mutex}; + use std::sync::Arc; use tokio::sync::mpsc::{channel}; use std::time::Duration; - use probabilistic_collections::bloom::BloomFilter; use super::*; use testing_logger; use avalanche_types::ids::Id; @@ -178,36 +164,6 @@ mod test { } } - // Mock implementation for the Set trait -//ToDo Should we move all tests to a new file ? - struct MockSet { - pub set: Vec, - pub bloom: BloomFilter, - } - - impl MockSet { - pub fn len(&self) -> usize { - println!("{}", self.set.len()); - self.set.len() - } - } - - impl Set for MockSet { - fn add(&mut self, _gossipable: T) -> Result<(), Box> { - self.set.push(_gossipable.clone()); - self.bloom.insert(&_gossipable.clone()); - Ok(()) - } - - fn iterate(&self, _f: &dyn FnMut(&T) -> bool) { - // Do nothing - } - - fn get_filter(&self) -> Result<(Vec, Vec), Box> { - Ok((vec![], vec![])) - } - } - /// RUST_LOG=debug cargo test --package network --lib -- p2p::gossip::test_gossip_shutdown --exact --show-output #[tokio::test] async fn test_gossip_shutdown() { @@ -219,16 +175,12 @@ mod test { let (stop_tx, stop_rx) = channel(1); // Create a new channel - let mut gossiper: Gossiper> = Gossiper::new( + let mut gossiper: Gossiper = Gossiper::new( Config { namespace: "test".to_string(), frequency: Duration::from_millis(200), poll_size: 0, }, - Arc::new(Mutex::new(MockSet { - set: Vec::new(), - bloom: BloomFilter::new(100, 0.5), - })), Arc::new(Client {}), stop_rx, ); @@ -257,16 +209,12 @@ mod test { let (stop_tx, stop_rx) = channel(1); // Create a new channel - let mut gossiper: Gossiper> = Gossiper::new( + let mut gossiper: Gossiper = Gossiper::new( Config { namespace: "test".to_string(), frequency: Duration::from_millis(200), poll_size: 0, }, - Arc::new(Mutex::new(MockSet { - set: Vec::new(), - bloom: BloomFilter::new(100, 0.5), - })), Arc::new(Client {}), stop_rx, ); @@ -288,16 +236,12 @@ mod test { let (stop_tx, stop_rx) = channel(1); // Create a new channel - let mut gossiper: Gossiper> = Gossiper::new( + let mut gossiper: Gossiper = Gossiper::new( Config { namespace: "test".to_string(), frequency: Duration::from_millis(200), poll_size: 0, }, - Arc::new(Mutex::new(MockSet { - set: Vec::new(), - bloom: BloomFilter::new(100, 0.5), - })), Arc::new(Client {}), stop_rx, ); @@ -315,9 +259,5 @@ mod test { gossiper .handle_response(Id::default(), response_bytes, None) .await; - - let read_guard = gossiper.set.lock().expect("Failed to acquire lock"); - - assert!(read_guard.len() == 2); } } diff --git a/core/network/src/p2p/gossip/handler.rs b/core/network/src/p2p/gossip/handler.rs index aefcadb..62669c4 100644 --- a/core/network/src/p2p/gossip/handler.rs +++ b/core/network/src/p2p/gossip/handler.rs @@ -1,44 +1,36 @@ use std::error::Error; use std::marker::PhantomData; -use std::sync::{Arc, Mutex}; +use std::sync::Arc; use std::time::Duration; -use probabilistic_collections::bloom::BloomFilter; -// use prost::bytes::BufMut; -use prost::{bytes, Message}; +use prost::Message; use avalanche_types::ids::node::Id; use crate::p2p; -use crate::p2p::gossip::{Gossipable, Set}; -use crate::p2p::gossip::bloom::{Bloom, Hasher}; +use crate::p2p::gossip::Gossipable; use crate::p2p::sdk::{PullGossipRequest, PullGossipResponse}; -use bytes::BufMut; pub struct HandlerConfig { pub namespace: String, pub target_response_size: usize, } -pub struct Handler> { +pub struct Handler { pub handler: Arc, - set: Arc>, target_response_size: usize, phantom: PhantomData, } -pub fn new>( +pub fn new( config: HandlerConfig, - set: Arc>, -) -> Handler { +) -> Handler { Handler { handler: Arc::new(p2p::handler::NoOpHandler {}), - set, target_response_size: config.target_response_size, phantom: PhantomData::default(), } } -impl p2p::handler::Handler for Handler +impl p2p::handler::Handler for Handler where T: Gossipable + Default, - S: Set, { fn app_gossip(&self, node_id: Id, gossip_bytes: Vec) -> Result<(), Box> { todo!() @@ -53,32 +45,7 @@ impl p2p::handler::Handler for Handler let mut request = PullGossipRequest::default(); request = PullGossipRequest::decode(request_bytes.as_slice()).expect("Failed to decode request_bytes"); - let salt = avalanche_types::ids::Id::from_slice(request.salt.as_slice()); - - //ToDo not sure about this ? - let mut filter = Bloom::new_bloom_filter_with_salt(100, 0.5, salt); - - //ToDo Am not sure this does exactly what the equivalent gocode does. - let de_filter: BloomFilter = bincode::deserialize(&request_bytes).unwrap(); - - filter.bloom = de_filter; - - let mut response_size = 0_usize; - let mut gossip_bytes: Vec> = Vec::new(); - - self.set.lock().expect("Failed to lock").iterate(&|gossipable| { - if filter.has(gossipable) { return true; } - - let bytes = match gossipable.serialize() { - Ok(b) => b, - Err(_) => return false, - }; - - gossip_bytes.push(bytes.clone()); - response_size += bytes.len(); - - response_size <= self.target_response_size - }); + let gossip_bytes: Vec> = Vec::new(); let mut response = PullGossipResponse::default(); response.gossip = gossip_bytes; diff --git a/core/network/src/p2p/gossip/mod.rs b/core/network/src/p2p/gossip/mod.rs index d731b5a..3a99bb2 100644 --- a/core/network/src/p2p/gossip/mod.rs +++ b/core/network/src/p2p/gossip/mod.rs @@ -1,4 +1,3 @@ -pub mod bloom; pub mod gossip; pub mod handler; @@ -8,10 +7,4 @@ pub trait Gossipable { fn get_id(&self) -> Id; fn serialize(&self) -> Result, Box>; fn deserialize(&mut self, bytes: &[u8]) -> Result<(), Box>; -} - -pub trait Set: Send + Sync { - fn add(&mut self, gossipable: T) -> Result<(), Box>; - fn iterate(&self, f: &dyn FnMut(&T) -> bool); - fn get_filter(&self) -> Result<(Vec, Vec), Box>; -} +} \ No newline at end of file From 9e674293524823fa3dde00e5550eebf5150b1439 Mon Sep 17 00:00:00 2001 From: sanghren Date: Fri, 15 Sep 2023 22:40:46 +0200 Subject: [PATCH 30/53] feat: address comments --- core/network/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/network/Cargo.toml b/core/network/Cargo.toml index f24a6a7..a9897da 100644 --- a/core/network/Cargo.toml +++ b/core/network/Cargo.toml @@ -22,7 +22,7 @@ rustls-native-certs = "0.6.3" probabilistic-collections = { version = "0.7.0", features = ["serde"] } hyper = { version = "0.14.27", features = ["full"], optional = true } tokio-rustls = { version = "0.24.1", optional = true } -tokio = { version = "1.32.0", features = ["full"] } +tokio = { version = "1.32.0", features = ["sync", "time"] } prost = "0.12.0" prost-types = "0.12.0" prost-build = "0.12.0" @@ -39,7 +39,7 @@ mockall = "0.11.4" proptest = "1.2.0" random-manager = "0.0.5" testing_logger = "0.1.1" -tokio = { version = "1.32.0", features = ["full"] } +tokio = { version = "1.32.0", features = ["sync", "time"] } tracing = "0.1.37" tracing-subscriber = "0.3.17" From 61c8256f6b6c6f7fd4b10122b55df677b8016153 Mon Sep 17 00:00:00 2001 From: sanghren Date: Fri, 15 Sep 2023 22:55:40 +0200 Subject: [PATCH 31/53] feat: address comments --- core/network/src/p2p/gossip/gossip.rs | 66 ++++++++++++++++++++++---- core/network/src/p2p/gossip/handler.rs | 33 ++++++++++--- core/network/src/p2p/gossip/mod.rs | 7 ++- 3 files changed, 90 insertions(+), 16 deletions(-) diff --git a/core/network/src/p2p/gossip/gossip.rs b/core/network/src/p2p/gossip/gossip.rs index d2bd16f..fb31d12 100644 --- a/core/network/src/p2p/gossip/gossip.rs +++ b/core/network/src/p2p/gossip/gossip.rs @@ -1,5 +1,5 @@ use crate::p2p::client::Client; -use crate::p2p::gossip::Gossipable; +use crate::p2p::gossip::{Gossipable, Set}; use crate::p2p::sdk::{PullGossipRequest, PullGossipResponse}; use avalanche_types::ids::Id; use log::{debug, error}; @@ -7,7 +7,7 @@ use prost::Message; use std::error::Error; use std::hash::Hash; use std::marker::PhantomData; -use std::sync::Arc; +use std::sync::{Arc, Mutex}; use std::time::Duration; use tokio::select; use tokio::sync::mpsc::{channel, Receiver}; @@ -19,24 +19,28 @@ pub struct Config { pub poll_size: usize, } -pub struct Gossiper { +pub struct Gossiper> { config: Config, + set: Arc>, client: Arc, stop_rx: Receiver<()>, phantom: PhantomData, // Had to use this to please the compiler about T not being used. } -impl Gossiper +impl Gossiper where T: Gossipable + Default, + S: Set, { pub fn new( config: Config, + set: Arc>, // Mutex or RWLock here ? client: Arc, stop_rx: Receiver<()>, ) -> Self { Self { config, + set, client, stop_rx, phantom: PhantomData, @@ -117,6 +121,15 @@ impl Gossiper let hash = gossipable.get_id(); debug!("received gossip, nodeID: {:?}, id: {:?}", node_id, hash); + + let mut set_guard = self.set.lock().expect("Failed to acquire lock"); + if let Err(e) = set_guard.add(gossipable) { + debug!( + "failed to add gossip to the known set, nodeID: {:?}, id: {:?}, error: {:?}", + node_id, hash, e + ); + continue; + } } } } @@ -124,7 +137,7 @@ impl Gossiper #[cfg(test)] mod test { - use std::sync::Arc; + use std::sync::{Arc, Mutex}; use tokio::sync::mpsc::{channel}; use std::time::Duration; use super::*; @@ -164,6 +177,30 @@ mod test { } } + // Mock implementation for the Set trait +//ToDo Should we move all tests to a new file ? + struct MockSet { + pub set: Vec, + } + + impl MockSet { + pub fn len(&self) -> usize { + println!("{}", self.set.len()); + self.set.len() + } + } + + impl Set for MockSet { + fn add(&mut self, _gossipable: T) -> Result<(), Box> { + self.set.push(_gossipable.clone()); + Ok(()) + } + + fn iterate(&self, _f: &dyn FnMut(&T) -> bool) { + // Do nothing + } + } + /// RUST_LOG=debug cargo test --package network --lib -- p2p::gossip::test_gossip_shutdown --exact --show-output #[tokio::test] async fn test_gossip_shutdown() { @@ -175,12 +212,15 @@ mod test { let (stop_tx, stop_rx) = channel(1); // Create a new channel - let mut gossiper: Gossiper = Gossiper::new( + let mut gossiper: Gossiper> = Gossiper::new( Config { namespace: "test".to_string(), frequency: Duration::from_millis(200), poll_size: 0, }, + Arc::new(Mutex::new(MockSet { + set: Vec::new(), + })), Arc::new(Client {}), stop_rx, ); @@ -209,12 +249,15 @@ mod test { let (stop_tx, stop_rx) = channel(1); // Create a new channel - let mut gossiper: Gossiper = Gossiper::new( + let mut gossiper: Gossiper> = Gossiper::new( Config { namespace: "test".to_string(), frequency: Duration::from_millis(200), poll_size: 0, }, + Arc::new(Mutex::new(MockSet { + set: Vec::new(), + })), Arc::new(Client {}), stop_rx, ); @@ -236,12 +279,15 @@ mod test { let (stop_tx, stop_rx) = channel(1); // Create a new channel - let mut gossiper: Gossiper = Gossiper::new( + let mut gossiper: Gossiper> = Gossiper::new( Config { namespace: "test".to_string(), frequency: Duration::from_millis(200), poll_size: 0, }, + Arc::new(Mutex::new(MockSet { + set: Vec::new(), + })), Arc::new(Client {}), stop_rx, ); @@ -259,5 +305,9 @@ mod test { gossiper .handle_response(Id::default(), response_bytes, None) .await; + + let read_guard = gossiper.set.lock().expect("Failed to acquire lock"); + + assert!(read_guard.len() == 2); } } diff --git a/core/network/src/p2p/gossip/handler.rs b/core/network/src/p2p/gossip/handler.rs index 62669c4..ae1d807 100644 --- a/core/network/src/p2p/gossip/handler.rs +++ b/core/network/src/p2p/gossip/handler.rs @@ -1,36 +1,40 @@ use std::error::Error; use std::marker::PhantomData; -use std::sync::Arc; +use std::sync::{Arc, Mutex}; use std::time::Duration; use prost::Message; use avalanche_types::ids::node::Id; use crate::p2p; -use crate::p2p::gossip::Gossipable; +use crate::p2p::gossip::{Gossipable, Set}; use crate::p2p::sdk::{PullGossipRequest, PullGossipResponse}; pub struct HandlerConfig { pub namespace: String, pub target_response_size: usize, } -pub struct Handler { +pub struct Handler> { pub handler: Arc, + set: Arc>, target_response_size: usize, phantom: PhantomData, } -pub fn new( +pub fn new>( config: HandlerConfig, -) -> Handler { + set: Arc>, +) -> Handler { Handler { handler: Arc::new(p2p::handler::NoOpHandler {}), + set, target_response_size: config.target_response_size, phantom: PhantomData::default(), } } -impl p2p::handler::Handler for Handler +impl p2p::handler::Handler for Handler where T: Gossipable + Default, + S: Set, { fn app_gossip(&self, node_id: Id, gossip_bytes: Vec) -> Result<(), Box> { todo!() @@ -45,7 +49,22 @@ impl p2p::handler::Handler for Handler let mut request = PullGossipRequest::default(); request = PullGossipRequest::decode(request_bytes.as_slice()).expect("Failed to decode request_bytes"); - let gossip_bytes: Vec> = Vec::new(); + let salt = avalanche_types::ids::Id::from_slice(request.salt.as_slice()); + + let mut response_size = 0_usize; + let mut gossip_bytes: Vec> = Vec::new(); + + self.set.lock().expect("Failed to lock").iterate(&|gossipable| { + let bytes = match gossipable.serialize() { + Ok(b) => b, + Err(_) => return false, + }; + + gossip_bytes.push(bytes.clone()); + response_size += bytes.len(); + + response_size <= self.target_response_size + }); let mut response = PullGossipResponse::default(); response.gossip = gossip_bytes; diff --git a/core/network/src/p2p/gossip/mod.rs b/core/network/src/p2p/gossip/mod.rs index 3a99bb2..2886228 100644 --- a/core/network/src/p2p/gossip/mod.rs +++ b/core/network/src/p2p/gossip/mod.rs @@ -7,4 +7,9 @@ pub trait Gossipable { fn get_id(&self) -> Id; fn serialize(&self) -> Result, Box>; fn deserialize(&mut self, bytes: &[u8]) -> Result<(), Box>; -} \ No newline at end of file +} + +pub trait Set: Send + Sync { + fn add(&mut self, gossipable: T) -> Result<(), Box>; + fn iterate(&self, f: &dyn FnMut(&T) -> bool); +} From 3a7a5cdf4fd9aa5492b8d15d018956f9fdef0fe3 Mon Sep 17 00:00:00 2001 From: sanghren Date: Fri, 15 Sep 2023 22:56:17 +0200 Subject: [PATCH 32/53] feat: address comments --- core/network/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/core/network/Cargo.toml b/core/network/Cargo.toml index a9897da..94ac297 100644 --- a/core/network/Cargo.toml +++ b/core/network/Cargo.toml @@ -19,7 +19,6 @@ rustls = { version = "0.21.5", features = ["logging", "dangerous_configuration"] rcgen = "0.10.0" hyper-rustls = "0.24.1" rustls-native-certs = "0.6.3" -probabilistic-collections = { version = "0.7.0", features = ["serde"] } hyper = { version = "0.14.27", features = ["full"], optional = true } tokio-rustls = { version = "0.24.1", optional = true } tokio = { version = "1.32.0", features = ["sync", "time"] } From 8cc6084d768c757ec38e69d1f29a06831a6e7deb Mon Sep 17 00:00:00 2001 From: sanghren Date: Sat, 16 Sep 2023 19:59:26 +0200 Subject: [PATCH 33/53] feat: use associated type instead of phantomdata --- core/network/src/p2p/gossip/gossip.rs | 22 ++++++++++------------ core/network/src/p2p/gossip/handler.rs | 16 +++++++--------- core/network/src/p2p/gossip/mod.rs | 7 ++++--- 3 files changed, 21 insertions(+), 24 deletions(-) diff --git a/core/network/src/p2p/gossip/gossip.rs b/core/network/src/p2p/gossip/gossip.rs index fb31d12..a164644 100644 --- a/core/network/src/p2p/gossip/gossip.rs +++ b/core/network/src/p2p/gossip/gossip.rs @@ -6,7 +6,6 @@ use log::{debug, error}; use prost::Message; use std::error::Error; use std::hash::Hash; -use std::marker::PhantomData; use std::sync::{Arc, Mutex}; use std::time::Duration; use tokio::select; @@ -19,18 +18,17 @@ pub struct Config { pub poll_size: usize, } -pub struct Gossiper> { +pub struct Gossiper { config: Config, set: Arc>, client: Arc, stop_rx: Receiver<()>, - phantom: PhantomData, // Had to use this to please the compiler about T not being used. } -impl Gossiper +impl Gossiper where - T: Gossipable + Default, - S: Set, + S: Set, + S::Item: Default { pub fn new( config: Config, @@ -43,7 +41,6 @@ impl Gossiper set, client, stop_rx, - phantom: PhantomData, } } @@ -110,7 +107,7 @@ impl Gossiper } for bytes in response.gossip.iter() { - let mut gossipable: T = T::default(); + let mut gossipable: S::Item = S::Item::default(); if let Err(e) = gossipable.deserialize(bytes) { error!( "failed to unmarshal gossip, nodeID: {:?}, error: {:?}", @@ -190,7 +187,8 @@ mod test { } } - impl Set for MockSet { + impl Set for MockSet { + type Item = T; fn add(&mut self, _gossipable: T) -> Result<(), Box> { self.set.push(_gossipable.clone()); Ok(()) @@ -212,7 +210,7 @@ mod test { let (stop_tx, stop_rx) = channel(1); // Create a new channel - let mut gossiper: Gossiper> = Gossiper::new( + let mut gossiper: Gossiper> = Gossiper::new( Config { namespace: "test".to_string(), frequency: Duration::from_millis(200), @@ -249,7 +247,7 @@ mod test { let (stop_tx, stop_rx) = channel(1); // Create a new channel - let mut gossiper: Gossiper> = Gossiper::new( + let mut gossiper: Gossiper> = Gossiper::new( Config { namespace: "test".to_string(), frequency: Duration::from_millis(200), @@ -279,7 +277,7 @@ mod test { let (stop_tx, stop_rx) = channel(1); // Create a new channel - let mut gossiper: Gossiper> = Gossiper::new( + let mut gossiper: Gossiper> = Gossiper::new( Config { namespace: "test".to_string(), frequency: Duration::from_millis(200), diff --git a/core/network/src/p2p/gossip/handler.rs b/core/network/src/p2p/gossip/handler.rs index ae1d807..624219e 100644 --- a/core/network/src/p2p/gossip/handler.rs +++ b/core/network/src/p2p/gossip/handler.rs @@ -1,5 +1,4 @@ use std::error::Error; -use std::marker::PhantomData; use std::sync::{Arc, Mutex}; use std::time::Duration; use prost::Message; @@ -12,29 +11,28 @@ pub struct HandlerConfig { pub target_response_size: usize, } -pub struct Handler> { +pub struct Handler { pub handler: Arc, set: Arc>, target_response_size: usize, - phantom: PhantomData, + } -pub fn new>( +pub fn new( config: HandlerConfig, set: Arc>, -) -> Handler { +) -> Handler { Handler { handler: Arc::new(p2p::handler::NoOpHandler {}), set, target_response_size: config.target_response_size, - phantom: PhantomData::default(), } } -impl p2p::handler::Handler for Handler +impl p2p::handler::Handler for Handler where - T: Gossipable + Default, - S: Set, + S: Set, + S::Item: Default { fn app_gossip(&self, node_id: Id, gossip_bytes: Vec) -> Result<(), Box> { todo!() diff --git a/core/network/src/p2p/gossip/mod.rs b/core/network/src/p2p/gossip/mod.rs index 2886228..961a071 100644 --- a/core/network/src/p2p/gossip/mod.rs +++ b/core/network/src/p2p/gossip/mod.rs @@ -9,7 +9,8 @@ pub trait Gossipable { fn deserialize(&mut self, bytes: &[u8]) -> Result<(), Box>; } -pub trait Set: Send + Sync { - fn add(&mut self, gossipable: T) -> Result<(), Box>; - fn iterate(&self, f: &dyn FnMut(&T) -> bool); +pub trait Set: Send + Sync { + type Item: Gossipable + ?Sized; + fn add(&mut self, gossipable: Self::Item) -> Result<(), Box>; + fn iterate(&self, f: &dyn FnMut(&Self::Item) -> bool); } From b676024f8955c2d3db9b08f0d9c81c72a0cc3edd Mon Sep 17 00:00:00 2001 From: sanghren Date: Mon, 18 Sep 2023 16:41:23 +0200 Subject: [PATCH 34/53] feat: address warnings --- core/network/src/p2p/gossip/gossip.rs | 4 ++-- core/network/src/p2p/gossip/handler.rs | 7 +++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/core/network/src/p2p/gossip/gossip.rs b/core/network/src/p2p/gossip/gossip.rs index a164644..78bc12d 100644 --- a/core/network/src/p2p/gossip/gossip.rs +++ b/core/network/src/p2p/gossip/gossip.rs @@ -76,8 +76,8 @@ impl Gossiper let mut msg_bytes = vec![]; request.encode(&mut msg_bytes)?; - for i in 0..self.config.poll_size { - self.client.app_request_any(); //ToDo out of scope of my PR + for _ in 0..self.config.poll_size { + let _ = self.client.app_request_any(); //ToDo out of scope of my PR } Ok(()) diff --git a/core/network/src/p2p/gossip/handler.rs b/core/network/src/p2p/gossip/handler.rs index 624219e..c9111a8 100644 --- a/core/network/src/p2p/gossip/handler.rs +++ b/core/network/src/p2p/gossip/handler.rs @@ -6,6 +6,7 @@ use avalanche_types::ids::node::Id; use crate::p2p; use crate::p2p::gossip::{Gossipable, Set}; use crate::p2p::sdk::{PullGossipRequest, PullGossipResponse}; + pub struct HandlerConfig { pub namespace: String, pub target_response_size: usize, @@ -35,7 +36,7 @@ impl p2p::handler::Handler for Handler S::Item: Default { fn app_gossip(&self, node_id: Id, gossip_bytes: Vec) -> Result<(), Box> { - todo!() + unimplemented!() } fn app_request( @@ -47,8 +48,6 @@ impl p2p::handler::Handler for Handler let mut request = PullGossipRequest::default(); request = PullGossipRequest::decode(request_bytes.as_slice()).expect("Failed to decode request_bytes"); - let salt = avalanche_types::ids::Id::from_slice(request.salt.as_slice()); - let mut response_size = 0_usize; let mut gossip_bytes: Vec> = Vec::new(); @@ -74,6 +73,6 @@ impl p2p::handler::Handler for Handler } fn cross_chain_app_request(&self, chain_id: Id, deadline: Duration, request_bytes: Vec) -> Result, Box> { - todo!() + unimplemented!() } } \ No newline at end of file From 3bec77617291db84135257b5d7f4263e69ed9c4f Mon Sep 17 00:00:00 2001 From: sanghren Date: Tue, 26 Sep 2023 15:01:00 +0200 Subject: [PATCH 35/53] feat: implement an example that run gossip logic --- core/network/Cargo.toml | 3 +- core/network/examples/peer_gossip.rs | 232 +++++++++++++++++++++++++ core/network/src/p2p/client.rs | 30 +++- core/network/src/p2p/gossip/gossip.rs | 127 +++++++------- core/network/src/p2p/gossip/handler.rs | 59 +++++-- core/network/src/p2p/gossip/mod.rs | 1 + core/network/src/p2p/handler.rs | 19 +- 7 files changed, 380 insertions(+), 91 deletions(-) create mode 100644 core/network/examples/peer_gossip.rs diff --git a/core/network/Cargo.toml b/core/network/Cargo.toml index 94ac297..91f9cf6 100644 --- a/core/network/Cargo.toml +++ b/core/network/Cargo.toml @@ -12,6 +12,7 @@ readme = "README.md" [dependencies] avalanche-types = { path = "../../crates/avalanche-types", features = ["message"] } +async-trait = { version = "0.1.73", features = [] } byteorder = "1.4.3" cert-manager = "0.0.10" # https://github.com/gyuho/cert-manager log = "0.4.20" @@ -38,7 +39,7 @@ mockall = "0.11.4" proptest = "1.2.0" random-manager = "0.0.5" testing_logger = "0.1.1" -tokio = { version = "1.32.0", features = ["sync", "time"] } +tokio = { version = "1.32.0", features = ["sync", "time", "rt-multi-thread"] } tracing = "0.1.37" tracing-subscriber = "0.3.17" diff --git a/core/network/examples/peer_gossip.rs b/core/network/examples/peer_gossip.rs new file mode 100644 index 0000000..e5b9f12 --- /dev/null +++ b/core/network/examples/peer_gossip.rs @@ -0,0 +1,232 @@ +use std::error::Error; +use std::hash::Hash; +use tokio::sync::Mutex; +use std::sync::Arc; +use std::time::Duration; +use async_trait::async_trait; +use tokio::net::{TcpListener, TcpStream}; +use tokio::io::{AsyncReadExt, AsyncWriteExt}; +use network::p2p::gossip::gossip::{Config, Gossiper}; +use tokio::sync::mpsc::{channel}; +use avalanche_types::ids::Id; +use network::p2p::client::{AppResponseCallback, Client}; +use network::p2p::gossip::{Gossipable, Set}; +use network::p2p::gossip::handler::{Handler, HandlerConfig, new_handler}; +use network::p2p::handler::Handler as TraitHandler; + +pub struct TestClient { + pub stream: Arc>, + pub listener: Arc>, +} + +#[async_trait] +#[allow(unused_variables)] +impl Client for TestClient { + async fn app_gossip(&mut self, request_bytes: Vec) { + unimplemented!() + } + + async fn app_request_any(&mut self, request_bytes: Vec, on_response: AppResponseCallback) { + let mut stream_guard = self.stream.try_lock().expect("aa"); + stream_guard.write_all(&*request_bytes).await.unwrap(); + + loop { + // Lock the listener and wait for a new connection + let clone = self.listener.clone(); + let listener = clone.try_lock().expect("Unable to lock listener"); + + match listener.accept().await { + Ok((mut stream, _)) => { + let mut buf = [0u8; 1024]; + match stream.read(&mut buf).await { + Ok(n) => { + if n == 0 { + break; + } + println!("Received a message of length: {}", n); + on_response(buf[0..n].to_vec()); + } + Err(e) => { + eprintln!("Error reading from stream: {}", e); + break; + } + } + break; + } + Err(e) => { + eprintln!("Error accepting connection: {}", e); + break; + } + } + } + } +} + +#[derive(Clone, Hash, Debug)] +struct TestGossipableType { + pub id: Id, +} + +impl Default for TestGossipableType { + fn default() -> Self { + TestGossipableType { + id: Default::default(), + } + } +} + +impl Gossipable for TestGossipableType { + fn get_id(&self) -> Id { + self.id + } + + fn serialize(&self) -> Result, Box> { + Ok(self.id.to_vec()) + } + + fn deserialize(&mut self, bytes: &[u8]) -> Result<(), Box> { + self.id = Id::from_slice(bytes); + Ok(()) + } +} + +// Mock implementation for the Set trait +//ToDo Should we move all tests to a new file ? +#[derive(Debug, Clone, Hash)] +pub struct MockSet { + pub set: Vec, +} + +impl MockSet { + pub fn len(&self) -> usize { + println!("{}", self.set.len()); + self.set.len() + } +} + +impl Set for MockSet { + type Item = T; + fn add(&mut self, _gossipable: T) -> Result<(), Box> { + self.set.push(_gossipable.clone()); + Ok(()) + } + + fn iterate(&self, _f: &dyn FnMut(&T) -> bool) { + // Do nothing + } + + fn fetch_elements(&self) -> Self::Item { + self.set.get(0).unwrap().clone() + } +} + +async fn fake_handler_server_logic(mut socket: TcpStream, client_socket: Arc>, handler: Handler>) { + + // Initialize a buffer of size 1024. + let mut buf = [0u8; 1024]; + + loop { + let n = socket.read(&mut buf).await.unwrap(); + + // Empty, wait 5 sec before next attempt + if n == 0 { + tokio::time::sleep(Duration::from_secs(5)).await; + continue; + } + + // Fake test data. + let node_id: avalanche_types::ids::node::Id = avalanche_types::ids::node::Id::from_slice(&random_manager::secure_bytes(20).unwrap()); + + let res_bytes = handler.app_gossip(node_id, buf[0..n].to_vec()).await.expect("Issue while attempting to gossip in fake_handler_logic"); + + let mut guard = client_socket.try_lock().expect("Lock of client_socket failed"); + + let _ = guard.write_all(&res_bytes).await; + } +} + +async fn start_fake_node(gossip_handler_addr: String, listener_handler_addr: String, client_addr: String) { + // Initialize the configuration for the gossiper + let config = Config { + namespace: "test".to_string(), + frequency: Duration::from_secs(10), + poll_size: 1, // As we only have 1 other "node" in our test setup, set it to 1 + }; + + // Create a TcpListener to receive messages on. + // Wrapping it in Arc and Mutex to safely share it between threads. + let handler_listener = Arc::new(Mutex::new(TcpListener::bind(listener_handler_addr.clone()).await.unwrap())); + let gossip_listener = Arc::new(Mutex::new(TcpListener::bind(gossip_handler_addr.clone()).await.unwrap())); + + // Create a TcpStream to send messages to. + // Wrapping it in Arc and Mutex to safely share it between threads. + let stream = Arc::new(Mutex::new(TcpStream::connect(client_addr).await.unwrap())); + + // Initialize the configuration for the handler and create a new handler + let handler_config = HandlerConfig { namespace: "test".to_string(), target_response_size: 100 }; + let handler = new_handler( + handler_config, + Arc::new(Mutex::new(MockSet { set: Vec::::new() })), + ); + + // Clone listener and stream for use inside the spawned task. + let listener_clone = handler_listener.clone(); + let stream_clone = stream.clone(); + // Spawn an asynchronous task that will handle incoming connections in a loop + tokio::spawn(async move { + // Accept incoming connections and spawn a new task to handle each connection + let (listener_socket, _) = listener_clone.try_lock().expect("Error acquiring lock on listener_clone").accept().await.unwrap(); + fake_handler_server_logic(listener_socket, stream_clone.clone(), handler.clone()).await; + }); + + // Initialize a MockSet and populate it with some test data + let set = Arc::new(Mutex::new(MockSet { set: Vec::::new() })); + // Generating fake data and pushing to set + { + for _ in 0..3 { + set.try_lock().expect("Error acquiring lock on set").set.push( + TestGossipableType { id: Id::from_slice(&random_manager::secure_bytes(32).unwrap()) } + ); + } + } + + let (stop_tx, stop_rx) = channel(1); + + // Spawn the gossiping task + let gossip_task = tokio::spawn(async move { + // Initialize a TestClient instance with the given stream and listener + let gossip_client = Arc::new(Mutex::new(TestClient { stream: stream.clone(), listener: gossip_listener.clone() })); + + // Create a channel for stopping the gossiper + + // Initialize the Gossiper with the provided configuration, set, client, and receiver end of the stop channel + let mut gossiper = Gossiper::new(config, set.clone(), gossip_client.clone(), stop_rx); + + gossiper.gossip().await; + }); + + // Sleep for a few seconds, make sure the whole process ran + tokio::time::sleep(Duration::from_secs(1)).await; + // Send the stop signal before awaiting the task. + if stop_tx.send(()).await.is_err() { + eprintln!("Failed to send stop signal"); + } + + // Await the completion of the gossiping task + let _ = gossip_task.await.expect("Gossip task failed"); +} + + +#[tokio::main] +async fn main() { + + // Start the client + // listen on 8080 , send message to 8081 + let client_01_handle = tokio::spawn(start_fake_node("127.0.0.1:8080".to_string(), "127.0.0.1:8081".to_string(), "127.0.0.1:8082".to_string())); + let client_02_handle = tokio::spawn(start_fake_node("127.0.0.1:8082".to_string(), "127.0.0.1:8083".to_string(), "127.0.0.1:8080".to_string())); + + // Wait for the server and client to complete + client_01_handle.await.unwrap(); + client_02_handle.await.unwrap(); +} + diff --git a/core/network/src/p2p/client.rs b/core/network/src/p2p/client.rs index 9aed8fc..f933f90 100644 --- a/core/network/src/p2p/client.rs +++ b/core/network/src/p2p/client.rs @@ -1,10 +1,22 @@ -pub struct Client {} - -impl Client { - pub async fn app_request_any(&self) {} - pub async fn app_request(&self) {} - pub async fn app_gossip(&self) {} - pub async fn app_gossip_specific(&self) {} - pub async fn cross_chain_app_request(&self) {} - pub async fn prefix_message(&self) {} +use std::sync::Arc; +use async_trait::async_trait; + +pub type AppResponseCallback = Arc) + Send + Sync>; +#[async_trait] +#[allow(unused_variables)] +pub trait Client: Send + Sync { + async fn app_request_any(&mut self, request_bytes: Vec, on_response: AppResponseCallback) {} + async fn app_request(&mut self, request_bytes: Vec) {} + async fn app_gossip(&mut self, request_bytes: Vec) {} + async fn app_gossip_specific(&mut self, request_bytes: Vec) {} + async fn cross_chain_app_request(&mut self, request_bytes: Vec) {} + async fn prefix_message(&mut self, request_bytes: Vec) {} +} + +pub struct NoOpClient; + +unsafe impl Sync for NoOpClient {} +unsafe impl Send for NoOpClient {} +impl Client for NoOpClient { + } diff --git a/core/network/src/p2p/gossip/gossip.rs b/core/network/src/p2p/gossip/gossip.rs index 78bc12d..dd2787b 100644 --- a/core/network/src/p2p/gossip/gossip.rs +++ b/core/network/src/p2p/gossip/gossip.rs @@ -1,4 +1,4 @@ -use crate::p2p::client::Client; +use crate::p2p::client::{AppResponseCallback, Client}; use crate::p2p::gossip::{Gossipable, Set}; use crate::p2p::sdk::{PullGossipRequest, PullGossipResponse}; use avalanche_types::ids::Id; @@ -6,7 +6,9 @@ use log::{debug, error}; use prost::Message; use std::error::Error; use std::hash::Hash; -use std::sync::{Arc, Mutex}; +use std::ops::Deref; +use tokio::sync::Mutex; +use std::sync::Arc; use std::time::Duration; use tokio::select; use tokio::sync::mpsc::{channel, Receiver}; @@ -18,13 +20,17 @@ pub struct Config { pub poll_size: usize, } -pub struct Gossiper { +pub struct Gossiper { config: Config, set: Arc>, - client: Arc, + client: Arc>, stop_rx: Receiver<()>, } +unsafe impl Sync for Gossiper {} + +unsafe impl Send for Gossiper {} + impl Gossiper where S: Set, @@ -33,7 +39,7 @@ impl Gossiper pub fn new( config: Config, set: Arc>, // Mutex or RWLock here ? - client: Arc, + client: Arc>, stop_rx: Receiver<()>, ) -> Self { Self { @@ -64,77 +70,80 @@ impl Gossiper } } - async fn execute(&self) -> Result<(), Box> { + async fn execute(&mut self) -> Result<(), Box> { //ToDo Dummy vec for now. let bloom = Vec::new(); - let request = PullGossipRequest { + let mut request = PullGossipRequest { filter: bloom, salt: Id::default().to_vec(), //ToDo Use default for now }; let mut msg_bytes = vec![]; - request.encode(&mut msg_bytes)?; - for _ in 0..self.config.poll_size { - let _ = self.client.app_request_any(); //ToDo out of scope of my PR - } + { + let set_guard = self.set.lock().await; - Ok(()) - } + let elem = set_guard.fetch_elements(); - async fn handle_response( - &mut self, - node_id: Id, - response_bytes: Vec, - err: Option>, - ) { - if let Some(e) = err { - error!( - "failed gossip request, nodeID: {:?}, error: {:?}", - node_id, e - ); - return; + let filter = elem.serialize().expect("Issue serializing elem"); + request.filter = filter; + request.encode(&mut msg_bytes)?; } - let mut response = PullGossipResponse::default(); - match PullGossipResponse::decode(response_bytes.as_slice()) { - Ok(res) => response = res, - Err(e) => { - error!("failed to unmarshal gossip response, error: {:?}", e); - return; - } - } - for bytes in response.gossip.iter() { - let mut gossipable: S::Item = S::Item::default(); - if let Err(e) = gossipable.deserialize(bytes) { - error!( - "failed to unmarshal gossip, nodeID: {:?}, error: {:?}", - node_id, e - ); - continue; - } - - let hash = gossipable.get_id(); - debug!("received gossip, nodeID: {:?}, id: {:?}", node_id, hash); + let set_clone = Arc::clone(&self.set.clone()); + for _ in 0..self.config.poll_size { + { + let set_clone = Arc::clone(&set_clone.clone()); + + // Initialize the callback that will be used upon receiving a response from our gossip attempt + let on_response: AppResponseCallback = Arc::new({ + move |response_bytes| { + let response = match PullGossipResponse::decode(response_bytes.as_slice()) { + Ok(res) => { + res + } + Err(e) => { + error!("failed to unmarshal gossip response, error: {:?}", e); + return; + } + }; + + // We iterate over the response's gossip + debug!("There are {} gossips", response.gossip.len()); + for bytes in response.gossip.iter() { + let mut gossipable: S::Item = S::Item::default(); + gossipable.deserialize(bytes).unwrap(); + + let hash = gossipable.get_id(); + + let mut set_guard = set_clone.try_lock().expect("Failed to acquire lock on set_clone"); + if let Err(e) = set_guard.add(gossipable) { + error!( + "failed to add gossip to the known set, id: {:?}, error: {:?}" + , hash, e + ); + continue; + } + } + } + }); - let mut set_guard = self.set.lock().expect("Failed to acquire lock"); - if let Err(e) = set_guard.add(gossipable) { - debug!( - "failed to add gossip to the known set, nodeID: {:?}, id: {:?}, error: {:?}", - node_id, hash, e - ); - continue; + let mut guard = self.client.try_lock().expect("Failed to acquire a lock on client"); + guard.app_request_any(msg_bytes.clone(), on_response).await; } } + + Ok(()) } } #[cfg(test)] mod test { - use std::sync::{Arc, Mutex}; + use tokio::sync::Mutex; + use std::sync::Arc; use tokio::sync::mpsc::{channel}; use std::time::Duration; use super::*; @@ -143,6 +152,7 @@ mod test { use crate::p2p::client::Client; use crate::p2p::gossip::gossip::{Config, Gossiper}; use crate::p2p::sdk::PullGossipResponse; + use crate::p2p::client::NoOpClient; struct MockClient; @@ -176,7 +186,7 @@ mod test { // Mock implementation for the Set trait //ToDo Should we move all tests to a new file ? - struct MockSet { + pub struct MockSet { pub set: Vec, } @@ -207,7 +217,8 @@ mod test { .is_test(true) .try_init() .unwrap(); - + let noopclient = NoOpClient {}; + noopclient.app_request(Vec::new()); let (stop_tx, stop_rx) = channel(1); // Create a new channel let mut gossiper: Gossiper> = Gossiper::new( @@ -219,7 +230,7 @@ mod test { Arc::new(Mutex::new(MockSet { set: Vec::new(), })), - Arc::new(Client {}), + Arc::new(NoOpClient {}), stop_rx, ); @@ -256,7 +267,7 @@ mod test { Arc::new(Mutex::new(MockSet { set: Vec::new(), })), - Arc::new(Client {}), + Arc::new(NoOpClient {}), stop_rx, ); @@ -286,7 +297,7 @@ mod test { Arc::new(Mutex::new(MockSet { set: Vec::new(), })), - Arc::new(Client {}), + Arc::new(NoOpClient {}), stop_rx, ); diff --git a/core/network/src/p2p/gossip/handler.rs b/core/network/src/p2p/gossip/handler.rs index c9111a8..8f643d4 100644 --- a/core/network/src/p2p/gossip/handler.rs +++ b/core/network/src/p2p/gossip/handler.rs @@ -1,6 +1,9 @@ use std::error::Error; -use std::sync::{Arc, Mutex}; +use std::fmt::Debug; +use tokio::sync::Mutex; +use std::sync::Arc; use std::time::Duration; +use async_trait::async_trait; use prost::Message; use avalanche_types::ids::node::Id; use crate::p2p; @@ -12,46 +15,72 @@ pub struct HandlerConfig { pub target_response_size: usize, } -pub struct Handler { - pub handler: Arc, - set: Arc>, - target_response_size: usize, +#[derive(Debug, Clone)] +pub struct Handler { + pub set: Arc>, + pub target_response_size: usize, } -pub fn new( +pub fn new_handler( config: HandlerConfig, set: Arc>, ) -> Handler { Handler { - handler: Arc::new(p2p::handler::NoOpHandler {}), set, target_response_size: config.target_response_size, } } +#[async_trait] +#[allow(unused_variables)] impl p2p::handler::Handler for Handler where - S: Set, + S: Set + Debug, S::Item: Default { - fn app_gossip(&self, node_id: Id, gossip_bytes: Vec) -> Result<(), Box> { - unimplemented!() + async fn app_gossip(&self, node_id: Id, gossip_bytes: Vec) -> Result, Box> { + let request = PullGossipRequest::decode(gossip_bytes.as_slice()).expect("Failed to decode request_bytes into PullGossipRequest"); + + let mut response_size = 0_usize; + let mut gossip_bytes: Vec> = Vec::new(); + let guard = self.set.try_lock().expect("Lock failed on set"); + guard.iterate(&|gossipable| { + let bytes = match gossipable.serialize() { + Ok(b) => { + b + } + Err(_) => { + return false; + } + }; + + gossip_bytes.push(bytes.clone()); + response_size += bytes.len(); + + response_size <= self.target_response_size + }); + let mut response = PullGossipResponse::default(); + response.gossip = gossip_bytes; + + let mut response_bytes = vec![]; + response.encode(&mut response_bytes).expect("Failed to encode response_bytes into PullGossipResponse"); + + Ok(response_bytes) } - fn app_request( + async fn app_request( &self, _: Id, _: Duration, request_bytes: Vec, ) -> Result, Box> { - let mut request = PullGossipRequest::default(); - request = PullGossipRequest::decode(request_bytes.as_slice()).expect("Failed to decode request_bytes"); + let request = PullGossipRequest::decode(request_bytes.as_slice()).expect("Failed to decode request_bytes"); let mut response_size = 0_usize; let mut gossip_bytes: Vec> = Vec::new(); - self.set.lock().expect("Failed to lock").iterate(&|gossipable| { + self.set.lock().await.iterate(&|gossipable| { let bytes = match gossipable.serialize() { Ok(b) => b, Err(_) => return false, @@ -72,7 +101,7 @@ impl p2p::handler::Handler for Handler Ok(response_bytes) } - fn cross_chain_app_request(&self, chain_id: Id, deadline: Duration, request_bytes: Vec) -> Result, Box> { + async fn cross_chain_app_request(&self, chain_id: Id, deadline: Duration, request_bytes: Vec) -> Result, Box> { unimplemented!() } } \ No newline at end of file diff --git a/core/network/src/p2p/gossip/mod.rs b/core/network/src/p2p/gossip/mod.rs index 961a071..21fec54 100644 --- a/core/network/src/p2p/gossip/mod.rs +++ b/core/network/src/p2p/gossip/mod.rs @@ -13,4 +13,5 @@ pub trait Set: Send + Sync { type Item: Gossipable + ?Sized; fn add(&mut self, gossipable: Self::Item) -> Result<(), Box>; fn iterate(&self, f: &dyn FnMut(&Self::Item) -> bool); + fn fetch_elements(&self) -> Self::Item; } diff --git a/core/network/src/p2p/handler.rs b/core/network/src/p2p/handler.rs index 15d1f6c..146af23 100644 --- a/core/network/src/p2p/handler.rs +++ b/core/network/src/p2p/handler.rs @@ -1,18 +1,20 @@ use std::error::Error; use std::time::Duration; use avalanche_types::ids::node::Id; +use async_trait::async_trait; +#[async_trait] pub trait Handler { // AppGossip is called when handling an AppGossip message. - fn app_gossip( + async fn app_gossip( &self, node_id: Id, gossip_bytes: Vec, - ) -> Result<(), Box>; + ) -> Result, Box>; // AppRequest is called when handling an AppRequest message. // Returns the bytes for the response corresponding to request_bytes - fn app_request( + async fn app_request( &self, node_id: Id, deadline: Duration, @@ -21,7 +23,7 @@ pub trait Handler { // CrossChainAppRequest is called when handling a CrossChainAppRequest message. // Returns the bytes for the response corresponding to request_bytes - fn cross_chain_app_request( + async fn cross_chain_app_request( &self, chain_id: Id, deadline: Duration, @@ -32,14 +34,15 @@ pub trait Handler { // NoOpHandler struct pub struct NoOpHandler; +#[async_trait] impl Handler for NoOpHandler { - fn app_gossip(&self, _: Id, _: Vec) -> Result<(), Box> { - Ok(()) + async fn app_gossip(&self, _: Id, _: Vec) -> Result, Box> { + Ok(vec![]) } - fn app_request(&self, _: Id, _: Duration, _: Vec) -> Result, Box> { + async fn app_request(&self, _: Id, _: Duration, _: Vec) -> Result, Box> { Ok(vec![]) } - fn cross_chain_app_request(&self, _: Id, _: Duration, _: Vec) -> Result, Box> { + async fn cross_chain_app_request(&self, _: Id, _: Duration, _: Vec) -> Result, Box> { Ok(vec![]) } } From e0460137fbba547db9bc9c91b6088319e1cfeadc Mon Sep 17 00:00:00 2001 From: sanghren Date: Tue, 26 Sep 2023 15:40:08 +0200 Subject: [PATCH 36/53] feat: implement an example that run gossip logic --- core/network/examples/peer_gossip.rs | 12 +++++++++++- core/network/src/p2p/gossip/gossip.rs | 7 +++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/core/network/examples/peer_gossip.rs b/core/network/examples/peer_gossip.rs index e5b9f12..25aecaf 100644 --- a/core/network/examples/peer_gossip.rs +++ b/core/network/examples/peer_gossip.rs @@ -190,9 +190,14 @@ async fn start_fake_node(gossip_handler_addr: String, listener_handler_addr: Str } } + { + assert_eq!(set.try_lock().expect("Failed to acquire lock").set.len().clone(), 3); + } + let (stop_tx, stop_rx) = channel(1); // Spawn the gossiping task + let set_clone = set.clone(); let gossip_task = tokio::spawn(async move { // Initialize a TestClient instance with the given stream and listener let gossip_client = Arc::new(Mutex::new(TestClient { stream: stream.clone(), listener: gossip_listener.clone() })); @@ -200,13 +205,18 @@ async fn start_fake_node(gossip_handler_addr: String, listener_handler_addr: Str // Create a channel for stopping the gossiper // Initialize the Gossiper with the provided configuration, set, client, and receiver end of the stop channel - let mut gossiper = Gossiper::new(config, set.clone(), gossip_client.clone(), stop_rx); + let mut gossiper = Gossiper::new(config, set_clone, gossip_client.clone(), stop_rx); gossiper.gossip().await; }); // Sleep for a few seconds, make sure the whole process ran tokio::time::sleep(Duration::from_secs(1)).await; + + { + assert_eq!(set.try_lock().expect("Failed to acquire lock").set.len(), 4); + } + // Send the stop signal before awaiting the task. if stop_tx.send(()).await.is_err() { eprintln!("Failed to send stop signal"); diff --git a/core/network/src/p2p/gossip/gossip.rs b/core/network/src/p2p/gossip/gossip.rs index dd2787b..7b49547 100644 --- a/core/network/src/p2p/gossip/gossip.rs +++ b/core/network/src/p2p/gossip/gossip.rs @@ -81,6 +81,7 @@ impl Gossiper let mut msg_bytes = vec![]; + // We scope the lock here to avoid issue later on { let set_guard = self.set.lock().await; @@ -91,11 +92,9 @@ impl Gossiper request.encode(&mut msg_bytes)?; } - - let set_clone = Arc::clone(&self.set.clone()); for _ in 0..self.config.poll_size { { - let set_clone = Arc::clone(&set_clone.clone()); + let set = Arc::clone(&self.set.clone()); // Initialize the callback that will be used upon receiving a response from our gossip attempt let on_response: AppResponseCallback = Arc::new({ @@ -118,7 +117,7 @@ impl Gossiper let hash = gossipable.get_id(); - let mut set_guard = set_clone.try_lock().expect("Failed to acquire lock on set_clone"); + let mut set_guard = set.try_lock().expect("Failed to acquire lock on set"); if let Err(e) = set_guard.add(gossipable) { error!( "failed to add gossip to the known set, id: {:?}, error: {:?}" From 13205e723b904da40be88a99dc6a0d0e2ec387f1 Mon Sep 17 00:00:00 2001 From: sanghren Date: Wed, 27 Sep 2023 22:14:53 +0200 Subject: [PATCH 37/53] feat: make things work - wip --- core/network/Cargo.toml | 3 +- core/network/examples/peer_gossip.rs | 193 ++++++++++++++++++------- core/network/src/p2p/gossip/gossip.rs | 16 +- core/network/src/p2p/gossip/handler.rs | 17 ++- core/network/src/p2p/gossip/mod.rs | 7 +- core/network/src/p2p/handler.rs | 2 + 6 files changed, 178 insertions(+), 60 deletions(-) diff --git a/core/network/Cargo.toml b/core/network/Cargo.toml index 91f9cf6..0415c65 100644 --- a/core/network/Cargo.toml +++ b/core/network/Cargo.toml @@ -30,7 +30,8 @@ bincode = "1.3.3" serde = { version = "1.0.188", features = ["derive"] } # for feature "pem" -pem = { version = "3.0.0", optional = true } # https://github.com/jcreekmore/pem-rs +pem = { version = "3.0.0", optional = true } +rand = "0.8.5" # https://github.com/jcreekmore/pem-rs [dev-dependencies] diff --git a/core/network/examples/peer_gossip.rs b/core/network/examples/peer_gossip.rs index 25aecaf..9f69857 100644 --- a/core/network/examples/peer_gossip.rs +++ b/core/network/examples/peer_gossip.rs @@ -1,13 +1,17 @@ use std::error::Error; +use std::fmt::Debug; use std::hash::Hash; use tokio::sync::Mutex; use std::sync::Arc; use std::time::Duration; use async_trait::async_trait; +use log::{debug, error}; +use rand::prelude::SliceRandom; use tokio::net::{TcpListener, TcpStream}; use tokio::io::{AsyncReadExt, AsyncWriteExt}; use network::p2p::gossip::gossip::{Config, Gossiper}; use tokio::sync::mpsc::{channel}; +use tracing::field::debug; use avalanche_types::ids::Id; use network::p2p::client::{AppResponseCallback, Client}; use network::p2p::gossip::{Gossipable, Set}; @@ -16,7 +20,7 @@ use network::p2p::handler::Handler as TraitHandler; pub struct TestClient { pub stream: Arc>, - pub listener: Arc>, + pub listener: Arc>, } #[async_trait] @@ -30,35 +34,51 @@ impl Client for TestClient { let mut stream_guard = self.stream.try_lock().expect("aa"); stream_guard.write_all(&*request_bytes).await.unwrap(); - loop { - // Lock the listener and wait for a new connection - let clone = self.listener.clone(); - let listener = clone.try_lock().expect("Unable to lock listener"); - - match listener.accept().await { - Ok((mut stream, _)) => { - let mut buf = [0u8; 1024]; - match stream.read(&mut buf).await { - Ok(n) => { - if n == 0 { - break; - } - println!("Received a message of length: {}", n); - on_response(buf[0..n].to_vec()); - } - Err(e) => { - eprintln!("Error reading from stream: {}", e); - break; - } + // Lock the listener and wait for a new connection + let clone = self.listener.clone(); + let mut listener = clone.try_lock().expect("Unable to lock listener"); + debug!("after acquiring lock on listener -- app_request_any -- {:?}", listener); + + let mut buf = [0u8; 1024]; + debug!("Loopity loop"); + match listener.read(&mut buf).await { + Ok(n) => { + debug!("Gossip -- Received a message of length: {} -- {:?}", n, buf); + if n == 0 { + // Connection was closed } - break; + // Handle received data here: buf[0..n] + + on_response(buf[0..n].to_vec()); } Err(e) => { - eprintln!("Error accepting connection: {}", e); - break; + // Handle the error. } } - } + // match listener.accept().await { + // Ok((mut stream, _)) => { + // debug!("in peer_gossip - app_request_any"); + // let mut buf = [0u8; 1024]; + // match stream.read(&mut buf).await { + // Ok(n) => { + // // if n == 0 { + // // debug!("did we not receive something"); + // // return; + // // } + // debug!("Received a message of length: {}", n); + // on_response(buf[0..n].to_vec()); + // } + // Err(e) => { + // error!("Error reading from stream: {}", e); + // } + // } + // } + // Err(e) => { + // error!("Error accepting connection: {}", e); + // } + // } + + debug!("End of app_request_any"); } } @@ -75,6 +95,12 @@ impl Default for TestGossipableType { } } +impl PartialEq for TestGossipableType { + fn eq(&self, other: &Self) -> bool { + self.id.eq(&other.id) + } +} + impl Gossipable for TestGossipableType { fn get_id(&self) -> Id { self.id @@ -104,19 +130,33 @@ impl MockSet { } } -impl Set for MockSet { +impl Set for MockSet { type Item = T; fn add(&mut self, _gossipable: T) -> Result<(), Box> { + debug!("SET LEN -- {:?}", self.set.len()); self.set.push(_gossipable.clone()); Ok(()) } - fn iterate(&self, _f: &dyn FnMut(&T) -> bool) { + fn has(&self, gossipable: &Self::Item) -> bool { + self.set.contains(gossipable) + } + + fn iterate(&self, _f: &mut dyn FnMut(&T) -> bool) { + debug!("In iteratteeeee"); + debug!("In iterateeeee {}", self.set.len()); + for item in &self.set { + debug!("In iterateeeee for item {:?}", item); + if _f(item) { + debug!("In iterateeeee for item -- false {:?}", item); + break; // Stop iterating if the closure returns false + } + } // Do nothing } fn fetch_elements(&self) -> Self::Item { - self.set.get(0).unwrap().clone() + self.set.choose(&mut rand::thread_rng()).cloned().expect("Set is empty") } } @@ -124,68 +164,91 @@ async fn fake_handler_server_logic(mut socket: TcpStream, client_socket: Arc, vec_gossip_remote_client: Vec) { // Initialize the configuration for the gossiper let config = Config { namespace: "test".to_string(), - frequency: Duration::from_secs(10), + frequency: Duration::from_millis(500), poll_size: 1, // As we only have 1 other "node" in our test setup, set it to 1 }; // Create a TcpListener to receive messages on. // Wrapping it in Arc and Mutex to safely share it between threads. - let handler_listener = Arc::new(Mutex::new(TcpListener::bind(listener_handler_addr.clone()).await.unwrap())); - let gossip_listener = Arc::new(Mutex::new(TcpListener::bind(gossip_handler_addr.clone()).await.unwrap())); + let own_handler_listener = Arc::new(Mutex::new(TcpListener::bind(own_handler.clone()).await.unwrap())); + let own_client_listener_r = Arc::new(Mutex::new(TcpListener::bind(own_client.clone()).await.unwrap())); // Create a TcpStream to send messages to. // Wrapping it in Arc and Mutex to safely share it between threads. - let stream = Arc::new(Mutex::new(TcpStream::connect(client_addr).await.unwrap())); + let other_client_stream = Arc::new(Mutex::new(TcpStream::connect(other_client).await.unwrap())); + let other_handler_stream = Arc::new(Mutex::new(TcpStream::connect(other_handler.clone()).await.unwrap())); // Initialize the configuration for the handler and create a new handler let handler_config = HandlerConfig { namespace: "test".to_string(), target_response_size: 100 }; + + let mut set = MockSet { set: Vec::::new() }; + // Generating fake data and pushing to set + { + for gossip in &vec_gossip_local_client { + set.set.push( + gossip.clone() + ); + } + } + let handler = new_handler( handler_config, - Arc::new(Mutex::new(MockSet { set: Vec::::new() })), + Arc::new(Mutex::new(set)), ); // Clone listener and stream for use inside the spawned task. - let listener_clone = handler_listener.clone(); - let stream_clone = stream.clone(); + let own_handler_listener_clone = own_handler_listener.clone(); + let other_client_stream_clone = other_client_stream.clone(); // Spawn an asynchronous task that will handle incoming connections in a loop - tokio::spawn(async move { + let handler_task = tokio::spawn(async move { // Accept incoming connections and spawn a new task to handle each connection - let (listener_socket, _) = listener_clone.try_lock().expect("Error acquiring lock on listener_clone").accept().await.unwrap(); - fake_handler_server_logic(listener_socket, stream_clone.clone(), handler.clone()).await; + debug!("Setting up the handler task"); + let guard = own_handler_listener_clone.try_lock().expect("Error acquiring lock on listener_clone"); + debug!("After lock"); + let (listener_socket, _) = guard.accept().await.unwrap(); + debug!("After accept"); + fake_handler_server_logic(listener_socket, other_client_stream_clone.clone(), handler.clone()).await; }); // Initialize a MockSet and populate it with some test data let set = Arc::new(Mutex::new(MockSet { set: Vec::::new() })); // Generating fake data and pushing to set { - for _ in 0..3 { - set.try_lock().expect("Error acquiring lock on set").set.push( - TestGossipableType { id: Id::from_slice(&random_manager::secure_bytes(32).unwrap()) } + for gossip in &vec_gossip_local_client { + set.try_lock().expect("Failed to lock").set.push( + gossip.clone() ); } } @@ -200,7 +263,9 @@ async fn start_fake_node(gossip_handler_addr: String, listener_handler_addr: Str let set_clone = set.clone(); let gossip_task = tokio::spawn(async move { // Initialize a TestClient instance with the given stream and listener - let gossip_client = Arc::new(Mutex::new(TestClient { stream: stream.clone(), listener: gossip_listener.clone() })); + let (stream, _) = own_client_listener_r.try_lock().expect("Failed to acquire lock").accept().await.expect("Fail"); + debug!("Gossip will be listening on {:?}", stream); + let gossip_client = Arc::new(Mutex::new(TestClient { stream: other_handler_stream.clone(), listener: Arc::new(Mutex::new(stream)) })); // Create a channel for stopping the gossiper @@ -210,30 +275,54 @@ async fn start_fake_node(gossip_handler_addr: String, listener_handler_addr: Str gossiper.gossip().await; }); - // Sleep for a few seconds, make sure the whole process ran + // Sleep for a few seconds, make sure the whole process ran at least a couple of times tokio::time::sleep(Duration::from_secs(1)).await; { - assert_eq!(set.try_lock().expect("Failed to acquire lock").set.len(), 4); + let guard = set.try_lock().expect("Failed to acquire lock"); + // As we have 3 elements in our set pre-gossip loop execution in each one of our fake gossip server, we should end up with 6 gossip at the end of our test run. + debug!("SET LEN {}", guard.set.len()); + // assert_eq!(guard.set.len(), 6); + // for gossip in vec_gossip_remote_client { + // assert_eq!(guard.set.contains(&gossip), true); + // } } // Send the stop signal before awaiting the task. if stop_tx.send(()).await.is_err() { eprintln!("Failed to send stop signal"); } + debug!("Checking if all things good"); // Await the completion of the gossiping task let _ = gossip_task.await.expect("Gossip task failed"); + let _ = handler_task.await.expect("Handler task failed"); } #[tokio::main] async fn main() { + env_logger::init_from_env( + env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, "info"), + ); + + let mut vec_gossip_client_01 = Vec::new(); + let mut vec_gossip_client_02 = Vec::new(); + + for _ in 0..3 { + vec_gossip_client_01.push( + TestGossipableType { id: Id::from_slice(&random_manager::secure_bytes(32).unwrap()) } + ); + vec_gossip_client_02.push( + TestGossipableType { id: Id::from_slice(&random_manager::secure_bytes(32).unwrap()) } + ); + }; + // Start the client // listen on 8080 , send message to 8081 - let client_01_handle = tokio::spawn(start_fake_node("127.0.0.1:8080".to_string(), "127.0.0.1:8081".to_string(), "127.0.0.1:8082".to_string())); - let client_02_handle = tokio::spawn(start_fake_node("127.0.0.1:8082".to_string(), "127.0.0.1:8083".to_string(), "127.0.0.1:8080".to_string())); + let client_01_handle = tokio::spawn(start_fake_node("127.0.0.1:8080".to_string(), "127.0.0.1:8081".to_string(), "127.0.0.1:8082".to_string(), "127.0.0.1:8083".to_string(), vec_gossip_client_01.clone(), vec_gossip_client_02.clone())); + let client_02_handle = tokio::spawn(start_fake_node("127.0.0.1:8082".to_string(), "127.0.0.1:8083".to_string(), "127.0.0.1:8080".to_string(), "127.0.0.1:8081".to_string(), vec_gossip_client_02.clone(), vec_gossip_client_01.clone())); // Wait for the server and client to complete client_01_handle.await.unwrap(); diff --git a/core/network/src/p2p/gossip/gossip.rs b/core/network/src/p2p/gossip/gossip.rs index 7b49547..779d50c 100644 --- a/core/network/src/p2p/gossip/gossip.rs +++ b/core/network/src/p2p/gossip/gossip.rs @@ -56,6 +56,7 @@ impl Gossiper loop { select! { _ = gossip_ticker.tick() => { + debug!("Gossip tick"); if let Err(e) = self.execute().await { error!("Failed to Gossip : {:?}", e); //ToDo @@ -92,15 +93,19 @@ impl Gossiper request.encode(&mut msg_bytes)?; } + debug!("Before going over the poll_size"); for _ in 0..self.config.poll_size { { + debug!("poll_size"); let set = Arc::clone(&self.set.clone()); // Initialize the callback that will be used upon receiving a response from our gossip attempt let on_response: AppResponseCallback = Arc::new({ move |response_bytes| { + debug!("In AppResponseCallback -- beginning"); let response = match PullGossipResponse::decode(response_bytes.as_slice()) { Ok(res) => { + debug!("Decoded in AppResponseCallback -- {:?}", res); res } Err(e) => { @@ -113,11 +118,15 @@ impl Gossiper debug!("There are {} gossips", response.gossip.len()); for bytes in response.gossip.iter() { let mut gossipable: S::Item = S::Item::default(); + debug!("In AppResponseCallback -- deserialized gossipable -- {:?}", gossipable); gossipable.deserialize(bytes).unwrap(); + debug!("In AppResponseCallback -- deserialized gossipable -- {:?}", gossipable); let hash = gossipable.get_id(); + debug!("In AppResponseCallback -- let hash = gossipable.get_id(); -- {:?}", hash); let mut set_guard = set.try_lock().expect("Failed to acquire lock on set"); + debug!("In AppResponseCallback -- set_guard = set.try_lock()"); if let Err(e) = set_guard.add(gossipable) { error!( "failed to add gossip to the known set, id: {:?}, error: {:?}" @@ -126,11 +135,14 @@ impl Gossiper continue; } } + debug!("In AppResponseCallback -- ending"); } }); let mut guard = self.client.try_lock().expect("Failed to acquire a lock on client"); + debug!("After acquiring lock for client in execute"); guard.app_request_any(msg_bytes.clone(), on_response).await; + debug!("After app_request_any in execute"); } } @@ -203,8 +215,8 @@ mod test { Ok(()) } - fn iterate(&self, _f: &dyn FnMut(&T) -> bool) { - // Do nothing + fn iterate(&self, _f: &mut dyn FnMut(&T) -> bool) { + unimplemented!() } } diff --git a/core/network/src/p2p/gossip/handler.rs b/core/network/src/p2p/gossip/handler.rs index 8f643d4..c4e1950 100644 --- a/core/network/src/p2p/gossip/handler.rs +++ b/core/network/src/p2p/gossip/handler.rs @@ -4,6 +4,7 @@ use tokio::sync::Mutex; use std::sync::Arc; use std::time::Duration; use async_trait::async_trait; +use log::debug; use prost::Message; use avalanche_types::ids::node::Id; use crate::p2p; @@ -41,11 +42,14 @@ impl p2p::handler::Handler for Handler { async fn app_gossip(&self, node_id: Id, gossip_bytes: Vec) -> Result, Box> { let request = PullGossipRequest::decode(gossip_bytes.as_slice()).expect("Failed to decode request_bytes into PullGossipRequest"); + debug!("Allloooo"); let mut response_size = 0_usize; let mut gossip_bytes: Vec> = Vec::new(); let guard = self.set.try_lock().expect("Lock failed on set"); - guard.iterate(&|gossipable| { + debug!("BEFORE Iterate over set gossipable items"); + guard.iterate(&mut |gossipable : &S::Item| { + debug!("Iterate over set gossipable items"); let bytes = match gossipable.serialize() { Ok(b) => { b @@ -55,6 +59,8 @@ impl p2p::handler::Handler for Handler } }; + debug!("In app_gossip -- bytes == {:?}", bytes); + gossip_bytes.push(bytes.clone()); response_size += bytes.len(); @@ -65,7 +71,7 @@ impl p2p::handler::Handler for Handler let mut response_bytes = vec![]; response.encode(&mut response_bytes).expect("Failed to encode response_bytes into PullGossipResponse"); - + debug!("Response bytes in app_gossip {:?}", response_bytes); Ok(response_bytes) } @@ -80,7 +86,12 @@ impl p2p::handler::Handler for Handler let mut response_size = 0_usize; let mut gossip_bytes: Vec> = Vec::new(); - self.set.lock().await.iterate(&|gossipable| { + self.set.lock().await.iterate(&mut |gossipable| { + + if self.set.try_lock().expect("ssss").has(gossipable) { + return true + }; + let bytes = match gossipable.serialize() { Ok(b) => b, Err(_) => return false, diff --git a/core/network/src/p2p/gossip/mod.rs b/core/network/src/p2p/gossip/mod.rs index 21fec54..eaca86c 100644 --- a/core/network/src/p2p/gossip/mod.rs +++ b/core/network/src/p2p/gossip/mod.rs @@ -1,6 +1,7 @@ pub mod gossip; pub mod handler; +use std::fmt::Debug; use avalanche_types::ids::Id; pub trait Gossipable { @@ -10,8 +11,10 @@ pub trait Gossipable { } pub trait Set: Send + Sync { - type Item: Gossipable + ?Sized; + type Item: Gossipable + ?Sized + Debug; fn add(&mut self, gossipable: Self::Item) -> Result<(), Box>; - fn iterate(&self, f: &dyn FnMut(&Self::Item) -> bool); + + fn has(&self, gossipable: &Self::Item) -> bool; + fn iterate(&self, f: &mut dyn FnMut(&Self::Item) -> bool); fn fetch_elements(&self) -> Self::Item; } diff --git a/core/network/src/p2p/handler.rs b/core/network/src/p2p/handler.rs index 146af23..40e1d61 100644 --- a/core/network/src/p2p/handler.rs +++ b/core/network/src/p2p/handler.rs @@ -2,6 +2,7 @@ use std::error::Error; use std::time::Duration; use avalanche_types::ids::node::Id; use async_trait::async_trait; +use log::debug; #[async_trait] pub trait Handler { @@ -40,6 +41,7 @@ impl Handler for NoOpHandler { Ok(vec![]) } async fn app_request(&self, _: Id, _: Duration, _: Vec) -> Result, Box> { + debug!("Ah non hein"); Ok(vec![]) } async fn cross_chain_app_request(&self, _: Id, _: Duration, _: Vec) -> Result, Box> { From f56ab2583458f7514e2dfaa33f78e35525027bcb Mon Sep 17 00:00:00 2001 From: sanghren Date: Sun, 1 Oct 2023 14:11:31 +0200 Subject: [PATCH 38/53] feat: wip --- core/network/Cargo.toml | 5 +- core/network/examples/peer_gossip.rs | 173 ++++++++++--------------- core/network/src/p2p/gossip/gossip.rs | 28 ++-- core/network/src/p2p/gossip/handler.rs | 37 ++++-- core/network/src/p2p/gossip/mod.rs | 5 +- 5 files changed, 109 insertions(+), 139 deletions(-) diff --git a/core/network/Cargo.toml b/core/network/Cargo.toml index 0415c65..36c98bd 100644 --- a/core/network/Cargo.toml +++ b/core/network/Cargo.toml @@ -30,8 +30,9 @@ bincode = "1.3.3" serde = { version = "1.0.188", features = ["derive"] } # for feature "pem" -pem = { version = "3.0.0", optional = true } -rand = "0.8.5" # https://github.com/jcreekmore/pem-rs +pem = { version = "3.0.0", optional = true } # https://github.com/jcreekmore/pem-rs +rand = "0.8.5" +serde_json = "1.0.105" [dev-dependencies] diff --git a/core/network/examples/peer_gossip.rs b/core/network/examples/peer_gossip.rs index 9f69857..346e363 100644 --- a/core/network/examples/peer_gossip.rs +++ b/core/network/examples/peer_gossip.rs @@ -7,11 +7,11 @@ use std::time::Duration; use async_trait::async_trait; use log::{debug, error}; use rand::prelude::SliceRandom; +use serde::{Deserialize, Serialize}; use tokio::net::{TcpListener, TcpStream}; use tokio::io::{AsyncReadExt, AsyncWriteExt}; use network::p2p::gossip::gossip::{Config, Gossiper}; use tokio::sync::mpsc::{channel}; -use tracing::field::debug; use avalanche_types::ids::Id; use network::p2p::client::{AppResponseCallback, Client}; use network::p2p::gossip::{Gossipable, Set}; @@ -27,62 +27,36 @@ pub struct TestClient { #[allow(unused_variables)] impl Client for TestClient { async fn app_gossip(&mut self, request_bytes: Vec) { - unimplemented!() + todo!() } async fn app_request_any(&mut self, request_bytes: Vec, on_response: AppResponseCallback) { - let mut stream_guard = self.stream.try_lock().expect("aa"); + let mut stream_guard = self.stream.lock().await; stream_guard.write_all(&*request_bytes).await.unwrap(); // Lock the listener and wait for a new connection let clone = self.listener.clone(); let mut listener = clone.try_lock().expect("Unable to lock listener"); - debug!("after acquiring lock on listener -- app_request_any -- {:?}", listener); - - let mut buf = [0u8; 1024]; - debug!("Loopity loop"); - match listener.read(&mut buf).await { - Ok(n) => { - debug!("Gossip -- Received a message of length: {} -- {:?}", n, buf); - if n == 0 { - // Connection was closed - } - // Handle received data here: buf[0..n] - - on_response(buf[0..n].to_vec()); - } - Err(e) => { - // Handle the error. + + let mut buf = [0u8; 1024]; + match listener.read(&mut buf).await { + Ok(n) => { + if n == 0 { + // Connection was closed } + // Handle received data here: buf[0..n] + + on_response(buf[0..n].to_vec()); + } + Err(e) => { + // Handle the error. } - // match listener.accept().await { - // Ok((mut stream, _)) => { - // debug!("in peer_gossip - app_request_any"); - // let mut buf = [0u8; 1024]; - // match stream.read(&mut buf).await { - // Ok(n) => { - // // if n == 0 { - // // debug!("did we not receive something"); - // // return; - // // } - // debug!("Received a message of length: {}", n); - // on_response(buf[0..n].to_vec()); - // } - // Err(e) => { - // error!("Error reading from stream: {}", e); - // } - // } - // } - // Err(e) => { - // error!("Error accepting connection: {}", e); - // } - // } - - debug!("End of app_request_any"); + } + } } -#[derive(Clone, Hash, Debug)] +#[derive(Clone, Hash, Debug, Serialize, Deserialize)] struct TestGossipableType { pub id: Id, } @@ -118,7 +92,7 @@ impl Gossipable for TestGossipableType { // Mock implementation for the Set trait //ToDo Should we move all tests to a new file ? -#[derive(Debug, Clone, Hash)] +#[derive(Debug, Clone, Hash, Serialize, Deserialize)] pub struct MockSet { pub set: Vec, } @@ -130,11 +104,17 @@ impl MockSet { } } -impl Set for MockSet { +impl Deserialize<'de> + Serialize> Set for MockSet { type Item = T; fn add(&mut self, _gossipable: T) -> Result<(), Box> { - debug!("SET LEN -- {:?}", self.set.len()); - self.set.push(_gossipable.clone()); + // Just for our test purpose am checking manually if we insert an already known gossip. + + if self.set.contains(&_gossipable) { + error!("Cannot insert this item, already known"); + } else { + self.set.push(_gossipable.clone()); + } + Ok(()) } @@ -143,13 +123,10 @@ impl Set for Moc } fn iterate(&self, _f: &mut dyn FnMut(&T) -> bool) { - debug!("In iteratteeeee"); - debug!("In iterateeeee {}", self.set.len()); for item in &self.set { - debug!("In iterateeeee for item {:?}", item); - if _f(item) { - debug!("In iterateeeee for item -- false {:?}", item); - break; // Stop iterating if the closure returns false + if !_f(item) { + println!("Filter sent over network knows about this item already {:?}", item); + break; } } // Do nothing @@ -158,37 +135,41 @@ impl Set for Moc fn fetch_elements(&self) -> Self::Item { self.set.choose(&mut rand::thread_rng()).cloned().expect("Set is empty") } + + fn fetch_all_elements(&self) -> Vec { + self.set.clone() + } } async fn fake_handler_server_logic(mut socket: TcpStream, client_socket: Arc>, handler: Handler>) { // Initialize a buffer of size 1024. let mut buf = [0u8; 1024]; - debug!("Fake Handler Server Logic"); loop { - debug!("New loop in fake_handler_server_logic"); let n = socket.read(&mut buf).await.unwrap(); - debug!("fake_handler_server_logic -- Received {:?} bytes from socket", n); // // Empty, wait 5 sec before next attempt if n == 0 { - debug!("received 0 bytes message)"); tokio::time::sleep(Duration::from_secs(5)).await; break; } // Fake test data. let node_id: avalanche_types::ids::node::Id = avalanche_types::ids::node::Id::from_slice(&random_manager::secure_bytes(20).unwrap()); - debug!("fake_handler_server_logic -- Node id {}", node_id); - let res_bytes = handler.app_gossip(node_id, buf[0..n].to_vec()).await.expect("Issue while attempting to gossip in fake_handler_logic"); - debug!("fake_handler_server_logic -- res_bytes {:?}", res_bytes); + let res_bytes = match handler.app_gossip(node_id, buf[0..n].to_vec()).await { + Ok(res) => { res} + Err(error) => { continue } + }; let mut guard = client_socket.try_lock().expect("Lock of client_socket failed"); - debug!("fake_handler_server_logic -- Send bytes to gossip : {:?} to {:?}", res_bytes, guard); - let _ = guard.write_all(&res_bytes).await; - // guard.write_all(random_manager::secure_bytes(32).unwrap().as_slice()).await; - - debug!("fake_handler_server_logic -- End loop in fake_handler_server_logic"); + if res_bytes.is_empty() { + // ToDo Whenever the handler return nothing , gossip part hang. Temp dev fix to get pass this + let mut temp_vec = Vec::new(); + temp_vec.push(1); + guard.write_all(temp_vec.as_slice()).await; + } else { + let _ = guard.write_all(&res_bytes).await; + } } } @@ -211,13 +192,13 @@ async fn start_fake_node(own_handler: String, own_client: String, other_handler: let other_handler_stream = Arc::new(Mutex::new(TcpStream::connect(other_handler.clone()).await.unwrap())); // Initialize the configuration for the handler and create a new handler - let handler_config = HandlerConfig { namespace: "test".to_string(), target_response_size: 100 }; + let handler_config = HandlerConfig { namespace: "test".to_string(), target_response_size: 1000 }; - let mut set = MockSet { set: Vec::::new() }; + let mut set = Arc::new(Mutex::new(MockSet { set: Vec::::new() })); // Generating fake data and pushing to set { for gossip in &vec_gossip_local_client { - set.set.push( + set.try_lock().expect("Failed to acquire lock").set.push( gossip.clone() ); } @@ -225,7 +206,7 @@ async fn start_fake_node(own_handler: String, own_client: String, other_handler: let handler = new_handler( handler_config, - Arc::new(Mutex::new(set)), + set.clone(), ); // Clone listener and stream for use inside the spawned task. @@ -234,25 +215,11 @@ async fn start_fake_node(own_handler: String, own_client: String, other_handler: // Spawn an asynchronous task that will handle incoming connections in a loop let handler_task = tokio::spawn(async move { // Accept incoming connections and spawn a new task to handle each connection - debug!("Setting up the handler task"); let guard = own_handler_listener_clone.try_lock().expect("Error acquiring lock on listener_clone"); - debug!("After lock"); let (listener_socket, _) = guard.accept().await.unwrap(); - debug!("After accept"); fake_handler_server_logic(listener_socket, other_client_stream_clone.clone(), handler.clone()).await; }); - // Initialize a MockSet and populate it with some test data - let set = Arc::new(Mutex::new(MockSet { set: Vec::::new() })); - // Generating fake data and pushing to set - { - for gossip in &vec_gossip_local_client { - set.try_lock().expect("Failed to lock").set.push( - gossip.clone() - ); - } - } - { assert_eq!(set.try_lock().expect("Failed to acquire lock").set.len().clone(), 3); } @@ -264,7 +231,6 @@ async fn start_fake_node(own_handler: String, own_client: String, other_handler: let gossip_task = tokio::spawn(async move { // Initialize a TestClient instance with the given stream and listener let (stream, _) = own_client_listener_r.try_lock().expect("Failed to acquire lock").accept().await.expect("Fail"); - debug!("Gossip will be listening on {:?}", stream); let gossip_client = Arc::new(Mutex::new(TestClient { stream: other_handler_stream.clone(), listener: Arc::new(Mutex::new(stream)) })); // Create a channel for stopping the gossiper @@ -276,22 +242,27 @@ async fn start_fake_node(own_handler: String, own_client: String, other_handler: }); // Sleep for a few seconds, make sure the whole process ran at least a couple of times - tokio::time::sleep(Duration::from_secs(1)).await; + tokio::time::sleep(Duration::from_secs(2)).await; { - let guard = set.try_lock().expect("Failed to acquire lock"); + let guard = set.lock().await; // As we have 3 elements in our set pre-gossip loop execution in each one of our fake gossip server, we should end up with 6 gossip at the end of our test run. - debug!("SET LEN {}", guard.set.len()); - // assert_eq!(guard.set.len(), 6); - // for gossip in vec_gossip_remote_client { - // assert_eq!(guard.set.contains(&gossip), true); - // } + assert!(guard.set.len() == 6); + // Need to find them all + for gossip in vec_gossip_remote_client { + debug!("Checking if gossip {:?} is present in set {:?}", gossip, guard.set); + assert!(guard.set.contains(&gossip)); + } } + debug!("Sending stop signal to gossiper"); + // Send the stop signal before awaiting the task. if stop_tx.send(()).await.is_err() { eprintln!("Failed to send stop signal"); } + tokio::time::sleep(Duration::from_secs(2)).await; + debug!("Checking if all things good"); // Await the completion of the gossiping task @@ -308,15 +279,13 @@ async fn main() { let mut vec_gossip_client_01 = Vec::new(); let mut vec_gossip_client_02 = Vec::new(); + vec_gossip_client_01.push(TestGossipableType { id: Id::from_slice(&[52, 25, 83, 149, 20, 226, 168, 61, 17, 53, 152, 11, 220, 226, 218, 254, 53, 104, 51, 247, 106, 6, 9, 26, 81, 52, 108, 232, 251, 122, 245, 112]) }); + vec_gossip_client_01.push(TestGossipableType { id: Id::from_slice(&[243, 156, 106, 56, 180, 213, 172, 165, 124, 118, 229, 60, 213, 183, 93, 241, 98, 214, 130, 235, 220, 45, 163, 151, 97, 64, 51, 126, 52, 164, 179, 23]) }); + vec_gossip_client_01.push(TestGossipableType { id: Id::from_slice(&[213, 8, 151, 77, 221, 160, 231, 33, 231, 180, 49, 113, 38, 196, 52, 156, 252, 66, 78, 250, 21, 56, 75, 247, 245, 87, 69, 157, 127, 53, 205, 121]) }); - for _ in 0..3 { - vec_gossip_client_01.push( - TestGossipableType { id: Id::from_slice(&random_manager::secure_bytes(32).unwrap()) } - ); - vec_gossip_client_02.push( - TestGossipableType { id: Id::from_slice(&random_manager::secure_bytes(32).unwrap()) } - ); - }; + vec_gossip_client_02.push(TestGossipableType { id: Id::from_slice(&[60, 209, 244, 35, 53, 217, 132, 157, 105, 97, 191, 32, 74, 199, 107, 124, 168, 61, 86, 203, 71, 247, 202, 161, 23, 124, 185, 63, 158, 54, 122, 216]) }); + vec_gossip_client_02.push(TestGossipableType { id: Id::from_slice(&[70, 203, 24, 230, 112, 82, 4, 22, 154, 173, 148, 189, 142, 217, 209, 191, 170, 242, 62, 213, 242, 133, 226, 200, 128, 87, 126, 157, 141, 78, 32, 67]) }); + vec_gossip_client_02.push(TestGossipableType { id: Id::from_slice(&[51, 215, 234, 45, 201, 210, 176, 176, 229, 6, 151, 169, 125, 219, 45, 56, 144, 205, 27, 74, 17, 13, 231, 59, 42, 214, 12, 184, 171, 251, 191, 197]) }); // Start the client @@ -325,7 +294,7 @@ async fn main() { let client_02_handle = tokio::spawn(start_fake_node("127.0.0.1:8082".to_string(), "127.0.0.1:8083".to_string(), "127.0.0.1:8080".to_string(), "127.0.0.1:8081".to_string(), vec_gossip_client_02.clone(), vec_gossip_client_01.clone())); // Wait for the server and client to complete - client_01_handle.await.unwrap(); - client_02_handle.await.unwrap(); + client_01_handle.await.expect("Issue with client01"); + client_02_handle.await.expect("Issue with client02"); } diff --git a/core/network/src/p2p/gossip/gossip.rs b/core/network/src/p2p/gossip/gossip.rs index 779d50c..30bf22b 100644 --- a/core/network/src/p2p/gossip/gossip.rs +++ b/core/network/src/p2p/gossip/gossip.rs @@ -10,6 +10,8 @@ use std::ops::Deref; use tokio::sync::Mutex; use std::sync::Arc; use std::time::Duration; +use serde::Serialize; +use serde_json::to_vec; use tokio::select; use tokio::sync::mpsc::{channel, Receiver}; use tokio::time::interval; @@ -50,7 +52,7 @@ impl Gossiper } } - pub async fn gossip(&mut self) { + pub async fn gossip(&mut self) where ::Item: Clone, ::Item: Serialize { let mut gossip_ticker = interval(self.config.frequency); loop { @@ -71,7 +73,7 @@ impl Gossiper } } - async fn execute(&mut self) -> Result<(), Box> { + async fn execute(&mut self) -> Result<(), Box> where ::Item: Clone, ::Item: Serialize { //ToDo Dummy vec for now. let bloom = Vec::new(); @@ -86,47 +88,38 @@ impl Gossiper { let set_guard = self.set.lock().await; - let elem = set_guard.fetch_elements(); + let elem = set_guard.fetch_all_elements(); - let filter = elem.serialize().expect("Issue serializing elem"); - request.filter = filter; + request.filter = to_vec(&elem)?; + + // debug!("TTTTT {:?}", t); request.encode(&mut msg_bytes)?; } - debug!("Before going over the poll_size"); for _ in 0..self.config.poll_size { { - debug!("poll_size"); let set = Arc::clone(&self.set.clone()); // Initialize the callback that will be used upon receiving a response from our gossip attempt let on_response: AppResponseCallback = Arc::new({ move |response_bytes| { - debug!("In AppResponseCallback -- beginning"); let response = match PullGossipResponse::decode(response_bytes.as_slice()) { Ok(res) => { - debug!("Decoded in AppResponseCallback -- {:?}", res); res } Err(e) => { - error!("failed to unmarshal gossip response, error: {:?}", e); return; } }; // We iterate over the response's gossip - debug!("There are {} gossips", response.gossip.len()); for bytes in response.gossip.iter() { let mut gossipable: S::Item = S::Item::default(); - debug!("In AppResponseCallback -- deserialized gossipable -- {:?}", gossipable); gossipable.deserialize(bytes).unwrap(); - debug!("In AppResponseCallback -- deserialized gossipable -- {:?}", gossipable); let hash = gossipable.get_id(); - debug!("In AppResponseCallback -- let hash = gossipable.get_id(); -- {:?}", hash); let mut set_guard = set.try_lock().expect("Failed to acquire lock on set"); - debug!("In AppResponseCallback -- set_guard = set.try_lock()"); if let Err(e) = set_guard.add(gossipable) { error!( "failed to add gossip to the known set, id: {:?}, error: {:?}" @@ -135,14 +128,11 @@ impl Gossiper continue; } } - debug!("In AppResponseCallback -- ending"); } }); let mut guard = self.client.try_lock().expect("Failed to acquire a lock on client"); - debug!("After acquiring lock for client in execute"); guard.app_request_any(msg_bytes.clone(), on_response).await; - debug!("After app_request_any in execute"); } } @@ -216,7 +206,7 @@ mod test { } fn iterate(&self, _f: &mut dyn FnMut(&T) -> bool) { - unimplemented!() + todo!() } } diff --git a/core/network/src/p2p/gossip/handler.rs b/core/network/src/p2p/gossip/handler.rs index c4e1950..6788087 100644 --- a/core/network/src/p2p/gossip/handler.rs +++ b/core/network/src/p2p/gossip/handler.rs @@ -1,15 +1,16 @@ use std::error::Error; use std::fmt::Debug; -use tokio::sync::Mutex; +use tokio::sync::{Mutex, MutexGuard, TryLockError}; use std::sync::Arc; use std::time::Duration; use async_trait::async_trait; -use log::debug; +use log::{debug, error}; use prost::Message; use avalanche_types::ids::node::Id; use crate::p2p; use crate::p2p::gossip::{Gossipable, Set}; use crate::p2p::sdk::{PullGossipRequest, PullGossipResponse}; +use serde_json::{from_slice, to_vec}; pub struct HandlerConfig { pub namespace: String, @@ -37,19 +38,30 @@ pub fn new_handler( #[allow(unused_variables)] impl p2p::handler::Handler for Handler where - S: Set + Debug, + S: Set + Debug + for <'de> serde::Deserialize<'de>, S::Item: Default { async fn app_gossip(&self, node_id: Id, gossip_bytes: Vec) -> Result, Box> { let request = PullGossipRequest::decode(gossip_bytes.as_slice()).expect("Failed to decode request_bytes into PullGossipRequest"); - debug!("Allloooo"); + //toDo look at this Box shennanigan here + let filter: Vec<::Item> = from_slice(&request.filter).unwrap(); let mut response_size = 0_usize; - let mut gossip_bytes: Vec> = Vec::new(); - let guard = self.set.try_lock().expect("Lock failed on set"); - debug!("BEFORE Iterate over set gossipable items"); + let mut response_bytes: Vec> = Vec::new(); + let guard = match self.set.try_lock() { + Ok(guard) => { guard } + Err(err) => { + error!("Could not lock self.set in app_gossip"); + return Err(Box::try_from("Could not lock self.set in app_gossip").unwrap()) + } + }; + guard.iterate(&mut |gossipable : &S::Item| { - debug!("Iterate over set gossipable items"); + println!("Iterating in handler"); + if filter.contains(&gossipable) { + return true + }; + let bytes = match gossipable.serialize() { Ok(b) => { b @@ -59,19 +71,17 @@ impl p2p::handler::Handler for Handler } }; - debug!("In app_gossip -- bytes == {:?}", bytes); - gossip_bytes.push(bytes.clone()); + response_bytes.push(bytes.clone()); response_size += bytes.len(); response_size <= self.target_response_size }); let mut response = PullGossipResponse::default(); - response.gossip = gossip_bytes; + response.gossip = response_bytes; let mut response_bytes = vec![]; response.encode(&mut response_bytes).expect("Failed to encode response_bytes into PullGossipResponse"); - debug!("Response bytes in app_gossip {:?}", response_bytes); Ok(response_bytes) } @@ -87,7 +97,6 @@ impl p2p::handler::Handler for Handler let mut gossip_bytes: Vec> = Vec::new(); self.set.lock().await.iterate(&mut |gossipable| { - if self.set.try_lock().expect("ssss").has(gossipable) { return true }; @@ -113,6 +122,6 @@ impl p2p::handler::Handler for Handler } async fn cross_chain_app_request(&self, chain_id: Id, deadline: Duration, request_bytes: Vec) -> Result, Box> { - unimplemented!() + todo!() } } \ No newline at end of file diff --git a/core/network/src/p2p/gossip/mod.rs b/core/network/src/p2p/gossip/mod.rs index eaca86c..50d0d0d 100644 --- a/core/network/src/p2p/gossip/mod.rs +++ b/core/network/src/p2p/gossip/mod.rs @@ -2,6 +2,7 @@ pub mod gossip; pub mod handler; use std::fmt::Debug; +use serde::{Deserialize, Serialize}; use avalanche_types::ids::Id; pub trait Gossipable { @@ -11,10 +12,10 @@ pub trait Gossipable { } pub trait Set: Send + Sync { - type Item: Gossipable + ?Sized + Debug; + type Item: Gossipable + ?Sized + Debug + Serialize + for<'de> Deserialize<'de> + PartialEq; fn add(&mut self, gossipable: Self::Item) -> Result<(), Box>; - fn has(&self, gossipable: &Self::Item) -> bool; fn iterate(&self, f: &mut dyn FnMut(&Self::Item) -> bool); fn fetch_elements(&self) -> Self::Item; + fn fetch_all_elements(&self) -> Vec where ::Item: Sized; } From 884f1fd20c0e93401ee4392f1d0e8e8341b7ec12 Mon Sep 17 00:00:00 2001 From: sanghren Date: Sun, 1 Oct 2023 14:55:22 +0200 Subject: [PATCH 39/53] feat: wip --- core/network/examples/peer_gossip.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/network/examples/peer_gossip.rs b/core/network/examples/peer_gossip.rs index 346e363..77cc6c7 100644 --- a/core/network/examples/peer_gossip.rs +++ b/core/network/examples/peer_gossip.rs @@ -31,8 +31,8 @@ impl Client for TestClient { } async fn app_request_any(&mut self, request_bytes: Vec, on_response: AppResponseCallback) { - let mut stream_guard = self.stream.lock().await; - stream_guard.write_all(&*request_bytes).await.unwrap(); + let mut stream = self.stream.lock().await; + stream.write_all(&*request_bytes).await.unwrap(); // Lock the listener and wait for a new connection let clone = self.listener.clone(); From c5446e6969587268d8e339594fb2d759860e53c9 Mon Sep 17 00:00:00 2001 From: sanghren Date: Sun, 1 Oct 2023 19:11:32 +0200 Subject: [PATCH 40/53] feat: wip --- core/network/examples/peer_gossip.rs | 72 +++++++++++++++++++++------- core/network/src/p2p/client.rs | 2 +- 2 files changed, 57 insertions(+), 17 deletions(-) diff --git a/core/network/examples/peer_gossip.rs b/core/network/examples/peer_gossip.rs index 77cc6c7..26bc788 100644 --- a/core/network/examples/peer_gossip.rs +++ b/core/network/examples/peer_gossip.rs @@ -10,8 +10,9 @@ use rand::prelude::SliceRandom; use serde::{Deserialize, Serialize}; use tokio::net::{TcpListener, TcpStream}; use tokio::io::{AsyncReadExt, AsyncWriteExt}; +use tokio::select; use network::p2p::gossip::gossip::{Config, Gossiper}; -use tokio::sync::mpsc::{channel}; +use tokio::sync::mpsc::{channel, Receiver}; use avalanche_types::ids::Id; use network::p2p::client::{AppResponseCallback, Client}; use network::p2p::gossip::{Gossipable, Set}; @@ -30,29 +31,29 @@ impl Client for TestClient { todo!() } - async fn app_request_any(&mut self, request_bytes: Vec, on_response: AppResponseCallback) { + async fn app_request_any(&mut self, request_bytes: Vec, on_response: AppResponseCallback) -> Result<(), std::io::Error> { let mut stream = self.stream.lock().await; - stream.write_all(&*request_bytes).await.unwrap(); + stream.write_all(&*request_bytes).await?; // Lock the listener and wait for a new connection let clone = self.listener.clone(); - let mut listener = clone.try_lock().expect("Unable to lock listener"); + let mut listener = clone.lock().await; let mut buf = [0u8; 1024]; match listener.read(&mut buf).await { Ok(n) => { if n == 0 { - // Connection was closed + debug!("Connection to the listener was closed"); + () } - // Handle received data here: buf[0..n] on_response(buf[0..n].to_vec()); } Err(e) => { - // Handle the error. + error!("Issue occured in app_request_any {:?}", e) } } - + Ok(()) } } @@ -141,19 +142,22 @@ impl D } } -async fn fake_handler_server_logic(mut socket: TcpStream, client_socket: Arc>, handler: Handler>) { +async fn fake_handler_server_logic(mut socket: TcpStream, client_socket: Arc>, handler: Handler>, mut stop_handler_rx: Receiver<()>) { // Initialize a buffer of size 1024. let mut buf = [0u8; 1024]; loop { - let n = socket.read(&mut buf).await.unwrap(); - // // Empty, wait 5 sec before next attempt - if n == 0 { - tokio::time::sleep(Duration::from_secs(5)).await; + select! { + result = socket.read(&mut buf) => { + debug!("Handler tick"); + match result { + Ok(n) if n == 0 => { + tokio::time::sleep(Duration::from_secs(5)).await; break; - } + } - // Fake test data. +Ok(n) => { + // Fake test data. let node_id: avalanche_types::ids::node::Id = avalanche_types::ids::node::Id::from_slice(&random_manager::secure_bytes(20).unwrap()); let res_bytes = match handler.app_gossip(node_id, buf[0..n].to_vec()).await { Ok(res) => { res} @@ -170,7 +174,29 @@ async fn fake_handler_server_logic(mut socket: TcpStream, client_socket: Arc { + error!("Error {:?}", err); + } +} + + + } + _ = stop_handler_rx.recv() => { + debug!("Shutting down handler"); + let mut guard = client_socket.try_lock().expect("Lock of client_socket failed"); + + let mut temp_vec = Vec::new(); + temp_vec.push(1); + guard.write_all(temp_vec.as_slice()).await; + break; + } + } + let n = socket.read(&mut buf).await.unwrap(); + // // Empty, wait 5 sec before next attempt } + + debug!("Out of handler loop"); } async fn start_fake_node(own_handler: String, own_client: String, other_handler: String, other_client: String, vec_gossip_local_client: Vec, vec_gossip_remote_client: Vec) { @@ -212,12 +238,15 @@ async fn start_fake_node(own_handler: String, own_client: String, other_handler: // Clone listener and stream for use inside the spawned task. let own_handler_listener_clone = own_handler_listener.clone(); let other_client_stream_clone = other_client_stream.clone(); + let (stop_handler_tx, stop_handler_rx) = channel(1); + // Spawn an asynchronous task that will handle incoming connections in a loop let handler_task = tokio::spawn(async move { // Accept incoming connections and spawn a new task to handle each connection let guard = own_handler_listener_clone.try_lock().expect("Error acquiring lock on listener_clone"); let (listener_socket, _) = guard.accept().await.unwrap(); - fake_handler_server_logic(listener_socket, other_client_stream_clone.clone(), handler.clone()).await; + fake_handler_server_logic(listener_socket, other_client_stream_clone.clone(), handler.clone(), stop_handler_rx).await; + debug!("HANDLER DONEZO"); }); { @@ -239,6 +268,7 @@ async fn start_fake_node(own_handler: String, own_client: String, other_handler: let mut gossiper = Gossiper::new(config, set_clone, gossip_client.clone(), stop_rx); gossiper.gossip().await; + debug!("GOSSIP DONEZO"); }); // Sleep for a few seconds, make sure the whole process ran at least a couple of times @@ -254,6 +284,12 @@ async fn start_fake_node(own_handler: String, own_client: String, other_handler: assert!(guard.set.contains(&gossip)); } } + debug!("Sending stop signal to handler"); + + // Send the stop signal before awaiting the task. + if stop_handler_tx.send(()).await.is_err() { + eprintln!("Failed to send stop signal"); + } debug!("Sending stop signal to gossiper"); @@ -261,13 +297,17 @@ async fn start_fake_node(own_handler: String, own_client: String, other_handler: if stop_tx.send(()).await.is_err() { eprintln!("Failed to send stop signal"); } + + tokio::time::sleep(Duration::from_secs(2)).await; debug!("Checking if all things good"); // Await the completion of the gossiping task let _ = gossip_task.await.expect("Gossip task failed"); + debug!("Gossip task completed"); let _ = handler_task.await.expect("Handler task failed"); + debug!("Handler task completed"); } diff --git a/core/network/src/p2p/client.rs b/core/network/src/p2p/client.rs index f933f90..d271420 100644 --- a/core/network/src/p2p/client.rs +++ b/core/network/src/p2p/client.rs @@ -5,7 +5,7 @@ pub type AppResponseCallback = Arc) + Send + Sync>; #[async_trait] #[allow(unused_variables)] pub trait Client: Send + Sync { - async fn app_request_any(&mut self, request_bytes: Vec, on_response: AppResponseCallback) {} + async fn app_request_any(&mut self, request_bytes: Vec, on_response: AppResponseCallback) -> Result<(), std::io::Error> { Ok(()) } async fn app_request(&mut self, request_bytes: Vec) {} async fn app_gossip(&mut self, request_bytes: Vec) {} async fn app_gossip_specific(&mut self, request_bytes: Vec) {} From e4b3400c5df2fd037bd3237e1a329ab4b7e2178a Mon Sep 17 00:00:00 2001 From: sanghren Date: Sun, 1 Oct 2023 19:26:58 +0200 Subject: [PATCH 41/53] feat: wip --- core/network/examples/peer_gossip.rs | 6 +++--- core/network/src/p2p/gossip/gossip.rs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/core/network/examples/peer_gossip.rs b/core/network/examples/peer_gossip.rs index 26bc788..13f4ada 100644 --- a/core/network/examples/peer_gossip.rs +++ b/core/network/examples/peer_gossip.rs @@ -107,13 +107,13 @@ impl MockSet { impl Deserialize<'de> + Serialize> Set for MockSet { type Item = T; - fn add(&mut self, _gossipable: T) -> Result<(), Box> { + fn add(&mut self, gossipable: T) -> Result<(), Box> { // Just for our test purpose am checking manually if we insert an already known gossip. - if self.set.contains(&_gossipable) { + if self.set.contains(&gossipable) { error!("Cannot insert this item, already known"); } else { - self.set.push(_gossipable.clone()); + self.set.push(gossipable.clone()); } Ok(()) diff --git a/core/network/src/p2p/gossip/gossip.rs b/core/network/src/p2p/gossip/gossip.rs index 30bf22b..dfdd128 100644 --- a/core/network/src/p2p/gossip/gossip.rs +++ b/core/network/src/p2p/gossip/gossip.rs @@ -200,8 +200,8 @@ mod test { impl Set for MockSet { type Item = T; - fn add(&mut self, _gossipable: T) -> Result<(), Box> { - self.set.push(_gossipable.clone()); + fn add(&mut self, gossipable: T) -> Result<(), Box> { + self.set.push(gossipable.clone()); Ok(()) } From fb0359e75f8266374c953ef41e00fdb6d8bede0d Mon Sep 17 00:00:00 2001 From: sanghren Date: Sun, 1 Oct 2023 19:29:11 +0200 Subject: [PATCH 42/53] feat: wip --- core/network/examples/peer_gossip.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/network/examples/peer_gossip.rs b/core/network/examples/peer_gossip.rs index 13f4ada..b801b01 100644 --- a/core/network/examples/peer_gossip.rs +++ b/core/network/examples/peer_gossip.rs @@ -14,6 +14,7 @@ use tokio::select; use network::p2p::gossip::gossip::{Config, Gossiper}; use tokio::sync::mpsc::{channel, Receiver}; use avalanche_types::ids::Id; +use avalanche_types::ids::node::Id as NodeId; use network::p2p::client::{AppResponseCallback, Client}; use network::p2p::gossip::{Gossipable, Set}; use network::p2p::gossip::handler::{Handler, HandlerConfig, new_handler}; @@ -158,7 +159,7 @@ async fn fake_handler_server_logic(mut socket: TcpStream, client_socket: Arc { // Fake test data. - let node_id: avalanche_types::ids::node::Id = avalanche_types::ids::node::Id::from_slice(&random_manager::secure_bytes(20).unwrap()); + let node_id: NodeId = NodeId::from_slice(&random_manager::secure_bytes(20).unwrap()); let res_bytes = match handler.app_gossip(node_id, buf[0..n].to_vec()).await { Ok(res) => { res} Err(error) => { continue } From ccce15b06088eef5b5c372c813c55cdd0c91263c Mon Sep 17 00:00:00 2001 From: sanghren Date: Sun, 1 Oct 2023 19:57:59 +0200 Subject: [PATCH 43/53] feat: wip --- core/network/examples/peer_gossip.rs | 76 +++++++++++++--------------- 1 file changed, 36 insertions(+), 40 deletions(-) diff --git a/core/network/examples/peer_gossip.rs b/core/network/examples/peer_gossip.rs index b801b01..79b4b4e 100644 --- a/core/network/examples/peer_gossip.rs +++ b/core/network/examples/peer_gossip.rs @@ -149,52 +149,48 @@ async fn fake_handler_server_logic(mut socket: TcpStream, client_socket: Arc { - debug!("Handler tick"); + result = socket.read(&mut buf) => { + debug!("Handler tick"); match result { Ok(n) if n == 0 => { - tokio::time::sleep(Duration::from_secs(5)).await; - break; + break; // to check } - -Ok(n) => { - // Fake test data. - let node_id: NodeId = NodeId::from_slice(&random_manager::secure_bytes(20).unwrap()); - let res_bytes = match handler.app_gossip(node_id, buf[0..n].to_vec()).await { - Ok(res) => { res} - Err(error) => { continue } - }; - - let mut guard = client_socket.try_lock().expect("Lock of client_socket failed"); - - if res_bytes.is_empty() { - // ToDo Whenever the handler return nothing , gossip part hang. Temp dev fix to get pass this - let mut temp_vec = Vec::new(); - temp_vec.push(1); - guard.write_all(temp_vec.as_slice()).await; - } else { - let _ = guard.write_all(&res_bytes).await; - } - } - Err(err) => { - error!("Error {:?}", err); - } -} - - + Ok(n) => { + let node_id: NodeId = NodeId::from_slice(&random_manager::secure_bytes(20).unwrap()); + let res_bytes = match handler.app_gossip(node_id, buf[0..n].to_vec()).await { + Ok(res) => { res} + Err(error) => { continue } + }; + + debug!("Before aa"); + let mut guard = client_socket.lock().await; + debug!("After aa {:?}", res_bytes); + + if res_bytes.is_empty() { + // ToDo Whenever the handler return nothing , gossip part hang. Temp dev fix to get pass this + let mut temp_vec = Vec::new(); + temp_vec.push(1); + guard.write_all(temp_vec.as_slice()).await; + } else { + let _ = guard.write_all(&res_bytes).await; + } + + } + Err(err) => { + error!("Error {:?}", err); + } } - _ = stop_handler_rx.recv() => { - debug!("Shutting down handler"); - let mut guard = client_socket.try_lock().expect("Lock of client_socket failed"); - + debug!("End of handler tick run"); + } + _ = stop_handler_rx.recv() => { + debug!("Shutting down handler"); + let mut guard = client_socket.try_lock().expect("Lock of client_socket failed"); let mut temp_vec = Vec::new(); - temp_vec.push(1); - guard.write_all(temp_vec.as_slice()).await; - break; - } + temp_vec.push(1); + guard.write_all(temp_vec.as_slice()).await; + break; } - let n = socket.read(&mut buf).await.unwrap(); - // // Empty, wait 5 sec before next attempt + } } debug!("Out of handler loop"); From 774ca6ef6e7e596193b837526d337c5b9c7b3cb8 Mon Sep 17 00:00:00 2001 From: sanghren Date: Sun, 1 Oct 2023 20:22:56 +0200 Subject: [PATCH 44/53] feat: wip --- core/network/examples/peer_gossip.rs | 18 +++++++++--------- core/network/src/p2p/gossip/gossip.rs | 7 +++---- core/network/src/p2p/gossip/handler.rs | 6 +++--- 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/core/network/examples/peer_gossip.rs b/core/network/examples/peer_gossip.rs index 79b4b4e..caaa4b2 100644 --- a/core/network/examples/peer_gossip.rs +++ b/core/network/examples/peer_gossip.rs @@ -153,26 +153,26 @@ async fn fake_handler_server_logic(mut socket: TcpStream, client_socket: Arc { - break; // to check + break; // to check, 0 means connection closed ? } Ok(n) => { - let node_id: NodeId = NodeId::from_slice(&random_manager::secure_bytes(20).unwrap()); + let node_id: NodeId = NodeId::from_slice(&random_manager::secure_bytes(20).unwrap()); // Since we fake the network layer, we need to fake this as well let res_bytes = match handler.app_gossip(node_id, buf[0..n].to_vec()).await { Ok(res) => { res} - Err(error) => { continue } + Err(error) => { error!("{:?}", error); continue } }; debug!("Before aa"); - let mut guard = client_socket.lock().await; + let mut stream = client_socket.lock().await; debug!("After aa {:?}", res_bytes); if res_bytes.is_empty() { // ToDo Whenever the handler return nothing , gossip part hang. Temp dev fix to get pass this let mut temp_vec = Vec::new(); temp_vec.push(1); - guard.write_all(temp_vec.as_slice()).await; + let _ = stream.write_all(temp_vec.as_slice()).await; // todo check, feels ugly } else { - let _ = guard.write_all(&res_bytes).await; + let _ = stream.write_all(&res_bytes).await; } } @@ -184,10 +184,10 @@ async fn fake_handler_server_logic(mut socket: TcpStream, client_socket: Arc { debug!("Shutting down handler"); - let mut guard = client_socket.try_lock().expect("Lock of client_socket failed"); + let mut stream = client_socket.lock().await; let mut temp_vec = Vec::new(); temp_vec.push(1); - guard.write_all(temp_vec.as_slice()).await; + let _ = stream.write_all(temp_vec.as_slice()).await; // todo check, feels ugly break; } } @@ -217,7 +217,7 @@ async fn start_fake_node(own_handler: String, own_client: String, other_handler: // Initialize the configuration for the handler and create a new handler let handler_config = HandlerConfig { namespace: "test".to_string(), target_response_size: 1000 }; - let mut set = Arc::new(Mutex::new(MockSet { set: Vec::::new() })); + let set = Arc::new(Mutex::new(MockSet { set: Vec::::new() })); // Generating fake data and pushing to set { for gossip in &vec_gossip_local_client { diff --git a/core/network/src/p2p/gossip/gossip.rs b/core/network/src/p2p/gossip/gossip.rs index dfdd128..d28b125 100644 --- a/core/network/src/p2p/gossip/gossip.rs +++ b/core/network/src/p2p/gossip/gossip.rs @@ -5,15 +5,13 @@ use avalanche_types::ids::Id; use log::{debug, error}; use prost::Message; use std::error::Error; -use std::hash::Hash; -use std::ops::Deref; use tokio::sync::Mutex; use std::sync::Arc; use std::time::Duration; use serde::Serialize; use serde_json::to_vec; use tokio::select; -use tokio::sync::mpsc::{channel, Receiver}; +use tokio::sync::mpsc::Receiver; use tokio::time::interval; pub struct Config { @@ -108,6 +106,7 @@ impl Gossiper res } Err(e) => { + error!("{:?}", e); return; } }; @@ -132,7 +131,7 @@ impl Gossiper }); let mut guard = self.client.try_lock().expect("Failed to acquire a lock on client"); - guard.app_request_any(msg_bytes.clone(), on_response).await; + let _ = guard.app_request_any(msg_bytes.clone(), on_response).await; } } diff --git a/core/network/src/p2p/gossip/handler.rs b/core/network/src/p2p/gossip/handler.rs index 6788087..6b0984f 100644 --- a/core/network/src/p2p/gossip/handler.rs +++ b/core/network/src/p2p/gossip/handler.rs @@ -1,16 +1,16 @@ use std::error::Error; use std::fmt::Debug; -use tokio::sync::{Mutex, MutexGuard, TryLockError}; +use tokio::sync::Mutex; use std::sync::Arc; use std::time::Duration; use async_trait::async_trait; -use log::{debug, error}; +use log::error; use prost::Message; use avalanche_types::ids::node::Id; use crate::p2p; use crate::p2p::gossip::{Gossipable, Set}; use crate::p2p::sdk::{PullGossipRequest, PullGossipResponse}; -use serde_json::{from_slice, to_vec}; +use serde_json::from_slice; pub struct HandlerConfig { pub namespace: String, From ec6767a3f96d677fc0aaa97f3c3b6edccc545b58 Mon Sep 17 00:00:00 2001 From: sanghren Date: Sun, 1 Oct 2023 20:26:51 +0200 Subject: [PATCH 45/53] feat: wip --- core/network/examples/peer_gossip.rs | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/core/network/examples/peer_gossip.rs b/core/network/examples/peer_gossip.rs index caaa4b2..8c6c951 100644 --- a/core/network/examples/peer_gossip.rs +++ b/core/network/examples/peer_gossip.rs @@ -217,15 +217,14 @@ async fn start_fake_node(own_handler: String, own_client: String, other_handler: // Initialize the configuration for the handler and create a new handler let handler_config = HandlerConfig { namespace: "test".to_string(), target_response_size: 1000 }; - let set = Arc::new(Mutex::new(MockSet { set: Vec::::new() })); - // Generating fake data and pushing to set - { - for gossip in &vec_gossip_local_client { - set.try_lock().expect("Failed to acquire lock").set.push( - gossip.clone() - ); - } + let mut mock_set = MockSet { set: Vec::::new() }; + for gossip in &vec_gossip_local_client { + mock_set.set.push( + gossip.clone() + ); } + let set = Arc::new(Mutex::new(mock_set )); + let handler = new_handler( handler_config, @@ -240,14 +239,14 @@ async fn start_fake_node(own_handler: String, own_client: String, other_handler: // Spawn an asynchronous task that will handle incoming connections in a loop let handler_task = tokio::spawn(async move { // Accept incoming connections and spawn a new task to handle each connection - let guard = own_handler_listener_clone.try_lock().expect("Error acquiring lock on listener_clone"); - let (listener_socket, _) = guard.accept().await.unwrap(); + let listener = own_handler_listener_clone.lock().await; + let (listener_socket, _) = listener.accept().await.unwrap(); fake_handler_server_logic(listener_socket, other_client_stream_clone.clone(), handler.clone(), stop_handler_rx).await; debug!("HANDLER DONEZO"); }); { - assert_eq!(set.try_lock().expect("Failed to acquire lock").set.len().clone(), 3); + assert_eq!(set.lock().await.set.len().clone(), 3); } let (stop_tx, stop_rx) = channel(1); @@ -256,7 +255,7 @@ async fn start_fake_node(own_handler: String, own_client: String, other_handler: let set_clone = set.clone(); let gossip_task = tokio::spawn(async move { // Initialize a TestClient instance with the given stream and listener - let (stream, _) = own_client_listener_r.try_lock().expect("Failed to acquire lock").accept().await.expect("Fail"); + let (stream, _) = own_client_listener_r.lock().await.accept().await.expect("Fail"); let gossip_client = Arc::new(Mutex::new(TestClient { stream: other_handler_stream.clone(), listener: Arc::new(Mutex::new(stream)) })); // Create a channel for stopping the gossiper From 7db76bc8e995f6a5fc376162783060b7c090c06d Mon Sep 17 00:00:00 2001 From: sanghren Date: Sun, 1 Oct 2023 20:52:45 +0200 Subject: [PATCH 46/53] feat: clean --- core/network/examples/peer_gossip.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/network/examples/peer_gossip.rs b/core/network/examples/peer_gossip.rs index 8c6c951..1e1dbba 100644 --- a/core/network/examples/peer_gossip.rs +++ b/core/network/examples/peer_gossip.rs @@ -270,9 +270,10 @@ async fn start_fake_node(own_handler: String, own_client: String, other_handler: // Sleep for a few seconds, make sure the whole process ran at least a couple of times tokio::time::sleep(Duration::from_secs(2)).await; + { let guard = set.lock().await; - // As we have 3 elements in our set pre-gossip loop execution in each one of our fake gossip server, we should end up with 6 gossip at the end of our test run. + // As we have 3 elements in our set (pre-gossip loop execution) in each one of our fake gossip server, we should end up with 6 gossip at the end of our test run. assert!(guard.set.len() == 6); // Need to find them all for gossip in vec_gossip_remote_client { @@ -280,6 +281,7 @@ async fn start_fake_node(own_handler: String, own_client: String, other_handler: assert!(guard.set.contains(&gossip)); } } + debug!("Sending stop signal to handler"); // Send the stop signal before awaiting the task. From 36c40dd76081b23e00db4c89e5b8f0a1dc9dcbfc Mon Sep 17 00:00:00 2001 From: sanghren Date: Sun, 1 Oct 2023 22:15:50 +0200 Subject: [PATCH 47/53] feat: clean --- core/network/examples/peer_gossip.rs | 19 +++---- core/network/src/p2p/client.rs | 4 +- core/network/src/p2p/gossip/gossip.rs | 75 ++++++++++++--------------- 3 files changed, 43 insertions(+), 55 deletions(-) diff --git a/core/network/examples/peer_gossip.rs b/core/network/examples/peer_gossip.rs index 1e1dbba..a05d8d5 100644 --- a/core/network/examples/peer_gossip.rs +++ b/core/network/examples/peer_gossip.rs @@ -32,9 +32,9 @@ impl Client for TestClient { todo!() } - async fn app_request_any(&mut self, request_bytes: Vec, on_response: AppResponseCallback) -> Result<(), std::io::Error> { + async fn app_request_any(&mut self, request_bytes: &Vec, on_response: AppResponseCallback) -> Result<(), std::io::Error> { let mut stream = self.stream.lock().await; - stream.write_all(&*request_bytes).await?; + stream.write_all(request_bytes).await?; // Lock the listener and wait for a new connection let clone = self.listener.clone(); @@ -196,7 +196,7 @@ async fn fake_handler_server_logic(mut socket: TcpStream, client_socket: Arc, vec_gossip_remote_client: Vec) { +async fn start_fake_node(own_handler: &str, own_client: &str, other_handler: &str, other_client: &str, vec_gossip_local_client: Vec, vec_gossip_remote_client: Vec) -> Result<(), std::io::Error> { // Initialize the configuration for the gossiper let config = Config { namespace: "test".to_string(), @@ -206,13 +206,13 @@ async fn start_fake_node(own_handler: String, own_client: String, other_handler: // Create a TcpListener to receive messages on. // Wrapping it in Arc and Mutex to safely share it between threads. - let own_handler_listener = Arc::new(Mutex::new(TcpListener::bind(own_handler.clone()).await.unwrap())); - let own_client_listener_r = Arc::new(Mutex::new(TcpListener::bind(own_client.clone()).await.unwrap())); + let own_handler_listener = Arc::new(Mutex::new(TcpListener::bind(own_handler).await?)); + let own_client_listener_r = Arc::new(Mutex::new(TcpListener::bind(own_client).await?)); // Create a TcpStream to send messages to. // Wrapping it in Arc and Mutex to safely share it between threads. - let other_client_stream = Arc::new(Mutex::new(TcpStream::connect(other_client).await.unwrap())); - let other_handler_stream = Arc::new(Mutex::new(TcpStream::connect(other_handler.clone()).await.unwrap())); + let other_client_stream = Arc::new(Mutex::new(TcpStream::connect(other_client).await?)); + let other_handler_stream = Arc::new(Mutex::new(TcpStream::connect(other_handler.clone()).await?)); // Initialize the configuration for the handler and create a new handler let handler_config = HandlerConfig { namespace: "test".to_string(), target_response_size: 1000 }; @@ -306,6 +306,7 @@ async fn start_fake_node(own_handler: String, own_client: String, other_handler: debug!("Gossip task completed"); let _ = handler_task.await.expect("Handler task failed"); debug!("Handler task completed"); + Ok(()) } @@ -328,8 +329,8 @@ async fn main() { // Start the client // listen on 8080 , send message to 8081 - let client_01_handle = tokio::spawn(start_fake_node("127.0.0.1:8080".to_string(), "127.0.0.1:8081".to_string(), "127.0.0.1:8082".to_string(), "127.0.0.1:8083".to_string(), vec_gossip_client_01.clone(), vec_gossip_client_02.clone())); - let client_02_handle = tokio::spawn(start_fake_node("127.0.0.1:8082".to_string(), "127.0.0.1:8083".to_string(), "127.0.0.1:8080".to_string(), "127.0.0.1:8081".to_string(), vec_gossip_client_02.clone(), vec_gossip_client_01.clone())); + let client_01_handle = tokio::spawn(start_fake_node("127.0.0.1:8080", "127.0.0.1:8081", "127.0.0.1:8082", "127.0.0.1:8083", vec_gossip_client_01.clone(), vec_gossip_client_02.clone())); + let client_02_handle = tokio::spawn(start_fake_node("127.0.0.1:8082", "127.0.0.1:8083", "127.0.0.1:8080", "127.0.0.1:8081", vec_gossip_client_02.clone(), vec_gossip_client_01.clone())); // Wait for the server and client to complete client_01_handle.await.expect("Issue with client01"); diff --git a/core/network/src/p2p/client.rs b/core/network/src/p2p/client.rs index d271420..c696900 100644 --- a/core/network/src/p2p/client.rs +++ b/core/network/src/p2p/client.rs @@ -5,7 +5,7 @@ pub type AppResponseCallback = Arc) + Send + Sync>; #[async_trait] #[allow(unused_variables)] pub trait Client: Send + Sync { - async fn app_request_any(&mut self, request_bytes: Vec, on_response: AppResponseCallback) -> Result<(), std::io::Error> { Ok(()) } + async fn app_request_any(&mut self, request_bytes: &Vec, on_response: AppResponseCallback) -> Result<(), std::io::Error> { Ok(()) } async fn app_request(&mut self, request_bytes: Vec) {} async fn app_gossip(&mut self, request_bytes: Vec) {} async fn app_gossip_specific(&mut self, request_bytes: Vec) {} @@ -15,8 +15,6 @@ pub trait Client: Send + Sync { pub struct NoOpClient; -unsafe impl Sync for NoOpClient {} -unsafe impl Send for NoOpClient {} impl Client for NoOpClient { } diff --git a/core/network/src/p2p/gossip/gossip.rs b/core/network/src/p2p/gossip/gossip.rs index d28b125..93f915a 100644 --- a/core/network/src/p2p/gossip/gossip.rs +++ b/core/network/src/p2p/gossip/gossip.rs @@ -27,10 +27,6 @@ pub struct Gossiper { stop_rx: Receiver<()>, } -unsafe impl Sync for Gossiper {} - -unsafe impl Send for Gossiper {} - impl Gossiper where S: Set, @@ -59,7 +55,7 @@ impl Gossiper debug!("Gossip tick"); if let Err(e) = self.execute().await { error!("Failed to Gossip : {:?}", e); - //ToDo + todo!(); } } @@ -83,56 +79,49 @@ impl Gossiper let mut msg_bytes = vec![]; // We scope the lock here to avoid issue later on - { - let set_guard = self.set.lock().await; + let elem = self.set.lock().await.fetch_all_elements(); - let elem = set_guard.fetch_all_elements(); + request.filter = to_vec(&elem)?; - request.filter = to_vec(&elem)?; + request.encode(&mut msg_bytes)?; - // debug!("TTTTT {:?}", t); - request.encode(&mut msg_bytes)?; - } for _ in 0..self.config.poll_size { - { - let set = Arc::clone(&self.set.clone()); - - // Initialize the callback that will be used upon receiving a response from our gossip attempt - let on_response: AppResponseCallback = Arc::new({ - move |response_bytes| { - let response = match PullGossipResponse::decode(response_bytes.as_slice()) { - Ok(res) => { - res - } - Err(e) => { - error!("{:?}", e); - return; - } - }; - - // We iterate over the response's gossip - for bytes in response.gossip.iter() { - let mut gossipable: S::Item = S::Item::default(); - gossipable.deserialize(bytes).unwrap(); - - let hash = gossipable.get_id(); - - let mut set_guard = set.try_lock().expect("Failed to acquire lock on set"); - if let Err(e) = set_guard.add(gossipable) { - error!( + let set = Arc::clone(&self.set); + + // Initialize the callback that will be used upon receiving a response from our gossip attempt + let on_response: AppResponseCallback = Arc::new( + move |response_bytes| { + let response = match PullGossipResponse::decode(response_bytes.as_slice()) { + Ok(res) => { + res + } + Err(e) => { + error!("{:?}", e); + return; + } + }; + + // We iterate over the response's gossip + for bytes in response.gossip.iter() { + let mut gossipable = S::Item::default(); + gossipable.deserialize(bytes).unwrap(); + + let hash = gossipable.get_id(); + + let mut set_guard = set.try_lock().expect("Failed to acquire lock on set"); + if let Err(e) = set_guard.add(gossipable) { + error!( "failed to add gossip to the known set, id: {:?}, error: {:?}" , hash, e ); - continue; - } + continue; } } }); - let mut guard = self.client.try_lock().expect("Failed to acquire a lock on client"); - let _ = guard.app_request_any(msg_bytes.clone(), on_response).await; - } + let mut guard = self.client.try_lock().expect("Failed to acquire a lock on client"); + let _ = guard.app_request_any(&msg_bytes, on_response).await; } Ok(()) From f6e8baff1cd1f7c1e74573db6f7f626e29e4b00f Mon Sep 17 00:00:00 2001 From: sanghren Date: Sun, 1 Oct 2023 22:19:45 +0200 Subject: [PATCH 48/53] feat: clean --- core/network/examples/peer_gossip.rs | 25 +++++++++++++++---- core/network/src/p2p/client.rs | 37 +++++++++++++++++++++++----- 2 files changed, 51 insertions(+), 11 deletions(-) diff --git a/core/network/examples/peer_gossip.rs b/core/network/examples/peer_gossip.rs index a05d8d5..bb57db9 100644 --- a/core/network/examples/peer_gossip.rs +++ b/core/network/examples/peer_gossip.rs @@ -26,12 +26,7 @@ pub struct TestClient { } #[async_trait] -#[allow(unused_variables)] impl Client for TestClient { - async fn app_gossip(&mut self, request_bytes: Vec) { - todo!() - } - async fn app_request_any(&mut self, request_bytes: &Vec, on_response: AppResponseCallback) -> Result<(), std::io::Error> { let mut stream = self.stream.lock().await; stream.write_all(request_bytes).await?; @@ -56,6 +51,26 @@ impl Client for TestClient { } Ok(()) } + + async fn app_request(&mut self, request_bytes: Vec) -> Result<(), std::io::Error> { + todo!() + } + + async fn app_gossip(&mut self, request_bytes: Vec) -> Result<(), std::io::Error> { + todo!() + } + + async fn app_gossip_specific(&mut self, request_bytes: Vec) -> Result<(), std::io::Error> { + todo!() + } + + async fn cross_chain_app_request(&mut self, request_bytes: Vec) -> Result<(), std::io::Error> { + todo!() + } + + async fn prefix_message(&mut self, request_bytes: Vec) -> Result<(), std::io::Error> { + todo!() + } } #[derive(Clone, Hash, Debug, Serialize, Deserialize)] diff --git a/core/network/src/p2p/client.rs b/core/network/src/p2p/client.rs index c696900..eefade3 100644 --- a/core/network/src/p2p/client.rs +++ b/core/network/src/p2p/client.rs @@ -1,20 +1,45 @@ +use std::io::Error; use std::sync::Arc; use async_trait::async_trait; pub type AppResponseCallback = Arc) + Send + Sync>; + #[async_trait] #[allow(unused_variables)] pub trait Client: Send + Sync { - async fn app_request_any(&mut self, request_bytes: &Vec, on_response: AppResponseCallback) -> Result<(), std::io::Error> { Ok(()) } - async fn app_request(&mut self, request_bytes: Vec) {} - async fn app_gossip(&mut self, request_bytes: Vec) {} - async fn app_gossip_specific(&mut self, request_bytes: Vec) {} - async fn cross_chain_app_request(&mut self, request_bytes: Vec) {} - async fn prefix_message(&mut self, request_bytes: Vec) {} + async fn app_request_any(&mut self, request_bytes: &Vec, on_response: AppResponseCallback) -> Result<(), std::io::Error>; + async fn app_request(&mut self, request_bytes: Vec) -> Result<(), std::io::Error>; + async fn app_gossip(&mut self, request_bytes: Vec) -> Result<(), std::io::Error>; + async fn app_gossip_specific(&mut self, request_bytes: Vec) -> Result<(), std::io::Error>; + async fn cross_chain_app_request(&mut self, request_bytes: Vec) -> Result<(), std::io::Error>; + async fn prefix_message(&mut self, request_bytes: Vec) -> Result<(), std::io::Error>; } pub struct NoOpClient; +#[async_trait] impl Client for NoOpClient { + async fn app_request_any(&mut self, request_bytes: &Vec, on_response: AppResponseCallback) -> Result<(), Error> { + todo!() + } + + async fn app_request(&mut self, request_bytes: Vec) -> Result<(), Error> { + todo!() + } + + async fn app_gossip(&mut self, request_bytes: Vec) -> Result<(), Error> { + todo!() + } + + async fn app_gossip_specific(&mut self, request_bytes: Vec) -> Result<(), Error> { + todo!() + } + + async fn cross_chain_app_request(&mut self, request_bytes: Vec) -> Result<(), Error> { + todo!() + } + async fn prefix_message(&mut self, request_bytes: Vec) -> Result<(), Error> { + todo!() + } } From 672c728ed3db67fe01bd806e0cb0f9d942fb06da Mon Sep 17 00:00:00 2001 From: sanghren Date: Sun, 1 Oct 2023 22:33:42 +0200 Subject: [PATCH 49/53] feat: clean --- core/network/examples/peer_gossip.rs | 12 +----------- core/network/src/p2p/gossip/handler.rs | 1 - core/network/src/p2p/handler.rs | 1 - 3 files changed, 1 insertion(+), 13 deletions(-) diff --git a/core/network/examples/peer_gossip.rs b/core/network/examples/peer_gossip.rs index bb57db9..60e7b98 100644 --- a/core/network/examples/peer_gossip.rs +++ b/core/network/examples/peer_gossip.rs @@ -177,9 +177,7 @@ async fn fake_handler_server_logic(mut socket: TcpStream, client_socket: Arc { error!("{:?}", error); continue } }; - debug!("Before aa"); let mut stream = client_socket.lock().await; - debug!("After aa {:?}", res_bytes); if res_bytes.is_empty() { // ToDo Whenever the handler return nothing , gossip part hang. Temp dev fix to get pass this @@ -195,7 +193,6 @@ async fn fake_handler_server_logic(mut socket: TcpStream, client_socket: Arc { debug!("Shutting down handler"); @@ -207,8 +204,6 @@ async fn fake_handler_server_logic(mut socket: TcpStream, client_socket: Arc, vec_gossip_remote_client: Vec) -> Result<(), std::io::Error> { @@ -257,7 +252,6 @@ async fn start_fake_node(own_handler: &str, own_client: &str, other_handler: &st let listener = own_handler_listener_clone.lock().await; let (listener_socket, _) = listener.accept().await.unwrap(); fake_handler_server_logic(listener_socket, other_client_stream_clone.clone(), handler.clone(), stop_handler_rx).await; - debug!("HANDLER DONEZO"); }); { @@ -279,7 +273,6 @@ async fn start_fake_node(own_handler: &str, own_client: &str, other_handler: &st let mut gossiper = Gossiper::new(config, set_clone, gossip_client.clone(), stop_rx); gossiper.gossip().await; - debug!("GOSSIP DONEZO"); }); // Sleep for a few seconds, make sure the whole process ran at least a couple of times @@ -292,7 +285,6 @@ async fn start_fake_node(own_handler: &str, own_client: &str, other_handler: &st assert!(guard.set.len() == 6); // Need to find them all for gossip in vec_gossip_remote_client { - debug!("Checking if gossip {:?} is present in set {:?}", gossip, guard.set); assert!(guard.set.contains(&gossip)); } } @@ -308,14 +300,12 @@ async fn start_fake_node(own_handler: &str, own_client: &str, other_handler: &st // Send the stop signal before awaiting the task. if stop_tx.send(()).await.is_err() { - eprintln!("Failed to send stop signal"); + error!("Failed to send stop signal"); } tokio::time::sleep(Duration::from_secs(2)).await; - debug!("Checking if all things good"); - // Await the completion of the gossiping task let _ = gossip_task.await.expect("Gossip task failed"); debug!("Gossip task completed"); diff --git a/core/network/src/p2p/gossip/handler.rs b/core/network/src/p2p/gossip/handler.rs index 6b0984f..42eaaad 100644 --- a/core/network/src/p2p/gossip/handler.rs +++ b/core/network/src/p2p/gossip/handler.rs @@ -57,7 +57,6 @@ impl p2p::handler::Handler for Handler }; guard.iterate(&mut |gossipable : &S::Item| { - println!("Iterating in handler"); if filter.contains(&gossipable) { return true }; diff --git a/core/network/src/p2p/handler.rs b/core/network/src/p2p/handler.rs index 40e1d61..988016a 100644 --- a/core/network/src/p2p/handler.rs +++ b/core/network/src/p2p/handler.rs @@ -41,7 +41,6 @@ impl Handler for NoOpHandler { Ok(vec![]) } async fn app_request(&self, _: Id, _: Duration, _: Vec) -> Result, Box> { - debug!("Ah non hein"); Ok(vec![]) } async fn cross_chain_app_request(&self, _: Id, _: Duration, _: Vec) -> Result, Box> { From b89abd973e5d6854c467c76997d4f149e782db8c Mon Sep 17 00:00:00 2001 From: sanghren Date: Mon, 2 Oct 2023 14:49:17 +0200 Subject: [PATCH 50/53] feat: remove arc for callback --- core/network/src/p2p/client.rs | 2 +- core/network/src/p2p/gossip/gossip.rs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/core/network/src/p2p/client.rs b/core/network/src/p2p/client.rs index eefade3..7b6aed1 100644 --- a/core/network/src/p2p/client.rs +++ b/core/network/src/p2p/client.rs @@ -2,7 +2,7 @@ use std::io::Error; use std::sync::Arc; use async_trait::async_trait; -pub type AppResponseCallback = Arc) + Send + Sync>; +pub type AppResponseCallback = Box) + Send + Sync + 'static>; #[async_trait] #[allow(unused_variables)] diff --git a/core/network/src/p2p/gossip/gossip.rs b/core/network/src/p2p/gossip/gossip.rs index 93f915a..1e4ed6c 100644 --- a/core/network/src/p2p/gossip/gossip.rs +++ b/core/network/src/p2p/gossip/gossip.rs @@ -90,8 +90,7 @@ impl Gossiper let set = Arc::clone(&self.set); // Initialize the callback that will be used upon receiving a response from our gossip attempt - let on_response: AppResponseCallback = Arc::new( - move |response_bytes| { + let on_response: AppResponseCallback = Box::new(move |response_bytes| { let response = match PullGossipResponse::decode(response_bytes.as_slice()) { Ok(res) => { res From 3faedf960c2875795696e387ec1979800f2f9dd9 Mon Sep 17 00:00:00 2001 From: sanghren Date: Mon, 2 Oct 2023 17:40:40 +0200 Subject: [PATCH 51/53] feat: format --- core/network/build.rs | 1 - core/network/examples/peer_gossip.rs | 194 ++++++++++++++++++------- core/network/src/p2p/client.rs | 30 ++-- core/network/src/p2p/gossip/gossip.rs | 128 ++++++++-------- core/network/src/p2p/gossip/handler.rs | 70 +++++---- core/network/src/p2p/gossip/mod.rs | 8 +- core/network/src/p2p/handler.rs | 12 +- core/network/src/p2p/mod.rs | 2 +- 8 files changed, 284 insertions(+), 161 deletions(-) diff --git a/core/network/build.rs b/core/network/build.rs index 4c06fdc..eb2cb4b 100644 --- a/core/network/build.rs +++ b/core/network/build.rs @@ -6,5 +6,4 @@ fn main() { .build_client(true) .compile(&["./src/p2p/gossip/sdk.proto"], &["./src/p2p/gossip/"]) .unwrap(); - } diff --git a/core/network/examples/peer_gossip.rs b/core/network/examples/peer_gossip.rs index 60e7b98..b8e05fc 100644 --- a/core/network/examples/peer_gossip.rs +++ b/core/network/examples/peer_gossip.rs @@ -1,24 +1,24 @@ +use async_trait::async_trait; +use avalanche_types::ids::node::Id as NodeId; +use avalanche_types::ids::Id; +use log::{debug, error}; +use network::p2p::client::{AppResponseCallback, Client}; +use network::p2p::gossip::gossip::{Config, Gossiper}; +use network::p2p::gossip::handler::{new_handler, Handler, HandlerConfig}; +use network::p2p::gossip::{Gossipable, Set}; +use network::p2p::handler::Handler as TraitHandler; +use rand::prelude::SliceRandom; +use serde::{Deserialize, Serialize}; use std::error::Error; use std::fmt::Debug; use std::hash::Hash; -use tokio::sync::Mutex; use std::sync::Arc; use std::time::Duration; -use async_trait::async_trait; -use log::{debug, error}; -use rand::prelude::SliceRandom; -use serde::{Deserialize, Serialize}; -use tokio::net::{TcpListener, TcpStream}; use tokio::io::{AsyncReadExt, AsyncWriteExt}; +use tokio::net::{TcpListener, TcpStream}; use tokio::select; -use network::p2p::gossip::gossip::{Config, Gossiper}; use tokio::sync::mpsc::{channel, Receiver}; -use avalanche_types::ids::Id; -use avalanche_types::ids::node::Id as NodeId; -use network::p2p::client::{AppResponseCallback, Client}; -use network::p2p::gossip::{Gossipable, Set}; -use network::p2p::gossip::handler::{Handler, HandlerConfig, new_handler}; -use network::p2p::handler::Handler as TraitHandler; +use tokio::sync::Mutex; pub struct TestClient { pub stream: Arc>, @@ -27,7 +27,11 @@ pub struct TestClient { #[async_trait] impl Client for TestClient { - async fn app_request_any(&mut self, request_bytes: &Vec, on_response: AppResponseCallback) -> Result<(), std::io::Error> { + async fn app_request_any( + &mut self, + request_bytes: &Vec, + on_response: AppResponseCallback, + ) -> Result<(), std::io::Error> { let mut stream = self.stream.lock().await; stream.write_all(request_bytes).await?; @@ -52,23 +56,26 @@ impl Client for TestClient { Ok(()) } - async fn app_request(&mut self, request_bytes: Vec) -> Result<(), std::io::Error> { + async fn app_request(&mut self, _: Vec) -> Result<(), std::io::Error> { todo!() } - async fn app_gossip(&mut self, request_bytes: Vec) -> Result<(), std::io::Error> { + async fn app_gossip(&mut self, _: Vec) -> Result<(), std::io::Error> { todo!() } - async fn app_gossip_specific(&mut self, request_bytes: Vec) -> Result<(), std::io::Error> { + async fn app_gossip_specific(&mut self, _: Vec) -> Result<(), std::io::Error> { todo!() } - async fn cross_chain_app_request(&mut self, request_bytes: Vec) -> Result<(), std::io::Error> { + async fn cross_chain_app_request( + &mut self, + _: Vec, + ) -> Result<(), std::io::Error> { todo!() } - async fn prefix_message(&mut self, request_bytes: Vec) -> Result<(), std::io::Error> { + async fn prefix_message(&mut self, _: Vec) -> Result<(), std::io::Error> { todo!() } } @@ -121,7 +128,18 @@ impl MockSet { } } -impl Deserialize<'de> + Serialize> Set for MockSet { +impl< + T: Gossipable + + Sync + + Send + + Clone + + Hash + + Debug + + PartialEq + + for<'de> Deserialize<'de> + + Serialize, + > Set for MockSet +{ type Item = T; fn add(&mut self, gossipable: T) -> Result<(), Box> { // Just for our test purpose am checking manually if we insert an already known gossip. @@ -142,7 +160,10 @@ impl D fn iterate(&self, _f: &mut dyn FnMut(&T) -> bool) { for item in &self.set { if !_f(item) { - println!("Filter sent over network knows about this item already {:?}", item); + println!( + "Filter sent over network knows about this item already {:?}", + item + ); break; } } @@ -150,7 +171,10 @@ impl D } fn fetch_elements(&self) -> Self::Item { - self.set.choose(&mut rand::thread_rng()).cloned().expect("Set is empty") + self.set + .choose(&mut rand::thread_rng()) + .cloned() + .expect("Set is empty") } fn fetch_all_elements(&self) -> Vec { @@ -158,8 +182,12 @@ impl D } } -async fn fake_handler_server_logic(mut socket: TcpStream, client_socket: Arc>, handler: Handler>, mut stop_handler_rx: Receiver<()>) { - +async fn fake_handler_server_logic( + mut socket: TcpStream, + client_socket: Arc>, + handler: Handler>, + mut stop_handler_rx: Receiver<()>, +) { // Initialize a buffer of size 1024. let mut buf = [0u8; 1024]; loop { @@ -206,7 +234,14 @@ async fn fake_handler_server_logic(mut socket: TcpStream, client_socket: Arc, vec_gossip_remote_client: Vec) -> Result<(), std::io::Error> { +async fn start_fake_node( + own_handler: &str, + own_client: &str, + other_handler: &str, + other_client: &str, + vec_gossip_local_client: Vec, + vec_gossip_remote_client: Vec, +) -> Result<(), std::io::Error> { // Initialize the configuration for the gossiper let config = Config { namespace: "test".to_string(), @@ -222,24 +257,24 @@ async fn start_fake_node(own_handler: &str, own_client: &str, other_handler: &st // Create a TcpStream to send messages to. // Wrapping it in Arc and Mutex to safely share it between threads. let other_client_stream = Arc::new(Mutex::new(TcpStream::connect(other_client).await?)); - let other_handler_stream = Arc::new(Mutex::new(TcpStream::connect(other_handler.clone()).await?)); + let other_handler_stream = + Arc::new(Mutex::new(TcpStream::connect(other_handler.clone()).await?)); // Initialize the configuration for the handler and create a new handler - let handler_config = HandlerConfig { namespace: "test".to_string(), target_response_size: 1000 }; + let handler_config = HandlerConfig { + namespace: "test".to_string(), + target_response_size: 1000, + }; - let mut mock_set = MockSet { set: Vec::::new() }; + let mut mock_set = MockSet { + set: Vec::::new(), + }; for gossip in &vec_gossip_local_client { - mock_set.set.push( - gossip.clone() - ); + mock_set.set.push(gossip.clone()); } - let set = Arc::new(Mutex::new(mock_set )); + let set = Arc::new(Mutex::new(mock_set)); - - let handler = new_handler( - handler_config, - set.clone(), - ); + let handler = new_handler(handler_config, set.clone()); // Clone listener and stream for use inside the spawned task. let own_handler_listener_clone = own_handler_listener.clone(); @@ -251,7 +286,13 @@ async fn start_fake_node(own_handler: &str, own_client: &str, other_handler: &st // Accept incoming connections and spawn a new task to handle each connection let listener = own_handler_listener_clone.lock().await; let (listener_socket, _) = listener.accept().await.unwrap(); - fake_handler_server_logic(listener_socket, other_client_stream_clone.clone(), handler.clone(), stop_handler_rx).await; + fake_handler_server_logic( + listener_socket, + other_client_stream_clone.clone(), + handler.clone(), + stop_handler_rx, + ) + .await; }); { @@ -264,8 +305,16 @@ async fn start_fake_node(own_handler: &str, own_client: &str, other_handler: &st let set_clone = set.clone(); let gossip_task = tokio::spawn(async move { // Initialize a TestClient instance with the given stream and listener - let (stream, _) = own_client_listener_r.lock().await.accept().await.expect("Fail"); - let gossip_client = Arc::new(Mutex::new(TestClient { stream: other_handler_stream.clone(), listener: Arc::new(Mutex::new(stream)) })); + let (stream, _) = own_client_listener_r + .lock() + .await + .accept() + .await + .expect("Fail"); + let gossip_client = Arc::new(Mutex::new(TestClient { + stream: other_handler_stream.clone(), + listener: Arc::new(Mutex::new(stream)), + })); // Create a channel for stopping the gossiper @@ -278,7 +327,6 @@ async fn start_fake_node(own_handler: &str, own_client: &str, other_handler: &st // Sleep for a few seconds, make sure the whole process ran at least a couple of times tokio::time::sleep(Duration::from_secs(2)).await; - { let guard = set.lock().await; // As we have 3 elements in our set (pre-gossip loop execution) in each one of our fake gossip server, we should end up with 6 gossip at the end of our test run. @@ -303,7 +351,6 @@ async fn start_fake_node(own_handler: &str, own_client: &str, other_handler: &st error!("Failed to send stop signal"); } - tokio::time::sleep(Duration::from_secs(2)).await; // Await the completion of the gossiping task @@ -314,7 +361,6 @@ async fn start_fake_node(own_handler: &str, own_client: &str, other_handler: &st Ok(()) } - #[tokio::main] async fn main() { env_logger::init_from_env( @@ -323,22 +369,64 @@ async fn main() { let mut vec_gossip_client_01 = Vec::new(); let mut vec_gossip_client_02 = Vec::new(); - vec_gossip_client_01.push(TestGossipableType { id: Id::from_slice(&[52, 25, 83, 149, 20, 226, 168, 61, 17, 53, 152, 11, 220, 226, 218, 254, 53, 104, 51, 247, 106, 6, 9, 26, 81, 52, 108, 232, 251, 122, 245, 112]) }); - vec_gossip_client_01.push(TestGossipableType { id: Id::from_slice(&[243, 156, 106, 56, 180, 213, 172, 165, 124, 118, 229, 60, 213, 183, 93, 241, 98, 214, 130, 235, 220, 45, 163, 151, 97, 64, 51, 126, 52, 164, 179, 23]) }); - vec_gossip_client_01.push(TestGossipableType { id: Id::from_slice(&[213, 8, 151, 77, 221, 160, 231, 33, 231, 180, 49, 113, 38, 196, 52, 156, 252, 66, 78, 250, 21, 56, 75, 247, 245, 87, 69, 157, 127, 53, 205, 121]) }); - - vec_gossip_client_02.push(TestGossipableType { id: Id::from_slice(&[60, 209, 244, 35, 53, 217, 132, 157, 105, 97, 191, 32, 74, 199, 107, 124, 168, 61, 86, 203, 71, 247, 202, 161, 23, 124, 185, 63, 158, 54, 122, 216]) }); - vec_gossip_client_02.push(TestGossipableType { id: Id::from_slice(&[70, 203, 24, 230, 112, 82, 4, 22, 154, 173, 148, 189, 142, 217, 209, 191, 170, 242, 62, 213, 242, 133, 226, 200, 128, 87, 126, 157, 141, 78, 32, 67]) }); - vec_gossip_client_02.push(TestGossipableType { id: Id::from_slice(&[51, 215, 234, 45, 201, 210, 176, 176, 229, 6, 151, 169, 125, 219, 45, 56, 144, 205, 27, 74, 17, 13, 231, 59, 42, 214, 12, 184, 171, 251, 191, 197]) }); + vec_gossip_client_01.push(TestGossipableType { + id: Id::from_slice(&[ + 52, 25, 83, 149, 20, 226, 168, 61, 17, 53, 152, 11, 220, 226, 218, 254, 53, 104, 51, + 247, 106, 6, 9, 26, 81, 52, 108, 232, 251, 122, 245, 112, + ]), + }); + vec_gossip_client_01.push(TestGossipableType { + id: Id::from_slice(&[ + 243, 156, 106, 56, 180, 213, 172, 165, 124, 118, 229, 60, 213, 183, 93, 241, 98, 214, + 130, 235, 220, 45, 163, 151, 97, 64, 51, 126, 52, 164, 179, 23, + ]), + }); + vec_gossip_client_01.push(TestGossipableType { + id: Id::from_slice(&[ + 213, 8, 151, 77, 221, 160, 231, 33, 231, 180, 49, 113, 38, 196, 52, 156, 252, 66, 78, + 250, 21, 56, 75, 247, 245, 87, 69, 157, 127, 53, 205, 121, + ]), + }); + vec_gossip_client_02.push(TestGossipableType { + id: Id::from_slice(&[ + 60, 209, 244, 35, 53, 217, 132, 157, 105, 97, 191, 32, 74, 199, 107, 124, 168, 61, 86, + 203, 71, 247, 202, 161, 23, 124, 185, 63, 158, 54, 122, 216, + ]), + }); + vec_gossip_client_02.push(TestGossipableType { + id: Id::from_slice(&[ + 70, 203, 24, 230, 112, 82, 4, 22, 154, 173, 148, 189, 142, 217, 209, 191, 170, 242, 62, + 213, 242, 133, 226, 200, 128, 87, 126, 157, 141, 78, 32, 67, + ]), + }); + vec_gossip_client_02.push(TestGossipableType { + id: Id::from_slice(&[ + 51, 215, 234, 45, 201, 210, 176, 176, 229, 6, 151, 169, 125, 219, 45, 56, 144, 205, 27, + 74, 17, 13, 231, 59, 42, 214, 12, 184, 171, 251, 191, 197, + ]), + }); // Start the client // listen on 8080 , send message to 8081 - let client_01_handle = tokio::spawn(start_fake_node("127.0.0.1:8080", "127.0.0.1:8081", "127.0.0.1:8082", "127.0.0.1:8083", vec_gossip_client_01.clone(), vec_gossip_client_02.clone())); - let client_02_handle = tokio::spawn(start_fake_node("127.0.0.1:8082", "127.0.0.1:8083", "127.0.0.1:8080", "127.0.0.1:8081", vec_gossip_client_02.clone(), vec_gossip_client_01.clone())); + let client_01_handle = tokio::spawn(start_fake_node( + "127.0.0.1:8080", + "127.0.0.1:8081", + "127.0.0.1:8082", + "127.0.0.1:8083", + vec_gossip_client_01.clone(), + vec_gossip_client_02.clone(), + )); + let client_02_handle = tokio::spawn(start_fake_node( + "127.0.0.1:8082", + "127.0.0.1:8083", + "127.0.0.1:8080", + "127.0.0.1:8081", + vec_gossip_client_02.clone(), + vec_gossip_client_01.clone(), + )); // Wait for the server and client to complete client_01_handle.await.expect("Issue with client01"); client_02_handle.await.expect("Issue with client02"); } - diff --git a/core/network/src/p2p/client.rs b/core/network/src/p2p/client.rs index 7b6aed1..e912325 100644 --- a/core/network/src/p2p/client.rs +++ b/core/network/src/p2p/client.rs @@ -1,17 +1,23 @@ -use std::io::Error; -use std::sync::Arc; use async_trait::async_trait; +use std::io::Error; pub type AppResponseCallback = Box) + Send + Sync + 'static>; #[async_trait] #[allow(unused_variables)] pub trait Client: Send + Sync { - async fn app_request_any(&mut self, request_bytes: &Vec, on_response: AppResponseCallback) -> Result<(), std::io::Error>; + async fn app_request_any( + &mut self, + request_bytes: &Vec, + on_response: AppResponseCallback, + ) -> Result<(), std::io::Error>; async fn app_request(&mut self, request_bytes: Vec) -> Result<(), std::io::Error>; async fn app_gossip(&mut self, request_bytes: Vec) -> Result<(), std::io::Error>; async fn app_gossip_specific(&mut self, request_bytes: Vec) -> Result<(), std::io::Error>; - async fn cross_chain_app_request(&mut self, request_bytes: Vec) -> Result<(), std::io::Error>; + async fn cross_chain_app_request( + &mut self, + request_bytes: Vec, + ) -> Result<(), std::io::Error>; async fn prefix_message(&mut self, request_bytes: Vec) -> Result<(), std::io::Error>; } @@ -19,27 +25,31 @@ pub struct NoOpClient; #[async_trait] impl Client for NoOpClient { - async fn app_request_any(&mut self, request_bytes: &Vec, on_response: AppResponseCallback) -> Result<(), Error> { + async fn app_request_any( + &mut self, + _: &Vec, + _: AppResponseCallback, + ) -> Result<(), Error> { todo!() } - async fn app_request(&mut self, request_bytes: Vec) -> Result<(), Error> { + async fn app_request(&mut self, _: Vec) -> Result<(), Error> { todo!() } - async fn app_gossip(&mut self, request_bytes: Vec) -> Result<(), Error> { + async fn app_gossip(&mut self, _: Vec) -> Result<(), Error> { todo!() } - async fn app_gossip_specific(&mut self, request_bytes: Vec) -> Result<(), Error> { + async fn app_gossip_specific(&mut self, _: Vec) -> Result<(), Error> { todo!() } - async fn cross_chain_app_request(&mut self, request_bytes: Vec) -> Result<(), Error> { + async fn cross_chain_app_request(&mut self, _: Vec) -> Result<(), Error> { todo!() } - async fn prefix_message(&mut self, request_bytes: Vec) -> Result<(), Error> { + async fn prefix_message(&mut self, _: Vec) -> Result<(), Error> { todo!() } } diff --git a/core/network/src/p2p/gossip/gossip.rs b/core/network/src/p2p/gossip/gossip.rs index 1e4ed6c..3a5b29a 100644 --- a/core/network/src/p2p/gossip/gossip.rs +++ b/core/network/src/p2p/gossip/gossip.rs @@ -4,14 +4,14 @@ use crate::p2p::sdk::{PullGossipRequest, PullGossipResponse}; use avalanche_types::ids::Id; use log::{debug, error}; use prost::Message; +use serde::Serialize; +use serde_json::to_vec; use std::error::Error; -use tokio::sync::Mutex; use std::sync::Arc; use std::time::Duration; -use serde::Serialize; -use serde_json::to_vec; use tokio::select; use tokio::sync::mpsc::Receiver; +use tokio::sync::Mutex; use tokio::time::interval; pub struct Config { @@ -28,9 +28,9 @@ pub struct Gossiper { } impl Gossiper - where - S: Set, - S::Item: Default +where + S: Set, + S::Item: Default, { pub fn new( config: Config, @@ -46,7 +46,11 @@ impl Gossiper } } - pub async fn gossip(&mut self) where ::Item: Clone, ::Item: Serialize { + pub async fn gossip(&mut self) + where + ::Item: Clone, + ::Item: Serialize, + { let mut gossip_ticker = interval(self.config.frequency); loop { @@ -67,7 +71,11 @@ impl Gossiper } } - async fn execute(&mut self) -> Result<(), Box> where ::Item: Clone, ::Item: Serialize { + async fn execute(&mut self) -> Result<(), Box> + where + ::Item: Clone, + ::Item: Serialize, + { //ToDo Dummy vec for now. let bloom = Vec::new(); @@ -85,41 +93,41 @@ impl Gossiper request.encode(&mut msg_bytes)?; - for _ in 0..self.config.poll_size { let set = Arc::clone(&self.set); // Initialize the callback that will be used upon receiving a response from our gossip attempt let on_response: AppResponseCallback = Box::new(move |response_bytes| { - let response = match PullGossipResponse::decode(response_bytes.as_slice()) { - Ok(res) => { - res - } - Err(e) => { - error!("{:?}", e); - return; - } - }; - - // We iterate over the response's gossip - for bytes in response.gossip.iter() { - let mut gossipable = S::Item::default(); - gossipable.deserialize(bytes).unwrap(); - - let hash = gossipable.get_id(); - - let mut set_guard = set.try_lock().expect("Failed to acquire lock on set"); - if let Err(e) = set_guard.add(gossipable) { - error!( - "failed to add gossip to the known set, id: {:?}, error: {:?}" - , hash, e + let response = match PullGossipResponse::decode(response_bytes.as_slice()) { + Ok(res) => res, + Err(e) => { + error!("{:?}", e); + return; + } + }; + + // We iterate over the response's gossip + for bytes in response.gossip.iter() { + let mut gossipable = S::Item::default(); + gossipable.deserialize(bytes).unwrap(); + + let hash = gossipable.get_id(); + + let mut set_guard = set.try_lock().expect("Failed to acquire lock on set"); + if let Err(e) = set_guard.add(gossipable) { + error!( + "failed to add gossip to the known set, id: {:?}, error: {:?}", + hash, e ); - continue; - } + continue; } - }); + } + }); - let mut guard = self.client.try_lock().expect("Failed to acquire a lock on client"); + let mut guard = self + .client + .try_lock() + .expect("Failed to acquire a lock on client"); let _ = guard.app_request_any(&msg_bytes, on_response).await; } @@ -127,20 +135,20 @@ impl Gossiper } } - #[cfg(test)] mod test { - use tokio::sync::Mutex; - use std::sync::Arc; - use tokio::sync::mpsc::{channel}; - use std::time::Duration; + use std::hash::Hash; use super::*; - use testing_logger; - use avalanche_types::ids::Id; use crate::p2p::client::Client; + use crate::p2p::client::NoOpClient; use crate::p2p::gossip::gossip::{Config, Gossiper}; use crate::p2p::sdk::PullGossipResponse; - use crate::p2p::client::NoOpClient; + use avalanche_types::ids::Id; + use std::sync::Arc; + use std::time::Duration; + use testing_logger; + use tokio::sync::mpsc::channel; + use tokio::sync::Mutex; struct MockClient; @@ -173,7 +181,7 @@ mod test { } // Mock implementation for the Set trait -//ToDo Should we move all tests to a new file ? + //ToDo Should we move all tests to a new file ? pub struct MockSet { pub set: Vec, } @@ -192,9 +200,21 @@ mod test { Ok(()) } + fn has(&self, gossipable: &Self::Item) -> bool { + todo!() + } + fn iterate(&self, _f: &mut dyn FnMut(&T) -> bool) { todo!() } + + fn fetch_elements(&self) -> Self::Item { + todo!() + } + + fn fetch_all_elements(&self) -> Vec where ::Item: Sized { + todo!() + } } /// RUST_LOG=debug cargo test --package network --lib -- p2p::gossip::test_gossip_shutdown --exact --show-output @@ -205,7 +225,7 @@ mod test { .is_test(true) .try_init() .unwrap(); - let noopclient = NoOpClient {}; + let mut noopclient = NoOpClient {}; noopclient.app_request(Vec::new()); let (stop_tx, stop_rx) = channel(1); // Create a new channel @@ -215,10 +235,8 @@ mod test { frequency: Duration::from_millis(200), poll_size: 0, }, - Arc::new(Mutex::new(MockSet { - set: Vec::new(), - })), - Arc::new(NoOpClient {}), + Arc::new(Mutex::new(MockSet { set: Vec::new() })), + Arc::new(Mutex::new(NoOpClient {})), stop_rx, ); @@ -252,10 +270,8 @@ mod test { frequency: Duration::from_millis(200), poll_size: 0, }, - Arc::new(Mutex::new(MockSet { - set: Vec::new(), - })), - Arc::new(NoOpClient {}), + Arc::new(Mutex::new(MockSet { set: Vec::new() })), + Arc::new(Mutex::new(NoOpClient {})), stop_rx, ); @@ -282,10 +298,8 @@ mod test { frequency: Duration::from_millis(200), poll_size: 0, }, - Arc::new(Mutex::new(MockSet { - set: Vec::new(), - })), - Arc::new(NoOpClient {}), + Arc::new(Mutex::new(MockSet { set: Vec::new() })), + Arc::new(Mutex::new(NoOpClient {})), stop_rx, ); diff --git a/core/network/src/p2p/gossip/handler.rs b/core/network/src/p2p/gossip/handler.rs index 42eaaad..1217075 100644 --- a/core/network/src/p2p/gossip/handler.rs +++ b/core/network/src/p2p/gossip/handler.rs @@ -1,16 +1,16 @@ -use std::error::Error; -use std::fmt::Debug; -use tokio::sync::Mutex; -use std::sync::Arc; -use std::time::Duration; -use async_trait::async_trait; -use log::error; -use prost::Message; -use avalanche_types::ids::node::Id; use crate::p2p; use crate::p2p::gossip::{Gossipable, Set}; use crate::p2p::sdk::{PullGossipRequest, PullGossipResponse}; +use async_trait::async_trait; +use avalanche_types::ids::node::Id; +use log::error; +use prost::Message; use serde_json::from_slice; +use std::error::Error; +use std::fmt::Debug; +use std::sync::Arc; +use std::time::Duration; +use tokio::sync::Mutex; pub struct HandlerConfig { pub namespace: String, @@ -21,13 +21,9 @@ pub struct HandlerConfig { pub struct Handler { pub set: Arc>, pub target_response_size: usize, - } -pub fn new_handler( - config: HandlerConfig, - set: Arc>, -) -> Handler { +pub fn new_handler(config: HandlerConfig, set: Arc>) -> Handler { Handler { set, target_response_size: config.target_response_size, @@ -37,40 +33,42 @@ pub fn new_handler( #[async_trait] #[allow(unused_variables)] impl p2p::handler::Handler for Handler - where - S: Set + Debug + for <'de> serde::Deserialize<'de>, - S::Item: Default +where + S: Set + Debug + for<'de> serde::Deserialize<'de>, + S::Item: Default, { - async fn app_gossip(&self, node_id: Id, gossip_bytes: Vec) -> Result, Box> { - let request = PullGossipRequest::decode(gossip_bytes.as_slice()).expect("Failed to decode request_bytes into PullGossipRequest"); + async fn app_gossip( + &self, + node_id: Id, + gossip_bytes: Vec, + ) -> Result, Box> { + let request = PullGossipRequest::decode(gossip_bytes.as_slice()) + .expect("Failed to decode request_bytes into PullGossipRequest"); //toDo look at this Box shennanigan here let filter: Vec<::Item> = from_slice(&request.filter).unwrap(); let mut response_size = 0_usize; let mut response_bytes: Vec> = Vec::new(); let guard = match self.set.try_lock() { - Ok(guard) => { guard } + Ok(guard) => guard, Err(err) => { error!("Could not lock self.set in app_gossip"); - return Err(Box::try_from("Could not lock self.set in app_gossip").unwrap()) + return Err(Box::try_from("Could not lock self.set in app_gossip").unwrap()); } }; - guard.iterate(&mut |gossipable : &S::Item| { + guard.iterate(&mut |gossipable: &S::Item| { if filter.contains(&gossipable) { - return true + return true; }; let bytes = match gossipable.serialize() { - Ok(b) => { - b - } + Ok(b) => b, Err(_) => { return false; } }; - response_bytes.push(bytes.clone()); response_size += bytes.len(); @@ -80,7 +78,9 @@ impl p2p::handler::Handler for Handler response.gossip = response_bytes; let mut response_bytes = vec![]; - response.encode(&mut response_bytes).expect("Failed to encode response_bytes into PullGossipResponse"); + response + .encode(&mut response_bytes) + .expect("Failed to encode response_bytes into PullGossipResponse"); Ok(response_bytes) } @@ -90,14 +90,15 @@ impl p2p::handler::Handler for Handler _: Duration, request_bytes: Vec, ) -> Result, Box> { - let request = PullGossipRequest::decode(request_bytes.as_slice()).expect("Failed to decode request_bytes"); + let request = PullGossipRequest::decode(request_bytes.as_slice()) + .expect("Failed to decode request_bytes"); let mut response_size = 0_usize; let mut gossip_bytes: Vec> = Vec::new(); self.set.lock().await.iterate(&mut |gossipable| { if self.set.try_lock().expect("ssss").has(gossipable) { - return true + return true; }; let bytes = match gossipable.serialize() { @@ -120,7 +121,12 @@ impl p2p::handler::Handler for Handler Ok(response_bytes) } - async fn cross_chain_app_request(&self, chain_id: Id, deadline: Duration, request_bytes: Vec) -> Result, Box> { + async fn cross_chain_app_request( + &self, + chain_id: Id, + deadline: Duration, + request_bytes: Vec, + ) -> Result, Box> { todo!() } -} \ No newline at end of file +} diff --git a/core/network/src/p2p/gossip/mod.rs b/core/network/src/p2p/gossip/mod.rs index 50d0d0d..02a3708 100644 --- a/core/network/src/p2p/gossip/mod.rs +++ b/core/network/src/p2p/gossip/mod.rs @@ -1,9 +1,9 @@ pub mod gossip; pub mod handler; -use std::fmt::Debug; -use serde::{Deserialize, Serialize}; use avalanche_types::ids::Id; +use serde::{Deserialize, Serialize}; +use std::fmt::Debug; pub trait Gossipable { fn get_id(&self) -> Id; @@ -17,5 +17,7 @@ pub trait Set: Send + Sync { fn has(&self, gossipable: &Self::Item) -> bool; fn iterate(&self, f: &mut dyn FnMut(&Self::Item) -> bool); fn fetch_elements(&self) -> Self::Item; - fn fetch_all_elements(&self) -> Vec where ::Item: Sized; + fn fetch_all_elements(&self) -> Vec + where + ::Item: Sized; } diff --git a/core/network/src/p2p/handler.rs b/core/network/src/p2p/handler.rs index 988016a..a410d9b 100644 --- a/core/network/src/p2p/handler.rs +++ b/core/network/src/p2p/handler.rs @@ -1,8 +1,7 @@ +use async_trait::async_trait; +use avalanche_types::ids::node::Id; use std::error::Error; use std::time::Duration; -use avalanche_types::ids::node::Id; -use async_trait::async_trait; -use log::debug; #[async_trait] pub trait Handler { @@ -43,7 +42,12 @@ impl Handler for NoOpHandler { async fn app_request(&self, _: Id, _: Duration, _: Vec) -> Result, Box> { Ok(vec![]) } - async fn cross_chain_app_request(&self, _: Id, _: Duration, _: Vec) -> Result, Box> { + async fn cross_chain_app_request( + &self, + _: Id, + _: Duration, + _: Vec, + ) -> Result, Box> { Ok(vec![]) } } diff --git a/core/network/src/p2p/mod.rs b/core/network/src/p2p/mod.rs index eef23d2..4bc2582 100644 --- a/core/network/src/p2p/mod.rs +++ b/core/network/src/p2p/mod.rs @@ -1,4 +1,4 @@ pub mod client; pub mod gossip; -pub mod sdk; pub mod handler; +pub mod sdk; From ff6522975a4b1c3bb0abb798a304040ec1b18bda Mon Sep 17 00:00:00 2001 From: sanghren Date: Mon, 2 Oct 2023 17:43:33 +0200 Subject: [PATCH 52/53] feat: format --- core/network/examples/peer_gossip.rs | 5 +---- core/network/src/p2p/client.rs | 6 +----- core/network/src/p2p/gossip/gossip.rs | 7 +++++-- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/core/network/examples/peer_gossip.rs b/core/network/examples/peer_gossip.rs index b8e05fc..111c8ca 100644 --- a/core/network/examples/peer_gossip.rs +++ b/core/network/examples/peer_gossip.rs @@ -68,10 +68,7 @@ impl Client for TestClient { todo!() } - async fn cross_chain_app_request( - &mut self, - _: Vec, - ) -> Result<(), std::io::Error> { + async fn cross_chain_app_request(&mut self, _: Vec) -> Result<(), std::io::Error> { todo!() } diff --git a/core/network/src/p2p/client.rs b/core/network/src/p2p/client.rs index e912325..22dd7ca 100644 --- a/core/network/src/p2p/client.rs +++ b/core/network/src/p2p/client.rs @@ -25,11 +25,7 @@ pub struct NoOpClient; #[async_trait] impl Client for NoOpClient { - async fn app_request_any( - &mut self, - _: &Vec, - _: AppResponseCallback, - ) -> Result<(), Error> { + async fn app_request_any(&mut self, _: &Vec, _: AppResponseCallback) -> Result<(), Error> { todo!() } diff --git a/core/network/src/p2p/gossip/gossip.rs b/core/network/src/p2p/gossip/gossip.rs index 3a5b29a..8d1cb7e 100644 --- a/core/network/src/p2p/gossip/gossip.rs +++ b/core/network/src/p2p/gossip/gossip.rs @@ -137,13 +137,13 @@ where #[cfg(test)] mod test { - use std::hash::Hash; use super::*; use crate::p2p::client::Client; use crate::p2p::client::NoOpClient; use crate::p2p::gossip::gossip::{Config, Gossiper}; use crate::p2p::sdk::PullGossipResponse; use avalanche_types::ids::Id; + use std::hash::Hash; use std::sync::Arc; use std::time::Duration; use testing_logger; @@ -212,7 +212,10 @@ mod test { todo!() } - fn fetch_all_elements(&self) -> Vec where ::Item: Sized { + fn fetch_all_elements(&self) -> Vec + where + ::Item: Sized, + { todo!() } } From 65e8a149e03b861ef23a235434a338bf499ab686 Mon Sep 17 00:00:00 2001 From: sanghren Date: Mon, 2 Oct 2023 20:27:59 +0200 Subject: [PATCH 53/53] feat: format --- core/network/src/p2p/client.rs | 16 ++++++---------- core/network/src/p2p/gossip/handler.rs | 13 ++++--------- 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/core/network/src/p2p/client.rs b/core/network/src/p2p/client.rs index 22dd7ca..2db106a 100644 --- a/core/network/src/p2p/client.rs +++ b/core/network/src/p2p/client.rs @@ -4,21 +4,17 @@ use std::io::Error; pub type AppResponseCallback = Box) + Send + Sync + 'static>; #[async_trait] -#[allow(unused_variables)] pub trait Client: Send + Sync { async fn app_request_any( &mut self, request_bytes: &Vec, on_response: AppResponseCallback, - ) -> Result<(), std::io::Error>; - async fn app_request(&mut self, request_bytes: Vec) -> Result<(), std::io::Error>; - async fn app_gossip(&mut self, request_bytes: Vec) -> Result<(), std::io::Error>; - async fn app_gossip_specific(&mut self, request_bytes: Vec) -> Result<(), std::io::Error>; - async fn cross_chain_app_request( - &mut self, - request_bytes: Vec, - ) -> Result<(), std::io::Error>; - async fn prefix_message(&mut self, request_bytes: Vec) -> Result<(), std::io::Error>; + ) -> Result<(), Error>; + async fn app_request(&mut self, request_bytes: Vec) -> Result<(), Error>; + async fn app_gossip(&mut self, request_bytes: Vec) -> Result<(), Error>; + async fn app_gossip_specific(&mut self, request_bytes: Vec) -> Result<(), Error>; + async fn cross_chain_app_request(&mut self, request_bytes: Vec) -> Result<(), Error>; + async fn prefix_message(&mut self, request_bytes: Vec) -> Result<(), Error>; } pub struct NoOpClient; diff --git a/core/network/src/p2p/gossip/handler.rs b/core/network/src/p2p/gossip/handler.rs index 1217075..eebd607 100644 --- a/core/network/src/p2p/gossip/handler.rs +++ b/core/network/src/p2p/gossip/handler.rs @@ -31,17 +31,12 @@ pub fn new_handler(config: HandlerConfig, set: Arc>) -> } #[async_trait] -#[allow(unused_variables)] impl p2p::handler::Handler for Handler where S: Set + Debug + for<'de> serde::Deserialize<'de>, S::Item: Default, { - async fn app_gossip( - &self, - node_id: Id, - gossip_bytes: Vec, - ) -> Result, Box> { + async fn app_gossip(&self, _: Id, gossip_bytes: Vec) -> Result, Box> { let request = PullGossipRequest::decode(gossip_bytes.as_slice()) .expect("Failed to decode request_bytes into PullGossipRequest"); //toDo look at this Box shennanigan here @@ -123,9 +118,9 @@ where async fn cross_chain_app_request( &self, - chain_id: Id, - deadline: Duration, - request_bytes: Vec, + _: Id, + _: Duration, + _: Vec, ) -> Result, Box> { todo!() }