Skip to content

Commit

Permalink
Write docs
Browse files Browse the repository at this point in the history
  • Loading branch information
Alex6323 committed Nov 5, 2021
1 parent 28f8d5a commit 6763d69
Show file tree
Hide file tree
Showing 14 changed files with 298 additions and 63 deletions.
104 changes: 103 additions & 1 deletion bee-autopeering/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,105 @@
# bee-autopeering

Allows peers to mutually discover each other automatically.
A system that allows peers in the same IOTA network to automatically discover each other.

## Example

In order to integrate the Autopeering functionality in your node implementation you need to provide the following things to its `init` function:
* an `AutopeeringConfig`;
* a protocol version (`u32`);
* a network name, e.g. "chrysalis-mainnet";
* a `Local` entity (either randomly created or from an `Ed25519` keypair), that additionally announces one or more services;
* a shutdown signal (`Future`);
* a peer store, e.g. the `InMemoryPeerStore` (non-persistent) or the `SledPeerStore` (persistent), or a custom peer store implementing the `PeerStore` trait;

```rust

use bee_autopeering::{
init,
peerstore::{SledPeerStore, SledPeerStoreConfig},
AutopeeringConfig, Event, Local, NeighborValidator, Peer, ServiceProtocol, AUTOPEERING_SERVICE_NAME,
};

// An example autopeering config in JSON format:
fn read_config() -> AutopeeringConfig {
let config_json = r#"
{
"bindAddress": "0.0.0.0:14627",
"entryNodes": [
"/dns/entry-hornet-0.h.chrysalis-mainnet.iotaledger.net/udp/14626/autopeering/iotaPHdAn7eueBnXtikZMwhfPXaeGJGXDt4RBuLuGgb",
"/dns/entry-hornet-1.h.chrysalis-mainnet.iotaledger.net/udp/14626/autopeering/iotaJJqMd5CQvv1A61coSQCYW9PNT1QKPs7xh2Qg5K2",
],
"entryNodesPreferIPv6": false,
"runAsEntryNode": false
}"#;

serde_json::from_str(config_json).expect("error deserializing json config")
}

#[tokio::main]
async fn main() {
// Peers will only accept each other as peer if they agree on the protocol version and the
// network name.
const VERSION: u32 = 1;
const NETWORK: &str = "chrysalis-mainnet";

// Read the config from a JSON file/string.
let config = read_config();

// Create a random local entity, that announces two services:
let local = {
let l = Local::default();
let mut write = l.write();
write.add_service(AUTOPEERING_SERVICE_NAME, ServiceProtocol::Udp, config.bind_addr.port());
write.add_service(NETWORK, ServiceProtocol::Tcp, 15600);
l
}

// You can choose between the `InMemoryPeerStore` (non-persistent) and the `SledPeerStore`
// (persistent).
let peerstore_config = SledPeerStoreConfig::new().path("./peerstore");

// The `NeighborValidator` allows you to customize the peer selection.
let neighbor_validator = GossipNeighborValidator {};

// We need to provide a shutdown signal (can basically be any `Future`).
let term_signal = tokio::signal::ctrl_c();

// Initialize the autopeering functionality.
let mut event_rx = bee_autopeering::init::<SledPeerStore, _, _, GossipNeighborValidator>(
config.clone(),
VERSION,
NETWORK,
local,
peerstore_config,
term_signal,
neighbor_validator,
)
.await
.expect("initializing autopeering system failed");

// Process autopeering events.
loop {
tokio::select! {
e = event_rx.recv() => {
if let Some(event) = e {
// handle the event
// process(event);
} else {
break;
}
}
};
}
}

#[derive(Clone)]
struct GossipNeighborValidator {}

impl NeighborValidator for GossipNeighborValidator {
fn is_valid(&self, peer: &Peer) -> bool {
peer.has_service(NETWORK)
}
}

```
10 changes: 8 additions & 2 deletions bee-autopeering/src/config.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
// Copyright 2021 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

//! Autopeering configuration.
use crate::multiaddr::AutopeeringMultiaddr;

use serde::{Deserialize, Serialize};

use std::net::SocketAddr;

#[rustfmt::skip]
// We adhere to Hornet's autopeering config:
//
// ```json
// "autopeering": {
// "bindAddress": "0.0.0.0:14626",
Expand All @@ -25,17 +25,23 @@ use std::net::SocketAddr;
// }
// ```

///
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(rename = "autopeering")]
pub struct AutopeeringConfig {
/// The bind address for the server.
#[serde(rename = "bindAddress")]
pub bind_addr: SocketAddr,
/// The entry nodes for bootstrapping.
#[serde(rename = "entryNodes")]
pub entry_nodes: Vec<AutopeeringMultiaddr>,
/// Whether `Ipv4` or `Ipv6` should be preferred in case a hostname supports both.
#[serde(rename = "entryNodesPreferIPv6")]
pub entry_nodes_prefer_ipv6: bool,
/// Whether the node should run as an entry node.
#[serde(rename = "runAsEntryNode")]
pub run_as_entry_node: bool,
/// Whether all neighbors should be disconnected from when the salts are updated.
#[serde(rename = "dropNeighborsOnSaltUpdate", default)]
pub drop_neighbors_on_salt_update: bool,
}
4 changes: 2 additions & 2 deletions bee-autopeering/src/discovery/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::{
discovery::messages::{DiscoveryRequest, DiscoveryResponse, VerificationRequest, VerificationResponse},
event::{Event, EventTx},
local::{
services::{ServiceMap, ServicePort, ServiceTransport, AUTOPEERING_SERVICE_NAME},
services::{ServiceMap, ServicePort, ServiceProtocol, AUTOPEERING_SERVICE_NAME},
Local,
},
multiaddr::{AddressKind, AutopeeringMultiaddr},
Expand Down Expand Up @@ -465,7 +465,7 @@ async fn add_master_peers(
};

let mut peer = Peer::new(entry_socketaddr.ip(), entry_addr.public_key().clone());
peer.add_service(AUTOPEERING_SERVICE_NAME, ServiceTransport::Udp, entry_socketaddr.port());
peer.add_service(AUTOPEERING_SERVICE_NAME, ServiceProtocol::Udp, entry_socketaddr.port());

let peer_id = peer.peer_id().clone();

Expand Down
4 changes: 4 additions & 0 deletions bee-autopeering/src/event.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright 2021 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

//! Events published to the user.
use crate::{
peer::{Peer, PeerId},
peering::{manager::Status, neighbor::Distance},
Expand All @@ -25,7 +27,9 @@ pub enum Event {
},
/// A SaltUpdated event is triggered, when the private and public salt were updated.
SaltUpdated {
/// Lifetime of the public salt.
public_salt_lifetime: u64,
/// Lifetime of the private salt.
private_salt_lifetime: u64,
},
/// An OutgoingPeering event is triggered, when a valid response of PeeringRequest has been received.
Expand Down
2 changes: 2 additions & 0 deletions bee-autopeering/src/init.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright 2021 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

//! Autopeering initialization.
use crate::{
command::{Command, CommandTx},
config::AutopeeringConfig,
Expand Down
106 changes: 103 additions & 3 deletions bee-autopeering/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,109 @@
// Copyright 2021 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

//! Autopeering implementation for the Bee framework.
//! A system that allows peers in the same IOTA network to automatically discover each other.
//! ## Example
//!
//! In order to integrate the Autopeering functionality in your node implementation you need to provide the following things to its `init` function:
//! * an `AutopeeringConfig`;
//! * a protocol version (`u32`);
//! * a network name, e.g. "chrysalis-mainnet";
//! * a `Local` entity (either randomly created or from an `Ed25519` keypair), that additionally announces one or more services;
//! * a shutdown signal (`Future`);
//! * a peer store, e.g. the `InMemoryPeerStore` (non-persistent) or the `SledPeerStore` (persistent), or a custom peer store implementing the `PeerStore` trait;
//!
//!```rust
//! use bee_autopeering::{
//! init,
//! peerstore::{SledPeerStore, SledPeerStoreConfig},
//! AutopeeringConfig, Event, Local, NeighborValidator, Peer, ServiceProtocol, AUTOPEERING_SERVICE_NAME,
//! };
// #![warn(missing_docs)]
//! // An example autopeering config in JSON format:
//! fn read_config() -> AutopeeringConfig {
//! let config_json = r#"
//! {
//! "bindAddress": "0.0.0.0:14627",
//! "entryNodes": [
//! "/dns/entry-hornet-0.h.chrysalis-mainnet.iotaledger.net/udp/14626/autopeering/iotaPHdAn7eueBnXtikZMwhfPXaeGJGXDt4RBuLuGgb",
//! "/dns/entry-hornet-1.h.chrysalis-mainnet.iotaledger.net/udp/14626/autopeering/iotaJJqMd5CQvv1A61coSQCYW9PNT1QKPs7xh2Qg5K2",
//! ],
//! "entryNodesPreferIPv6": false,
//! "runAsEntryNode": false
//! }"#;
//!
//! serde_json::from_str(config_json).expect("error deserializing json config")
//! }
//! #[tokio::main]
//! async fn main() {
//! // Peers will only accept each other as peer if they agree on the protocol version and the
//! // network name.
//! const VERSION: u32 = 1;
//! const NETWORK: &str = "chrysalis-mainnet";
//!
//! // Read the config from a JSON file/string.
//! let config = read_config();
//!
//! // Create a random local entity, that announces two services:
//! let local = {
//! let l = Local::default();
//! let mut write = l.write();
//! write.add_service(AUTOPEERING_SERVICE_NAME, ServiceProtocol::Udp, config.bind_addr.port());
//! write.add_service(NETWORK, ServiceProtocol::Tcp, 15600);
//! l
//! }
//!
//! // You can choose between the `InMemoryPeerStore` (non-persistent) and the `SledPeerStore`
//! // (persistent).
//! let peerstore_config = SledPeerStoreConfig::new().path("./peerstore");
//!
//! // The `NeighborValidator` allows you to customize the peer selection.
//! let neighbor_validator = GossipNeighborValidator {};
//!
//! // We need to provide a shutdown signal (can basically be any `Future`).
//! let term_signal = tokio::signal::ctrl_c();
//!
//! // Initialize the autopeering functionality.
//! let mut event_rx = bee_autopeering::init::<SledPeerStore, _, _, GossipNeighborValidator>(
//! config.clone(),
//! VERSION,
//! NETWORK,
//! local,
//! peerstore_config,
//! term_signal,
//! neighbor_validator,
//! )
//! .await
//! .expect("initializing autopeering system failed");
//!
//! // Process autopeering events.
//! loop {
//! tokio::select! {
//! e = event_rx.recv() => {
//! if let Some(event) = e {
//! // handle the event
//! // process(event);
//! } else {
//! break;
//! }
//! }
//! };
//! }
//! }
//!
//! #[derive(Clone)]
//! struct GossipNeighborValidator {}
//!
//! impl NeighborValidator for GossipNeighborValidator {
//! fn is_valid(&self, peer: &Peer) -> bool {
//! peer.has_service(NETWORK)
//! }
//! }
//!
//! ```
#![deny(missing_docs)]
#![allow(warnings)]

mod command;
Expand Down Expand Up @@ -32,7 +132,7 @@ pub use event::Event;
pub use init::init;
pub use local::services::AUTOPEERING_SERVICE_NAME;
pub use local::{
services::{ServiceMap, ServiceName, ServiceTransport},
services::{ServiceMap, ServiceName, ServiceProtocol},
Local,
};
pub use peer::{peer_id, peer_id::PeerId, peerstore, Peer};
Expand Down
16 changes: 12 additions & 4 deletions bee-autopeering/src/local/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ pub(crate) mod salt;
pub mod services;

use salt::Salt;
use services::{ServiceMap, ServiceTransport};
use services::{ServiceMap, ServiceProtocol};

use crate::{
delay::DelayFactory,
Expand All @@ -30,7 +30,12 @@ use std::{

use self::salt::SALT_LIFETIME_SECS;

/// A type that represents a local identity - able to sign outgoing messages.
/// Represents a local entity.
///
/// It allows:
/// * message signing and verification;
/// * neighbor distance calculation;
/// * service announcements;
#[derive(Clone, Default)]
pub struct Local {
inner: Arc<RwLock<LocalInner>>,
Expand All @@ -50,6 +55,7 @@ impl Local {
Self::default()
}

/// Creates a local identity from an ED25519 keypair.
pub fn from_keypair(keypair: Keypair) -> Self {
let private_key_bytes: [u8; SECRET_KEY_LENGTH] = keypair
.secret()
Expand Down Expand Up @@ -97,10 +103,12 @@ impl Local {
}
}

/// Provides read access to the inner value.
pub fn read(&self) -> RwLockReadGuard<LocalInner> {
self.inner.read().expect("error getting read access")
}

/// Provides write access to the inner value.
pub fn write(&self) -> RwLockWriteGuard<LocalInner> {
self.inner.write().expect("error getting write access")
}
Expand Down Expand Up @@ -143,8 +151,8 @@ impl LocalInner {
}

/// Adds a service to this local peer.
pub fn add_service(&mut self, service_name: impl ToString, transport: ServiceTransport, port: u16) {
self.services.insert(service_name, transport, port)
pub fn add_service(&mut self, service_name: impl ToString, protocol: ServiceProtocol, port: u16) {
self.services.insert(service_name, protocol, port)
}

/// Returns the list of services this identity supports.
Expand Down
Loading

0 comments on commit 6763d69

Please sign in to comment.