-
Notifications
You must be signed in to change notification settings - Fork 60
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #47 from iotaledger/feat-p2p
Feat p2p
- Loading branch information
Showing
17 changed files
with
2,382 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
--- | ||
"stronghold-communication": minor | ||
--- | ||
Introduction of the libp2p communication subsystem for Stronghold. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,29 @@ | ||
[package] | ||
name = "stronghold-communication" | ||
version = "0.1.0" | ||
authors = ["Daniel Thompson-Yvetot <daniel.yvetot@iota.org>"] | ||
authors = ["Elena Frank <elena.frank@iota.org>"] | ||
edition = "2018" | ||
license = "Apache-2.0" | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
readme = "README.md" | ||
|
||
[dependencies] | ||
async-std = "1.6.2" | ||
async-trait = "0.1.40" | ||
bytes = "0.5.6" | ||
clap = { version = "3.0.0-beta.1", features = ["yaml"] } | ||
futures = "0.3.1" | ||
libp2p = {version = "0.28.1", default-features = false, features = ["dns", "identify", "mdns-async-std", "mplex", "noise", "request-response", "tcp-async-std", "yamux", "websocket"]} | ||
prost = {version = "0.6.1", default-features = false, features = ["prost-derive"] } | ||
regex = "1.3.9" | ||
thiserror = "1.0.21" | ||
serde = { version = "1.0.117", default-features = false, features = ["alloc", "derive"] } | ||
serde_json = { version = "1.0.59", default-features = false, features = ["alloc"] } | ||
riker = "0.4" | ||
|
||
[features] | ||
default = ["mdns"] | ||
|
||
mdns = [] | ||
|
||
[build-dependencies] | ||
prost-build = "0.6.1" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
## Introduction | ||
|
||
This library enables strongholds on different devices and in different networks to communicate with each other. | ||
The main basis for its functionality is the [rust-libp2p](https://github.com/libp2p/rust-libp2p) library, which is a system of protocols, specifications and | ||
libraries that enable the development of peer-to-peer network applications (https://libp2p.io/). | ||
|
||
Libp2p was originally the network protocol of IPFS and has evolved into a modular system with implementations in | ||
Node.js, Go and Rust. It is important to note that at the current status, the Rust implementation doesn't have all features | ||
yet and especially peer discovery in different networks, NAT Traversal and Firewalls pose a problem that we solved | ||
for stronghold by using a mailbox concept that is described later. | ||
|
||
## Transport and the Swarm | ||
|
||
Libp2p uses the `transport` as the lowest layer, that is responsible for sending and receiving data over a network. | ||
The current rust implementation supports tcp and websockets, and apart from that provides the option to upgrade a | ||
connection with protocols for multiplexing and authentication. | ||
|
||
The second important concept of libp2p is its `Swarm` (in newer implementations and documents also called `Switch`). | ||
The swarm is responsible for negotiating protocols, managing transports and sending and receiving messages via different | ||
protocols. It is possible to combine different protocols into a so called `NetworkBehaviour`, which is what this library is doing. | ||
Stronghold-communication uses multicast DNS (mDNS) for peer discovery in a local network and the RequestResponse protocol in order to send / receive | ||
custom messages and parse them. | ||
|
||
## Multiplexing and Noise-encryption | ||
|
||
The transport of stronghold-communication is upgraded with yamux for multiplexing and the noise protocol, this noise protocol uses the XX-Handshake and ensures authentification and encryption. | ||
|
||
## Stronghold-Communication | ||
|
||
Similar to the swarm in libp2p, the stronghold-communication creates the `P2PNetworkBehaviour` struct that manages sending messages and reacting upon the outcome of the operation. | ||
Upon creating a new instance, a transport is created and upgraded, and combined with a the P2PNetworkBehaviour into a ExpandedSwarm. This Swarm is returned to the caller and serves as entrypoint for all communication to other peers. It implements methods for listening to the swarm, sending outbound messages, and manually adding and dialing peers. Incoming `P2PEvent` can be handled by polling from the swarm, e.g. via the `poll_next_unpin` method. | ||
Due to libp2ps concept of `multiaddresses`, the swarm has multiple listening addresses that encode different addressing schemes for different | ||
protocols. Apart from IPv4 and IPv6 Addresses, these multiaddresses can also be dns addresses, which is relevant if a peer is listening | ||
to such an address on a server. The listed multiaddresses are only the ones within the same local network, but if port forwarding was configured, | ||
the local /ip4/my-local-address/tcp/12345 Address can be replaced by the public one or by `/dns/my.public.server.address/tcp/12345`, where the | ||
`/tcp/12345` part describes the port. | ||
|
||
## Mailbox Concept | ||
|
||
Since not all peers can be dialed directly e.g. because they are behind a firewall, stronghold-communication includes methods for using | ||
a mailbox. The mailbox is a peer running on a server with public IP Address that can be reached by all other peers. If can be | ||
used to deposit records for unavailable remote peers by sending a `Request::PutRecord` message with the record to the mailbox, and that can then return the Records to remote peers upon receiving a `Request::GetRecord` request. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
[log] | ||
level = "info" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
# Copyright 2020 IOTA Stiftung | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
FROM rust:latest as build | ||
RUN USER=root cargo new --bin stronghold-communication | ||
WORKDIR /stronghold-communication | ||
|
||
COPY ./Cargo.toml ./Cargo.toml | ||
|
||
# cache dependencies | ||
RUN cargo build --release | ||
RUN rm src/*.rs | ||
COPY ./src ./src | ||
COPY ./examples ./examples | ||
RUN cargo clean | ||
|
||
# build mailbox | ||
RUN cargo build --example mailbox | ||
FROM rust:latest | ||
WORKDIR /app | ||
|
||
# copy the build artifact from the build stage | ||
COPY --from=build /stronghold-communication/target/debug/examples/mailbox . | ||
ENTRYPOINT ["/app/mailbox"] | ||
CMD ["start-mailbox"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
// Copyright 2020 IOTA Stiftung | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
use core::time::Duration; | ||
use libp2p::core::identity::Keypair; | ||
use riker::actors::*; | ||
use serde::{Deserialize, Serialize}; | ||
use stronghold_communication::{ | ||
actor::{CommunicationActor, CommunicationEvent}, | ||
behaviour::message::P2PReqResEvent, | ||
}; | ||
|
||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] | ||
pub enum Request { | ||
Ping, | ||
} | ||
|
||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] | ||
pub enum Response { | ||
Pong, | ||
} | ||
|
||
struct TestActor { | ||
chan: ChannelRef<CommunicationEvent<Request, Response>>, | ||
} | ||
|
||
impl ActorFactoryArgs<ChannelRef<CommunicationEvent<Request, Response>>> for TestActor { | ||
fn create_args(chan: ChannelRef<CommunicationEvent<Request, Response>>) -> Self { | ||
TestActor { chan } | ||
} | ||
} | ||
|
||
impl Actor for TestActor { | ||
type Msg = CommunicationEvent<Request, Response>; | ||
|
||
fn pre_start(&mut self, ctx: &Context<Self::Msg>) { | ||
let topic = Topic::from("from_swarm"); | ||
let sub = Box::new(ctx.myself()); | ||
self.chan.tell(Subscribe { actor: sub, topic }, None); | ||
} | ||
|
||
fn recv(&mut self, ctx: &Context<Self::Msg>, msg: Self::Msg, _sender: Sender) { | ||
println!("{}: -> got msg: {:?}", ctx.myself.name(), msg); | ||
if let CommunicationEvent::Message(P2PReqResEvent::Req { | ||
peer_id, | ||
request_id: Some(request_id), | ||
request: Request::Ping, | ||
}) = msg | ||
{ | ||
let response = CommunicationEvent::Message(P2PReqResEvent::Res { | ||
peer_id, | ||
request_id, | ||
response: Response::Pong, | ||
}); | ||
self.chan.tell( | ||
Publish { | ||
msg: response, | ||
topic: Topic::from("to_swarm"), | ||
}, | ||
None, | ||
); | ||
} | ||
} | ||
} | ||
|
||
fn main() { | ||
let local_keys = Keypair::generate_ed25519(); | ||
let sys = ActorSystem::new().unwrap(); | ||
let chan: ChannelRef<CommunicationEvent<Request, Response>> = channel("p2p", &sys).unwrap(); | ||
sys.actor_of_args::<CommunicationActor<Request, Response>, _>( | ||
"communication-actor", | ||
(local_keys, chan.clone(), None), | ||
) | ||
.unwrap(); | ||
sys.actor_of_args::<TestActor, _>("test-actor", chan).unwrap(); | ||
std::thread::sleep(Duration::from_secs(600)); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
name: Communication CLI | ||
version: '1.0' | ||
author: Elena Frank <elena.frank@iota.org> | ||
about: Encrypts data into the Engine Vault. Creates snapshots and can load from snapshots. | ||
subcommands: | ||
- start-mailbox: | ||
about: Start a mailbox that publishes records in kademlia upon receiving them in a request | ||
args: | ||
- port: | ||
short: p | ||
long: port | ||
value_name: listening-port | ||
about: the listening port for the peer, default is 16384 | ||
required: false | ||
takes_value: true | ||
- put-mailbox: | ||
about: Put record into the mailbox | ||
args: | ||
- mailbox_addr: | ||
short: a | ||
long: mail-addr | ||
value_name: mailbox-multi-addr | ||
about: the multiaddr of the mailbox | ||
required: true | ||
takes_value: true | ||
- key: | ||
short: k | ||
long: key | ||
value_name: record-key | ||
about: the key for the record | ||
required: true | ||
takes_value: true | ||
- value: | ||
short: v | ||
long: value | ||
value_name: record-value | ||
about: the value for the record | ||
required: true | ||
takes_value: true | ||
- get-record: | ||
about: Get record from local or the mailbox | ||
args: | ||
- mailbox_addr: | ||
short: a | ||
long: mail-addr | ||
value_name: mailbox-multi-addr | ||
about: the multi-address of the mailbox | ||
required: true | ||
takes_value: true | ||
- key: | ||
short: k | ||
long: key | ||
value_name: record-key | ||
about: the key for the record | ||
required: true | ||
takes_value: true |
Oops, something went wrong.