grapevine

Crates.iograpevine
lib.rsgrapevine
version1.0.0
created_at2023-01-17 03:17:56.131219+00
updated_at2025-11-11 21:01:31.397559+00
descriptionA modern, asynchronous peer-to-peer gossip protocol library and application
homepagehttps://github.com/kobby-pentangeli/grapevine
repositoryhttps://github.com/kobby-pentangeli/grapevine
max_upload_size
id760788
size265,594
Kobby Pentangeli (kobby-pentangeli)

documentation

https://docs.rs/grapevine

README

Grapevine

Crates.io Documentation CI License

A modern, asynchronous peer-to-peer gossip protocol library and application.

Features

  • Async/await - Built on Tokio for high-performance async I/O
  • Epidemic broadcast - Probabilistic message forwarding for efficient network coverage
  • Anti-entropy - Periodic synchronization ensures eventual consistency
  • Rate limiting - Per-peer token bucket rate limiting prevents DoS attacks
  • Highly configurable - Fine-tune gossip parameters for your use case
  • Zero unsafe code - Memory safe and thread safe

Installation

As a Library

To use Grapevine in your Rust project:

cargo add grapevine

Or add manually to your Cargo.toml:

[dependencies]
grapevine = "1.0"
tokio = { version = "1", features = ["full"] }
bytes = "1"

As a CLI Application

To install the standalone gossip client binary:

cargo install grapevine

Then run:

grapevine --help

Quick Start

Basic Example

use grapevine::{Node, NodeConfig};
use bytes::Bytes;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create a node with default configuration
    let config = NodeConfig::default();
    let node = Node::new(config).await?;

    // Set up message handler
    node.on_message(|origin, data| {
        println!("Received from {origin}: {data:?}");
    }).await;

    // Start the node
    node.start().await?;

    // Broadcast a message
    node.broadcast(Bytes::from("Hello, gossip!")).await?;

    // Keep running until explicit shutdown
    tokio::signal::ctrl_c().await?;
    node.shutdown().await?;

    Ok(())
}

Multi-Node Cluster

use grapevine::{Node, NodeConfig, NodeConfigBuilder};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create first node
    let node1 = Node::new(NodeConfig::default()).await?;
    node1.start().await?;
    let addr1 = node1.local_addr().await.unwrap();

    // Create second node, bootstrapping from first
    let config2 = NodeConfigBuilder::new()
        .add_bootstrap_peer(addr1)
        .fanout(5)
        .build()?;
    let node2 = Node::new(config2).await?;
    node2.start().await?;

    // Nodes will automatically discover and connect to each other

    Ok(())
}

Configuration

Grapevine is highly configurable. See NodeConfig for all options:

use grapevine::NodeConfigBuilder;
use std::time::Duration;

let config = NodeConfigBuilder::new()
    .bind_addr("127.0.0.1:8000".parse().unwrap())
    .gossip_interval(Duration::from_secs(5))
    .fanout(3)
    .max_peers(50)
    .max_message_size(1024 * 1024)
    .build()?;

Feature Flags

  • crypto - Enable message signing and verification (deferred to v1.1)

Note: QUIC transport support is planned for v1.1+

Architecture

Grapevine implements a push-based gossip protocol with the following components:

  • Epidemic Broadcast: Probabilistic message forwarding (default 70% probability, max 5 forwards)
  • Anti-Entropy: Periodic digest exchange and repair (every 30s) ensures eventual consistency
  • Peer Management: Automatic health monitoring with state machine (Connecting => Connected => Stale => Disconnected)
  • Rate Limiting: Per-peer token bucket (100 capacity, 50 tokens/sec) prevents DoS attacks
  • Message Deduplication: Time-based eviction (5 minute TTL) prevents duplicates
  • Graceful Shutdown: Phased shutdown with goodbye notifications to peers

See Architecture Documentation for details.

Testing

# Run all tests
cargo test --all-features

# Run integration tests only
cargo test --test integration

# Run with logging
RUST_LOG=debug cargo test

CLI Usage

Grapevine includes a standalone binary for running gossip nodes. For a complete guide on starting nodes, joining networks, broadcasting messages, and more, see the CLI Usage Guide.

Environment Variables

For a straightforward run, first copy .env.example to .env and customize:

cp .env.example .env
# Edit .env with your configuration
cargo run

CLI Arguments

-H, --host <HOST>                Host to bind to [env: BIND_HOST] [default: 127.0.0.1]
-p, --port <PORT>                Port to listen on [env: BIND_PORT] [default: 8000]
-b, --peer <PEER>                Bootstrap peer addresses [env: BOOTSTRAP_PEERS]
-g, --gossip-interval <SECS>     Gossip interval in seconds [env: GOSSIP_INTERVAL_SECS] [default: 5]
-f, --fanout <FANOUT>            Fan-out factor [env: FANOUT] [default: 3]
-m, --max-peers <MAX_PEERS>      Maximum number of peers [env: MAX_PEERS] [default: 50]
-l, --log-level <LEVEL>          Log level (trace, debug, info, warn, error) [env: RUST_LOG] [default: info]

Common Operations

# Start a seed node
cargo run

# Join the network from another terminal
cargo run -- --port 8001 --peer 127.0.0.1:8000

# Join with multiple bootstrap peers
cargo run -- --port 8002 \
  --peer 127.0.0.1:8000,127.0.0.1:8001

# Start with custom configuration
cargo run -- \
  --host 0.0.0.0 \
  --port 9000 \
  --fanout 5 \
  --gossip-interval 3

# Use environment variables
BIND_HOST=0.0.0.0 BIND_PORT=9000 cargo run

# Enable debug logging
cargo run -- --log-level debug

# Graceful shutdown
# Press Ctrl+C to send goodbye messages and cleanly exit

See docs/client.md for:

  • Step-by-step setup instructions
  • Multi-node cluster examples
  • Network tuning parameters
  • Troubleshooting common issues

Examples

See the examples directory:

Run an example:

RUST_LOG=info cargo run --example simple_node

Contributing

Contributions are welcome! Please read our Contributing Guidelines and Code of Conduct.

License

Licensed under either of

at your option.

Commit count: 43

cargo fmt