Module swarm_nl::core

source ·
Expand description

Core data structures and protocol implementations for building a swarm.

§Network builder

To build a network or a node, you first need to create a CoreBuilder object using the CoreBuilder::with_config method to create a bootstrap node, then you can simply call CoreBuilder::build to set up the network. This will create a Core struct with methods you can use to send and receive data to/from the network.

The CoreBuilder::with_config method takes two parameters:

  1. BootstrapConfig to pass in a bootstrap node configuration.
  2. EventHandler to respond to network events.

§Default setup

Here’s how you would build a bootstrap node with the default library settings, using a DefaultHandler struct to respond to network events:

// Default config
let config = BootstrapConfig::default();
// Default Handler
let handler = DefaultHandler;
let mut network = CoreBuilder::with_config(config, handler)
	.build()
	.await
	.unwrap();

§Custom event handler

To customize how your application handles network events, you’ll need to implement the methods from EventHandler. It’s best to implement EventHandler on your application’s state. This allows you to:

  • make critical state changes in response to network events.
  • log state data at different point during network event changes.
use swarm_nl::core::EventHandler;

#[derive(Clone)]
struct ApplicationState {
	name: String,
	version: f32,
}

impl EventHandler for ApplicationState {
	async fn new_listen_addr(
		&mut self,
		local_peer_id: PeerId,
		listener_id: swarm_nl::ListenerId,
		addr: swarm_nl::Multiaddr,
	) {
		// Announce interfaces we're listening on
		println!("Peer id: {}", local_peer_id);
		println!("We're listening on the {}", addr);
		println!(
			"Connected to {}, current version: {} ",
			self.name, self.version
		);
	}

	// Echo data recieved from a RPC
	fn rpc_handle_incoming_message(&mut self, data: Vec<Vec<u8>>) -> Vec<Vec<u8>> {
		println!("Recvd incoming RPC: {:?}", data);
		data
	}

	// Handle the incoming gossip message
	fn gossipsub_handle_incoming_message(&mut self, source: PeerId, data: Vec<String>) {
		println!("Recvd incoming gossip: {:?}", data);
	}
}

§Overriding the default network configuration

You can explicitly overrride the default values of CoreBuilder::with_config by calling the methods like the following before building the network:

For example:

		// Default config
		let config = BootstrapConfig::default();
		// Default handler
		let handler = DefaultHandler;

		// Create a default network core builder
		let default_node = CoreBuilder::with_config(config, handler);

		// Override default with custom configurations
		// Network Id
		let mut custom_network_id = "/custom-protocol/1.0".to_string();		
		// Transport
		let mut custom_transport = TransportOpts::TcpQuic {		
			tcp_config: TcpConfig::Custom {
				ttl: 10,
				nodelay: true,
				backlog: 10,
			},
		};
		// Keep-alive	
		let mut custom_keep_alive_duration = 20;	
		// IP address
		let mut custom_ip_address = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));	

		// Build a custom configured node
		let custom_node = default_node
			.with_network_id(custom_network_id.clone())
			.with_transports(custom_transport.clone())
			.with_idle_connection_timeout(custom_keep_alive_duration.clone())
			.listen_on(custom_ip_address.clone())
			.build()
			.await.
			.unwrap();

§Application Interaction

The core library provides very simple interfaces to communicate with the network layer to trigger and drive network behaviour or to make enquiries about internal network state. This is achieved by constructing a request with the AppData struct and passing it to the network. An AppResponse structure is returned, containing the network’s response to the applications request.
There are two ways of querying the network layer with each having its own peculiarities and use-cases:

  • Using the Core::query_network() method: This method aims to complete its operations atomically and blocks until the network returns a reponse or if the request times out. It is useful when the response from the network is important for the application logic to continue.
    // Default config
    let config = BootstrapConfig::default();
    // Default handler
    let handler = DefaultHandler;

    // Create a default network core builder
    let node = CoreBuilder::with_config(config, handler);

    // Join a network (subscribe to a topic)
    let gossip_request = AppData::GossipsubJoinNetwork(MY_NETWORK.to_string());

    // Blocks until response is returned from the network layer
    if let Ok(_) = node.query_network(gossip_request).await {
        println!("Subscription successfull");
    }
  • Using the Core::send_to_network() and Core::recv_from_network() method: This method does not block and is split into two parts - sending and recieving. When the request is recieved by the network layer through the Core::send_to_network() method, a StreamId is immediately returned and the request is handled. When there is a response (or a timeout), it is stored internally in a response buffer until it is returned by explicitly polling the network through the Core::recv_from_network() method which takes in the StreamId returned earlier. The StreamId helps to track the requests and their corresponding responses internally in the network layer.
    // Default config
    let config = BootstrapConfig::default();
    // Default handler
    let handler = DefaultHandler;

    // Create a default network core builder
    let node = CoreBuilder::with_config(config, handler);

    // Join a network (subscribe to a topic)
    let gossip_request = AppData::GossipsubJoinNetwork(MY_NETWORK.to_string());

    // Send request to the application layer
    let stream_id = node.send_to_network(gossip_request).await.unwrap();

    // ...
    // Run other application logic
    //...

    // Explicitly retrieve the response of our request
    if let Ok(result) = node.recv_from_network(stream_id).await {
        println!("Subscription successfull");
        assert_eq!(AppResponse::GossipsubJoinSuccess, result);
    }

Note: The internal buffer is limited in capacity and pending responses should be removed as soon as possibe. A full buffer will prevent the network from recieving more requests.

Modules§

  • Module that contains important data structures to manage Ping operations on the network.

Structs§

  • The core interface for the application layer to interface with the networking layer.
  • Structure containing necessary data to build Core.
  • Default network event handler.
  • The configuration for the RPC protocol.
  • A simple struct used to track requests sent from the application layer to the network layer.

Enums§

  • Request sent from the application layer to the networking layer.
  • Response to requests sent from the application to the network layer.
  • Network error type containing errors encountered during network operations.

Constants§

  • The duration (in seconds) to wait for response from the network layer before timing out.
  • The time it takes for the task to sleep before it can recheck if an output has been placed in the repsonse buffer;

Traits§

  • The high level trait that provides an interface for the application layer to respond to network events.

Type Aliases§

  • Type that contains the result of querying the network layer.