MCPcopy Index your code
hub / github.com/algorealmInc/SwarmNL

github.com/algorealmInc/SwarmNL @main

Chat with this repo
repository ↗ · DeepWiki ↗ · + Follow
281 symbols 926 edges 25 files 155 documented · 55%
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

crates.io maintenance

SwarmNL

A library to build custom networking layers for decentralized and distributed applications

SwarmNL is a library designed for P2P networking in distributed systems. It's lightweight, scalable, and easy to configure, making it perfect for decentralized applications. Powered by libp2p, SwarmNL simplifies networking so developers can focus on building.

Visit the deployed Rust docs here.

Why SwarmNL?

SwarmNL makes buiding a peer-to-peer decentralized and distributed networking stack for your application a breeze. With SwarmNL, you can effortlessly configure nodes, tailor network conditions, and fine-tune behaviors specific to your project's needs, allowing you to dive into networking without any hassle.

Say goodbye to the complexities of networking and hello to simplicity. With SwarmNL, all the hard work is done for you, leaving you to focus on simple configurations and your application logic.

Tutorials and examples

Have a look at these step-by-step examples that demonstrate the use of SwarmNL in various contexts:

  • Echo server tutorial: demonstrates a simple use case of setting up a node and querying the network layer.
  • File sharing application tutorial: demonstrates interacting with the DHT and sending/recieving RPCs from peers.
  • Simple game tutorial: demonstrates communicating with peers over the network through gossiping.
  • Sharding tutorial: demonstrates splitting a network into shards for scaling and handling communication between various nodes in a shard and across the network.
  • Replication tutorials: demonstrates the replication of data across nodes specially configured to provide redundancy to the network.

Visit the examples folder here to gain a fuller understanding on ways to use the library, including how to integrate SwarmNL with IPFS and HTTP servers.

Research and technicalities

Have a look at this document for a technical overview of SwarmNL and it's design choices.

Node configuration

SwarmNL provides a simple interface to configure a node and specify parameters to dictate its behaviour. This includes:

  • Selection and configuration of the transport layers to be supported by the node
  • Selection of cryptographic keypairs (ed25519, RSA, secp256k1, ecdsa)
  • Storage and retrieval of keypair locally
  • PeerID and multiaddress generation
  • Protocol specification and handlers
  • Event handlers for network events and logging

Example: node configuration with default settings

      #![cfg_attr(not(doctest))]
      //! Using the default node setup configuration

      // Default config
      let config = BootstrapConfig::default();
      // Build node or network core
      let node = CoreBuilder::with_config(config)
          .build()
          .await
          .unwrap();

      //! Using a custom node setup configuration

      // Custom configuration
      // a. Using config from an `.ini` file
      let config = BootstrapConfig::from_file("bootstrap_config.ini");

      // b. Using config methods
      let mut bootnode = HashMap::new();  // Bootnodes
      let ports = (1509, 2710);  // TCP, UDP ports

      bootnode.insert(
          PeerId::random(),
          "/ip4/x.x.x.x/tcp/1509".to_string()
      );

      let config = BootstrapConfig::new()
          .with_bootnodes(bootnode)
          .with_tcp(ports.0)
          .with_udp(ports.1);

      // Build node or network core
      let node = CoreBuilder::with_config(config)
          .build()
          .await
          .unwrap();

Please look at a template .ini file here for configuring a node in the network.

Event handling

During network operations, various events are generated. These events help us track the activities in the network layer. When generated, they are stored in an internal buffer until they are explicitly polled and consumed, or until the queue is full. It is important to consume critical events promptly to prevent loss if the buffer becomes full.

    #![cfg_attr(not(doctest))]
    //! Consuming the events by retrieving it as a iterator

   // Default config
    let config = BootstrapConfig::default();
    // Build node or network core
    let node = CoreBuilder::with_config(config)
        .build()
        .await
        .unwrap();

    // Read all currently buffered network events
    let events = node.events().await;

    let _ = events
        .map(|e| {
            match e {
                NetworkEvent::NewListenAddr {
                    local_peer_id,
                    listener_id: _,
                    address,
                } => {
                    // Announce interfaces we're listening on
                    println!("Peer id: {}", local_peer_id);
                    println!("We're listening on the {}", address);
                },
                NetworkEvent::ConnectionEstablished {
                    peer_id,
                    connection_id: _,
                    endpoint: _,
                    num_established: _,
                    established_in: _,
                } => {
                    println!("Connection established with peer: {:?}", peer_id);
                },
                _ => {},
            }
        })
        .collect::<Vec<_>>();


    //! Consume the immediate next events in the internal event buffer

    // Read events generated at setup
    while let Some(event) = node.next_event().await {
        match event {
            NetworkEvent::NewListenAddr {
                local_peer_id,
                listener_id: _,
                address,
            } => {
                // announce interfaces we're listening on
                println!("Peer id: {}", local_peer_id);
                println!("We're listening on the {}", address);
            },
            NetworkEvent::ConnectionEstablished {
                peer_id,
                connection_id: _,
                endpoint: _,
                num_established: _,
                established_in: _,
            } => {
                println!("Connection established with peer: {:?}", peer_id);
            },
            _ => {},
        }
    }

Node communication

For communication, SwarmNL leverages the powerful capabilities of libp2p. These includes:

  • The Kadmlia DHT: Developers can use the DHT to store infomation and leverage the capabilities of the DHT to build powerful applications, easily.
  • A simple RPC mechanism to exchange data quickly between peers.
  • Gossiping: SwarmNL uses the Gossipsub 1.1 protocol, specified by the libp2p spec.

Example: communicating with the network layer

      #![cfg_attr(not(doctest))]
      //! Communicate with remote nodes using the simple and familiar async-await paradigm.

      // Build node or network core
      let node = CoreBuilder::with_config(config, state)
          .build()
          .await
          .unwrap();

      // Communication interfaces
      // a. Kademlia DHT e.g

      // Prepare an kademlia `store_record` request to send to the network layer
      let (key, value, expiration_time, explicit_peers) = (
          KADEMLIA_TEST_KEY.as_bytes().to_vec(),
          KADEMLIA_TEST_VALUE.as_bytes().to_vec(),
          None,
          None,
      );

      let kad_request = AppData::KademliaStoreRecord {
          key: key.clone(),
          value,
          expiration_time,
          explicit_peers,
      };

      // Send request
      if let Ok(result) = node.query_network(kad_request).await {
          assert_eq!(KademliaStoreRecordSuccess,result);
        }

      // b. RPC (request-response) e.g

      // Prepare a RPC fetch request
      let fetch_key = vec!["SomeFetchKey".as_bytes().to_vec()];

      let fetch_request = AppData::SendRpc {
          keys: fetch_key.clone(),
          peer: node4_peer_id,
      };

      // Get a stream id to track the request
      let stream_id = node.send_to_network(fetch_request).await.unwrap();

      // Poll for the result
      if let Ok(result) = node.recv_from_network(stream_id).await {
          // Here, the request data was simply echoed by the remote peer
          assert_eq!(AppResponse::SendRpc(fetch_key), result);
      }

      // c. Gossiping e.g

      // Prepare gossip request
      let gossip_request = AppData::GossipsubBroadcastMessage {
          topic: GOSSIP_NETWORK.to_string(),
          message: vec!["Daniel".to_string(), "Deborah".to_string()],
      };

      if let Ok(result) = node.query_network(gossip_request).await {
          assert_eq!(AppResponse::GossipsubBroadcastSuccess, result);
      }

Replication

SwarmNL makes fault tolerance through redundancy simple and easy to integrate into your application. With replication built into SwarmNL, you can achieve robust and scalable systems effortlessly.

Key features

  • Consistency models: Choose from a variety of consistency models, including strong consistency with customizable parameters.
  • Dynamic node management: Nodes can seamlessly join and leave replica networks without disrupting operations. Events are quickly propagated to all nodes.
  • Ease of use: Minimal setup is required to add replication to your system, ensuring quick integration and deployment.
  • Node cloning: Complete instant cloning of data in the buffer of a replica peer.

Example: configuring and using replication

Here’s how you can set up and use SwarmNL's replication capabilities:

Configuring a node for replication

    #![cfg_attr(not(doctest))]
    //! Configure the node for replication with a strong consistency model

    // Define the replica network ID
    const REPL_NETWORK_ID: &str = "replica_xx";

    // Configure replication settings
    let repl_config = ReplNetworkConfig::Custom {
        queue_length: 150,
        expiry_time: Some(10),
        sync_wait_time: 5,
        consistency_model: ConsistencyModel::Strong(ConsensusModel::All),
        data_aging_period: 2,
    };

    // Build the node with replication enabled
    let node = builder.with_replication(repl_config).build().await.unwrap();

    // Join a replica network
    node.join_repl_network(REPL_NETWORK_ID.into()).await;

    // Replicate data across the network
    node.replicate(payload, REPL_NETWORK_ID).await;

Handling replication events

SwarmNL exposes network events to your application, allowing you to process incoming replica data effectively.

    //! Listen for replication events

    loop {
        // Check for incoming data events
        if let Some(event) = node.next_event().await {
            if let NetworkEvent::ReplicaDataIncoming { source, .. } = event {
                println!("Received incoming replica data from {}", source.to_base58());
            }
        }

        // Try to consume data from the replication buffer
        if let Some(repl_data) = node.consume_repl_data(REPL_NETWORK_ID).await {
            println!(
                "Data received from replica: {} ({} confirmations)",
                repl_data.data[0],
                repl_data.confirmations.unwrap()
            );
        }
    }

Why use SwarmNL for replication?

  • Reliability: Ensures data integrity across multiple nodes with customizable consistency guarantees.
  • Scalability: Handles dynamic node changes with ease, making it suitable for large distributed systems.
  • Flexibility: Provides a range of replication configurations to meet diverse application needs.

Sharding

Sharding is a capability in distributed systems that enables networks to scale efficiently. SwarmNL provides a generic sharding functionality, allowing applications to easily partition their network and configure it for sharding.

Key features

  • Customizable Sharding Algorithms: SwarmNL supports generic interfaces that let you specify your own sharding algorithm, such as hash-based or range-based, while leveraging the full capabilities of the network.
  • Replication-Driven Sharding: Sharding in SwarmNL is built on its replication capabilities, ensuring the library remains lightweight and highly functional.
  • Data Forwarding: SwarmNL implements data-forwarding, allowing any node to handle requests for data stored on other nodes within any shard. Data is forwarded to the appropriate node for storage, and a network search algorithm enables retrieval from any node in any shard.
  • Integrated Application Layer Traps: To maintain flexibility, SwarmNL permits nodes storing data to trap into the application layer when handling data requests. This ensures practicality and usability in real-world scenarios.

Example: configuring and operating a sharded network

Here’s how you can set up and use SwarmNL's sharding capabilities:

Configuring a node for sharding

```rust #![cfg_

Extension points exported contracts — how you extend this code

ShardStorage (Interface)
Trait that interfaces with the storage layer of a node in a shard. It is important for handling forwarded data requests. [4 …
swarm-nl/src/core/sharding.rs
CustomFrom (Interface)
An implementation of [`From<&str>`] for [`KeyType`] to read a key type from a bootstrap config file. We define a custom [1 …
swarm-nl/src/prelude.rs
Sharding (Interface)
(no doc) [3 implementers]
swarm-nl/src/core/sharding.rs

Core symbols most depended-on inside this repo

insert
called by 115
swarm-nl/src/core/prelude.rs
query_network
called by 40
swarm-nl/src/core/mod.rs
join_repl_network
called by 28
swarm-nl/src/core/mod.rs
with_tcp
called by 25
swarm-nl/src/setup.rs
replicate
called by 24
swarm-nl/src/core/mod.rs
with_udp
called by 21
swarm-nl/src/setup.rs
generate_keypair_from_protobuf
called by 21
swarm-nl/src/setup.rs
next_event
called by 20
swarm-nl/src/core/mod.rs

Shape

Function 147
Method 86
Class 29
Enum 16
Interface 3

Languages

Rust100%

Modules by API surface

swarm-nl/src/core/mod.rs39 symbols
swarm-nl/src/setup.rs29 symbols
swarm-nl/src/core/prelude.rs28 symbols
swarm-nl/src/core/tests/layer_communication.rs27 symbols
swarm-nl/src/core/replication.rs26 symbols
swarm-nl/src/util.rs23 symbols
swarm-nl/src/core/tests/sharding.rs13 symbols
examples/sharding/hash-based/src/main.rs12 symbols
swarm-nl/src/core/tests/replication.rs10 symbols
swarm-nl/src/core/sharding.rs10 symbols
examples/sharding/range-based/src/main.rs10 symbols
swarm-nl/src/core/tests/node_behaviour.rs8 symbols

For agents

$ claude mcp add SwarmNL \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact