-
Notifications
You must be signed in to change notification settings - Fork 19
Add gossipable trait + relevant logic #45
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
base: main
Are you sure you want to change the base?
Changes from 41 commits
5cbdd66
a0e662a
aa7f63c
ed23c1e
0c35d21
86580a6
bb397b9
10657e0
baf2923
1fea689
9f1ab3b
f5a464b
7ba33ea
cc7edeb
231d93b
c1b42c2
1f57923
db4cf30
e52b0a1
94085a6
3c3e138
c63269c
476016a
139dacb
b9fc9ec
a606351
573db11
f1b752a
bbf1488
5654fb1
20db932
27df668
0c446e9
9e67429
61c8256
3a7a5cd
8cc6084
b676024
acb1de0
3bec776
e046013
13205e7
7b1e8eb
f56ab25
884f1fd
c5446e6
e4b3400
fb0359e
ccce15b
774ca6e
ec6767a
7db76bc
36c40dd
f6e8baf
672c728
b89abd9
3faedf9
ff65229
65e8a14
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,25 +12,42 @@ 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" | ||
| 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" | ||
| 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"] } | ||
| 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" | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
| random-manager = "0.0.5" | ||
| tokio = { version = "1.32.0", features = ["full"] } | ||
| testing_logger = "0.1.1" | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 = ["sync", "time", "rt-multi-thread"] } | ||
| 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"] | ||
|
|
||
| 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(); | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,242 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 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; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 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; | |
| use async_trait::async_trait; | |
| use avalanche_types::ids::Id; | |
| use network::p2p::{ | |
| client::{AppResponseCallback, Client}, | |
| gossip::{ | |
| gossip::{Config, Gossiper}, | |
| handler::{new_handler, Handler, HandlerConfig}, | |
| Gossipable, Set, | |
| }, | |
| handler::Handler as TraitHandler, | |
| }; | |
| use std::{error::Error, hash::Hash, sync::Arc, time::Duration}; | |
| use tokio::{ | |
| io::{AsyncReadExt, AsyncWriteExt}, | |
| net::{TcpListener, TcpStream}, | |
| sync::{mpsc::channel, Mutex}, | |
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh I overlooked this, should check how you can configure this in CLion .
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FYI, todo! is a little shorter, and they pretty much do the same thing.
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤔, you should be using lock().await here. It's also idiomatic to remove the _guard suffix since the type will deref to the stream anyway.
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's interesting that you chose to put a lock around the listener when you lock it in what seems to be an infinite loop.
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm... you can't accept any new incoming connections while your reading the stream here. I think you want to spawn this in a new task. You could use something like an mpsc and select! on listener.accept() and rx.recv() to see if there are any errors and shutdown
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
variable names shouldn't start with _
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When socket.read returns 0, that means the client has disconnected. You will forever get 0, so this is an infinite loop.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think if the client disconnects, the read call will error and the program will panic on that unwrap. If wouldn't infinite loop.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's not true. Example program: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=d809a48e2983d4fe94833852a8a28961
Client drops the tcp_stream on line 35, and waits for the server to finish up before exiting. While it's in this state, read() repeatedly returns Ok(0)
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should fully qualify Id such that you can write:
let node_id = Id::from_slice(&random_manager::secure_bytes(20).unwrap());
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If someone else was holding the lock around the client_socket, this code would crash. I know it's an example, but all you have to do is call let socket = client_socket.lock().await.
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment about addresses, they should be &str. You shouldn't be cloning here.
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You shouldn't be cloning Strings here, you can just pass in &str instead.
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's a cool pattern for cloning
tokio::spawn({
let (listener, stream) = (listener.clone(), stream.clone());
async move {
// Accept incoming connections and spawn a new task to handle each connection
let (listener_socket, _) =
listener
.try_lock()
.expect("Error acquiring lock on listener_clone")
.accept()
.await
.unwrap();
fake_handler_server_logic(listener_socket, stream_clone.clone(), handler.clone()).await;
}
});This also suffers from the same issue, with only one thread being able to access the listener at a time.
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You don't need the extra code block. The guard is dropped at the end of every loop iteration. If it wasn't, the program would panic trying to acquire the lock again.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You shouldn't need it here, either.
| 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; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| use std::sync::Arc; | ||
| use async_trait::async_trait; | ||
|
|
||
| pub type AppResponseCallback = Arc<dyn Fn(Vec<u8>) + Send + Sync>; | ||
|
||
| #[async_trait] | ||
| #[allow(unused_variables)] | ||
| pub trait Client: Send + Sync { | ||
| async fn app_request_any(&mut self, request_bytes: Vec<u8>, on_response: AppResponseCallback) {} | ||
| async fn app_request(&mut self, request_bytes: Vec<u8>) {} | ||
| async fn app_gossip(&mut self, request_bytes: Vec<u8>) {} | ||
| async fn app_gossip_specific(&mut self, request_bytes: Vec<u8>) {} | ||
| async fn cross_chain_app_request(&mut self, request_bytes: Vec<u8>) {} | ||
| async fn prefix_message(&mut self, request_bytes: Vec<u8>) {} | ||
| } | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure if you meant to have a default implementation for all of these methods. It's also likely that you would want to return |
||
|
|
||
| pub struct NoOpClient; | ||
|
|
||
| unsafe impl Sync for NoOpClient {} | ||
| unsafe impl Send for NoOpClient {} | ||
|
||
| impl Client for NoOpClient { | ||
|
|
||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤔, usually libraries re-export
async-traitsuch that the trait definition remains consistent with the trait implementation.I know I'll get my answer below, but are we defining traits with the macro or as we implementing traits with the macro? Or both?