From 47a098ffe8858606173c6ec232e8494c806f30b0 Mon Sep 17 00:00:00 2001 From: Denis K Date: Thu, 16 Feb 2023 20:55:14 +0700 Subject: [PATCH 01/23] ADD: publish, subscribe --- Cargo.lock | 49 ++++++++++++++++++++++++++++-- Cargo.toml | 1 + protocol/examples/ros/.gitignore | 1 + protocol/examples/ros/Cargo.toml | 43 ++++++++++++++++++++++++++ protocol/examples/ros/src/main.rs | 50 +++++++++++++++++++++++++++++++ protocol/src/network/behaviour.rs | 17 +++++++++-- 6 files changed, 156 insertions(+), 5 deletions(-) create mode 100644 protocol/examples/ros/.gitignore create mode 100644 protocol/examples/ros/Cargo.toml create mode 100644 protocol/examples/ros/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index fefdda1ca..1bbf1dc0d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4140,7 +4140,7 @@ dependencies = [ "libp2p-metrics 0.7.0", "libp2p-mplex 0.34.0", "libp2p-noise 0.37.0", - "libp2p-ping", + "libp2p-ping 0.37.0", "libp2p-plaintext", "libp2p-pnet", "libp2p-relay", @@ -4180,6 +4180,7 @@ dependencies = [ "libp2p-metrics 0.10.0", "libp2p-mplex 0.37.0", "libp2p-noise 0.40.0", + "libp2p-ping 0.40.1", "libp2p-request-response 0.22.1", "libp2p-swarm 0.40.1", "libp2p-swarm-derive 0.30.1", @@ -4522,7 +4523,7 @@ dependencies = [ "libp2p-gossipsub 0.39.0", "libp2p-identify", "libp2p-kad 0.38.0", - "libp2p-ping", + "libp2p-ping 0.37.0", "libp2p-relay", "libp2p-swarm 0.37.0", "prometheus-client 0.16.0", @@ -4537,6 +4538,7 @@ dependencies = [ "libp2p-core 0.37.0", "libp2p-gossipsub 0.42.1", "libp2p-kad 0.41.0", + "libp2p-ping 0.40.1", "libp2p-swarm 0.40.1", "prometheus-client 0.18.1", ] @@ -4637,6 +4639,22 @@ dependencies = [ "void", ] +[[package]] +name = "libp2p-ping" +version = "0.40.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7228b9318d34689521349a86eb39a3c3a802c9efc99a0568062ffb80913e3f91" +dependencies = [ + "futures", + "futures-timer", + "instant", + "libp2p-core 0.37.0", + "libp2p-swarm 0.40.1", + "log", + "rand 0.8.5", + "void", +] + [[package]] name = "libp2p-plaintext" version = "0.34.0" @@ -8981,6 +8999,33 @@ dependencies = [ "tokio", ] +[[package]] +name = "robonomics-ros-example" +version = "0.1.0" +dependencies = [ + "async-trait", + "bincode", + "chrono", + "derive_more", + "futures", + "futures-timer", + "instant", + "jsonrpsee 0.14.0", + "libp2p 0.49.0", + "log", + "parity-scale-codec", + "rand 0.8.5", + "robonomics-protocol", + "rust-base58", + "serde", + "serde_json", + "sp-core 6.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-runtime 6.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "subxt", + "tokio", + "void", +] + [[package]] name = "robonomics-rpc" version = "2.7.0" diff --git a/Cargo.toml b/Cargo.toml index 230e07dd7..46481096e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,7 @@ members = [ "primitives", "protocol", "protocol/examples/reqres", + "protocol/examples/ros", "rpc", "runtime/local", "runtime/alpha", diff --git a/protocol/examples/ros/.gitignore b/protocol/examples/ros/.gitignore new file mode 100644 index 000000000..ea8c4bf7f --- /dev/null +++ b/protocol/examples/ros/.gitignore @@ -0,0 +1 @@ +/target diff --git a/protocol/examples/ros/Cargo.toml b/protocol/examples/ros/Cargo.toml new file mode 100644 index 000000000..344fc3ab1 --- /dev/null +++ b/protocol/examples/ros/Cargo.toml @@ -0,0 +1,43 @@ +[package] +name = "robonomics-ros-example" +version = "0.1.0" +edition = "2021" + +[dependencies] +serde = { version = "1.0.130", features = ["derive"] } +serde_json = "1.0.68" +codec = { package = "parity-scale-codec", version = "3.0", features = [ + "derive", +] } +async-trait = "0.1.30" +derive_more = "0.99.11" +futures-timer = "3.0.2" +subxt = "0.22.0" +sp-runtime = "6.0.0" +sp-core = "6.0.0" +futures = "0.3.15" +bincode = "1.3.1" +log = "0.4.11" +jsonrpsee = { version = "0.14.0", features = ["server"] } +rand = "0.8.4" +rust-base58 = "0.0.4" +chrono = "0.4" +void = "1.0" +instant = "0.1.12" +libp2p = { version = "0.49", features = [ + "gossipsub", + "kad", + "mdns", + "request-response", + "noise", + "tcp", + "yamux", + "websocket", + "mplex", + "dns", + "tokio", + "rsa", + "ping", +] } +tokio = { version = "1.23.0", features = ["full"] } +robonomics-protocol = { path = "../.." } diff --git a/protocol/examples/ros/src/main.rs b/protocol/examples/ros/src/main.rs new file mode 100644 index 000000000..3094030e6 --- /dev/null +++ b/protocol/examples/ros/src/main.rs @@ -0,0 +1,50 @@ +use futures::StreamExt; +use libp2p::{ + core::{identity::Keypair, Multiaddr, PeerId}, + gossipsub::IdentTopic as Topic, + swarm::{SwarmBuilder, SwarmEvent}, +}; +use robonomics_protocol::network::behaviour::RobonomicsNetworkBehaviour; +use std::{env::args, error::Error}; +use tokio::io::{self, AsyncBufReadExt, BufReader}; + +#[tokio::main] +async fn main() -> Result<(), Box> { + let local_key = Keypair::generate_ed25519(); + let local_peer_id = PeerId::from(local_key.public()); + println!("Local peer id: {:?}", local_peer_id); + + let transport = libp2p::tokio_development_transport(local_key.clone())?; + let behaviour = RobonomicsNetworkBehaviour::new(local_key, local_peer_id, 1000, true, true)?; + let mut swarm = SwarmBuilder::new(transport, behaviour, local_peer_id) + .executor(Box::new(|fut| { + tokio::spawn(fut); + })) + .build(); + + if let Some(addr) = args().nth(1) { + let remote: Multiaddr = addr.parse()?; + swarm.dial(remote)?; + } + + swarm.listen_on("/ip4/0.0.0.0/tcp/0".parse()?)?; + + let topic = Topic::new("ros"); + let _ = swarm.behaviour_mut().ros_subscribe(&topic)?; + + println!("Enter messages"); + let mut stdin = BufReader::new(io::stdin()).lines(); + + loop { + tokio::select! { + line = stdin.next_line() => { + let message = line?.expect("stdin closed"); + let _message_id = swarm.behaviour_mut().ros_publish(&topic, message)?; + }, + event = swarm.select_next_some() => match event { + SwarmEvent::Behaviour(event) => println!("event: {:?}", event), + _ => {} + } + } + } +} diff --git a/protocol/src/network/behaviour.rs b/protocol/src/network/behaviour.rs index 0919420e7..921b79444 100644 --- a/protocol/src/network/behaviour.rs +++ b/protocol/src/network/behaviour.rs @@ -19,8 +19,8 @@ use libp2p::{ gossipsub::{ - Gossipsub, GossipsubConfigBuilder, GossipsubEvent, GossipsubMessage, MessageAuthenticity, - MessageId, + Gossipsub, GossipsubConfigBuilder, GossipsubEvent, GossipsubMessage, IdentTopic as Topic, + MessageAuthenticity, MessageId, }, identity::Keypair, kad::{record::store::MemoryStore, Kademlia, KademliaEvent}, @@ -36,7 +36,10 @@ use std::{ }; use crate::{ - error::Result, + error::{ + Error::{PublishError, SubscriptionError}, + Result, + }, reqres::{Request, Response}, }; @@ -97,6 +100,14 @@ impl RobonomicsNetworkBehaviour { kademlia, }) } + pub fn ros_subscribe(&mut self, topic: &Topic) -> Result { + self.pubsub.subscribe(topic).map_err(|_| SubscriptionError) + } + pub fn ros_publish(&mut self, topic: &Topic, message: String) -> Result { + self.pubsub + .publish(topic.to_owned(), message.clone()) + .map_err(|_| PublishError) + } } #[derive(Debug)] From d29514a39b0b7576211b9d0bb81ad4fb68e0f72c Mon Sep 17 00:00:00 2001 From: Denis K Date: Thu, 23 Feb 2023 14:28:43 +0700 Subject: [PATCH 02/23] WIP: discovery and ROS --- Cargo.lock | 2 + bin/node/Cargo.toml | 1 + bin/node/src/main.rs | 6 ++ protocol/Cargo.toml | 4 +- protocol/src/network.rs | 17 +--- protocol/src/network/behaviour.rs | 17 +--- protocol/src/network/discovery.rs | 20 ++-- protocol/src/network/worker.rs | 9 +- protocol/src/pubsub.rs | 3 + service/Cargo.toml | 20 +++- service/src/cli.rs | 6 +- service/src/command.rs | 152 ++++++++++++++---------------- 12 files changed, 127 insertions(+), 130 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1bbf1dc0d..9d520cd51 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8925,6 +8925,7 @@ version = "2.7.0" dependencies = [ "parity-util-mem", "robonomics-service", + "tokio", ] [[package]] @@ -9150,6 +9151,7 @@ dependencies = [ "substrate-build-script-utils", "substrate-frame-rpc-system", "substrate-prometheus-endpoint", + "tokio", "vergen", ] diff --git a/bin/node/Cargo.toml b/bin/node/Cargo.toml index 5b17644b7..14ad19527 100644 --- a/bin/node/Cargo.toml +++ b/bin/node/Cargo.toml @@ -26,6 +26,7 @@ parity-util-mem = { version = "0.11", default-features = false, features = [ "jemalloc-global", ] } robonomics-service = { path = "../../service", default-features = false } +tokio = { version = "1.23.0", features = ["full"] } [features] default = ["robonomics-service/kusama", "robonomics-service/wasmtime"] diff --git a/bin/node/src/main.rs b/bin/node/src/main.rs index c916f1af8..d95144965 100644 --- a/bin/node/src/main.rs +++ b/bin/node/src/main.rs @@ -19,6 +19,12 @@ #![warn(missing_docs)] +#[cfg(not(feature = "discovery"))] fn main() -> robonomics_service::Result<()> { robonomics_service::run() } +#[cfg(feature = "discovery")] +#[tokio::main] +async fn main() -> robonomics_service::Result<()> { + robonomics_service::run().await +} diff --git a/protocol/Cargo.toml b/protocol/Cargo.toml index cd1b13204..9697d5525 100644 --- a/protocol/Cargo.toml +++ b/protocol/Cargo.toml @@ -38,6 +38,4 @@ libp2p = { version = "0.49", features = [ "tokio", "rsa", ] } - -tokio = { version = "1", features = ["full"] } - +tokio = { version = "1.23.0", features = ["full"] } diff --git a/protocol/src/network.rs b/protocol/src/network.rs index 62b308294..779281678 100644 --- a/protocol/src/network.rs +++ b/protocol/src/network.rs @@ -19,7 +19,7 @@ use futures::prelude::*; use libp2p::{identity::Keypair, Multiaddr, PeerId}; -use std::{collections::HashMap, sync::Arc}; +use std::sync::Arc; use crate::{ error::{FutureResult, Result}, @@ -33,7 +33,6 @@ pub mod worker; pub struct RobonomicsNetwork { pub pubsub: Arc, - pub peers: HashMap, } impl RobonomicsNetwork { @@ -45,7 +44,6 @@ impl RobonomicsNetwork { disable_mdns: bool, disable_kad: bool, ) -> Result<(Arc, impl Future)> { - let mut peers = HashMap::new(); let mut network_worker = NetworkWorker::new( local_key, heartbeat_interval, @@ -55,18 +53,9 @@ impl RobonomicsNetwork { )?; // Reach out to another nodes if specified - discovery::add_explicit_peers( - &mut network_worker.swarm, - &mut peers, - bootnodes, - disable_kad, - ); - - Ok((Arc::new(Self { pubsub, peers }), network_worker)) - } + discovery::add_explicit_peers(&mut network_worker.swarm, bootnodes, disable_kad); - pub fn get_address(&self, peer_id: PeerId) -> Option<&Multiaddr> { - self.peers.get(&peer_id) + Ok((Arc::new(Self { pubsub }), network_worker)) } } diff --git a/protocol/src/network/behaviour.rs b/protocol/src/network/behaviour.rs index 921b79444..0919420e7 100644 --- a/protocol/src/network/behaviour.rs +++ b/protocol/src/network/behaviour.rs @@ -19,8 +19,8 @@ use libp2p::{ gossipsub::{ - Gossipsub, GossipsubConfigBuilder, GossipsubEvent, GossipsubMessage, IdentTopic as Topic, - MessageAuthenticity, MessageId, + Gossipsub, GossipsubConfigBuilder, GossipsubEvent, GossipsubMessage, MessageAuthenticity, + MessageId, }, identity::Keypair, kad::{record::store::MemoryStore, Kademlia, KademliaEvent}, @@ -36,10 +36,7 @@ use std::{ }; use crate::{ - error::{ - Error::{PublishError, SubscriptionError}, - Result, - }, + error::Result, reqres::{Request, Response}, }; @@ -100,14 +97,6 @@ impl RobonomicsNetworkBehaviour { kademlia, }) } - pub fn ros_subscribe(&mut self, topic: &Topic) -> Result { - self.pubsub.subscribe(topic).map_err(|_| SubscriptionError) - } - pub fn ros_publish(&mut self, topic: &Topic, message: String) -> Result { - self.pubsub - .publish(topic.to_owned(), message.clone()) - .map_err(|_| PublishError) - } } #[derive(Debug)] diff --git a/protocol/src/network/discovery.rs b/protocol/src/network/discovery.rs index 367069c71..f05a41ae1 100644 --- a/protocol/src/network/discovery.rs +++ b/protocol/src/network/discovery.rs @@ -19,28 +19,28 @@ use super::behaviour::RobonomicsNetworkBehaviour; use libp2p::{Multiaddr, PeerId, Swarm}; -use std::collections::HashMap; pub fn add_explicit_peers( swarm: &mut Swarm, - peers: &mut HashMap, bootnodes: Vec, - disable_kad: bool, + _disable_kad: bool, ) { for node in bootnodes { if let Ok(addr) = node.parse::() { if let Some(peer) = PeerId::try_from_multiaddr(&addr) { - peers.insert(peer, addr.clone()); + if let Err(e) = swarm.dial(peer) { + println!("Dial error: {:?}", e); + } // Add node to PubSub - swarm.behaviour_mut().pubsub.add_explicit_peer(&peer); + // swarm.behaviour_mut().pubsub.add_explicit_peer(&peer); // Add node to DHT - if !disable_kad { - if let Some(kademlia) = swarm.behaviour_mut().kademlia.as_mut() { - kademlia.add_address(&peer, addr); - }; - } + // if !disable_kad { + // if let Some(kademlia) = swarm.behaviour_mut().kademlia.as_mut() { + // kademlia.add_address(&peer, addr); + // }; + // } } } } diff --git a/protocol/src/network/worker.rs b/protocol/src/network/worker.rs index c0cfa396d..276616f9b 100644 --- a/protocol/src/network/worker.rs +++ b/protocol/src/network/worker.rs @@ -22,7 +22,7 @@ use libp2p::{ identity::Keypair, kad::KademliaEvent, request_response::{RequestResponseEvent, RequestResponseMessage}, - swarm::SwarmEvent, + swarm::{SwarmBuilder, SwarmEvent}, PeerId, Swarm, }; use std::{ @@ -67,7 +67,12 @@ impl NetworkWorker { )?; // Create a Swarm to manage peers and events - let swarm = Swarm::new(transport, behaviour, peer_id.clone()); + // let swarm = Swarm::new(transport, behaviour, peer_id.clone()); + let swarm = SwarmBuilder::new(transport, behaviour, peer_id.clone()) + .executor(Box::new(|fut| { + tokio::spawn(fut); + })) + .build(); Ok(Self { swarm, pubsub }) } diff --git a/protocol/src/pubsub.rs b/protocol/src/pubsub.rs index f4924187d..bba169a62 100644 --- a/protocol/src/pubsub.rs +++ b/protocol/src/pubsub.rs @@ -299,6 +299,9 @@ impl Future for PubSubWorker { loop { match self.swarm.poll_next_unpin(cx) { Poll::Ready(Some(swarm_event)) => match swarm_event { + SwarmEvent::NewListenAddr { address, .. } => { + println!("23Listening on {:?}", address) + } SwarmEvent::Behaviour(event) => match event { GossipsubEvent::Message { propagation_source: peer_id, diff --git a/service/Cargo.toml b/service/Cargo.toml index 1d12ddb12..bcf3a8ccd 100644 --- a/service/Cargo.toml +++ b/service/Cargo.toml @@ -18,7 +18,23 @@ jsonrpsee = { version = "0.15.1", features = ["server"] } codec = { package = "parity-scale-codec", version = "3.0.0" } hex-literal = "0.3.1" log = "0.4.17" -libp2p = { version = "0.49", optional = true } +# libp2p = { version = "0.49", optional = true } +tokio = { version = "1.23.0", features = ["full"], optional = true } +libp2p = { version = "0.49", features = [ + "gossipsub", + "kad", + "mdns", + "request-response", + "noise", + "tcp", + "yamux", + "websocket", + "mplex", + "dns", + "tokio", + "rsa", + "ping", +], optional = true } # primitives robonomics-primitives = { path = "../primitives", default-features = false } @@ -127,6 +143,7 @@ robonomics-pair = { path = "../pair", optional = true } vergen = { version = "3.1.0", optional = true } clap = { version = "3.0", features = ["derive"], optional = true } clap_complete = { version = "3.0", optional = true } +tokio = { version = "1.23.0", features = ["full"], optional = true } [features] ## Build fully functional node by default. @@ -171,6 +188,7 @@ discovery = [ "clap_complete", "robonomics-protocol", "libp2p", + "tokio", ] ## Enable Kusama parachain. diff --git a/service/src/cli.rs b/service/src/cli.rs index 955ca39ff..703150f6d 100644 --- a/service/src/cli.rs +++ b/service/src/cli.rs @@ -17,7 +17,7 @@ /////////////////////////////////////////////////////////////////////////////// use clap::Parser; -use robonomics_pair; +// use robonomics_pair; use sc_cli::{KeySubcommand, SignCmd, VanityCmd, VerifyCmd}; /// An overarching CLI command definition. @@ -53,7 +53,7 @@ pub struct Cli { pub heartbeat_interval: Option, /// Nodes for connect. - #[clap(long)] + #[clap(long, value_delimiter = ',')] pub robonomics_bootnodes: Vec, /// Disable mDNS. @@ -101,7 +101,7 @@ pub enum Subcommand { /// Pair by peerId operatins /// robonomics pair listen --peer peerID_to_listen /// robonomics pair connect --peer peerID_to_listen - Pair(robonomics_pair::pair::PairCmd), + // Pair(robonomics_pair::pair::PairCmd), /// Benchmarking runtime pallets. #[cfg(feature = "frame-benchmarking-cli")] diff --git a/service/src/command.rs b/service/src/command.rs index 176b8ba46..902cbad06 100644 --- a/service/src/command.rs +++ b/service/src/command.rs @@ -21,21 +21,16 @@ use crate::cli::{Cli, Subcommand}; use crate::{chain_spec::*, service::robonomics}; #[cfg(feature = "discovery")] use libp2p::{ - futures::{executor, StreamExt}, - kad::KademliaEvent, - swarm::SwarmEvent, + futures::StreamExt, + swarm::{SwarmBuilder, SwarmEvent}, + PeerId, }; use robonomics_protocol::id; #[cfg(feature = "discovery")] -use robonomics_protocol::{ - network::behaviour::OutEvent, - network::{discovery, worker::NetworkWorker}, - pubsub::{PubSub, Pubsub}, -}; +use robonomics_protocol::network::{behaviour::RobonomicsNetworkBehaviour, discovery}; use sc_cli::{ChainSpec, RuntimeVersion, SubstrateCli}; -use std::path::Path; #[cfg(feature = "discovery")] -use std::{collections::HashMap, thread}; +use std::path::Path; #[cfg(feature = "parachain")] use crate::parachain; @@ -106,71 +101,63 @@ impl SubstrateCli for Cli { } } +#[cfg(feature = "discovery")] +pub async fn run() -> sc_cli::Result<()> { + let cli = Cli::from_args(); + + // Get local key + let local_key = cli.local_key_file.map_or(id::random(), |file_name| { + id::load(Path::new(&file_name)).expect("Correct file path") + }); + let local_peer_id = PeerId::from(local_key.public()); + println!("Local peer id: {:?}", local_peer_id); + + let transport = + libp2p::tokio_development_transport(local_key.clone()).expect("Correct transport"); + let behaviour = RobonomicsNetworkBehaviour::new(local_key, local_peer_id, 1000, true, true) + .expect("Correct behaviour"); + let mut swarm = SwarmBuilder::new(transport, behaviour, local_peer_id) + .executor(Box::new(|fut| { + tokio::spawn(fut); + })) + .build(); + + discovery::add_explicit_peers(&mut swarm, cli.robonomics_bootnodes, cli.disable_kad); + + swarm + .listen_on("/ip4/0.0.0.0/tcp/0".parse().unwrap()) + .expect("Swarm listen"); + + let peers = swarm.connected_peers(); + for p in peers { + println!("connected peer: {:?}", p); + } + + loop { + tokio::select! { + event = swarm.select_next_some() => match event { + SwarmEvent::NewListenAddr { address, .. } => println!("Listening on {:?}", address), + SwarmEvent::Behaviour(event) => println!("Event: {:?}", event), + event => { + println!("Other event: {:?}", event); + let ps = swarm.connected_peers(); + for p in ps { + println!("connected peer: {:?}", p); + } + } + } + } + } +} + /// Parse command line arguments into service configuration. +#[cfg(not(feature = "discovery"))] pub fn run() -> sc_cli::Result<()> { let cli = Cli::from_args(); match &cli.subcommand { #[cfg(not(feature = "full"))] - None => { - #[cfg(feature = "discovery")] - { - // Get local key - let local_key = cli.local_key_file.map_or(id::random(), |file_name| { - id::load(Path::new(&file_name)).expect("Correct file path") - }); - - // Default interval 1 sec - let heartbeat_interval = cli.heartbeat_interval.unwrap_or_else(|| 1000); - - let (pubsub, _) = Pubsub::new(local_key.clone(), heartbeat_interval) - .expect("New robonomics pubsub"); - - let mut network_worker = NetworkWorker::new( - local_key, - heartbeat_interval, - pubsub.clone(), - cli.disable_mdns, - cli.disable_kad, - ) - .expect("Correct network worker"); - - let mut peers = HashMap::new(); - discovery::add_explicit_peers( - &mut network_worker.swarm, - &mut peers, - cli.robonomics_bootnodes, - cli.disable_kad, - ); - - network_worker - .swarm - .listen_on("/ip4/0.0.0.0/tcp/0".parse().unwrap()) - .expect("Swarm starts to listen"); - - thread::spawn(move || loop { - match executor::block_on(network_worker.swarm.select_next_some()) { - SwarmEvent::Behaviour(OutEvent::Kademlia( - KademliaEvent::RoutingUpdated { - peer, addresses, .. - }, - )) => { - for addr in addresses.iter() { - println!("Kad discovered peer: {}", peer); - let _ = pubsub.connect(addr.clone()); - } - } - other_event => { - println!("Event: {:?}", other_event); - } - } - }) - .join() - .unwrap(); - } - - Ok(()) - } + None => Ok(()), #[cfg(feature = "full")] None => { let runner = cli.create_runner(&cli.run.normalize())?; @@ -285,20 +272,19 @@ pub fn run() -> sc_cli::Result<()> { runner.sync_run(|config| cmd.run(config.database)) } - #[cfg(feature = "full")] - Some(Subcommand::Pair(cmd)) => match &cmd.subcommand { - Some(robonomics_pair::pair::PairSubCmds::Connect(cmd)) => { - robonomics_pair::pair::ConnectCmd::run(cmd).map_err(|e| e.to_string().into()) - } - Some(robonomics_pair::pair::PairSubCmds::Listen(cmd)) => { - robonomics_pair::pair::ListenCmd::run(cmd).map_err(|e| e.to_string().into()) - } - _ => { - println!("pair args {:?}", cmd); - Ok(()) - } - }, - + // #[cfg(feature = "full")] + // Some(Subcommand::Pair(cmd)) => match &cmd.subcommand { + // Some(robonomics_pair::pair::PairSubCmds::Connect(cmd)) => { + // robonomics_pair::pair::ConnectCmd::run(cmd).map_err(|e| e.to_string().into()) + // } + // Some(robonomics_pair::pair::PairSubCmds::Listen(cmd)) => { + // robonomics_pair::pair::ListenCmd::run(cmd).map_err(|e| e.to_string().into()) + // } + // _ => { + // println!("pair args {:?}", cmd); + // Ok(()) + // } + // }, #[cfg(feature = "robonomics-cli")] Some(Subcommand::Io(cmd)) => { let runner = cli.create_runner(&*cli.run)?; From 10f976c98571146144edbd9e2f8364828e72c191 Mon Sep 17 00:00:00 2001 From: Denis K Date: Fri, 24 Feb 2023 18:56:48 +0700 Subject: [PATCH 03/23] WIP: discovery and ROS --- protocol/examples/ros/src/main.rs | 24 +++++++++++++++------ protocol/src/network/discovery.rs | 35 ++++++++++++++++++------------- protocol/src/network/worker.rs | 12 ++++++++++- protocol/src/pubsub.rs | 12 ++++++++++- service/src/command.rs | 33 +++++++++++++++++------------ 5 files changed, 80 insertions(+), 36 deletions(-) diff --git a/protocol/examples/ros/src/main.rs b/protocol/examples/ros/src/main.rs index 3094030e6..af66a9324 100644 --- a/protocol/examples/ros/src/main.rs +++ b/protocol/examples/ros/src/main.rs @@ -1,8 +1,10 @@ use futures::StreamExt; use libp2p::{ - core::{identity::Keypair, Multiaddr, PeerId}, + core::{identity::Keypair, upgrade, Multiaddr, PeerId}, gossipsub::IdentTopic as Topic, + mplex, noise, swarm::{SwarmBuilder, SwarmEvent}, + tcp, Transport, }; use robonomics_protocol::network::behaviour::RobonomicsNetworkBehaviour; use std::{env::args, error::Error}; @@ -15,6 +17,15 @@ async fn main() -> Result<(), Box> { println!("Local peer id: {:?}", local_peer_id); let transport = libp2p::tokio_development_transport(local_key.clone())?; + // let transport = tcp::TokioTcpTransport::new(tcp::GenTcpConfig::default().nodelay(true)) + // .upgrade(upgrade::Version::V1) + // .authenticate( + // noise::NoiseAuthenticated::xx(&local_key) + // .expect("Signing libp2p-noise static DH keypair failed."), + // ) + // .multiplex(mplex::MplexConfig::new()) + // .boxed(); + let behaviour = RobonomicsNetworkBehaviour::new(local_key, local_peer_id, 1000, true, true)?; let mut swarm = SwarmBuilder::new(transport, behaviour, local_peer_id) .executor(Box::new(|fut| { @@ -30,7 +41,7 @@ async fn main() -> Result<(), Box> { swarm.listen_on("/ip4/0.0.0.0/tcp/0".parse()?)?; let topic = Topic::new("ros"); - let _ = swarm.behaviour_mut().ros_subscribe(&topic)?; + let _ = swarm.behaviour_mut().pubsub.subscribe(&topic)?; println!("Enter messages"); let mut stdin = BufReader::new(io::stdin()).lines(); @@ -38,12 +49,13 @@ async fn main() -> Result<(), Box> { loop { tokio::select! { line = stdin.next_line() => { - let message = line?.expect("stdin closed"); - let _message_id = swarm.behaviour_mut().ros_publish(&topic, message)?; + // let message = line?.expect("stdin closed"); + // let message = "test".to_string().as_bytes(); + let _message_id = swarm.behaviour_mut().pubsub.publish(topic.clone(),"test".to_string().as_bytes())?; }, event = swarm.select_next_some() => match event { - SwarmEvent::Behaviour(event) => println!("event: {:?}", event), - _ => {} + SwarmEvent::Behaviour(event) => println!("swarm event: {:?}", event), + event => println!("event: {:?}", event), } } } diff --git a/protocol/src/network/discovery.rs b/protocol/src/network/discovery.rs index f05a41ae1..cb625bc61 100644 --- a/protocol/src/network/discovery.rs +++ b/protocol/src/network/discovery.rs @@ -18,7 +18,8 @@ //! Robonomics protocol node discovery. use super::behaviour::RobonomicsNetworkBehaviour; -use libp2p::{Multiaddr, PeerId, Swarm}; +// use libp2p::{Multiaddr, PeerId, Swarm}; +use libp2p::{Multiaddr, Swarm}; pub fn add_explicit_peers( swarm: &mut Swarm, @@ -27,21 +28,25 @@ pub fn add_explicit_peers( ) { for node in bootnodes { if let Ok(addr) = node.parse::() { - if let Some(peer) = PeerId::try_from_multiaddr(&addr) { - if let Err(e) = swarm.dial(peer) { - println!("Dial error: {:?}", e); - } - - // Add node to PubSub - // swarm.behaviour_mut().pubsub.add_explicit_peer(&peer); - - // Add node to DHT - // if !disable_kad { - // if let Some(kademlia) = swarm.behaviour_mut().kademlia.as_mut() { - // kademlia.add_address(&peer, addr); - // }; - // } + if let Err(e) = swarm.dial(addr) { + println!("Dial error: {:?}", e); } + + // if let Some(peer) = PeerId::try_from_multiaddr(&addr) { + // if let Err(e) = swarm.dial(peer) { + // println!("Dial error: {:?}", e); + // } + // + // // Add node to PubSub + // // swarm.behaviour_mut().pubsub.add_explicit_peer(&peer); + // + // // Add node to DHT + // // if !disable_kad { + // // if let Some(kademlia) = swarm.behaviour_mut().kademlia.as_mut() { + // // kademlia.add_address(&peer, addr); + // // }; + // // } + // } } } } diff --git a/protocol/src/network/worker.rs b/protocol/src/network/worker.rs index 276616f9b..2e9487ee7 100644 --- a/protocol/src/network/worker.rs +++ b/protocol/src/network/worker.rs @@ -19,11 +19,13 @@ use futures::{prelude::*, Future}; use libp2p::{ + core::upgrade, identity::Keypair, kad::KademliaEvent, + mplex, noise, request_response::{RequestResponseEvent, RequestResponseMessage}, swarm::{SwarmBuilder, SwarmEvent}, - PeerId, Swarm, + tcp, PeerId, Swarm, Transport, }; use std::{ pin::Pin, @@ -56,6 +58,14 @@ impl NetworkWorker { // Set up an encrypted WebSocket compatible Transport let transport = libp2p::tokio_development_transport(local_key.clone())?; + // let transport = tcp::TokioTcpTransport::new(tcp::GenTcpConfig::default().nodelay(true)) + // .upgrade(upgrade::Version::V1) + // .authenticate( + // noise::NoiseAuthenticated::xx(&local_key) + // .expect("Signing libp2p-noise static DH keypair failed."), + // ) + // .multiplex(mplex::MplexConfig::new()) + // .boxed(); // Build a combined network behaviour let behaviour = RobonomicsNetworkBehaviour::new( diff --git a/protocol/src/pubsub.rs b/protocol/src/pubsub.rs index bba169a62..a97a62535 100644 --- a/protocol/src/pubsub.rs +++ b/protocol/src/pubsub.rs @@ -23,13 +23,15 @@ use futures::{ }; use libp2p::{ core::transport::ListenerId, + core::upgrade, gossipsub::{ Gossipsub, GossipsubConfigBuilder, GossipsubEvent, GossipsubMessage, MessageAuthenticity, MessageId, Sha256Topic as Topic, TopicHash, }, identity::Keypair, + mplex, noise, swarm::{SwarmBuilder, SwarmEvent}, - Multiaddr, PeerId, Swarm, + tcp, Multiaddr, PeerId, Swarm, Transport, }; use serde::Serialize; use std::{ @@ -197,6 +199,14 @@ impl PubSubWorker { // Set up an encrypted WebSocket compatible Transport over the Mplex and Yamux protocols let transport = libp2p::tokio_development_transport(local_key.clone())?; + // let transport = tcp::TokioTcpTransport::new(tcp::GenTcpConfig::default().nodelay(true)) + // .upgrade(upgrade::Version::V1) + // .authenticate( + // noise::NoiseAuthenticated::xx(&local_key) + // .expect("Signing libp2p-noise static DH keypair failed."), + // ) + // .multiplex(mplex::MplexConfig::new()) + // .boxed(); // Set custom gossipsub let gossipsub_config = GossipsubConfigBuilder::default() diff --git a/service/src/command.rs b/service/src/command.rs index 902cbad06..ecedb02fb 100644 --- a/service/src/command.rs +++ b/service/src/command.rs @@ -21,15 +21,16 @@ use crate::cli::{Cli, Subcommand}; use crate::{chain_spec::*, service::robonomics}; #[cfg(feature = "discovery")] use libp2p::{ + core::upgrade, futures::StreamExt, + mplex, noise, swarm::{SwarmBuilder, SwarmEvent}, - PeerId, + tcp, Multiaddr, PeerId, Transport, }; use robonomics_protocol::id; #[cfg(feature = "discovery")] -use robonomics_protocol::network::{behaviour::RobonomicsNetworkBehaviour, discovery}; +use robonomics_protocol::network::behaviour::RobonomicsNetworkBehaviour; use sc_cli::{ChainSpec, RuntimeVersion, SubstrateCli}; -#[cfg(feature = "discovery")] use std::path::Path; #[cfg(feature = "parachain")] @@ -104,8 +105,6 @@ impl SubstrateCli for Cli { #[cfg(feature = "discovery")] pub async fn run() -> sc_cli::Result<()> { let cli = Cli::from_args(); - - // Get local key let local_key = cli.local_key_file.map_or(id::random(), |file_name| { id::load(Path::new(&file_name)).expect("Correct file path") }); @@ -114,6 +113,14 @@ pub async fn run() -> sc_cli::Result<()> { let transport = libp2p::tokio_development_transport(local_key.clone()).expect("Correct transport"); + // let transport = tcp::TokioTcpTransport::new(tcp::GenTcpConfig::default().nodelay(true)) + // .upgrade(upgrade::Version::V1) + // .authenticate( + // noise::NoiseAuthenticated::xx(&local_key) + // .expect("Signing libp2p-noise static DH keypair failed."), + // ) + // .multiplex(mplex::MplexConfig::new()) + // .boxed(); let behaviour = RobonomicsNetworkBehaviour::new(local_key, local_peer_id, 1000, true, true) .expect("Correct behaviour"); let mut swarm = SwarmBuilder::new(transport, behaviour, local_peer_id) @@ -122,17 +129,18 @@ pub async fn run() -> sc_cli::Result<()> { })) .build(); - discovery::add_explicit_peers(&mut swarm, cli.robonomics_bootnodes, cli.disable_kad); + for node in cli.robonomics_bootnodes { + if let Ok(address) = node.parse::() { + if let Err(error) = swarm.dial(address) { + println!("Dial error: {:?}", error); + } + } + } swarm .listen_on("/ip4/0.0.0.0/tcp/0".parse().unwrap()) .expect("Swarm listen"); - let peers = swarm.connected_peers(); - for p in peers { - println!("connected peer: {:?}", p); - } - loop { tokio::select! { event = swarm.select_next_some() => match event { @@ -140,8 +148,7 @@ pub async fn run() -> sc_cli::Result<()> { SwarmEvent::Behaviour(event) => println!("Event: {:?}", event), event => { println!("Other event: {:?}", event); - let ps = swarm.connected_peers(); - for p in ps { + for p in swarm.connected_peers() { println!("connected peer: {:?}", p); } } From 1bf58d00a842ca76db75391afa531cbf76c689f7 Mon Sep 17 00:00:00 2001 From: Denis K Date: Tue, 28 Feb 2023 22:05:17 +0700 Subject: [PATCH 04/23] ADD: correct example for ros --- Cargo.lock | 17 ------- protocol/examples/ros/Cargo.toml | 39 ++------------ protocol/examples/ros/src/main.rs | 84 +++++++++++++++++++------------ protocol/src/network.rs | 2 +- protocol/src/network/discovery.rs | 43 +++++++--------- service/src/command.rs | 50 +++++++++--------- 6 files changed, 99 insertions(+), 136 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9d520cd51..e89d2ea44 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9004,27 +9004,10 @@ dependencies = [ name = "robonomics-ros-example" version = "0.1.0" dependencies = [ - "async-trait", - "bincode", - "chrono", - "derive_more", "futures", - "futures-timer", - "instant", - "jsonrpsee 0.14.0", "libp2p 0.49.0", - "log", - "parity-scale-codec", - "rand 0.8.5", "robonomics-protocol", - "rust-base58", - "serde", - "serde_json", - "sp-core 6.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sp-runtime 6.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "subxt", "tokio", - "void", ] [[package]] diff --git a/protocol/examples/ros/Cargo.toml b/protocol/examples/ros/Cargo.toml index 344fc3ab1..d7cb92a3b 100644 --- a/protocol/examples/ros/Cargo.toml +++ b/protocol/examples/ros/Cargo.toml @@ -4,40 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] -serde = { version = "1.0.130", features = ["derive"] } -serde_json = "1.0.68" -codec = { package = "parity-scale-codec", version = "3.0", features = [ - "derive", -] } -async-trait = "0.1.30" -derive_more = "0.99.11" -futures-timer = "3.0.2" -subxt = "0.22.0" -sp-runtime = "6.0.0" -sp-core = "6.0.0" -futures = "0.3.15" -bincode = "1.3.1" -log = "0.4.11" -jsonrpsee = { version = "0.14.0", features = ["server"] } -rand = "0.8.4" -rust-base58 = "0.0.4" -chrono = "0.4" -void = "1.0" -instant = "0.1.12" -libp2p = { version = "0.49", features = [ - "gossipsub", - "kad", - "mdns", - "request-response", - "noise", - "tcp", - "yamux", - "websocket", - "mplex", - "dns", - "tokio", - "rsa", - "ping", -] } -tokio = { version = "1.23.0", features = ["full"] } robonomics-protocol = { path = "../.." } +tokio = { version = "1.23", features = ["full"] } +futures = "0.3" +libp2p = "0.49" diff --git a/protocol/examples/ros/src/main.rs b/protocol/examples/ros/src/main.rs index af66a9324..ccf7ba946 100644 --- a/protocol/examples/ros/src/main.rs +++ b/protocol/examples/ros/src/main.rs @@ -1,61 +1,81 @@ use futures::StreamExt; use libp2p::{ - core::{identity::Keypair, upgrade, Multiaddr, PeerId}, - gossipsub::IdentTopic as Topic, - mplex, noise, + gossipsub::{GossipsubEvent, IdentTopic as Topic}, + identity, swarm::{SwarmBuilder, SwarmEvent}, - tcp, Transport, + Multiaddr, PeerId, }; -use robonomics_protocol::network::behaviour::RobonomicsNetworkBehaviour; -use std::{env::args, error::Error}; -use tokio::io::{self, AsyncBufReadExt, BufReader}; +use std::{env, error::Error}; +use tokio::io::{self, AsyncBufReadExt}; + +use robonomics_protocol::network::behaviour::{OutEvent, RobonomicsNetworkBehaviour}; #[tokio::main] async fn main() -> Result<(), Box> { - let local_key = Keypair::generate_ed25519(); + // Create a random PeerId + let local_key = identity::Keypair::generate_ed25519(); let local_peer_id = PeerId::from(local_key.public()); - println!("Local peer id: {:?}", local_peer_id); + println!("Local peer id: {local_peer_id}"); + // Set up an encrypted DNS-enabled TCP Transport over the Mplex protocol let transport = libp2p::tokio_development_transport(local_key.clone())?; - // let transport = tcp::TokioTcpTransport::new(tcp::GenTcpConfig::default().nodelay(true)) - // .upgrade(upgrade::Version::V1) - // .authenticate( - // noise::NoiseAuthenticated::xx(&local_key) - // .expect("Signing libp2p-noise static DH keypair failed."), - // ) - // .multiplex(mplex::MplexConfig::new()) - // .boxed(); - - let behaviour = RobonomicsNetworkBehaviour::new(local_key, local_peer_id, 1000, true, true)?; + + // Create robonomics network behaviour + let mut behaviour = RobonomicsNetworkBehaviour::new(local_key, local_peer_id, 1000, true, true) + .expect("Correct behaviour"); + + // Create topic + let topic = Topic::new("ROS"); + + // Subscribe to topic + behaviour.pubsub.subscribe(&topic)?; + + // Create swarm let mut swarm = SwarmBuilder::new(transport, behaviour, local_peer_id) .executor(Box::new(|fut| { tokio::spawn(fut); })) .build(); - if let Some(addr) = args().nth(1) { - let remote: Multiaddr = addr.parse()?; - swarm.dial(remote)?; + // Add nodes + if let Some(to_dial) = env::args().nth(1) { + let addr: Multiaddr = to_dial.parse()?; + swarm.dial(addr.clone())?; + println!("Dialed {to_dial:?}"); + + if let Some(peer) = PeerId::try_from_multiaddr(&addr) { + swarm.behaviour_mut().pubsub.add_explicit_peer(&peer); + } } - swarm.listen_on("/ip4/0.0.0.0/tcp/0".parse()?)?; + // Read full lines from stdin + let mut stdin = io::BufReader::new(io::stdin()).lines(); - let topic = Topic::new("ros"); - let _ = swarm.behaviour_mut().pubsub.subscribe(&topic)?; + // Listen on all interfaces and whatever port the OS assigns + swarm.listen_on("/ip4/0.0.0.0/tcp/0".parse()?)?; - println!("Enter messages"); - let mut stdin = BufReader::new(io::stdin()).lines(); + println!("Enter messages via STDIN and they will be sent to connected peers using Pubsub"); loop { tokio::select! { line = stdin.next_line() => { - // let message = line?.expect("stdin closed"); - // let message = "test".to_string().as_bytes(); - let _message_id = swarm.behaviour_mut().pubsub.publish(topic.clone(),"test".to_string().as_bytes())?; + if let Err(e) = swarm + .behaviour_mut() + .pubsub + .publish(topic.clone(), line.expect("Stdin not to close").expect("").as_bytes()) { + println!("Publish error: {e:?}"); + } }, event = swarm.select_next_some() => match event { - SwarmEvent::Behaviour(event) => println!("swarm event: {:?}", event), - event => println!("event: {:?}", event), + SwarmEvent::Behaviour(OutEvent::Pubsub(GossipsubEvent::Message { + propagation_source: peer_id, + message_id: id, + message, + })) => println!( + "Got message: '{}' with id: {id} from peer: {peer_id}", + String::from_utf8_lossy(&message.data), + ), + event => println!("event: {event:?}"), } } } diff --git a/protocol/src/network.rs b/protocol/src/network.rs index 779281678..f54841c6f 100644 --- a/protocol/src/network.rs +++ b/protocol/src/network.rs @@ -53,7 +53,7 @@ impl RobonomicsNetwork { )?; // Reach out to another nodes if specified - discovery::add_explicit_peers(&mut network_worker.swarm, bootnodes, disable_kad); + discovery::add_peers(&mut network_worker.swarm, bootnodes); Ok((Arc::new(Self { pubsub }), network_worker)) } diff --git a/protocol/src/network/discovery.rs b/protocol/src/network/discovery.rs index cb625bc61..28455c9fc 100644 --- a/protocol/src/network/discovery.rs +++ b/protocol/src/network/discovery.rs @@ -18,35 +18,28 @@ //! Robonomics protocol node discovery. use super::behaviour::RobonomicsNetworkBehaviour; -// use libp2p::{Multiaddr, PeerId, Swarm}; -use libp2p::{Multiaddr, Swarm}; +use libp2p::{Multiaddr, PeerId, Swarm}; -pub fn add_explicit_peers( - swarm: &mut Swarm, - bootnodes: Vec, - _disable_kad: bool, -) { +pub fn add_peers(swarm: &mut Swarm, bootnodes: Vec) { for node in bootnodes { if let Ok(addr) = node.parse::() { - if let Err(e) = swarm.dial(addr) { - println!("Dial error: {:?}", e); - } + println!("Addr: {addr}"); + if let Err(e) = swarm.dial(addr.clone()) { + println!("Dial error: {e}"); + } else { + // Add node to pubsub swarm + if let Some(peer) = PeerId::try_from_multiaddr(&addr) { + println!("Adding peer to swarm: {peer}"); + swarm.behaviour_mut().pubsub.add_explicit_peer(&peer); + } - // if let Some(peer) = PeerId::try_from_multiaddr(&addr) { - // if let Err(e) = swarm.dial(peer) { - // println!("Dial error: {:?}", e); - // } - // - // // Add node to PubSub - // // swarm.behaviour_mut().pubsub.add_explicit_peer(&peer); - // - // // Add node to DHT - // // if !disable_kad { - // // if let Some(kademlia) = swarm.behaviour_mut().kademlia.as_mut() { - // // kademlia.add_address(&peer, addr); - // // }; - // // } - // } + // Add node to DHT + // if !disable_kad { + // if let Some(kademlia) = swarm.behaviour_mut().kademlia.as_mut() { + // kademlia.add_address(&peer, addr); + // }; + // } + } } } } diff --git a/service/src/command.rs b/service/src/command.rs index ecedb02fb..43b6f8552 100644 --- a/service/src/command.rs +++ b/service/src/command.rs @@ -17,21 +17,22 @@ /////////////////////////////////////////////////////////////////////////////// use crate::cli::{Cli, Subcommand}; + #[cfg(feature = "full")] use crate::{chain_spec::*, service::robonomics}; +use robonomics_protocol::id; +use sc_cli::{ChainSpec, RuntimeVersion, SubstrateCli}; +use std::path::Path; + #[cfg(feature = "discovery")] use libp2p::{ core::upgrade, futures::StreamExt, - mplex, noise, + gossipsub, mdns, mplex, noise, swarm::{SwarmBuilder, SwarmEvent}, tcp, Multiaddr, PeerId, Transport, }; -use robonomics_protocol::id; -#[cfg(feature = "discovery")] -use robonomics_protocol::network::behaviour::RobonomicsNetworkBehaviour; -use sc_cli::{ChainSpec, RuntimeVersion, SubstrateCli}; -use std::path::Path; +use robonomics_protocol::network::{behaviour::RobonomicsNetworkBehaviour, discovery}; #[cfg(feature = "parachain")] use crate::parachain; @@ -113,29 +114,27 @@ pub async fn run() -> sc_cli::Result<()> { let transport = libp2p::tokio_development_transport(local_key.clone()).expect("Correct transport"); - // let transport = tcp::TokioTcpTransport::new(tcp::GenTcpConfig::default().nodelay(true)) - // .upgrade(upgrade::Version::V1) - // .authenticate( - // noise::NoiseAuthenticated::xx(&local_key) - // .expect("Signing libp2p-noise static DH keypair failed."), - // ) - // .multiplex(mplex::MplexConfig::new()) - // .boxed(); let behaviour = RobonomicsNetworkBehaviour::new(local_key, local_peer_id, 1000, true, true) .expect("Correct behaviour"); + // ??? let mut swarm = SwarmBuilder::new(transport, behaviour, local_peer_id) .executor(Box::new(|fut| { tokio::spawn(fut); })) .build(); - for node in cli.robonomics_bootnodes { - if let Ok(address) = node.parse::() { - if let Err(error) = swarm.dial(address) { - println!("Dial error: {:?}", error); - } - } - } + // discovery::add_peers(&mut swarm, cli.robonomics_bootnodes); + + // use libp2p::Multiaddr; + // if let Some(to_dial) = std::env::args().nth(1) { + // let addr: Multiaddr = to_dial.parse()?; + // swarm.dial(addr.clone())?; + // println!("Dialed {to_dial:?}"); + // + // if let Some(peer) = PeerId::try_from_multiaddr(&addr) { + // swarm.behaviour_mut().pubsub.add_explicit_peer(&peer); + // } + // } swarm .listen_on("/ip4/0.0.0.0/tcp/0".parse().unwrap()) @@ -145,13 +144,14 @@ pub async fn run() -> sc_cli::Result<()> { tokio::select! { event = swarm.select_next_some() => match event { SwarmEvent::NewListenAddr { address, .. } => println!("Listening on {:?}", address), - SwarmEvent::Behaviour(event) => println!("Event: {:?}", event), - event => { - println!("Other event: {:?}", event); + SwarmEvent::Behaviour(event) => + { + println!("Event: {:?}", event); for p in swarm.connected_peers() { - println!("connected peer: {:?}", p); + println!("Connected peer: {p}"); } } + _ => {} } } } From 652486a1dc2557ebcbda6a0c7863ee8454ef0381 Mon Sep 17 00:00:00 2001 From: Denis K Date: Tue, 28 Feb 2023 22:25:04 +0700 Subject: [PATCH 05/23] WIP: discovery --- protocol/src/network/worker.rs | 13 +------------ protocol/src/pubsub.rs | 12 +----------- service/src/command.rs | 30 ++++++++++++++++-------------- 3 files changed, 18 insertions(+), 37 deletions(-) diff --git a/protocol/src/network/worker.rs b/protocol/src/network/worker.rs index 2e9487ee7..9957d9e4b 100644 --- a/protocol/src/network/worker.rs +++ b/protocol/src/network/worker.rs @@ -19,13 +19,11 @@ use futures::{prelude::*, Future}; use libp2p::{ - core::upgrade, identity::Keypair, kad::KademliaEvent, - mplex, noise, request_response::{RequestResponseEvent, RequestResponseMessage}, swarm::{SwarmBuilder, SwarmEvent}, - tcp, PeerId, Swarm, Transport, + PeerId, Swarm, }; use std::{ pin::Pin, @@ -58,14 +56,6 @@ impl NetworkWorker { // Set up an encrypted WebSocket compatible Transport let transport = libp2p::tokio_development_transport(local_key.clone())?; - // let transport = tcp::TokioTcpTransport::new(tcp::GenTcpConfig::default().nodelay(true)) - // .upgrade(upgrade::Version::V1) - // .authenticate( - // noise::NoiseAuthenticated::xx(&local_key) - // .expect("Signing libp2p-noise static DH keypair failed."), - // ) - // .multiplex(mplex::MplexConfig::new()) - // .boxed(); // Build a combined network behaviour let behaviour = RobonomicsNetworkBehaviour::new( @@ -77,7 +67,6 @@ impl NetworkWorker { )?; // Create a Swarm to manage peers and events - // let swarm = Swarm::new(transport, behaviour, peer_id.clone()); let swarm = SwarmBuilder::new(transport, behaviour, peer_id.clone()) .executor(Box::new(|fut| { tokio::spawn(fut); diff --git a/protocol/src/pubsub.rs b/protocol/src/pubsub.rs index a97a62535..bba169a62 100644 --- a/protocol/src/pubsub.rs +++ b/protocol/src/pubsub.rs @@ -23,15 +23,13 @@ use futures::{ }; use libp2p::{ core::transport::ListenerId, - core::upgrade, gossipsub::{ Gossipsub, GossipsubConfigBuilder, GossipsubEvent, GossipsubMessage, MessageAuthenticity, MessageId, Sha256Topic as Topic, TopicHash, }, identity::Keypair, - mplex, noise, swarm::{SwarmBuilder, SwarmEvent}, - tcp, Multiaddr, PeerId, Swarm, Transport, + Multiaddr, PeerId, Swarm, }; use serde::Serialize; use std::{ @@ -199,14 +197,6 @@ impl PubSubWorker { // Set up an encrypted WebSocket compatible Transport over the Mplex and Yamux protocols let transport = libp2p::tokio_development_transport(local_key.clone())?; - // let transport = tcp::TokioTcpTransport::new(tcp::GenTcpConfig::default().nodelay(true)) - // .upgrade(upgrade::Version::V1) - // .authenticate( - // noise::NoiseAuthenticated::xx(&local_key) - // .expect("Signing libp2p-noise static DH keypair failed."), - // ) - // .multiplex(mplex::MplexConfig::new()) - // .boxed(); // Set custom gossipsub let gossipsub_config = GossipsubConfigBuilder::default() diff --git a/service/src/command.rs b/service/src/command.rs index 43b6f8552..915ba681c 100644 --- a/service/src/command.rs +++ b/service/src/command.rs @@ -26,13 +26,15 @@ use std::path::Path; #[cfg(feature = "discovery")] use libp2p::{ - core::upgrade, futures::StreamExt, - gossipsub, mdns, mplex, noise, + gossipsub::GossipsubEvent, swarm::{SwarmBuilder, SwarmEvent}, - tcp, Multiaddr, PeerId, Transport, + PeerId, +}; +use robonomics_protocol::network::{ + behaviour::{OutEvent, RobonomicsNetworkBehaviour}, + discovery, }; -use robonomics_protocol::network::{behaviour::RobonomicsNetworkBehaviour, discovery}; #[cfg(feature = "parachain")] use crate::parachain; @@ -110,13 +112,12 @@ pub async fn run() -> sc_cli::Result<()> { id::load(Path::new(&file_name)).expect("Correct file path") }); let local_peer_id = PeerId::from(local_key.public()); - println!("Local peer id: {:?}", local_peer_id); + println!("Local peer id: {local_peer_id:?}"); let transport = libp2p::tokio_development_transport(local_key.clone()).expect("Correct transport"); let behaviour = RobonomicsNetworkBehaviour::new(local_key, local_peer_id, 1000, true, true) .expect("Correct behaviour"); - // ??? let mut swarm = SwarmBuilder::new(transport, behaviour, local_peer_id) .executor(Box::new(|fut| { tokio::spawn(fut); @@ -144,14 +145,15 @@ pub async fn run() -> sc_cli::Result<()> { tokio::select! { event = swarm.select_next_some() => match event { SwarmEvent::NewListenAddr { address, .. } => println!("Listening on {:?}", address), - SwarmEvent::Behaviour(event) => - { - println!("Event: {:?}", event); - for p in swarm.connected_peers() { - println!("Connected peer: {p}"); - } - } - _ => {} + SwarmEvent::Behaviour(OutEvent::Pubsub(GossipsubEvent::Message { + propagation_source: peer_id, + message_id: id, + message, + })) => println!( + "Got message: '{}' with id: {id} from peer: {peer_id}", + String::from_utf8_lossy(&message.data), + ), + event => println!("event: {event:?}"), } } } From 053a635d10cac20c8b8a54c954137d65bcdeaebd Mon Sep 17 00:00:00 2001 From: Denis K Date: Tue, 28 Feb 2023 22:43:20 +0700 Subject: [PATCH 06/23] WIP: discovery --- service/src/command.rs | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/service/src/command.rs b/service/src/command.rs index 915ba681c..567279b65 100644 --- a/service/src/command.rs +++ b/service/src/command.rs @@ -116,26 +116,22 @@ pub async fn run() -> sc_cli::Result<()> { let transport = libp2p::tokio_development_transport(local_key.clone()).expect("Correct transport"); - let behaviour = RobonomicsNetworkBehaviour::new(local_key, local_peer_id, 1000, true, true) + + let mut behaviour = RobonomicsNetworkBehaviour::new(local_key, local_peer_id, 1000, true, true) .expect("Correct behaviour"); + + behaviour + .pubsub + .subscribe(&libp2p::gossipsub::IdentTopic::new("ROS")) + .expect("ROS topic"); + let mut swarm = SwarmBuilder::new(transport, behaviour, local_peer_id) .executor(Box::new(|fut| { tokio::spawn(fut); })) .build(); - // discovery::add_peers(&mut swarm, cli.robonomics_bootnodes); - - // use libp2p::Multiaddr; - // if let Some(to_dial) = std::env::args().nth(1) { - // let addr: Multiaddr = to_dial.parse()?; - // swarm.dial(addr.clone())?; - // println!("Dialed {to_dial:?}"); - // - // if let Some(peer) = PeerId::try_from_multiaddr(&addr) { - // swarm.behaviour_mut().pubsub.add_explicit_peer(&peer); - // } - // } + discovery::add_peers(&mut swarm, cli.robonomics_bootnodes); swarm .listen_on("/ip4/0.0.0.0/tcp/0".parse().unwrap()) From 1bce64f6fd1ade7e1fdba585b3bf44d1809e0805 Mon Sep 17 00:00:00 2001 From: Denis K Date: Thu, 2 Mar 2023 17:06:52 +0700 Subject: [PATCH 07/23] ADD: pubsub port, ROS topic --- protocol/examples/ros/src/main.rs | 13 +++++++++++-- protocol/src/network/worker.rs | 14 +++++++++++--- protocol/src/pubsub.rs | 3 --- service/src/command.rs | 9 +++++---- service/src/service.rs | 1 + 5 files changed, 28 insertions(+), 12 deletions(-) diff --git a/protocol/examples/ros/src/main.rs b/protocol/examples/ros/src/main.rs index ccf7ba946..f52617e48 100644 --- a/protocol/examples/ros/src/main.rs +++ b/protocol/examples/ros/src/main.rs @@ -59,12 +59,21 @@ async fn main() -> Result<(), Box> { loop { tokio::select! { line = stdin.next_line() => { - if let Err(e) = swarm + match swarm .behaviour_mut() .pubsub .publish(topic.clone(), line.expect("Stdin not to close").expect("").as_bytes()) { - println!("Publish error: {e:?}"); + Ok(mid) => + println!("Message : {mid:?}"), + Err(e) => + println!("Publish error: {e:?}"), } + // if let Err(e) = swarm + // .behaviour_mut() + // .pubsub + // .publish(topic.clone(), line.expect("Stdin not to close").expect("").as_bytes()) { + // println!("Publish error: {e:?}"); + // } }, event = swarm.select_next_some() => match event { SwarmEvent::Behaviour(OutEvent::Pubsub(GossipsubEvent::Message { diff --git a/protocol/src/network/worker.rs b/protocol/src/network/worker.rs index 9957d9e4b..c5091560b 100644 --- a/protocol/src/network/worker.rs +++ b/protocol/src/network/worker.rs @@ -23,7 +23,7 @@ use libp2p::{ kad::KademliaEvent, request_response::{RequestResponseEvent, RequestResponseMessage}, swarm::{SwarmBuilder, SwarmEvent}, - PeerId, Swarm, + Multiaddr, PeerId, Swarm, }; use std::{ pin::Pin, @@ -58,7 +58,7 @@ impl NetworkWorker { let transport = libp2p::tokio_development_transport(local_key.clone())?; // Build a combined network behaviour - let behaviour = RobonomicsNetworkBehaviour::new( + let mut behaviour = RobonomicsNetworkBehaviour::new( local_key, peer_id, heartbeat_interval, @@ -66,13 +66,21 @@ impl NetworkWorker { disable_kad, )?; + // ??? + use libp2p::gossipsub::IdentTopic; + behaviour.pubsub.subscribe(&IdentTopic::new("ROS"))?; + // Create a Swarm to manage peers and events - let swarm = SwarmBuilder::new(transport, behaviour, peer_id.clone()) + let mut swarm = SwarmBuilder::new(transport, behaviour, peer_id.clone()) .executor(Box::new(|fut| { tokio::spawn(fut); })) .build(); + // Listen RNB pubsub port + let listen_address: Multiaddr = "/ip4/127.0.0.1/tcp/30400".parse().unwrap(); + Swarm::listen_on(&mut swarm, listen_address)?; + Ok(Self { swarm, pubsub }) } } diff --git a/protocol/src/pubsub.rs b/protocol/src/pubsub.rs index bba169a62..f4924187d 100644 --- a/protocol/src/pubsub.rs +++ b/protocol/src/pubsub.rs @@ -299,9 +299,6 @@ impl Future for PubSubWorker { loop { match self.swarm.poll_next_unpin(cx) { Poll::Ready(Some(swarm_event)) => match swarm_event { - SwarmEvent::NewListenAddr { address, .. } => { - println!("23Listening on {:?}", address) - } SwarmEvent::Behaviour(event) => match event { GossipsubEvent::Message { propagation_source: peer_id, diff --git a/service/src/command.rs b/service/src/command.rs index 567279b65..5f3c7cabe 100644 --- a/service/src/command.rs +++ b/service/src/command.rs @@ -31,6 +31,7 @@ use libp2p::{ swarm::{SwarmBuilder, SwarmEvent}, PeerId, }; +#[cfg(feature = "discovery")] use robonomics_protocol::network::{ behaviour::{OutEvent, RobonomicsNetworkBehaviour}, discovery, @@ -120,10 +121,10 @@ pub async fn run() -> sc_cli::Result<()> { let mut behaviour = RobonomicsNetworkBehaviour::new(local_key, local_peer_id, 1000, true, true) .expect("Correct behaviour"); - behaviour - .pubsub - .subscribe(&libp2p::gossipsub::IdentTopic::new("ROS")) - .expect("ROS topic"); + // behaviour + // .pubsub + // .subscribe(&libp2p::gossipsub::IdentTopic::new("ROS")) + // .expect("ROS topic"); let mut swarm = SwarmBuilder::new(transport, behaviour, local_peer_id) .executor(Box::new(|fut| { diff --git a/service/src/service.rs b/service/src/service.rs index 04009477c..d3512be92 100644 --- a/service/src/service.rs +++ b/service/src/service.rs @@ -180,6 +180,7 @@ where }, )?; + // TODO: single pubsub ??? let (pubsub, pubsub_worker) = Pubsub::new(local_key.clone(), heartbeat_interval).expect("New robonomics pubsub"); From 9022385a7110e14e2b2085b4d656ae037595d8e2 Mon Sep 17 00:00:00 2001 From: Denis K Date: Thu, 2 Mar 2023 18:53:16 +0700 Subject: [PATCH 08/23] WIP: --- service/src/command.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/service/src/command.rs b/service/src/command.rs index 5f3c7cabe..9ca7fa390 100644 --- a/service/src/command.rs +++ b/service/src/command.rs @@ -142,6 +142,11 @@ pub async fn run() -> sc_cli::Result<()> { tokio::select! { event = swarm.select_next_some() => match event { SwarmEvent::NewListenAddr { address, .. } => println!("Listening on {:?}", address), + SwarmEvent::ConnectionEstablished { peer_id, .. } => { + // ??? + println!("Adding peer to swarm: {peer_id}"); + swarm.behaviour_mut().pubsub.add_explicit_peer(&peer_id); + }, SwarmEvent::Behaviour(OutEvent::Pubsub(GossipsubEvent::Message { propagation_source: peer_id, message_id: id, From d3d2616adc715d7fc23bb2906034e10eb233866b Mon Sep 17 00:00:00 2001 From: Denis K Date: Tue, 7 Mar 2023 21:52:43 +0700 Subject: [PATCH 09/23] WIP: network --- protocol/src/network.rs | 11 +++-------- protocol/src/network/worker.rs | 14 ++++++-------- service/src/command.rs | 5 ----- service/src/service.rs | 19 +++++++++++-------- 4 files changed, 20 insertions(+), 29 deletions(-) diff --git a/protocol/src/network.rs b/protocol/src/network.rs index f54841c6f..a5356c77c 100644 --- a/protocol/src/network.rs +++ b/protocol/src/network.rs @@ -44,16 +44,11 @@ impl RobonomicsNetwork { disable_mdns: bool, disable_kad: bool, ) -> Result<(Arc, impl Future)> { - let mut network_worker = NetworkWorker::new( - local_key, - heartbeat_interval, - pubsub.clone(), - disable_mdns, - disable_kad, - )?; + let mut network_worker = + NetworkWorker::new(local_key, heartbeat_interval, disable_mdns, disable_kad)?; // Reach out to another nodes if specified - discovery::add_peers(&mut network_worker.swarm, bootnodes); + // discovery::add_peers(&mut network_worker.swarm, bootnodes); Ok((Arc::new(Self { pubsub }), network_worker)) } diff --git a/protocol/src/network/worker.rs b/protocol/src/network/worker.rs index c5091560b..9aaf070ed 100644 --- a/protocol/src/network/worker.rs +++ b/protocol/src/network/worker.rs @@ -40,7 +40,6 @@ use crate::{ pub struct NetworkWorker { pub swarm: Swarm, - pub pubsub: Arc, } impl NetworkWorker { @@ -48,7 +47,6 @@ impl NetworkWorker { pub fn new( local_key: Keypair, heartbeat_interval: u64, - pubsub: Arc, disable_mdns: bool, disable_kad: bool, ) -> Result { @@ -67,8 +65,8 @@ impl NetworkWorker { )?; // ??? - use libp2p::gossipsub::IdentTopic; - behaviour.pubsub.subscribe(&IdentTopic::new("ROS"))?; + // use libp2p::gossipsub::IdentTopic; + // behaviour.pubsub.subscribe(&IdentTopic::new("ROS"))?; // Create a Swarm to manage peers and events let mut swarm = SwarmBuilder::new(transport, behaviour, peer_id.clone()) @@ -81,7 +79,7 @@ impl NetworkWorker { let listen_address: Multiaddr = "/ip4/127.0.0.1/tcp/30400".parse().unwrap(); Swarm::listen_on(&mut swarm, listen_address)?; - Ok(Self { swarm, pubsub }) + Ok(Self { swarm }) } } @@ -103,9 +101,9 @@ impl Future for NetworkWorker { log::debug!("Bootstrap error: {:?}", e); }; } - for address in addresses.iter() { - let _ = self.pubsub.connect(address.clone()); - } + // for address in addresses.iter() { + // let _ = self.pubsub.connect(address.clone()); + // } } SwarmEvent::Behaviour(OutEvent::RequestResponse( RequestResponseEvent::Message { diff --git a/service/src/command.rs b/service/src/command.rs index 9ca7fa390..5f3c7cabe 100644 --- a/service/src/command.rs +++ b/service/src/command.rs @@ -142,11 +142,6 @@ pub async fn run() -> sc_cli::Result<()> { tokio::select! { event = swarm.select_next_some() => match event { SwarmEvent::NewListenAddr { address, .. } => println!("Listening on {:?}", address), - SwarmEvent::ConnectionEstablished { peer_id, .. } => { - // ??? - println!("Adding peer to swarm: {peer_id}"); - swarm.behaviour_mut().pubsub.add_explicit_peer(&peer_id); - }, SwarmEvent::Behaviour(OutEvent::Pubsub(GossipsubEvent::Message { propagation_source: peer_id, message_id: id, diff --git a/service/src/service.rs b/service/src/service.rs index d3512be92..fcc28a4c1 100644 --- a/service/src/service.rs +++ b/service/src/service.rs @@ -180,13 +180,14 @@ where }, )?; - // TODO: single pubsub ??? + //------------------------------------------------ + let (pubsub, pubsub_worker) = Pubsub::new(local_key.clone(), heartbeat_interval).expect("New robonomics pubsub"); - task_manager - .spawn_handle() - .spawn("pubsub_service", None, pubsub_worker); + // task_manager + // .spawn_handle() + // .spawn("pubsub_service", None, pubsub_worker); let (robonomics_network, network_worker) = RobonomicsNetwork::new( local_key, @@ -198,9 +199,11 @@ where ) .expect("New robonomics network layer"); - task_manager - .spawn_handle() - .spawn("network_service", None, network_worker); + // task_manager + // .spawn_handle() + // .spawn("network_service", None, network_worker); + + //------------------------------------------------ let rpc_extensions_builder = { let client = client.clone(); @@ -211,7 +214,7 @@ where client: client.clone(), pool: pool.clone(), deny_unsafe, - network: robonomics_network.clone(), + network: robonomics_network.to_owned(), }; robonomics_rpc::create_full(deps).map_err(Into::into) From 8747a414e2f4905dbf677347dbcfa829963f2d5c Mon Sep 17 00:00:00 2001 From: Denis K Date: Tue, 7 Mar 2023 23:18:02 +0700 Subject: [PATCH 10/23] WIP: new network --- protocol/src/network.rs | 167 ++++++++++++++++++++++++++++++- protocol/src/network/worker.rs | 8 +- service/src/parachain/service.rs | 47 +++++---- service/src/service.rs | 32 ++++-- 4 files changed, 215 insertions(+), 39 deletions(-) diff --git a/protocol/src/network.rs b/protocol/src/network.rs index a5356c77c..87fd92ea9 100644 --- a/protocol/src/network.rs +++ b/protocol/src/network.rs @@ -18,19 +18,176 @@ //! Robonomics network layer. use futures::prelude::*; -use libp2p::{identity::Keypair, Multiaddr, PeerId}; -use std::sync::Arc; +use libp2p::{ + identity::Keypair, + kad::KademliaEvent, + request_response::{RequestResponseEvent, RequestResponseMessage}, + swarm::{SwarmBuilder, SwarmEvent}, + Multiaddr, PeerId, Swarm, +}; +use std::{ + pin::Pin, + sync::Arc, + task::{Context, Poll}, +}; use crate::{ error::{FutureResult, Result}, - network::worker::NetworkWorker, + network::{ + behaviour::{OutEvent, RobonomicsNetworkBehaviour}, + worker::NetworkWorker, + }, pubsub::{Inbox, PubSub, Pubsub}, + reqres::Response, }; pub mod behaviour; pub mod discovery; pub mod worker; +pub struct Network { + swarm: Swarm, +} + +impl Network { + pub fn new( + local_key: Keypair, + heartbeat_interval: u64, + bootnodes: Vec, + disable_mdns: bool, + disable_kad: bool, + ) -> Result { + let peer_id = PeerId::from(local_key.public()); + let transport = libp2p::tokio_development_transport(local_key.clone())?; + let behaviour = RobonomicsNetworkBehaviour::new( + local_key, + peer_id, + heartbeat_interval, + disable_mdns, + disable_kad, + )?; + let mut swarm = SwarmBuilder::new(transport, behaviour, peer_id) + .executor(Box::new(|fut| { + tokio::spawn(fut); + })) + .build(); + + Swarm::listen_on(&mut swarm, "/ip4/127.0.0.1/tcp/30400".parse().unwrap())?; + discovery::add_peers(&mut swarm, bootnodes); + + Ok(Self { swarm }) + } +} + +impl Future for Network { + type Output = (); + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll { + loop { + match self.swarm.poll_next_unpin(cx) { + Poll::Ready(Some(swarm_event)) => match swarm_event { + SwarmEvent::Behaviour(OutEvent::Kademlia(KademliaEvent::RoutingUpdated { + peer, + // addresses, + .. + })) => { + log::info!("Received kademlia peer: {:?}", peer); + // if let Some(kademlia) = self.swarm.behaviour_mut().kademlia.as_mut() { + // if let Err(e) = kademlia.bootstrap() { + // log::debug!("Bootstrap error: {:?}", e); + // }; + // } + // for address in addresses.iter() { + // let _ = self.pubsub.connect(address.clone()); + // } + } + SwarmEvent::Behaviour(OutEvent::RequestResponse( + RequestResponseEvent::Message { + peer, + message: + RequestResponseMessage::Response { + request_id, + response, + }, + }, + )) => match response { + Response::Pong => { + log::debug!( + " peer2 Resp{} {:?} from {:?}", + request_id, + &response, + peer + ); + break; + } + Response::Data(data) => { + let decoded: Vec = bincode::deserialize(&data.to_vec()).unwrap(); + log::debug!( + " peer2 Resp: Data '{}' from {:?}", + String::from_utf8_lossy(&decoded[..]), + peer // ??? + ); + log::debug!("{}", String::from_utf8_lossy(&decoded[..])); + break; + } + }, + _ => {} + }, + Poll::Ready(None) | Poll::Pending => { + break; + } + } + } + + Poll::Pending + } +} + +// impl PubSub for Network { +// fn peer_id(&self) -> PeerId { +// self.swarm.behaviour_mut().pubsub.peer_id() +// } +// +// fn listen(&self, address: Multiaddr) -> FutureResult { +// self.swarm.behaviour_mut().pubsub.listen(address) +// } +// +// fn listeners(&self) -> FutureResult> { +// self.swarm.behaviour_mut().pubsub.listeners() +// } +// +// fn connect(&self, address: Multiaddr) -> FutureResult { +// self.swarm.behaviour_mut().pubsub.connect(address) +// } +// +// fn subscribe(&self, topic_name: &T) -> Inbox { +// self.swarm +// .behaviour_mut() +// .pubsub +// .subscribe(&topic_name.to_string()) +// } +// +// fn unsubscribe(&self, topic_name: &T) -> FutureResult { +// self.swarm +// .behaviour_mut() +// .pubsub +// .unsubscribe(&topic_name.to_string()) +// } +// +// fn publish>>( +// &self, +// topic_name: &T, +// message: M, +// ) -> FutureResult { +// self.swarm +// .behaviour_mut() +// .pubsub +// .publish(&topic_name.to_string(), message.into()) +// } +// } + +//------------------------------------------------ + pub struct RobonomicsNetwork { pub pubsub: Arc, } @@ -40,11 +197,11 @@ impl RobonomicsNetwork { local_key: Keypair, pubsub: Arc, heartbeat_interval: u64, - bootnodes: Vec, + _bootnodes: Vec, disable_mdns: bool, disable_kad: bool, ) -> Result<(Arc, impl Future)> { - let mut network_worker = + let network_worker = NetworkWorker::new(local_key, heartbeat_interval, disable_mdns, disable_kad)?; // Reach out to another nodes if specified diff --git a/protocol/src/network/worker.rs b/protocol/src/network/worker.rs index 9aaf070ed..7054d4720 100644 --- a/protocol/src/network/worker.rs +++ b/protocol/src/network/worker.rs @@ -27,14 +27,14 @@ use libp2p::{ }; use std::{ pin::Pin, - sync::Arc, + // sync::Arc, task::{Context, Poll}, }; use crate::{ error::Result, network::behaviour::{OutEvent, RobonomicsNetworkBehaviour}, - pubsub::{PubSub, Pubsub}, + // pubsub::{PubSub, Pubsub}, reqres::Response, }; @@ -56,7 +56,7 @@ impl NetworkWorker { let transport = libp2p::tokio_development_transport(local_key.clone())?; // Build a combined network behaviour - let mut behaviour = RobonomicsNetworkBehaviour::new( + let behaviour = RobonomicsNetworkBehaviour::new( local_key, peer_id, heartbeat_interval, @@ -92,7 +92,7 @@ impl Future for NetworkWorker { Poll::Ready(Some(swarm_event)) => match swarm_event { SwarmEvent::Behaviour(OutEvent::Kademlia(KademliaEvent::RoutingUpdated { peer, - addresses, + // addresses, .. })) => { log::info!("Received kademlia peer: {:?}", peer); diff --git a/service/src/parachain/service.rs b/service/src/parachain/service.rs index 2ac03388a..906d8a4cb 100644 --- a/service/src/parachain/service.rs +++ b/service/src/parachain/service.rs @@ -202,9 +202,9 @@ pub async fn start_node_impl( build_consensus: BIC, local_key: Keypair, heartbeat_interval: u64, - bootnodes: Vec, - disable_mdns: bool, - disable_kad: bool, + _bootnodes: Vec, + _disable_mdns: bool, + _disable_kad: bool, ) -> sc_service::error::Result where Executor: sc_executor::NativeExecutionDispatch + 'static, @@ -301,26 +301,26 @@ where let rpc_client = client.clone(); let rpc_pool = transaction_pool.clone(); - let (pubsub, pubsub_worker) = + let (pubsub, _pubsub_worker) = Pubsub::new(local_key.clone(), heartbeat_interval).expect("New robonomics pubsub"); - task_manager - .spawn_handle() - .spawn("pubsub_service", None, pubsub_worker); - - let (robonomics_network, network_worker) = RobonomicsNetwork::new( - local_key, - pubsub.clone(), - heartbeat_interval, - bootnodes, - disable_mdns, - disable_kad, - ) - .expect("New robonomics network layer"); - - task_manager - .spawn_handle() - .spawn("network_service", None, network_worker); + // task_manager + // .spawn_handle() + // .spawn("pubsub_service", None, pubsub_worker); + // + // let (robonomics_network, network_worker) = RobonomicsNetwork::new( + // local_key, + // pubsub.clone(), + // heartbeat_interval, + // bootnodes, + // disable_mdns, + // disable_kad, + // ) + // .expect("New robonomics network layer"); + // + // task_manager + // .spawn_handle() + // .spawn("network_service", None, network_worker); sc_service::spawn_tasks(sc_service::SpawnTasksParams { rpc_builder: Box::new(move |deny_unsafe, _| { @@ -328,7 +328,10 @@ where client: rpc_client.clone(), pool: rpc_pool.clone(), deny_unsafe, - network: robonomics_network.clone(), + // network: robonomics_network.clone(), + network: Arc::new(RobonomicsNetwork { + pubsub: pubsub.clone(), + }), }; robonomics_rpc::create_full(deps).map_err(Into::into) diff --git a/service/src/service.rs b/service/src/service.rs index fcc28a4c1..8be43eb11 100644 --- a/service/src/service.rs +++ b/service/src/service.rs @@ -19,7 +19,7 @@ use libp2p::core::identity::Keypair; use robonomics_primitives::{AccountId, Balance, Block, Index}; -use robonomics_protocol::{network::RobonomicsNetwork, pubsub::Pubsub}; +use robonomics_protocol::{network::Network, network::RobonomicsNetwork, pubsub::Pubsub}; use sc_client_api::{BlockBackend, ExecutorProvider}; use sc_consensus_aura::{ImportQueueParams, SlotProportion, StartAuraParams}; pub use sc_executor::NativeElseWasmExecutor; @@ -182,26 +182,39 @@ where //------------------------------------------------ - let (pubsub, pubsub_worker) = + let (pubsub, _pubsub_worker) = Pubsub::new(local_key.clone(), heartbeat_interval).expect("New robonomics pubsub"); // task_manager // .spawn_handle() // .spawn("pubsub_service", None, pubsub_worker); - let (robonomics_network, network_worker) = RobonomicsNetwork::new( + // let (robonomics_network, network_worker) = RobonomicsNetwork::new( + // local_key, + // pubsub.clone(), + // heartbeat_interval, + // bootnodes, + // disable_mdns, + // disable_kad, + // ) + // .expect("New robonomics network layer"); + + // task_manager + // .spawn_handle() + // .spawn("network_service", None, network_worker); + + let _network = Network::new( local_key, - pubsub.clone(), heartbeat_interval, bootnodes, disable_mdns, disable_kad, - ) - .expect("New robonomics network layer"); + ); + // ???? // task_manager // .spawn_handle() - // .spawn("network_service", None, network_worker); + // .spawn("network_service", None, network); //------------------------------------------------ @@ -214,7 +227,10 @@ where client: client.clone(), pool: pool.clone(), deny_unsafe, - network: robonomics_network.to_owned(), + // network: robonomics_network.to_owned(), + network: Arc::new(RobonomicsNetwork { + pubsub: pubsub.clone(), + }), }; robonomics_rpc::create_full(deps).map_err(Into::into) From ba430baf1ae5723f13bad2fba670bee1b0b9103f Mon Sep 17 00:00:00 2001 From: Denis K Date: Wed, 8 Mar 2023 12:41:14 +0700 Subject: [PATCH 11/23] ADD: new network --- protocol/src/network.rs | 15 ++++++++++----- service/src/command.rs | 8 ++++---- service/src/service.rs | 14 +++++++------- 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/protocol/src/network.rs b/protocol/src/network.rs index 87fd92ea9..a8bf634b7 100644 --- a/protocol/src/network.rs +++ b/protocol/src/network.rs @@ -45,27 +45,32 @@ pub mod behaviour; pub mod discovery; pub mod worker; -pub struct Network { +pub struct RNetwork { swarm: Swarm, } -impl Network { +impl RNetwork { pub fn new( local_key: Keypair, heartbeat_interval: u64, bootnodes: Vec, disable_mdns: bool, disable_kad: bool, - ) -> Result { + ) -> Result> { + // ) -> Result<(Self, impl Future)> { let peer_id = PeerId::from(local_key.public()); let transport = libp2p::tokio_development_transport(local_key.clone())?; - let behaviour = RobonomicsNetworkBehaviour::new( + let mut behaviour = RobonomicsNetworkBehaviour::new( local_key, peer_id, heartbeat_interval, disable_mdns, disable_kad, )?; + + let topic = libp2p::gossipsub::IdentTopic::new("ROS"); + behaviour.pubsub.subscribe(&topic)?; + let mut swarm = SwarmBuilder::new(transport, behaviour, peer_id) .executor(Box::new(|fut| { tokio::spawn(fut); @@ -79,7 +84,7 @@ impl Network { } } -impl Future for Network { +impl Future for RNetwork { type Output = (); fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll { diff --git a/service/src/command.rs b/service/src/command.rs index 5f3c7cabe..1c9c5b684 100644 --- a/service/src/command.rs +++ b/service/src/command.rs @@ -121,10 +121,10 @@ pub async fn run() -> sc_cli::Result<()> { let mut behaviour = RobonomicsNetworkBehaviour::new(local_key, local_peer_id, 1000, true, true) .expect("Correct behaviour"); - // behaviour - // .pubsub - // .subscribe(&libp2p::gossipsub::IdentTopic::new("ROS")) - // .expect("ROS topic"); + behaviour + .pubsub + .subscribe(&libp2p::gossipsub::IdentTopic::new("ROS")) + .expect("ROS topic"); let mut swarm = SwarmBuilder::new(transport, behaviour, local_peer_id) .executor(Box::new(|fut| { diff --git a/service/src/service.rs b/service/src/service.rs index 8be43eb11..ddaf16235 100644 --- a/service/src/service.rs +++ b/service/src/service.rs @@ -19,7 +19,7 @@ use libp2p::core::identity::Keypair; use robonomics_primitives::{AccountId, Balance, Block, Index}; -use robonomics_protocol::{network::Network, network::RobonomicsNetwork, pubsub::Pubsub}; +use robonomics_protocol::{network::RNetwork, network::RobonomicsNetwork, pubsub::Pubsub}; use sc_client_api::{BlockBackend, ExecutorProvider}; use sc_consensus_aura::{ImportQueueParams, SlotProportion, StartAuraParams}; pub use sc_executor::NativeElseWasmExecutor; @@ -203,18 +203,18 @@ where // .spawn_handle() // .spawn("network_service", None, network_worker); - let _network = Network::new( + let network_worker = RNetwork::new( local_key, heartbeat_interval, bootnodes, disable_mdns, disable_kad, - ); + ) + .expect("New robonomics network"); - // ???? - // task_manager - // .spawn_handle() - // .spawn("network_service", None, network); + task_manager + .spawn_handle() + .spawn("network_service", None, network_worker); //------------------------------------------------ From f98e9c8d0ddb9696b1b2bb3904049faf8346e71e Mon Sep 17 00:00:00 2001 From: Denis K Date: Thu, 9 Mar 2023 13:28:32 +0700 Subject: [PATCH 12/23] WIP: --- Cargo.lock | 22 +---- protocol/src/network.rs | 174 +++++++++++++++++++++++++++++----------- protocol/src/pubsub.rs | 4 + service/Cargo.toml | 17 +--- service/src/service.rs | 20 ++++- 5 files changed, 150 insertions(+), 87 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e89d2ea44..9c42ba0e1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4140,7 +4140,7 @@ dependencies = [ "libp2p-metrics 0.7.0", "libp2p-mplex 0.34.0", "libp2p-noise 0.37.0", - "libp2p-ping 0.37.0", + "libp2p-ping", "libp2p-plaintext", "libp2p-pnet", "libp2p-relay", @@ -4180,7 +4180,6 @@ dependencies = [ "libp2p-metrics 0.10.0", "libp2p-mplex 0.37.0", "libp2p-noise 0.40.0", - "libp2p-ping 0.40.1", "libp2p-request-response 0.22.1", "libp2p-swarm 0.40.1", "libp2p-swarm-derive 0.30.1", @@ -4523,7 +4522,7 @@ dependencies = [ "libp2p-gossipsub 0.39.0", "libp2p-identify", "libp2p-kad 0.38.0", - "libp2p-ping 0.37.0", + "libp2p-ping", "libp2p-relay", "libp2p-swarm 0.37.0", "prometheus-client 0.16.0", @@ -4538,7 +4537,6 @@ dependencies = [ "libp2p-core 0.37.0", "libp2p-gossipsub 0.42.1", "libp2p-kad 0.41.0", - "libp2p-ping 0.40.1", "libp2p-swarm 0.40.1", "prometheus-client 0.18.1", ] @@ -4639,22 +4637,6 @@ dependencies = [ "void", ] -[[package]] -name = "libp2p-ping" -version = "0.40.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7228b9318d34689521349a86eb39a3c3a802c9efc99a0568062ffb80913e3f91" -dependencies = [ - "futures", - "futures-timer", - "instant", - "libp2p-core 0.37.0", - "libp2p-swarm 0.40.1", - "log", - "rand 0.8.5", - "void", -] - [[package]] name = "libp2p-plaintext" version = "0.34.0" diff --git a/protocol/src/network.rs b/protocol/src/network.rs index a8bf634b7..0eb7c8aa2 100644 --- a/protocol/src/network.rs +++ b/protocol/src/network.rs @@ -17,8 +17,12 @@ /////////////////////////////////////////////////////////////////////////////// //! Robonomics network layer. -use futures::prelude::*; +use futures::{ + channel::{mpsc, oneshot}, + prelude::*, +}; use libp2p::{ + gossipsub::{GossipsubEvent, TopicHash}, identity::Keypair, kad::KademliaEvent, request_response::{RequestResponseEvent, RequestResponseMessage}, @@ -26,6 +30,7 @@ use libp2p::{ Multiaddr, PeerId, Swarm, }; use std::{ + collections::hash_map::HashMap, pin::Pin, sync::Arc, task::{Context, Poll}, @@ -37,7 +42,7 @@ use crate::{ behaviour::{OutEvent, RobonomicsNetworkBehaviour}, worker::NetworkWorker, }, - pubsub::{Inbox, PubSub, Pubsub}, + pubsub::{Inbox, Message, PubSub, Pubsub, ToWorkerMsg}, reqres::Response, }; @@ -47,6 +52,9 @@ pub mod worker; pub struct RNetwork { swarm: Swarm, + inbox: HashMap>, + from_service: mpsc::UnboundedReceiver, + pub service: Arc, } impl RNetwork { @@ -56,8 +64,7 @@ impl RNetwork { bootnodes: Vec, disable_mdns: bool, disable_kad: bool, - ) -> Result> { - // ) -> Result<(Self, impl Future)> { + ) -> Result { let peer_id = PeerId::from(local_key.public()); let transport = libp2p::tokio_development_transport(local_key.clone())?; let mut behaviour = RobonomicsNetworkBehaviour::new( @@ -68,6 +75,7 @@ impl RNetwork { disable_kad, )?; + // XXX let topic = libp2p::gossipsub::IdentTopic::new("ROS"); behaviour.pubsub.subscribe(&topic)?; @@ -78,9 +86,22 @@ impl RNetwork { .build(); Swarm::listen_on(&mut swarm, "/ip4/127.0.0.1/tcp/30400".parse().unwrap())?; + // Swarm::listen_on(&mut swarm, "/ip4/127.0.0.1/tcp/30401".parse().unwrap())?; discovery::add_peers(&mut swarm, bootnodes); - Ok(Self { swarm }) + // Create worker communication channel + let (to_worker, from_service) = mpsc::unbounded::(); + + // Create PubSub service + let service = Arc::new(Pubsub::create(to_worker, peer_id)); + // let service = Arc::new(Pubsub { to_worker, peer_id }); + + Ok(Self { + swarm, + inbox: HashMap::new(), + from_service, + service, + }) } } @@ -91,6 +112,31 @@ impl Future for RNetwork { loop { match self.swarm.poll_next_unpin(cx) { Poll::Ready(Some(swarm_event)) => match swarm_event { + SwarmEvent::Behaviour(OutEvent::Pubsub(GossipsubEvent::Message { + propagation_source: peer_id, + message_id: id, + message, + })) => { + log::debug!( + target: "robonomics-pubsub", + "Received message with id: {} from peer: {}", id, peer_id.to_base58() + ); + + // Dispatch handlers by topic name hash + if let Some(inbox) = self.inbox.get_mut(&message.topic) { + if let Some(sender) = &message.source { + let _ = inbox.unbounded_send(Message { + from: sender.clone().to_bytes(), + data: message.data.clone(), + }); + } + } else { + log::warn!( + target: "robonomics-pubsub", + "Topic {} have no associated inbox!", message.topic + ); + } + } SwarmEvent::Behaviour(OutEvent::Kademlia(KademliaEvent::RoutingUpdated { peer, // addresses, @@ -144,52 +190,86 @@ impl Future for RNetwork { } } + loop { + match self.from_service.poll_next_unpin(cx) { + Poll::Ready(Some(request)) => match request { + ToWorkerMsg::Listen(addr, result) => { + let _ = result.send(self.listen(addr).is_ok()); + } + ToWorkerMsg::Listeners(result) => { + let _ = result.send(self.listeners()); + } + ToWorkerMsg::Connect(addr, result) => { + let _ = result.send(self.connect(addr).is_ok()); + } + ToWorkerMsg::Subscribe(topic_name, inbox) => { + let _ = self.subscribe(topic_name, inbox); + } + ToWorkerMsg::Unsubscribe(topic_name, result) => { + let _ = result.send(self.unsubscribe(topic_name).is_ok()); + } + ToWorkerMsg::Publish(topic_name, message, result) => { + let _ = result.send(self.publish(topic_name, message).is_ok()); + } + }, + Poll::Ready(None) | Poll::Pending => break, + } + } + Poll::Pending } } -// impl PubSub for Network { -// fn peer_id(&self) -> PeerId { -// self.swarm.behaviour_mut().pubsub.peer_id() -// } -// -// fn listen(&self, address: Multiaddr) -> FutureResult { -// self.swarm.behaviour_mut().pubsub.listen(address) -// } -// -// fn listeners(&self) -> FutureResult> { -// self.swarm.behaviour_mut().pubsub.listeners() -// } -// -// fn connect(&self, address: Multiaddr) -> FutureResult { -// self.swarm.behaviour_mut().pubsub.connect(address) -// } -// -// fn subscribe(&self, topic_name: &T) -> Inbox { -// self.swarm -// .behaviour_mut() -// .pubsub -// .subscribe(&topic_name.to_string()) -// } -// -// fn unsubscribe(&self, topic_name: &T) -> FutureResult { -// self.swarm -// .behaviour_mut() -// .pubsub -// .unsubscribe(&topic_name.to_string()) -// } -// -// fn publish>>( -// &self, -// topic_name: &T, -// message: M, -// ) -> FutureResult { -// self.swarm -// .behaviour_mut() -// .pubsub -// .publish(&topic_name.to_string(), message.into()) -// } -// } +impl PubSub for RNetwork { + fn peer_id(&self) -> PeerId { + // self.swarm.behaviour_mut().pubsub.peer_id() + self.service.peer_id() + } + + fn listen(&self, address: Multiaddr) -> FutureResult { + // self.swarm.behaviour_mut().pubsub.listen(address) + self.service.listen(address) + } + + fn listeners(&self) -> FutureResult> { + // self.swarm.behaviour_mut().pubsub.listeners() + self.service.listeners() + } + + fn connect(&self, address: Multiaddr) -> FutureResult { + // self.swarm.behaviour_mut().pubsub.connect(address) + self.service.connect(address) + } + + fn subscribe(&self, topic_name: &T) -> Inbox { + // self.swarm + // .behaviour_mut() + // .pubsub + // .subscribe(&topic_name.to_string()) + self.service.subscribe(&topic_name.to_string()) + } + + fn unsubscribe(&self, topic_name: &T) -> FutureResult { + // self.swarm + // .behaviour_mut() + // .pubsub + // .unsubscribe(&topic_name.to_string()) + self.service.unsubscribe(&topic_name.to_string()) + } + + fn publish>>( + &self, + topic_name: &T, + message: M, + ) -> FutureResult { + // self.swarm + // .behaviour_mut() + // .pubsub + // .publish(&topic_name.to_string(), message.into()) + self.service + .publish(&topic_name.to_string(), message.into()) + } +} //------------------------------------------------ diff --git a/protocol/src/pubsub.rs b/protocol/src/pubsub.rs index f4924187d..1dd92be75 100644 --- a/protocol/src/pubsub.rs +++ b/protocol/src/pubsub.rs @@ -120,6 +120,10 @@ impl Pubsub { PubSubWorker::new(local_key, heartbeat_interval) .map(|worker| (worker.service.clone(), worker)) } + + pub fn create(to_worker: mpsc::UnboundedSender, peer_id: PeerId) -> Self { + Self { to_worker, peer_id } + } } impl PubSub for Pubsub { diff --git a/service/Cargo.toml b/service/Cargo.toml index bcf3a8ccd..81bb05384 100644 --- a/service/Cargo.toml +++ b/service/Cargo.toml @@ -18,23 +18,8 @@ jsonrpsee = { version = "0.15.1", features = ["server"] } codec = { package = "parity-scale-codec", version = "3.0.0" } hex-literal = "0.3.1" log = "0.4.17" -# libp2p = { version = "0.49", optional = true } +libp2p = { version = "0.49", optional = true } tokio = { version = "1.23.0", features = ["full"], optional = true } -libp2p = { version = "0.49", features = [ - "gossipsub", - "kad", - "mdns", - "request-response", - "noise", - "tcp", - "yamux", - "websocket", - "mplex", - "dns", - "tokio", - "rsa", - "ping", -], optional = true } # primitives robonomics-primitives = { path = "../primitives", default-features = false } diff --git a/service/src/service.rs b/service/src/service.rs index ddaf16235..f445ebb77 100644 --- a/service/src/service.rs +++ b/service/src/service.rs @@ -182,7 +182,7 @@ where //------------------------------------------------ - let (pubsub, _pubsub_worker) = + let (pubsub, pubsub_worker) = Pubsub::new(local_key.clone(), heartbeat_interval).expect("New robonomics pubsub"); // task_manager @@ -203,7 +203,7 @@ where // .spawn_handle() // .spawn("network_service", None, network_worker); - let network_worker = RNetwork::new( + let robonomics_network = RNetwork::new( local_key, heartbeat_interval, bootnodes, @@ -212,9 +212,19 @@ where ) .expect("New robonomics network"); + let aaa = robonomics_network.service.clone(); + task_manager .spawn_handle() - .spawn("network_service", None, network_worker); + .spawn("network_service", None, robonomics_network); + + // task_manager + // .spawn_handle() + // .spawn("network_service", None, network_worker); + + // use robonomics_protocol::pubsub::PubSub; + // let a = aaa.peer_id(); + // let b = pubsub.peer_id(); //------------------------------------------------ @@ -227,9 +237,11 @@ where client: client.clone(), pool: pool.clone(), deny_unsafe, + // network: robonomics_network.service, // network: robonomics_network.to_owned(), network: Arc::new(RobonomicsNetwork { - pubsub: pubsub.clone(), + // pubsub: pubsub.clone(), + pubsub: aaa.to_owned(), }), }; From 667d2146293f215c1a2cd1399dd03a41e3e26078 Mon Sep 17 00:00:00 2001 From: Denis K Date: Fri, 10 Mar 2023 13:02:04 +0700 Subject: [PATCH 13/23] WIP: --- protocol/src/network.rs | 145 ++++++++++++++++++++++++++-------------- protocol/src/pubsub.rs | 1 + 2 files changed, 95 insertions(+), 51 deletions(-) diff --git a/protocol/src/network.rs b/protocol/src/network.rs index 0eb7c8aa2..fab1f6adf 100644 --- a/protocol/src/network.rs +++ b/protocol/src/network.rs @@ -22,7 +22,8 @@ use futures::{ prelude::*, }; use libp2p::{ - gossipsub::{GossipsubEvent, TopicHash}, + core::transport::ListenerId, + gossipsub::{GossipsubEvent, IdentTopic as Topic, TopicHash}, identity::Keypair, kad::KademliaEvent, request_response::{RequestResponseEvent, RequestResponseMessage}, @@ -103,6 +104,63 @@ impl RNetwork { service, }) } + + fn listen(&mut self, address: Multiaddr) -> Result { + let listener = Swarm::listen_on(&mut self.swarm, address.clone())?; + log::debug!( + target: "robonomics-pubsub", + "Listener for address {} created: {:?}", address, listener + ); + + Ok(listener) + } + + fn listeners(&self) -> Vec { + let listeners = Swarm::listeners(&self.swarm).cloned().collect(); + log::debug!(target: "robonomics-pubsub", "Listeners: {:?}", listeners); + + listeners + } + + fn connect(&mut self, address: Multiaddr) -> Result<()> { + Swarm::dial(&mut self.swarm, address.clone())?; + log::debug!(target: "robonomics-pubsub", "Connected to {}", address); + + Ok(()) + } + + fn subscribe( + &mut self, + topic_name: String, + inbox: mpsc::UnboundedSender, + ) -> Result { + let topic = Topic::new(topic_name.clone()); + self.swarm.behaviour_mut().pubsub.subscribe(&topic)?; + self.inbox.insert(topic.hash(), inbox); + log::debug!(target: "robonomics-pubsub", "Subscribed to {}", topic_name); + + Ok(true) + } + + fn unsubscribe(&mut self, topic_name: String) -> Result { + let topic = Topic::new(topic_name.clone()); + self.swarm.behaviour_mut().pubsub.unsubscribe(&topic)?; + self.inbox.remove(&topic.hash()); + log::debug!(target: "robonomics-pubsub", "Unsubscribed from {}", topic_name); + + Ok(true) + } + + fn publish(&mut self, topic_name: String, message: Vec) -> Result { + let topic = Topic::new(topic_name.clone()); + self.swarm + .behaviour_mut() + .pubsub + .publish(topic.clone(), message)?; + log::debug!(target: "robonomics-pubsub", "Publish to {}", topic_name); + + Ok(true) + } } impl Future for RNetwork { @@ -190,6 +248,7 @@ impl Future for RNetwork { } } + // эти методы берутся из реализации PubSub, а нужно из воркера loop { match self.from_service.poll_next_unpin(cx) { Poll::Ready(Some(request)) => match request { @@ -220,56 +279,40 @@ impl Future for RNetwork { } } -impl PubSub for RNetwork { - fn peer_id(&self) -> PeerId { - // self.swarm.behaviour_mut().pubsub.peer_id() - self.service.peer_id() - } - - fn listen(&self, address: Multiaddr) -> FutureResult { - // self.swarm.behaviour_mut().pubsub.listen(address) - self.service.listen(address) - } - - fn listeners(&self) -> FutureResult> { - // self.swarm.behaviour_mut().pubsub.listeners() - self.service.listeners() - } - - fn connect(&self, address: Multiaddr) -> FutureResult { - // self.swarm.behaviour_mut().pubsub.connect(address) - self.service.connect(address) - } - - fn subscribe(&self, topic_name: &T) -> Inbox { - // self.swarm - // .behaviour_mut() - // .pubsub - // .subscribe(&topic_name.to_string()) - self.service.subscribe(&topic_name.to_string()) - } - - fn unsubscribe(&self, topic_name: &T) -> FutureResult { - // self.swarm - // .behaviour_mut() - // .pubsub - // .unsubscribe(&topic_name.to_string()) - self.service.unsubscribe(&topic_name.to_string()) - } - - fn publish>>( - &self, - topic_name: &T, - message: M, - ) -> FutureResult { - // self.swarm - // .behaviour_mut() - // .pubsub - // .publish(&topic_name.to_string(), message.into()) - self.service - .publish(&topic_name.to_string(), message.into()) - } -} +// impl PubSub for RNetwork { +// fn peer_id(&self) -> PeerId { +// self.service.peer_id() +// } +// +// fn listen(&self, address: Multiaddr) -> FutureResult { +// self.service.listen(address) +// } +// +// fn listeners(&self) -> FutureResult> { +// self.service.listeners() +// } +// +// fn connect(&self, address: Multiaddr) -> FutureResult { +// self.service.connect(address) +// } +// +// fn subscribe(&self, topic_name: &T) -> Inbox { +// self.service.subscribe(&topic_name.to_string()) +// } +// +// fn unsubscribe(&self, topic_name: &T) -> FutureResult { +// self.service.unsubscribe(&topic_name.to_string()) +// } +// +// fn publish>>( +// &self, +// topic_name: &T, +// message: M, +// ) -> FutureResult { +// self.service +// .publish(&topic_name.to_string(), message.into()) +// } +// } //------------------------------------------------ diff --git a/protocol/src/pubsub.rs b/protocol/src/pubsub.rs index 1dd92be75..caab13c7d 100644 --- a/protocol/src/pubsub.rs +++ b/protocol/src/pubsub.rs @@ -121,6 +121,7 @@ impl Pubsub { .map(|worker| (worker.service.clone(), worker)) } + // !!! pub fn create(to_worker: mpsc::UnboundedSender, peer_id: PeerId) -> Self { Self { to_worker, peer_id } } From bc400bb8c16cfb324be3e7d0bda032b2d9fb183b Mon Sep 17 00:00:00 2001 From: Denis K Date: Fri, 10 Mar 2023 14:20:51 +0700 Subject: [PATCH 14/23] WIP: testing --- protocol/src/network.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/protocol/src/network.rs b/protocol/src/network.rs index fab1f6adf..8297b5826 100644 --- a/protocol/src/network.rs +++ b/protocol/src/network.rs @@ -248,26 +248,31 @@ impl Future for RNetwork { } } - // эти методы берутся из реализации PubSub, а нужно из воркера loop { match self.from_service.poll_next_unpin(cx) { Poll::Ready(Some(request)) => match request { ToWorkerMsg::Listen(addr, result) => { + println!("---------------------------- listen"); let _ = result.send(self.listen(addr).is_ok()); } ToWorkerMsg::Listeners(result) => { + println!("---------------------------- listeners"); let _ = result.send(self.listeners()); } ToWorkerMsg::Connect(addr, result) => { + println!("---------------------------- connect"); let _ = result.send(self.connect(addr).is_ok()); } ToWorkerMsg::Subscribe(topic_name, inbox) => { + println!("---------------------------- subscribe"); let _ = self.subscribe(topic_name, inbox); } ToWorkerMsg::Unsubscribe(topic_name, result) => { + println!("---------------------------- unsubscribe"); let _ = result.send(self.unsubscribe(topic_name).is_ok()); } ToWorkerMsg::Publish(topic_name, message, result) => { + println!("---------------------------- publish"); let _ = result.send(self.publish(topic_name, message).is_ok()); } }, From 6af64c6a7ed3b064d74f6e2b95fdc5877da7a445 Mon Sep 17 00:00:00 2001 From: Denis K Date: Fri, 10 Mar 2023 17:18:52 +0700 Subject: [PATCH 15/23] WIP: cleaning --- protocol/src/network.rs | 9 +++------ rpc/src/lib.rs | 12 +++++++---- service/src/parachain/service.rs | 34 +++++++++++++++++++++++--------- service/src/service.rs | 15 +++++++------- 4 files changed, 44 insertions(+), 26 deletions(-) diff --git a/protocol/src/network.rs b/protocol/src/network.rs index 8297b5826..cd3cd5fc0 100644 --- a/protocol/src/network.rs +++ b/protocol/src/network.rs @@ -17,10 +17,7 @@ /////////////////////////////////////////////////////////////////////////////// //! Robonomics network layer. -use futures::{ - channel::{mpsc, oneshot}, - prelude::*, -}; +use futures::{channel::mpsc, prelude::*}; use libp2p::{ core::transport::ListenerId, gossipsub::{GossipsubEvent, IdentTopic as Topic, TopicHash}, @@ -86,8 +83,8 @@ impl RNetwork { })) .build(); - Swarm::listen_on(&mut swarm, "/ip4/127.0.0.1/tcp/30400".parse().unwrap())?; - // Swarm::listen_on(&mut swarm, "/ip4/127.0.0.1/tcp/30401".parse().unwrap())?; + // Swarm::listen_on(&mut swarm, "/ip4/127.0.0.1/tcp/30400".parse().unwrap())?; + Swarm::listen_on(&mut swarm, "/ip4/127.0.0.1/tcp/30401".parse().unwrap())?; discovery::add_peers(&mut swarm, bootnodes); // Create worker communication channel diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index 6e567ba29..6f06c6b03 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -20,7 +20,8 @@ use std::sync::Arc; use robonomics_primitives::{AccountId, Balance, Block, Index}; -use robonomics_protocol::network::RobonomicsNetwork; +// use robonomics_protocol::network::RobonomicsNetwork; +use robonomics_protocol::pubsub::Pubsub; use jsonrpsee::RpcModule; use sc_client_api::AuxStore; @@ -47,7 +48,8 @@ pub struct FullDeps { /// Whether to deny unsafe calls. pub deny_unsafe: DenyUnsafe, /// Robonomics Network. - pub network: Arc, + pub pubsub: Arc, + // pub network: Arc, } /// Instantiate all Full RPC extensions. @@ -75,12 +77,14 @@ where client, pool, deny_unsafe, - network, + // network, + pubsub, } = deps; io.merge(System::new(client.clone(), pool.clone(), deny_unsafe).into_rpc())?; io.merge(TransactionPayment::new(client.clone()).into_rpc())?; - io.merge(PubSubRpc::new(network.clone()).into_rpc())?; + // io.merge(PubSubRpc::new(network.clone()).into_rpc())?; + io.merge(PubSubRpc::new(pubsub.clone()).into_rpc())?; io.merge(ExtrinsicRpc::new(client.clone()).into_rpc())?; io.merge(ReqRespRpc::new().into_rpc())?; // io.merge(ReqRespRpc::new(network).into_rpc())?; diff --git a/service/src/parachain/service.rs b/service/src/parachain/service.rs index 906d8a4cb..27353f2a4 100644 --- a/service/src/parachain/service.rs +++ b/service/src/parachain/service.rs @@ -35,7 +35,7 @@ use hex_literal::hex; use libp2p::core::identity::Keypair; use polkadot_service::CollatorPair; use robonomics_primitives::{AccountId, Balance, Block, Hash, Index}; -use robonomics_protocol::{network::RobonomicsNetwork, pubsub::Pubsub}; +use robonomics_protocol::{network::RNetwork, network::RobonomicsNetwork, pubsub::Pubsub}; pub use sc_executor::NativeElseWasmExecutor; use sc_network::{NetworkBlock, NetworkService}; use sc_service::{Configuration, Role, TFullBackend, TFullClient, TaskManager}; @@ -202,9 +202,9 @@ pub async fn start_node_impl( build_consensus: BIC, local_key: Keypair, heartbeat_interval: u64, - _bootnodes: Vec, - _disable_mdns: bool, - _disable_kad: bool, + bootnodes: Vec, + disable_mdns: bool, + disable_kad: bool, ) -> sc_service::error::Result where Executor: sc_executor::NativeExecutionDispatch + 'static, @@ -301,8 +301,8 @@ where let rpc_client = client.clone(); let rpc_pool = transaction_pool.clone(); - let (pubsub, _pubsub_worker) = - Pubsub::new(local_key.clone(), heartbeat_interval).expect("New robonomics pubsub"); + // let (pubsub, _pubsub_worker) = + // Pubsub::new(local_key.clone(), heartbeat_interval).expect("New robonomics pubsub"); // task_manager // .spawn_handle() @@ -322,6 +322,21 @@ where // .spawn_handle() // .spawn("network_service", None, network_worker); + let robonomics_network = RNetwork::new( + local_key, + heartbeat_interval, + bootnodes, + disable_mdns, + disable_kad, + ) + .expect("New robonomics network"); + + let pubsub = robonomics_network.service.clone(); + + task_manager + .spawn_handle() + .spawn("network_service", None, robonomics_network); + sc_service::spawn_tasks(sc_service::SpawnTasksParams { rpc_builder: Box::new(move |deny_unsafe, _| { let deps = robonomics_rpc::FullDeps { @@ -329,9 +344,10 @@ where pool: rpc_pool.clone(), deny_unsafe, // network: robonomics_network.clone(), - network: Arc::new(RobonomicsNetwork { - pubsub: pubsub.clone(), - }), + // network: Arc::new(RobonomicsNetwork { + // pubsub: pubsub.clone(), + // }), + pubsub: pubsub.to_owned(), }; robonomics_rpc::create_full(deps).map_err(Into::into) diff --git a/service/src/service.rs b/service/src/service.rs index f445ebb77..e9b76f954 100644 --- a/service/src/service.rs +++ b/service/src/service.rs @@ -182,8 +182,8 @@ where //------------------------------------------------ - let (pubsub, pubsub_worker) = - Pubsub::new(local_key.clone(), heartbeat_interval).expect("New robonomics pubsub"); + // let (pubsub, pubsub_worker) = + // Pubsub::new(local_key.clone(), heartbeat_interval).expect("New robonomics pubsub"); // task_manager // .spawn_handle() @@ -212,7 +212,7 @@ where ) .expect("New robonomics network"); - let aaa = robonomics_network.service.clone(); + let pubsub = robonomics_network.service.clone(); task_manager .spawn_handle() @@ -239,10 +239,11 @@ where deny_unsafe, // network: robonomics_network.service, // network: robonomics_network.to_owned(), - network: Arc::new(RobonomicsNetwork { - // pubsub: pubsub.clone(), - pubsub: aaa.to_owned(), - }), + // network: Arc::new(RobonomicsNetwork { + // // pubsub: pubsub.clone(), + // pubsub: aaa.to_owned(), + // }), + pubsub: pubsub.to_owned(), }; robonomics_rpc::create_full(deps).map_err(Into::into) From 8e700f078739c69c085da3df90a9999bc30674b9 Mon Sep 17 00:00:00 2001 From: Denis K Date: Fri, 10 Mar 2023 18:54:29 +0700 Subject: [PATCH 16/23] WIP: test network --- Cargo.lock | 2 +- protocol/examples/ros/src/main.rs | 8 +- protocol/src/network.rs | 147 +++----------------- protocol/src/network/worker.rs | 148 -------------------- protocol/src/pubsub.rs | 218 +----------------------------- rpc/src/lib.rs | 7 +- service/Cargo.toml | 2 +- service/src/command.rs | 7 +- service/src/parachain/service.rs | 31 +---- service/src/service.rs | 45 +----- 10 files changed, 33 insertions(+), 582 deletions(-) delete mode 100644 protocol/src/network/worker.rs diff --git a/Cargo.lock b/Cargo.lock index 9c42ba0e1..616ce0054 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9027,7 +9027,7 @@ dependencies = [ [[package]] name = "robonomics-service" -version = "2.6.1" +version = "2.7.0" dependencies = [ "alpha-runtime", "clap 3.2.23", diff --git a/protocol/examples/ros/src/main.rs b/protocol/examples/ros/src/main.rs index f52617e48..dc876c0e1 100644 --- a/protocol/examples/ros/src/main.rs +++ b/protocol/examples/ros/src/main.rs @@ -64,16 +64,10 @@ async fn main() -> Result<(), Box> { .pubsub .publish(topic.clone(), line.expect("Stdin not to close").expect("").as_bytes()) { Ok(mid) => - println!("Message : {mid:?}"), + println!("Message id: {mid:?}"), Err(e) => println!("Publish error: {e:?}"), } - // if let Err(e) = swarm - // .behaviour_mut() - // .pubsub - // .publish(topic.clone(), line.expect("Stdin not to close").expect("").as_bytes()) { - // println!("Publish error: {e:?}"); - // } }, event = swarm.select_next_some() => match event { SwarmEvent::Behaviour(OutEvent::Pubsub(GossipsubEvent::Message { diff --git a/protocol/src/network.rs b/protocol/src/network.rs index cd3cd5fc0..5b83a94f5 100644 --- a/protocol/src/network.rs +++ b/protocol/src/network.rs @@ -35,71 +35,62 @@ use std::{ }; use crate::{ - error::{FutureResult, Result}, - network::{ - behaviour::{OutEvent, RobonomicsNetworkBehaviour}, - worker::NetworkWorker, - }, - pubsub::{Inbox, Message, PubSub, Pubsub, ToWorkerMsg}, + error::Result, + network::behaviour::{OutEvent, RobonomicsNetworkBehaviour}, + pubsub::{Message, Pubsub, ToWorkerMsg}, reqres::Response, }; pub mod behaviour; pub mod discovery; -pub mod worker; -pub struct RNetwork { +pub struct RobonomicsNetwork { swarm: Swarm, inbox: HashMap>, from_service: mpsc::UnboundedReceiver, - pub service: Arc, } -impl RNetwork { +impl RobonomicsNetwork { pub fn new( local_key: Keypair, heartbeat_interval: u64, bootnodes: Vec, disable_mdns: bool, disable_kad: bool, - ) -> Result { + ) -> Result<(Self, Arc)> { let peer_id = PeerId::from(local_key.public()); let transport = libp2p::tokio_development_transport(local_key.clone())?; - let mut behaviour = RobonomicsNetworkBehaviour::new( + let behaviour = RobonomicsNetworkBehaviour::new( local_key, peer_id, heartbeat_interval, disable_mdns, disable_kad, )?; - - // XXX - let topic = libp2p::gossipsub::IdentTopic::new("ROS"); - behaviour.pubsub.subscribe(&topic)?; - let mut swarm = SwarmBuilder::new(transport, behaviour, peer_id) .executor(Box::new(|fut| { tokio::spawn(fut); })) .build(); - // Swarm::listen_on(&mut swarm, "/ip4/127.0.0.1/tcp/30400".parse().unwrap())?; - Swarm::listen_on(&mut swarm, "/ip4/127.0.0.1/tcp/30401".parse().unwrap())?; + Swarm::listen_on(&mut swarm, "/ip4/127.0.0.1/tcp/30400".parse().unwrap())?; + // Swarm::listen_on(&mut swarm, "/ip4/127.0.0.1/tcp/30401".parse().unwrap())?; discovery::add_peers(&mut swarm, bootnodes); // Create worker communication channel let (to_worker, from_service) = mpsc::unbounded::(); // Create PubSub service - let service = Arc::new(Pubsub::create(to_worker, peer_id)); - // let service = Arc::new(Pubsub { to_worker, peer_id }); - - Ok(Self { - swarm, - inbox: HashMap::new(), - from_service, + let service = Arc::new(Pubsub::new(peer_id, to_worker)); + + Ok(( + Self { + swarm, + inbox: HashMap::new(), + from_service, + }, service, - }) + )) } fn listen(&mut self, address: Multiaddr) -> Result { @@ -160,7 +151,7 @@ impl RNetwork { } } -impl Future for RNetwork { +impl Future for RobonomicsNetwork { type Output = (); fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll { @@ -249,27 +240,21 @@ impl Future for RNetwork { match self.from_service.poll_next_unpin(cx) { Poll::Ready(Some(request)) => match request { ToWorkerMsg::Listen(addr, result) => { - println!("---------------------------- listen"); let _ = result.send(self.listen(addr).is_ok()); } ToWorkerMsg::Listeners(result) => { - println!("---------------------------- listeners"); let _ = result.send(self.listeners()); } ToWorkerMsg::Connect(addr, result) => { - println!("---------------------------- connect"); let _ = result.send(self.connect(addr).is_ok()); } ToWorkerMsg::Subscribe(topic_name, inbox) => { - println!("---------------------------- subscribe"); let _ = self.subscribe(topic_name, inbox); } ToWorkerMsg::Unsubscribe(topic_name, result) => { - println!("---------------------------- unsubscribe"); let _ = result.send(self.unsubscribe(topic_name).is_ok()); } ToWorkerMsg::Publish(topic_name, message, result) => { - println!("---------------------------- publish"); let _ = result.send(self.publish(topic_name, message).is_ok()); } }, @@ -280,97 +265,3 @@ impl Future for RNetwork { Poll::Pending } } - -// impl PubSub for RNetwork { -// fn peer_id(&self) -> PeerId { -// self.service.peer_id() -// } -// -// fn listen(&self, address: Multiaddr) -> FutureResult { -// self.service.listen(address) -// } -// -// fn listeners(&self) -> FutureResult> { -// self.service.listeners() -// } -// -// fn connect(&self, address: Multiaddr) -> FutureResult { -// self.service.connect(address) -// } -// -// fn subscribe(&self, topic_name: &T) -> Inbox { -// self.service.subscribe(&topic_name.to_string()) -// } -// -// fn unsubscribe(&self, topic_name: &T) -> FutureResult { -// self.service.unsubscribe(&topic_name.to_string()) -// } -// -// fn publish>>( -// &self, -// topic_name: &T, -// message: M, -// ) -> FutureResult { -// self.service -// .publish(&topic_name.to_string(), message.into()) -// } -// } - -//------------------------------------------------ - -pub struct RobonomicsNetwork { - pub pubsub: Arc, -} - -impl RobonomicsNetwork { - pub fn new( - local_key: Keypair, - pubsub: Arc, - heartbeat_interval: u64, - _bootnodes: Vec, - disable_mdns: bool, - disable_kad: bool, - ) -> Result<(Arc, impl Future)> { - let network_worker = - NetworkWorker::new(local_key, heartbeat_interval, disable_mdns, disable_kad)?; - - // Reach out to another nodes if specified - // discovery::add_peers(&mut network_worker.swarm, bootnodes); - - Ok((Arc::new(Self { pubsub }), network_worker)) - } -} - -impl PubSub for RobonomicsNetwork { - fn peer_id(&self) -> PeerId { - self.pubsub.peer_id() - } - - fn listen(&self, address: Multiaddr) -> FutureResult { - self.pubsub.listen(address) - } - - fn listeners(&self) -> FutureResult> { - self.pubsub.listeners() - } - - fn connect(&self, address: Multiaddr) -> FutureResult { - self.pubsub.connect(address) - } - - fn subscribe(&self, topic_name: &T) -> Inbox { - self.pubsub.subscribe(&topic_name.to_string()) - } - - fn unsubscribe(&self, topic_name: &T) -> FutureResult { - self.pubsub.unsubscribe(&topic_name.to_string()) - } - - fn publish>>( - &self, - topic_name: &T, - message: M, - ) -> FutureResult { - self.pubsub.publish(&topic_name.to_string(), message.into()) - } -} diff --git a/protocol/src/network/worker.rs b/protocol/src/network/worker.rs deleted file mode 100644 index 7054d4720..000000000 --- a/protocol/src/network/worker.rs +++ /dev/null @@ -1,148 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2018-2022 Robonomics Network -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -/////////////////////////////////////////////////////////////////////////////// -//! Robonomics network worker. - -use futures::{prelude::*, Future}; -use libp2p::{ - identity::Keypair, - kad::KademliaEvent, - request_response::{RequestResponseEvent, RequestResponseMessage}, - swarm::{SwarmBuilder, SwarmEvent}, - Multiaddr, PeerId, Swarm, -}; -use std::{ - pin::Pin, - // sync::Arc, - task::{Context, Poll}, -}; - -use crate::{ - error::Result, - network::behaviour::{OutEvent, RobonomicsNetworkBehaviour}, - // pubsub::{PubSub, Pubsub}, - reqres::Response, -}; - -pub struct NetworkWorker { - pub swarm: Swarm, -} - -impl NetworkWorker { - /// Create new network worker instance - pub fn new( - local_key: Keypair, - heartbeat_interval: u64, - disable_mdns: bool, - disable_kad: bool, - ) -> Result { - let peer_id = PeerId::from(local_key.public()); - - // Set up an encrypted WebSocket compatible Transport - let transport = libp2p::tokio_development_transport(local_key.clone())?; - - // Build a combined network behaviour - let behaviour = RobonomicsNetworkBehaviour::new( - local_key, - peer_id, - heartbeat_interval, - disable_mdns, - disable_kad, - )?; - - // ??? - // use libp2p::gossipsub::IdentTopic; - // behaviour.pubsub.subscribe(&IdentTopic::new("ROS"))?; - - // Create a Swarm to manage peers and events - let mut swarm = SwarmBuilder::new(transport, behaviour, peer_id.clone()) - .executor(Box::new(|fut| { - tokio::spawn(fut); - })) - .build(); - - // Listen RNB pubsub port - let listen_address: Multiaddr = "/ip4/127.0.0.1/tcp/30400".parse().unwrap(); - Swarm::listen_on(&mut swarm, listen_address)?; - - Ok(Self { swarm }) - } -} - -impl Future for NetworkWorker { - type Output = (); - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll { - loop { - match self.swarm.poll_next_unpin(cx) { - Poll::Ready(Some(swarm_event)) => match swarm_event { - SwarmEvent::Behaviour(OutEvent::Kademlia(KademliaEvent::RoutingUpdated { - peer, - // addresses, - .. - })) => { - log::info!("Received kademlia peer: {:?}", peer); - if let Some(kademlia) = self.swarm.behaviour_mut().kademlia.as_mut() { - if let Err(e) = kademlia.bootstrap() { - log::debug!("Bootstrap error: {:?}", e); - }; - } - // for address in addresses.iter() { - // let _ = self.pubsub.connect(address.clone()); - // } - } - SwarmEvent::Behaviour(OutEvent::RequestResponse( - RequestResponseEvent::Message { - peer, - message: - RequestResponseMessage::Response { - request_id, - response, - }, - }, - )) => match response { - Response::Pong => { - log::debug!( - " peer2 Resp{} {:?} from {:?}", - request_id, - &response, - peer - ); - break; - } - Response::Data(data) => { - let decoded: Vec = bincode::deserialize(&data.to_vec()).unwrap(); - log::debug!( - " peer2 Resp: Data '{}' from {:?}", - String::from_utf8_lossy(&decoded[..]), - peer // ??? - ); - log::debug!("{}", String::from_utf8_lossy(&decoded[..])); - break; - } - }, - _ => {} - }, - Poll::Ready(None) | Poll::Pending => { - break; - } - } - } - - Poll::Pending - } -} diff --git a/protocol/src/pubsub.rs b/protocol/src/pubsub.rs index caab13c7d..adec1bedb 100644 --- a/protocol/src/pubsub.rs +++ b/protocol/src/pubsub.rs @@ -21,28 +21,11 @@ use futures::{ channel::{mpsc, oneshot}, prelude::*, }; -use libp2p::{ - core::transport::ListenerId, - gossipsub::{ - Gossipsub, GossipsubConfigBuilder, GossipsubEvent, GossipsubMessage, MessageAuthenticity, - MessageId, Sha256Topic as Topic, TopicHash, - }, - identity::Keypair, - swarm::{SwarmBuilder, SwarmEvent}, - Multiaddr, PeerId, Swarm, -}; +use libp2p::{Multiaddr, PeerId}; use serde::Serialize; -use std::{ - collections::hash_map::{DefaultHasher, HashMap}, - fmt, - hash::{Hash, Hasher}, - pin::Pin, - sync::Arc, - task::{Context, Poll}, - time::Duration, -}; +use std::fmt; -use crate::error::{FutureResult, Result}; +use crate::error::FutureResult; /// Robonomics PubSub message. #[derive(PartialEq, Eq, Clone, Debug, Serialize)] @@ -112,18 +95,8 @@ pub struct Pubsub { } impl Pubsub { - /// Create Gossipsub based PubSub service and worker. - pub fn new( - local_key: Keypair, - heartbeat_interval: u64, - ) -> Result<(Arc, impl Future)> { - PubSubWorker::new(local_key, heartbeat_interval) - .map(|worker| (worker.service.clone(), worker)) - } - - // !!! - pub fn create(to_worker: mpsc::UnboundedSender, peer_id: PeerId) -> Self { - Self { to_worker, peer_id } + pub fn new(peer_id: PeerId, to_worker: mpsc::UnboundedSender) -> Self { + Self { peer_id, to_worker } } } @@ -187,184 +160,3 @@ impl PubSub for Pubsub { receiver.boxed() } } - -struct PubSubWorker { - swarm: Swarm, - inbox: HashMap>, - from_service: mpsc::UnboundedReceiver, - service: Arc, -} - -impl PubSubWorker { - /// Create new PubSub Worker instance - pub fn new(local_key: Keypair, heartbeat_interval: u64) -> Result { - let peer_id = PeerId::from(local_key.public()); - - // Set up an encrypted WebSocket compatible Transport over the Mplex and Yamux protocols - let transport = libp2p::tokio_development_transport(local_key.clone())?; - - // Set custom gossipsub - let gossipsub_config = GossipsubConfigBuilder::default() - .heartbeat_interval(Duration::from_millis(heartbeat_interval)) - .message_id_fn(|message: &GossipsubMessage| { - // To content-address message, - // we can take the hash of message and use it as an ID. - let mut s = DefaultHasher::new(); - message.data.hash(&mut s); - MessageId::from(s.finish().to_string()) - }) - .build() - .expect("Valid gossipsub config"); - - // Build a gossipsub network behaviour - let gossipsub = Gossipsub::new(MessageAuthenticity::Signed(local_key), gossipsub_config) - .expect("Correct configuration"); - - // Create a Swarm to manage peers and events - let swarm = SwarmBuilder::new(transport, gossipsub, peer_id.clone()) - .executor(Box::new(|fut| { - tokio::spawn(fut); - })) - .build(); - - // Create worker communication channel - let (to_worker, from_service) = mpsc::unbounded(); - - // Create PubSub service - let service = Arc::new(Pubsub { to_worker, peer_id }); - - // Create worker instance with empty subscribers - Ok(PubSubWorker { - swarm, - inbox: HashMap::new(), - from_service, - service, - }) - } - - fn listen(&mut self, address: Multiaddr) -> Result { - let listener = Swarm::listen_on(&mut self.swarm, address.clone())?; - log::debug!( - target: "robonomics-pubsub", - "Listener for address {} created: {:?}", address, listener - ); - - Ok(listener) - } - - fn listeners(&self) -> Vec { - let listeners = Swarm::listeners(&self.swarm).cloned().collect(); - log::debug!(target: "robonomics-pubsub", "Listeners: {:?}", listeners); - - listeners - } - - fn connect(&mut self, address: Multiaddr) -> Result<()> { - Swarm::dial(&mut self.swarm, address.clone())?; - log::debug!(target: "robonomics-pubsub", "Connected to {}", address); - - Ok(()) - } - - fn subscribe( - &mut self, - topic_name: String, - inbox: mpsc::UnboundedSender, - ) -> Result { - let topic = Topic::new(topic_name.clone()); - self.swarm.behaviour_mut().subscribe(&topic)?; - self.inbox.insert(topic.hash(), inbox); - log::debug!(target: "robonomics-pubsub", "Subscribed to {}", topic_name); - - Ok(true) - } - - fn unsubscribe(&mut self, topic_name: String) -> Result { - let topic = Topic::new(topic_name.clone()); - self.swarm.behaviour_mut().unsubscribe(&topic)?; - self.inbox.remove(&topic.hash()); - log::debug!(target: "robonomics-pubsub", "Unsubscribed from {}", topic_name); - - Ok(true) - } - - fn publish(&mut self, topic_name: String, message: Vec) -> Result { - let topic = Topic::new(topic_name.clone()); - self.swarm.behaviour_mut().publish(topic.clone(), message)?; - log::debug!(target: "robonomics-pubsub", "Publish to {}", topic_name); - - Ok(true) - } -} - -impl Future for PubSubWorker { - type Output = (); - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll { - loop { - match self.swarm.poll_next_unpin(cx) { - Poll::Ready(Some(swarm_event)) => match swarm_event { - SwarmEvent::Behaviour(event) => match event { - GossipsubEvent::Message { - propagation_source: peer_id, - message_id: id, - message, - } => { - log::debug!( - target: "robonomics-pubsub", - "Received message with id: {} from peer: {}", id, peer_id.to_base58() - ); - - // Dispatch handlers by topic name hash - if let Some(inbox) = self.inbox.get_mut(&message.topic) { - if let Some(sender) = &message.source { - let _ = inbox.unbounded_send(Message { - from: sender.clone().to_bytes(), - data: message.data.clone(), - }); - } - } else { - log::warn!( - target: "robonomics-pubsub", - "Topic {} have no associated inbox!", message.topic - ); - } - } - _ => {} - }, - _ => {} - }, - Poll::Ready(None) | Poll::Pending => { - break; - } - } - } - - loop { - match self.from_service.poll_next_unpin(cx) { - Poll::Ready(Some(request)) => match request { - ToWorkerMsg::Listen(addr, result) => { - let _ = result.send(self.listen(addr).is_ok()); - } - ToWorkerMsg::Listeners(result) => { - let _ = result.send(self.listeners()); - } - ToWorkerMsg::Connect(addr, result) => { - let _ = result.send(self.connect(addr).is_ok()); - } - ToWorkerMsg::Subscribe(topic_name, inbox) => { - let _ = self.subscribe(topic_name, inbox); - } - ToWorkerMsg::Unsubscribe(topic_name, result) => { - let _ = result.send(self.unsubscribe(topic_name).is_ok()); - } - ToWorkerMsg::Publish(topic_name, message, result) => { - let _ = result.send(self.publish(topic_name, message).is_ok()); - } - }, - Poll::Ready(None) | Poll::Pending => break, - } - } - Poll::Pending - } -} diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index 6f06c6b03..2fc33b57b 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -20,7 +20,6 @@ use std::sync::Arc; use robonomics_primitives::{AccountId, Balance, Block, Index}; -// use robonomics_protocol::network::RobonomicsNetwork; use robonomics_protocol::pubsub::Pubsub; use jsonrpsee::RpcModule; @@ -49,7 +48,6 @@ pub struct FullDeps { pub deny_unsafe: DenyUnsafe, /// Robonomics Network. pub pubsub: Arc, - // pub network: Arc, } /// Instantiate all Full RPC extensions. @@ -77,17 +75,14 @@ where client, pool, deny_unsafe, - // network, pubsub, } = deps; io.merge(System::new(client.clone(), pool.clone(), deny_unsafe).into_rpc())?; io.merge(TransactionPayment::new(client.clone()).into_rpc())?; - // io.merge(PubSubRpc::new(network.clone()).into_rpc())?; - io.merge(PubSubRpc::new(pubsub.clone()).into_rpc())?; + io.merge(PubSubRpc::new(pubsub.to_owned()).into_rpc())?; io.merge(ExtrinsicRpc::new(client.clone()).into_rpc())?; io.merge(ReqRespRpc::new().into_rpc())?; - // io.merge(ReqRespRpc::new(network).into_rpc())?; Ok(io) } diff --git a/service/Cargo.toml b/service/Cargo.toml index 81bb05384..05343026c 100644 --- a/service/Cargo.toml +++ b/service/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "robonomics-service" -version = "2.6.1" +version = "2.7.0" authors = ["Airalab "] description = "Robonomics node console line interface." build = "build.rs" diff --git a/service/src/command.rs b/service/src/command.rs index 1c9c5b684..6873ea9b1 100644 --- a/service/src/command.rs +++ b/service/src/command.rs @@ -118,14 +118,9 @@ pub async fn run() -> sc_cli::Result<()> { let transport = libp2p::tokio_development_transport(local_key.clone()).expect("Correct transport"); - let mut behaviour = RobonomicsNetworkBehaviour::new(local_key, local_peer_id, 1000, true, true) + let behaviour = RobonomicsNetworkBehaviour::new(local_key, local_peer_id, 1000, true, true) .expect("Correct behaviour"); - behaviour - .pubsub - .subscribe(&libp2p::gossipsub::IdentTopic::new("ROS")) - .expect("ROS topic"); - let mut swarm = SwarmBuilder::new(transport, behaviour, local_peer_id) .executor(Box::new(|fut| { tokio::spawn(fut); diff --git a/service/src/parachain/service.rs b/service/src/parachain/service.rs index 27353f2a4..b95120593 100644 --- a/service/src/parachain/service.rs +++ b/service/src/parachain/service.rs @@ -35,7 +35,7 @@ use hex_literal::hex; use libp2p::core::identity::Keypair; use polkadot_service::CollatorPair; use robonomics_primitives::{AccountId, Balance, Block, Hash, Index}; -use robonomics_protocol::{network::RNetwork, network::RobonomicsNetwork, pubsub::Pubsub}; +use robonomics_protocol::network::RobonomicsNetwork; pub use sc_executor::NativeElseWasmExecutor; use sc_network::{NetworkBlock, NetworkService}; use sc_service::{Configuration, Role, TFullBackend, TFullClient, TaskManager}; @@ -301,28 +301,7 @@ where let rpc_client = client.clone(); let rpc_pool = transaction_pool.clone(); - // let (pubsub, _pubsub_worker) = - // Pubsub::new(local_key.clone(), heartbeat_interval).expect("New robonomics pubsub"); - - // task_manager - // .spawn_handle() - // .spawn("pubsub_service", None, pubsub_worker); - // - // let (robonomics_network, network_worker) = RobonomicsNetwork::new( - // local_key, - // pubsub.clone(), - // heartbeat_interval, - // bootnodes, - // disable_mdns, - // disable_kad, - // ) - // .expect("New robonomics network layer"); - // - // task_manager - // .spawn_handle() - // .spawn("network_service", None, network_worker); - - let robonomics_network = RNetwork::new( + let (robonomics_network, pubsub) = RobonomicsNetwork::new( local_key, heartbeat_interval, bootnodes, @@ -331,8 +310,6 @@ where ) .expect("New robonomics network"); - let pubsub = robonomics_network.service.clone(); - task_manager .spawn_handle() .spawn("network_service", None, robonomics_network); @@ -343,10 +320,6 @@ where client: rpc_client.clone(), pool: rpc_pool.clone(), deny_unsafe, - // network: robonomics_network.clone(), - // network: Arc::new(RobonomicsNetwork { - // pubsub: pubsub.clone(), - // }), pubsub: pubsub.to_owned(), }; diff --git a/service/src/service.rs b/service/src/service.rs index e9b76f954..7dcce8640 100644 --- a/service/src/service.rs +++ b/service/src/service.rs @@ -19,7 +19,7 @@ use libp2p::core::identity::Keypair; use robonomics_primitives::{AccountId, Balance, Block, Index}; -use robonomics_protocol::{network::RNetwork, network::RobonomicsNetwork, pubsub::Pubsub}; +use robonomics_protocol::network::RobonomicsNetwork; use sc_client_api::{BlockBackend, ExecutorProvider}; use sc_consensus_aura::{ImportQueueParams, SlotProportion, StartAuraParams}; pub use sc_executor::NativeElseWasmExecutor; @@ -180,30 +180,7 @@ where }, )?; - //------------------------------------------------ - - // let (pubsub, pubsub_worker) = - // Pubsub::new(local_key.clone(), heartbeat_interval).expect("New robonomics pubsub"); - - // task_manager - // .spawn_handle() - // .spawn("pubsub_service", None, pubsub_worker); - - // let (robonomics_network, network_worker) = RobonomicsNetwork::new( - // local_key, - // pubsub.clone(), - // heartbeat_interval, - // bootnodes, - // disable_mdns, - // disable_kad, - // ) - // .expect("New robonomics network layer"); - - // task_manager - // .spawn_handle() - // .spawn("network_service", None, network_worker); - - let robonomics_network = RNetwork::new( + let (robonomics_network, pubsub) = RobonomicsNetwork::new( local_key, heartbeat_interval, bootnodes, @@ -212,22 +189,10 @@ where ) .expect("New robonomics network"); - let pubsub = robonomics_network.service.clone(); - task_manager .spawn_handle() .spawn("network_service", None, robonomics_network); - // task_manager - // .spawn_handle() - // .spawn("network_service", None, network_worker); - - // use robonomics_protocol::pubsub::PubSub; - // let a = aaa.peer_id(); - // let b = pubsub.peer_id(); - - //------------------------------------------------ - let rpc_extensions_builder = { let client = client.clone(); let pool = transaction_pool.clone(); @@ -237,12 +202,6 @@ where client: client.clone(), pool: pool.clone(), deny_unsafe, - // network: robonomics_network.service, - // network: robonomics_network.to_owned(), - // network: Arc::new(RobonomicsNetwork { - // // pubsub: pubsub.clone(), - // pubsub: aaa.to_owned(), - // }), pubsub: pubsub.to_owned(), }; From 1020093662c7ac99145898b7de44112a320a84d4 Mon Sep 17 00:00:00 2001 From: Denis K Date: Fri, 10 Mar 2023 19:07:23 +0700 Subject: [PATCH 17/23] ADD: robonomics network --- protocol/src/network.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/protocol/src/network.rs b/protocol/src/network.rs index 5b83a94f5..baf644f92 100644 --- a/protocol/src/network.rs +++ b/protocol/src/network.rs @@ -74,7 +74,6 @@ impl RobonomicsNetwork { .build(); Swarm::listen_on(&mut swarm, "/ip4/127.0.0.1/tcp/30400".parse().unwrap())?; - // Swarm::listen_on(&mut swarm, "/ip4/127.0.0.1/tcp/30401".parse().unwrap())?; discovery::add_peers(&mut swarm, bootnodes); // Create worker communication channel From 28d9703d27fee5417bf0ee48e1deb2df8fd3eb27 Mon Sep 17 00:00:00 2001 From: Denis K Date: Tue, 28 Mar 2023 17:47:27 +0700 Subject: [PATCH 18/23] ADD: Identify behaviour --- Cargo.lock | 44 ++++++++++++++++++++++++++++--- protocol/Cargo.toml | 1 + protocol/src/network/behaviour.rs | 21 ++++++++++++++- 3 files changed, 61 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 616ce0054..a6e5eeb95 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4134,7 +4134,7 @@ dependencies = [ "libp2p-dns 0.34.0", "libp2p-floodsub", "libp2p-gossipsub 0.39.0", - "libp2p-identify", + "libp2p-identify 0.37.0", "libp2p-kad 0.38.0", "libp2p-mdns 0.38.0", "libp2p-metrics 0.7.0", @@ -4175,6 +4175,7 @@ dependencies = [ "libp2p-core 0.37.0", "libp2p-dns 0.37.0", "libp2p-gossipsub 0.42.1", + "libp2p-identify 0.40.0", "libp2p-kad 0.41.0", "libp2p-mdns 0.41.0", "libp2p-metrics 0.10.0", @@ -4409,7 +4410,28 @@ dependencies = [ "lru 0.7.8", "prost 0.10.4", "prost-build 0.10.4", - "prost-codec", + "prost-codec 0.1.0", + "smallvec", + "thiserror", + "void", +] + +[[package]] +name = "libp2p-identify" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf9a121f699e8719bda2e6e9e9b6ddafc6cff4602471d6481c1067930ccb29b" +dependencies = [ + "asynchronous-codec", + "futures", + "futures-timer", + "libp2p-core 0.37.0", + "libp2p-swarm 0.40.1", + "log", + "lru 0.8.1", + "prost 0.11.3", + "prost-build 0.11.4", + "prost-codec 0.2.0", "smallvec", "thiserror", "void", @@ -4520,7 +4542,7 @@ checksum = "ef8aff4a1abef42328fbb30b17c853fff9be986dc39af17ee39f9c5f755c5e0c" dependencies = [ "libp2p-core 0.34.0", "libp2p-gossipsub 0.39.0", - "libp2p-identify", + "libp2p-identify 0.37.0", "libp2p-kad 0.38.0", "libp2p-ping", "libp2p-relay", @@ -4536,6 +4558,7 @@ checksum = "9ee31b08e78b7b8bfd1c4204a9dd8a87b4fcdf6dafc57eb51701c1c264a81cb9" dependencies = [ "libp2p-core 0.37.0", "libp2p-gossipsub 0.42.1", + "libp2p-identify 0.40.0", "libp2p-kad 0.41.0", "libp2p-swarm 0.40.1", "prometheus-client 0.18.1", @@ -4686,7 +4709,7 @@ dependencies = [ "pin-project", "prost 0.10.4", "prost-build 0.10.4", - "prost-codec", + "prost-codec 0.1.0", "rand 0.8.5", "smallvec", "static_assertions", @@ -8521,6 +8544,19 @@ dependencies = [ "unsigned-varint", ] +[[package]] +name = "prost-codec" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "011ae9ff8359df7915f97302d591cdd9e0e27fbd5a4ddc5bd13b71079bb20987" +dependencies = [ + "asynchronous-codec", + "bytes", + "prost 0.11.3", + "thiserror", + "unsigned-varint", +] + [[package]] name = "prost-derive" version = "0.10.1" diff --git a/protocol/Cargo.toml b/protocol/Cargo.toml index 9697d5525..ef24ee9a8 100644 --- a/protocol/Cargo.toml +++ b/protocol/Cargo.toml @@ -25,6 +25,7 @@ rand = "0.8.4" rust-base58 = "0.0.4" chrono = "0.4" libp2p = { version = "0.49", features = [ + "identify", "gossipsub", "kad", "mdns", diff --git a/protocol/src/network/behaviour.rs b/protocol/src/network/behaviour.rs index 0919420e7..a30ff13f7 100644 --- a/protocol/src/network/behaviour.rs +++ b/protocol/src/network/behaviour.rs @@ -22,6 +22,7 @@ use libp2p::{ Gossipsub, GossipsubConfigBuilder, GossipsubEvent, GossipsubMessage, MessageAuthenticity, MessageId, }, + identify::{Behaviour as Identify, Config as IdentifyConfig, Event as IdentifyEvent}, identity::Keypair, kad::{record::store::MemoryStore, Kademlia, KademliaEvent}, mdns::{MdnsConfig, MdnsEvent, TokioMdns}, @@ -43,6 +44,7 @@ use crate::{ #[derive(NetworkBehaviour)] #[behaviour(out_event = "OutEvent")] pub struct RobonomicsNetworkBehaviour { + pub identify: Identify, pub pubsub: Gossipsub, pub mdns: Toggle, pub kademlia: Toggle>, @@ -56,6 +58,12 @@ impl RobonomicsNetworkBehaviour { disable_mdns: bool, disable_kad: bool, ) -> Result { + // Build identify network behaviour + let identify = Identify::new(IdentifyConfig::new( + "/ipfs/id/1.0.0".to_string(), + local_key.public(), + )); + // Set custom gossipsub let gossipsub_config = GossipsubConfigBuilder::default() .heartbeat_interval(Duration::from_millis(heartbeat_interval)) @@ -69,7 +77,10 @@ impl RobonomicsNetworkBehaviour { .build()?; // Build a gossipsub network behaviour - let pubsub = Gossipsub::new(MessageAuthenticity::Signed(local_key), gossipsub_config)?; + let pubsub = Gossipsub::new( + MessageAuthenticity::Signed(local_key.clone()), + gossipsub_config, + )?; // Build mDNS network behaviour let mdns = if !disable_mdns { @@ -92,6 +103,7 @@ impl RobonomicsNetworkBehaviour { // Combined network behaviour Ok(RobonomicsNetworkBehaviour { + identify, pubsub, mdns, kademlia, @@ -104,6 +116,7 @@ pub enum OutEvent { Pubsub(GossipsubEvent), Mdns(MdnsEvent), Kademlia(KademliaEvent), + Identify(IdentifyEvent), RequestResponse(RequestResponseEvent), } @@ -125,6 +138,12 @@ impl From for OutEvent { } } +impl From for OutEvent { + fn from(v: IdentifyEvent) -> Self { + Self::Identify(v) + } +} + impl From> for OutEvent { fn from(v: RequestResponseEvent) -> Self { Self::RequestResponse(v) From 9ae563da0c0cdd0ed4b0fa757f4da40eb46e042c Mon Sep 17 00:00:00 2001 From: Denis K Date: Tue, 28 Mar 2023 19:08:18 +0700 Subject: [PATCH 19/23] FIX: Identify behaviour --- protocol/src/network/behaviour.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/protocol/src/network/behaviour.rs b/protocol/src/network/behaviour.rs index a30ff13f7..dc5da04a5 100644 --- a/protocol/src/network/behaviour.rs +++ b/protocol/src/network/behaviour.rs @@ -41,6 +41,8 @@ use crate::{ reqres::{Request, Response}, }; +const PROTOCOL_NAME: &str = "robonomics/1.0.0"; + #[derive(NetworkBehaviour)] #[behaviour(out_event = "OutEvent")] pub struct RobonomicsNetworkBehaviour { @@ -60,7 +62,7 @@ impl RobonomicsNetworkBehaviour { ) -> Result { // Build identify network behaviour let identify = Identify::new(IdentifyConfig::new( - "/ipfs/id/1.0.0".to_string(), + PROTOCOL_NAME.to_string(), local_key.public(), )); From c1932d4c96864749c72b04b7b1280209854aa607 Mon Sep 17 00:00:00 2001 From: Denis K Date: Tue, 28 Mar 2023 20:04:48 +0700 Subject: [PATCH 20/23] FIX: heartbeat interval --- protocol/src/network.rs | 3 ++- protocol/src/network/behaviour.rs | 4 ++-- service/src/command.rs | 5 +++-- service/src/parachain.rs | 6 +++--- service/src/parachain/service.rs | 2 +- service/src/service.rs | 8 +++++--- 6 files changed, 16 insertions(+), 12 deletions(-) diff --git a/protocol/src/network.rs b/protocol/src/network.rs index baf644f92..cda42bcfb 100644 --- a/protocol/src/network.rs +++ b/protocol/src/network.rs @@ -32,6 +32,7 @@ use std::{ pin::Pin, sync::Arc, task::{Context, Poll}, + time::Duration, }; use crate::{ @@ -53,7 +54,7 @@ pub struct RobonomicsNetwork { impl RobonomicsNetwork { pub fn new( local_key: Keypair, - heartbeat_interval: u64, + heartbeat_interval: Duration, bootnodes: Vec, disable_mdns: bool, disable_kad: bool, diff --git a/protocol/src/network/behaviour.rs b/protocol/src/network/behaviour.rs index dc5da04a5..a03780738 100644 --- a/protocol/src/network/behaviour.rs +++ b/protocol/src/network/behaviour.rs @@ -56,7 +56,7 @@ impl RobonomicsNetworkBehaviour { pub fn new( local_key: Keypair, peer_id: PeerId, - heartbeat_interval: u64, + heartbeat_interval: Duration, disable_mdns: bool, disable_kad: bool, ) -> Result { @@ -68,7 +68,7 @@ impl RobonomicsNetworkBehaviour { // Set custom gossipsub let gossipsub_config = GossipsubConfigBuilder::default() - .heartbeat_interval(Duration::from_millis(heartbeat_interval)) + .heartbeat_interval(heartbeat_interval) .message_id_fn(|message: &GossipsubMessage| { // To content-address message, // we can take the hash of message and use it as an ID. diff --git a/service/src/command.rs b/service/src/command.rs index 6873ea9b1..f4c65e8cd 100644 --- a/service/src/command.rs +++ b/service/src/command.rs @@ -22,7 +22,7 @@ use crate::cli::{Cli, Subcommand}; use crate::{chain_spec::*, service::robonomics}; use robonomics_protocol::id; use sc_cli::{ChainSpec, RuntimeVersion, SubstrateCli}; -use std::path::Path; +use std::{path::Path, time::Duration}; #[cfg(feature = "discovery")] use libp2p::{ @@ -170,7 +170,8 @@ pub fn run() -> sc_cli::Result<()> { }); // Default interval 1 sec - let heartbeat_interval = cli.heartbeat_interval.unwrap_or_else(|| 1000); + let heartbeat_interval = + Duration::from_millis(cli.heartbeat_interval.unwrap_or_else(|| 1000)); match runner.config().chain_spec.family() { RobonomicsFamily::Development => runner.run_node_until_exit(|config| async move { diff --git a/service/src/parachain.rs b/service/src/parachain.rs index 8c7248469..bcd3a713c 100644 --- a/service/src/parachain.rs +++ b/service/src/parachain.rs @@ -66,7 +66,7 @@ pub mod alpha { para_id: cumulus_primitives_core::ParaId, lighthouse_account: Option, local_key: Keypair, - heartbeat_interval: u64, + heartbeat_interval: std::time::Duration, bootnodes: Vec, disable_mdns: bool, disable_kad: bool, @@ -117,7 +117,7 @@ pub mod main { para_id: cumulus_primitives_core::ParaId, lighthouse_account: Option, local_key: Keypair, - heartbeat_interval: u64, + heartbeat_interval: std::time::Duration, bootnodes: Vec, disable_mdns: bool, disable_kad: bool, @@ -167,7 +167,7 @@ pub mod ipci { para_id: cumulus_primitives_core::ParaId, lighthouse_account: Option, local_key: Keypair, - heartbeat_interval: u64, + heartbeat_interval: std::time::Duration, bootnodes: Vec, disable_mdns: bool, disable_kad: bool, diff --git a/service/src/parachain/service.rs b/service/src/parachain/service.rs index b95120593..7ae0e0faf 100644 --- a/service/src/parachain/service.rs +++ b/service/src/parachain/service.rs @@ -201,7 +201,7 @@ pub async fn start_node_impl( build_import_queue: BIQ, build_consensus: BIC, local_key: Keypair, - heartbeat_interval: u64, + heartbeat_interval: Duration, bootnodes: Vec, disable_mdns: bool, disable_kad: bool, diff --git a/service/src/service.rs b/service/src/service.rs index 7dcce8640..daa93e5c2 100644 --- a/service/src/service.rs +++ b/service/src/service.rs @@ -30,6 +30,7 @@ use sp_api::ConstructRuntimeApi; use sp_consensus_aura::sr25519::{AuthorityId as AuraId, AuthorityPair as AuraPair}; use sp_runtime::traits::{BlakeTwo256, Block as BlockT}; use std::sync::Arc; +use std::time::Duration; type FullClient = sc_service::TFullClient>; @@ -74,7 +75,7 @@ where pub fn new_partial( config: &Configuration, local_key: Keypair, - heartbeat_interval: u64, + heartbeat_interval: Duration, bootnodes: Vec, disable_mdns: bool, disable_kad: bool, @@ -230,7 +231,7 @@ where pub fn full_base( mut config: Configuration, local_key: Keypair, - heartbeat_interval: u64, + heartbeat_interval: Duration, bootnodes: Vec, disable_mdns: bool, disable_kad: bool, @@ -435,6 +436,7 @@ pub mod robonomics { use libp2p::core::identity::Keypair; use local_runtime::RuntimeApi; use sc_service::{config::Configuration, error::Result, TaskManager}; + use std::time::Duration; pub struct LocalExecutor; impl sc_executor::NativeExecutionDispatch for LocalExecutor { @@ -458,7 +460,7 @@ pub mod robonomics { pub fn new( config: Configuration, local_key: Keypair, - heartbeat_interval: u64, + heartbeat_interval: Duration, bootnodes: Vec, disable_mdns: bool, disable_kad: bool, From 894a2fd6e3433f4141601ac4e4b513b93c759c50 Mon Sep 17 00:00:00 2001 From: Denis K Date: Wed, 29 Mar 2023 17:20:39 +0700 Subject: [PATCH 21/23] ADD: network listen address, toggle pubsub --- protocol/src/network.rs | 53 ++++++++++++++++++------------- protocol/src/network/behaviour.rs | 42 ++++++++++++++---------- protocol/src/network/discovery.rs | 14 +++++--- service/src/parachain/service.rs | 10 ++++++ service/src/service.rs | 12 ++++++- 5 files changed, 87 insertions(+), 44 deletions(-) diff --git a/protocol/src/network.rs b/protocol/src/network.rs index cda42bcfb..86bab28ea 100644 --- a/protocol/src/network.rs +++ b/protocol/src/network.rs @@ -55,7 +55,9 @@ impl RobonomicsNetwork { pub fn new( local_key: Keypair, heartbeat_interval: Duration, + network_listen_address: Multiaddr, bootnodes: Vec, + disable_pubsub: bool, disable_mdns: bool, disable_kad: bool, ) -> Result<(Self, Arc)> { @@ -65,6 +67,7 @@ impl RobonomicsNetwork { local_key, peer_id, heartbeat_interval, + disable_pubsub, disable_mdns, disable_kad, )?; @@ -74,8 +77,8 @@ impl RobonomicsNetwork { })) .build(); - Swarm::listen_on(&mut swarm, "/ip4/127.0.0.1/tcp/30400".parse().unwrap())?; - discovery::add_peers(&mut swarm, bootnodes); + Swarm::listen_on(&mut swarm, network_listen_address)?; + discovery::add_peers(&mut swarm, bootnodes, disable_kad); // Create worker communication channel let (to_worker, from_service) = mpsc::unbounded::(); @@ -122,32 +125,38 @@ impl RobonomicsNetwork { topic_name: String, inbox: mpsc::UnboundedSender, ) -> Result { - let topic = Topic::new(topic_name.clone()); - self.swarm.behaviour_mut().pubsub.subscribe(&topic)?; - self.inbox.insert(topic.hash(), inbox); - log::debug!(target: "robonomics-pubsub", "Subscribed to {}", topic_name); - - Ok(true) + if let Some(pubsub) = self.swarm.behaviour_mut().pubsub.as_mut() { + let topic = Topic::new(topic_name.clone()); + pubsub.subscribe(&topic)?; + self.inbox.insert(topic.hash(), inbox); + log::debug!(target: "robonomics-pubsub", "Subscribed to {}", topic_name); + Ok(true) + } else { + Ok(false) + } } fn unsubscribe(&mut self, topic_name: String) -> Result { - let topic = Topic::new(topic_name.clone()); - self.swarm.behaviour_mut().pubsub.unsubscribe(&topic)?; - self.inbox.remove(&topic.hash()); - log::debug!(target: "robonomics-pubsub", "Unsubscribed from {}", topic_name); - - Ok(true) + if let Some(pubsub) = self.swarm.behaviour_mut().pubsub.as_mut() { + let topic = Topic::new(topic_name.clone()); + pubsub.unsubscribe(&topic)?; + self.inbox.remove(&topic.hash()); + log::debug!(target: "robonomics-pubsub", "Unsubscribed from {}", topic_name); + Ok(true) + } else { + Ok(false) + } } fn publish(&mut self, topic_name: String, message: Vec) -> Result { - let topic = Topic::new(topic_name.clone()); - self.swarm - .behaviour_mut() - .pubsub - .publish(topic.clone(), message)?; - log::debug!(target: "robonomics-pubsub", "Publish to {}", topic_name); - - Ok(true) + if let Some(pubsub) = self.swarm.behaviour_mut().pubsub.as_mut() { + let topic = Topic::new(topic_name.clone()); + pubsub.publish(topic.clone(), message)?; + log::debug!(target: "robonomics-pubsub", "Publish to {}", topic_name); + Ok(true) + } else { + Ok(false) + } } } diff --git a/protocol/src/network/behaviour.rs b/protocol/src/network/behaviour.rs index a03780738..0b0457ad4 100644 --- a/protocol/src/network/behaviour.rs +++ b/protocol/src/network/behaviour.rs @@ -47,7 +47,7 @@ const PROTOCOL_NAME: &str = "robonomics/1.0.0"; #[behaviour(out_event = "OutEvent")] pub struct RobonomicsNetworkBehaviour { pub identify: Identify, - pub pubsub: Gossipsub, + pub pubsub: Toggle, pub mdns: Toggle, pub kademlia: Toggle>, } @@ -57,6 +57,7 @@ impl RobonomicsNetworkBehaviour { local_key: Keypair, peer_id: PeerId, heartbeat_interval: Duration, + disable_pubsub: bool, disable_mdns: bool, disable_kad: bool, ) -> Result { @@ -66,23 +67,30 @@ impl RobonomicsNetworkBehaviour { local_key.public(), )); - // Set custom gossipsub - let gossipsub_config = GossipsubConfigBuilder::default() - .heartbeat_interval(heartbeat_interval) - .message_id_fn(|message: &GossipsubMessage| { - // To content-address message, - // we can take the hash of message and use it as an ID. - let mut s = DefaultHasher::new(); - message.data.hash(&mut s); - MessageId::from(s.finish().to_string()) - }) - .build()?; - // Build a gossipsub network behaviour - let pubsub = Gossipsub::new( - MessageAuthenticity::Signed(local_key.clone()), - gossipsub_config, - )?; + let pubsub = if !disable_pubsub { + log::info!("Using Pubsub."); + + // Set custom gossipsub + let gossipsub_config = GossipsubConfigBuilder::default() + .heartbeat_interval(heartbeat_interval) + .message_id_fn(|message: &GossipsubMessage| { + // To content-address message, + // we can take the hash of message and use it as an ID. + let mut s = DefaultHasher::new(); + message.data.hash(&mut s); + MessageId::from(s.finish().to_string()) + }) + .build()?; + + let pubsub = Gossipsub::new( + MessageAuthenticity::Signed(local_key.clone()), + gossipsub_config, + )?; + Toggle::from(Some(pubsub)) + } else { + Toggle::from(None) + }; // Build mDNS network behaviour let mdns = if !disable_mdns { diff --git a/protocol/src/network/discovery.rs b/protocol/src/network/discovery.rs index 28455c9fc..cd0d85602 100644 --- a/protocol/src/network/discovery.rs +++ b/protocol/src/network/discovery.rs @@ -20,7 +20,11 @@ use super::behaviour::RobonomicsNetworkBehaviour; use libp2p::{Multiaddr, PeerId, Swarm}; -pub fn add_peers(swarm: &mut Swarm, bootnodes: Vec) { +pub fn add_peers( + swarm: &mut Swarm, + bootnodes: Vec, + _disable_kad: bool, +) { for node in bootnodes { if let Ok(addr) = node.parse::() { println!("Addr: {addr}"); @@ -28,9 +32,11 @@ pub fn add_peers(swarm: &mut Swarm, bootnodes: Vec Date: Wed, 29 Mar 2023 17:38:12 +0700 Subject: [PATCH 22/23] FIX: discovery --- service/src/command.rs | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/service/src/command.rs b/service/src/command.rs index f4c65e8cd..55a88ff01 100644 --- a/service/src/command.rs +++ b/service/src/command.rs @@ -114,24 +114,36 @@ pub async fn run() -> sc_cli::Result<()> { }); let local_peer_id = PeerId::from(local_key.public()); println!("Local peer id: {local_peer_id:?}"); + let heartbeat_interval = Duration::from_millis(1000); + let disable_pubsub = false; + let disable_mdns = true; + let disable_kad = true; + let network_listen_address = "/ip4/0.0.0.0/tcp/0" + .parse() + .expect("robonomics network listen address"); let transport = libp2p::tokio_development_transport(local_key.clone()).expect("Correct transport"); - - let behaviour = RobonomicsNetworkBehaviour::new(local_key, local_peer_id, 1000, true, true) - .expect("Correct behaviour"); - + let behaviour = RobonomicsNetworkBehaviour::new( + local_key, + local_peer_id, + heartbeat_interval, + disable_pubsub, + disable_mdns, + disable_kad, + ) + .expect("Correct behaviour"); let mut swarm = SwarmBuilder::new(transport, behaviour, local_peer_id) .executor(Box::new(|fut| { tokio::spawn(fut); })) .build(); - discovery::add_peers(&mut swarm, cli.robonomics_bootnodes); + discovery::add_peers(&mut swarm, cli.robonomics_bootnodes, disable_kad); swarm - .listen_on("/ip4/0.0.0.0/tcp/0".parse().unwrap()) - .expect("Swarm listen"); + .listen_on(network_listen_address) + .expect("swarm listen"); loop { tokio::select! { From 4bfaa9975c0ea7f4278ae24fa917fc6bac223ff7 Mon Sep 17 00:00:00 2001 From: Denis K Date: Wed, 29 Mar 2023 18:02:10 +0700 Subject: [PATCH 23/23] FIX: example --- protocol/examples/ros/src/main.rs | 58 +++++++++++++++++++------------ 1 file changed, 36 insertions(+), 22 deletions(-) diff --git a/protocol/examples/ros/src/main.rs b/protocol/examples/ros/src/main.rs index dc876c0e1..687186b9b 100644 --- a/protocol/examples/ros/src/main.rs +++ b/protocol/examples/ros/src/main.rs @@ -5,7 +5,7 @@ use libp2p::{ swarm::{SwarmBuilder, SwarmEvent}, Multiaddr, PeerId, }; -use std::{env, error::Error}; +use std::{env, error::Error, time::Duration}; use tokio::io::{self, AsyncBufReadExt}; use robonomics_protocol::network::behaviour::{OutEvent, RobonomicsNetworkBehaviour}; @@ -17,18 +17,28 @@ async fn main() -> Result<(), Box> { let local_peer_id = PeerId::from(local_key.public()); println!("Local peer id: {local_peer_id}"); + // Set params + let heartbeat_interval = Duration::from_millis(1000); + let disable_pubsub = false; + let disable_mdns = true; + let disable_kad = true; + let network_listen_address = "/ip4/0.0.0.0/tcp/0" + .parse() + .expect("network listen address"); + // Set up an encrypted DNS-enabled TCP Transport over the Mplex protocol let transport = libp2p::tokio_development_transport(local_key.clone())?; // Create robonomics network behaviour - let mut behaviour = RobonomicsNetworkBehaviour::new(local_key, local_peer_id, 1000, true, true) - .expect("Correct behaviour"); - - // Create topic - let topic = Topic::new("ROS"); - - // Subscribe to topic - behaviour.pubsub.subscribe(&topic)?; + let behaviour = RobonomicsNetworkBehaviour::new( + local_key, + local_peer_id, + heartbeat_interval, + disable_pubsub, + disable_mdns, + disable_kad, + ) + .expect("Correct behaviour"); // Create swarm let mut swarm = SwarmBuilder::new(transport, behaviour, local_peer_id) @@ -37,14 +47,24 @@ async fn main() -> Result<(), Box> { })) .build(); + // Create topic + let topic = Topic::new("ROS"); + + // Subscribe to topic + if let Some(pubsub) = swarm.behaviour_mut().pubsub.as_mut() { + pubsub.subscribe(&topic)?; + } + // Add nodes if let Some(to_dial) = env::args().nth(1) { let addr: Multiaddr = to_dial.parse()?; swarm.dial(addr.clone())?; - println!("Dialed {to_dial:?}"); - if let Some(peer) = PeerId::try_from_multiaddr(&addr) { - swarm.behaviour_mut().pubsub.add_explicit_peer(&peer); + // Add node to pubsub swarm + if let Some(pubsub) = swarm.behaviour_mut().pubsub.as_mut() { + if let Some(peer) = PeerId::try_from_multiaddr(&addr) { + pubsub.add_explicit_peer(&peer); + } } } @@ -52,21 +72,15 @@ async fn main() -> Result<(), Box> { let mut stdin = io::BufReader::new(io::stdin()).lines(); // Listen on all interfaces and whatever port the OS assigns - swarm.listen_on("/ip4/0.0.0.0/tcp/0".parse()?)?; + swarm.listen_on(network_listen_address)?; println!("Enter messages via STDIN and they will be sent to connected peers using Pubsub"); loop { tokio::select! { line = stdin.next_line() => { - match swarm - .behaviour_mut() - .pubsub - .publish(topic.clone(), line.expect("Stdin not to close").expect("").as_bytes()) { - Ok(mid) => - println!("Message id: {mid:?}"), - Err(e) => - println!("Publish error: {e:?}"), + if let Some(pubsub) = swarm.behaviour_mut().pubsub.as_mut() { + pubsub.publish(topic.clone(), line.expect("Stdin not to close").expect("").as_bytes())?; } }, event = swarm.select_next_some() => match event { @@ -78,7 +92,7 @@ async fn main() -> Result<(), Box> { "Got message: '{}' with id: {id} from peer: {peer_id}", String::from_utf8_lossy(&message.data), ), - event => println!("event: {event:?}"), + _ => {}, } } }