Using the P2P Networking Utilities
SDK source (GitHub): https://github.com/tangle-network/blueprint/tree/v2/crates/networking
To spin up a P2P network, build a NetworkConfig and start a NetworkService. The service spawns its event loop and
returns a NetworkServiceHandle you can clone into jobs and background services.
Example
use blueprint_sdk::crypto::k256::K256Ecdsa;
use blueprint_sdk::networking::{AllowedKeys, NetworkConfig, NetworkService};
use blueprint_sdk::networking::types::MessageRouting;
use libp2p::identity::Keypair;
use std::collections::HashSet;
use std::time::Duration;
async fn example_usage() -> Result<(), blueprint_sdk::networking::error::Error> {
let instance_key_pair = K256Ecdsa::generate_with_seed(None).expect("instance key");
let local_key = Keypair::generate_ed25519();
let listen_addr = "/ip4/0.0.0.0/tcp/0".parse().expect("multiaddr");
let config = NetworkConfig::<K256Ecdsa> {
network_name: "my-blueprint".to_string(),
instance_id: "service-1".to_string(),
instance_key_pair: instance_key_pair.clone(),
local_key,
listen_addr,
target_peer_count: 10,
bootstrap_peers: vec![],
enable_mdns: true,
enable_kademlia: true,
using_evm_address_for_handshake_verification: false,
};
let mut allowed = HashSet::new();
allowed.insert(K256Ecdsa::public_from_secret(&instance_key_pair));
let (allowed_keys_tx, allowed_keys_rx) = crossbeam_channel::unbounded();
let service = NetworkService::new(
config,
AllowedKeys::InstancePublicKeys(allowed),
allowed_keys_rx,
)?;
let mut handle = service.start();
// Optional: update the whitelist later.
// allowed_keys_tx.send(AllowedKeys::InstancePublicKeys(updated_set)).ok();
let routing = MessageRouting {
message_id: 1,
round_id: 0,
sender: handle.local_peer_id,
recipient: None,
};
handle
.send(routing, b"hello from a blueprint".to_vec())
.expect("send message");
loop {
if let Some(message) = handle.next_protocol_message() {
println!("Received: {:?}", message);
}
tokio::time::sleep(Duration::from_millis(100)).await;
}
}If you prefer to verify handshakes using EVM addresses, set using_evm_address_for_handshake_verification: true and use
AllowedKeys::EvmAddresses with the operator address set for the service.
Integrating Networking with Blueprint Contexts
Store the NetworkServiceHandle inside your context so job handlers and background services can send or receive messages:
use blueprint_sdk::crypto::k256::K256Ecdsa;
use blueprint_sdk::networking::NetworkServiceHandle;
use blueprint_sdk::{Router, tangle_evm::TangleEvmLayer};
#[derive(Clone)]
struct P2pContext {
network: NetworkServiceHandle<K256Ecdsa>,
}
let context = P2pContext {
network: handle.clone(),
};
let router = Router::new()
.route(MY_JOB_ID, my_job.layer(TangleEvmLayer))
.with_context(context);Round-Based Protocols
round-based is a library for building structured round-based protocols (especially MPC). The SDK ships a compatibility
layer in the blueprint-networking-round-based-extension crate.
use blueprint_networking_round_based_extension::RoundBasedNetworkAdapter;
use blueprint_sdk::crypto::k256::K256Ecdsa;
use libp2p::PeerId;
use round_based::{PartyIndex, party::MpcParty};
use std::collections::HashMap;
let parties: HashMap<PartyIndex, PeerId> = /* map your party indices to peer IDs */;
let adapter = RoundBasedNetworkAdapter::<MyMsg, K256Ecdsa>::new(
handle.clone(),
my_index,
&parties,
"my/protocol",
);
let party = MpcParty::connected(adapter);MyMsg should implement round_based::ProtocolMessage and be Serialize/Deserialize so it can be encoded over the wire.