Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add gossipable trait + relevant logic #45

Draft
wants to merge 59 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 31 commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
5cbdd66
feat: add gossipable trait
Sep 7, 2023
a0e662a
feat: add gossip
Sep 7, 2023
aa7f63c
feat: add channel to gossiper
Sep 7, 2023
ed23c1e
feat: add gossipable trait
Sep 7, 2023
0c35d21
feat: add gossip
Sep 7, 2023
86580a6
feat: add channel to gossiper
Sep 7, 2023
bb397b9
Merge remote-tracking branch 'origin/add_gossipable' into add_gossipable
Sep 8, 2023
10657e0
feat: add bloom
Sep 9, 2023
baf2923
feat: add test for bloom
Sep 9, 2023
1fea689
feat: add test for bloom
Sep 9, 2023
9f1ab3b
Merge branch 'ava-labs:main' into add_gossipable
Sanghren Sep 11, 2023
f5a464b
Merge branch 'ava-labs:main' into add_gossipable
Sanghren Sep 11, 2023
7ba33ea
feat: add proto
Sep 11, 2023
cc7edeb
feat: add proto generated file
Sep 11, 2023
231d93b
feat: some cleanup
Sep 12, 2023
c1b42c2
feat: some cleanup
Sep 12, 2023
1f57923
feat: add Namespace to Config
Sep 12, 2023
db4cf30
feat: add test
Sep 12, 2023
e52b0a1
feat: add test
Sep 12, 2023
94085a6
Merge branch 'ava-labs:main' into add_gossipable
Sanghren Sep 12, 2023
3c3e138
feat: remove warning debug print
Sep 12, 2023
c63269c
feat: add handler.rs
Sep 13, 2023
476016a
feat: cargo.toml dep
Sep 13, 2023
139dacb
feat: cargo.toml dep
Sep 14, 2023
b9fc9ec
feat: lint
Sep 14, 2023
a606351
feat: finish handler accept_request
Sep 14, 2023
573db11
feat: unused app-request param
Sep 14, 2023
f1b752a
feat: put tests under mod test
Sep 14, 2023
bbf1488
feat: clean up
Sep 15, 2023
5654fb1
feat: pass reference to bloom.has
Sep 15, 2023
20db932
feat: clean up
Sep 15, 2023
27df668
feat: address comments
Sep 15, 2023
0c446e9
feat: address comments
Sep 15, 2023
9e67429
feat: address comments
Sep 15, 2023
61c8256
feat: address comments
Sep 15, 2023
3a7a5cd
feat: address comments
Sep 15, 2023
8cc6084
feat: use associated type instead of phantomdata
Sep 16, 2023
b676024
feat: address warnings
Sep 18, 2023
acb1de0
Merge branch 'ava-labs:main' into add_gossipable
Sanghren Sep 19, 2023
3bec776
feat: implement an example that run gossip logic
Sep 26, 2023
e046013
feat: implement an example that run gossip logic
Sep 26, 2023
13205e7
feat: make things work - wip
Sep 27, 2023
7b1e8eb
Merge branch 'ava-labs:main' into add_gossipable
Sanghren Sep 29, 2023
f56ab25
feat: wip
Oct 1, 2023
884f1fd
feat: wip
Oct 1, 2023
c5446e6
feat: wip
Oct 1, 2023
e4b3400
feat: wip
Oct 1, 2023
fb0359e
feat: wip
Oct 1, 2023
ccce15b
feat: wip
Oct 1, 2023
774ca6e
feat: wip
Oct 1, 2023
ec6767a
feat: wip
Oct 1, 2023
7db76bc
feat: clean
Oct 1, 2023
36c40dd
feat: clean
Oct 1, 2023
f6e8baf
feat: clean
Oct 1, 2023
672c728
feat: clean
Oct 1, 2023
b89abd9
feat: remove arc for callback
Oct 2, 2023
3faedf9
feat: format
Oct 2, 2023
ff65229
feat: format
Oct 2, 2023
65e8a14
feat: format
Oct 2, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion core/network/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
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"] }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding the full tokio set of features is really big. Can we only enable the features we definitely need?

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"
mockall = "0.11.4"
proptest = "1.2.0"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

random-manager = "0.0.5"
testing_logger = "0.1.1"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔, not sure we need this as it looks like it's unmaintained. I guess I'll see where it's used.

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"]
Expand Down
10 changes: 10 additions & 0 deletions core/network/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/// ref. <https://github.com/hyperium/tonic/tree/master/tonic-build>
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();

}
1 change: 1 addition & 0 deletions core/network/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
//! A library for building p2p inbound and outbound connections.
pub mod p2p;
pub mod peer;
10 changes: 10 additions & 0 deletions core/network/src/p2p/client.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
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) {}
}
175 changes: 175 additions & 0 deletions core/network/src/p2p/gossip/bloom.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
use crate::p2p::gossip::Gossipable;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

avalanchego uses the holiman/bloomfilter implementation so I'm not sure this is compatible. I think we can remove the bloom stuff for now.

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<Hasher>,
pub salt: Id,
}

#[derive(Debug, Hash, Deserialize)]
pub struct Hasher {
hash: Vec<u8>,
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<T: Gossipable>(&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<T: Gossipable>(&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<usize, std::io::Error> {
self.hash.extend_from_slice(p);
Ok(p.len())
}

pub fn sum(&mut self, b: &[u8]) -> Vec<u8> {
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 marshal(&self) -> Result<Vec<u8>, Box<dyn Error>> {
todo!()
}

fn unmarshal(&mut self, bytes: &[u8]) -> Result<(), Box<dyn Error>> {
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))
}
}
}
}
}
Loading
Loading