grapevine 1.1.0

A modern, asynchronous peer-to-peer gossip protocol library and application
Documentation
# Grapevine Architecture

This document describes the internal architecture of Grapevine.

## Overview

Grapevine is structured in layers:

┌─────────────────────────────────┐
│          Application            │
├─────────────────────────────────┤
│           Node API              │
├─────────────────────────────────┤
│         Protocol Engine         │
│(gossip, epidemic, anti-entropy) │
├─────────────────────────────────┤
│        Transport Layer          │
│       (TCP, QUIC, etc)          │
├─────────────────────────────────┤
│          Core Types             │
└─────────────────────────────────┘

## Components

### Core Types (`src/core/`)

- **Message**: Gossip message structure with ID, TTL, payload, and the origin's public key plus signature
- **MessageCodec**: Length-prefixed framing and bincode serialization. Message size limit: 10MB default (configurable)
- **Identity**: Per-node Ed25519 keypair; signs authored messages and exposes the node's `PeerId`
- **PeerId**: Cryptographic node identity (the Ed25519 public key)
- **Peer**: Represents a connected peer with health tracking
- **PeerInfo**: Per-connection metadata with health score, failure tracking, state machine
- **RateLimiter**: Per-peer token bucket rate limiting (100 capacity, 50 tokens/sec)

### Transport Layer (`src/transport/`)

- **Tcp**: TCP-based transport that owns the authoritative peer registry
  - Each outbound message is encoded exactly once, by the peer's writer task at the socket
  - Per-peer write channels are bounded and lossy under backpressure (drop-newest); the shared inbound channel is bounded and applies backpressure to readers
  - Shutdown stops accepting, flushes queued frames (such as goodbyes), and awaits every connection task instead of sleeping a fixed grace period
- Note: QUIC transport planned for a later release

### Protocol Engine (`src/protocol/`)

- **Gossip**: Main protocol engine with background tasks
- **Epidemic**: Probabilistic broadcast (70% forward probability, blind variant)
- **Anti-Entropy**: Periodic version-vector reconciliation and repair (every 30s)

## Message Flow

1. Application calls `node.broadcast(data)`
2. Protocol authors a `Message` with a per-origin `(origin, sequence)` ID and signs it with the node's `Identity`
3. Message stored in `seen_messages` cache with metadata
4. Transport enqueues the message to a random subset of peers (fan-out)
5. Each peer's writer task encodes the message once (`MessageCodec`) and writes it to the socket
6. Receiving nodes:
   - Rate limiting check (token bucket per peer)
   - Deserialize message via `MessageCodec`
   - Authenticate: verify the origin's signature and enforce the trust-on-first-use origin/key binding (reject on failure)
   - Check if already seen (deduplication via `MessageId`)
   - Store in `seen_messages` with `MessageEntry` metadata
   - Forward to application handler (if `Application` payload)
   - With probability `forward_probability` (default 70%), re-gossip once (unchanged signature) to a fanout that excludes the sender and origin (if TTL > 1)

## Peer Discovery

1. Node connects to bootstrap peers
2. Requests peer list via `PeerListRequest`
3. Receives `PeerListResponse` with known peers
4. Connects to discovered peers
5. Repeats until reaching `max_peers`

## Heartbeat & Peer Health

- Nodes send periodic heartbeats (configurable interval)
- `last_seen` timestamp updated on any message
- Peer state machine: Connecting => Connected => Stale => Disconnected
- Health score based on:
  - Success/failure ratio
  - Connection age (older connections get bonus)
  - Consecutive failures (penalty)
- Peers with 5 consecutive failures are disconnected
- Peer maintenance runs every 10 seconds
- Stale peers marked after `peer_timeout` (default: 30s)

## Configuration

All behavior is configurable via `NodeConfig`:

- `gossip_interval`: How often to send heartbeats (default: 5s)
- `fanout`: Number of peers per gossip round (default: 3)
- `max_peers`: Maximum peer connections (default: 50)
- `peer_timeout`: Stale peer timeout (default: 30s)
- `message_dedup_ttl`: How long to remember seen messages (default: 5 minutes)
- `anti_entropy`: Anti-entropy protocol configuration
  - `enabled`: Enable/disable anti-entropy (default: true)
  - `interval`: How often to sync (default: 30s)
  - `fanout`: Peers to sync with (default: 3)
- `epidemic`: Epidemic broadcast configuration
  - `forward_probability`: Probability of forwarding a newly learned rumor (default: 0.7)
- `rate_limit`: Rate limiting configuration
  - `enabled`: Enable/disable rate limiting (default: true)
  - `capacity`: Token bucket capacity (default: 100)
  - `refill_rate`: Tokens per second (default: 50)

See `NodeConfig` and `NodeConfigBuilder` documentation for all options and validation rules.