BrightChain Gossip Delivery Protocol

Overview

The BrightChain Gossip Delivery Protocol provides decentralized, peer-to-peer message delivery using epidemic-style gossip propagation. Messages are announced through the network via block announcements that propagate with configurable fanout and time-to-live (TTL) parameters, enabling efficient delivery without centralized routing infrastructure.

Core Principles

  1. Epidemic Propagation: Messages spread through the network like an epidemic, with each node forwarding to a subset of peers
  2. Priority-Based Delivery: High-priority messages receive increased fanout and TTL for faster propagation
  3. Delivery Acknowledgments: Recipients send cryptographic acknowledgments back through the gossip network
  4. Automatic Retry: Unacknowledged deliveries are automatically retried with exponential backoff
  5. Privacy-Preserving: Sensitive metadata (message delivery info, acks) can be encrypted per-peer using ECIES
  6. Block Discovery: Bloom filter-based discovery protocol enables efficient block location across the network

Architecture Components

1. Gossip Service (IGossipService)

The core gossip protocol implementation handling block announcements and message delivery.

Key Responsibilities

  • Announce new blocks to the network
  • Forward announcements with TTL decrement
  • Batch announcements for network efficiency
  • Apply priority-based fanout for message delivery
  • Encrypt sensitive announcements per-peer
  • Emit events for message delivery and acknowledgments

Block Announcement Structure

interface BlockAnnouncement {
  type: 'add' | 'remove' | 'ack';
  blockId: string;
  nodeId: string;
  timestamp: Date;
  ttl: number;
  messageDelivery?: MessageDeliveryMetadata;
  deliveryAck?: DeliveryAckMetadata;
}

Message Delivery Metadata

interface MessageDeliveryMetadata {
  messageId: string;
  recipientIds: string[];
  priority: 'normal' | 'high';
  blockIds: string[];
  cblBlockId: string;
  ackRequired: boolean;
}

Delivery Acknowledgment Metadata

interface DeliveryAckMetadata {
  messageId: string;
  recipientId: string;
  status: 'delivered' | 'read' | 'failed' | 'bounced';
  originalSenderNode: string;
}

2. Gossip Configuration

Configurable parameters control propagation behavior and network efficiency.

interface GossipConfig {
  // Default block-level announcement settings
  fanout: number;              // Default: 3 peers
  defaultTtl: number;          // Default: 3 hops
  
  // Batching for network efficiency
  batchIntervalMs: number;     // Default: 1000ms
  maxBatchSize: number;        // Default: 100 announcements
  
  // Priority-based message delivery
  messagePriority: {
    normal: { fanout: 5, ttl: 5 };
    high: { fanout: 7, ttl: 7 };
  };
}

Configuration Validation

  • All fanout values must be positive integers (≥1)
  • All TTL values must be positive integers (≥1)
  • Invalid configurations throw InvalidGossipConfigError at service initialization

3. Announcement Types

Add Announcements

  • Announce new blocks to the network
  • May include messageDelivery metadata for message-aware delivery
  • TTL decremented on each forward
  • Stopped when TTL reaches 0

Remove Announcements

  • Announce block deletions to the network
  • Propagate with same fanout/TTL as add announcements
  • Allow peers to update their block registries

Ack Announcements

  • Delivery acknowledgments sent back through gossip
  • Must include deliveryAck metadata
  • Routed back to original sender node
  • Enable delivery tracking and retry logic

4. Message Delivery Flow

Sending a Message

1. MessagePassingService.sendMessage()
   ↓
2. MessageCBLService.createMessage()
   - Store message content as CBL blocks
   - Generate message metadata
   ↓
3. GossipService.announceMessage()
   - Create BlockAnnouncements with messageDelivery metadata
   - Apply priority-based fanout/TTL
   - Queue for batch sending
   ↓
4. GossipService.flushAnnouncements()
   - Group by fanout requirements
   - Select random peers (Fisher-Yates shuffle)
   - Encrypt sensitive batches per-peer (ECIES)
   - Send to selected peers

Receiving a Message

1. GossipService.handleAnnouncement()
   ↓
2. Check announcement type:
   - 'ack' → dispatch to deliveryAck handlers
   - 'add' with messageDelivery → check recipient match
   ↓
3. If recipientIds match local users:
   - Trigger messageDelivery handlers
   - Auto-send ack if ackRequired=true
   - Do NOT forward (terminal recipient)
   ↓
4. If recipientIds don't match:
   - Forward with decremented TTL
   - Continue propagation

Acknowledgment Flow

1. Recipient receives message delivery announcement
   ↓
2. GossipService auto-sends ack (if ackRequired=true)
   - Create 'ack' type BlockAnnouncement
   - Include deliveryAck metadata
   - Queue for batch sending
   ↓
3. Ack propagates through network
   ↓
4. Original sender receives ack
   - deliveryAck handlers triggered
   - MessagePassingService updates delivery status
   - GossipRetryService stops retrying for that recipient

5. Retry Service (GossipRetryService)

Manages automatic retry logic for unacknowledged message deliveries.

Retry Configuration

interface RetryConfig {
  initialTimeoutMs: number;      // Default: 30000 (30s)
  backoffMultiplier: number;     // Default: 2
  maxRetries: number;            // Default: 5
  maxBackoffMs: number;          // Default: 240000 (4min)
}

Retry Schedule (with defaults)

  • Retry 1: 30 seconds
  • Retry 2: 60 seconds (2^1 × 30s)
  • Retry 3: 120 seconds (2^2 × 30s)
  • Retry 4: 240 seconds (2^3 × 30s, capped)
  • Retry 5: 240 seconds (capped at maxBackoffMs)

Retry State Machine

ANNOUNCED → (timeout) → RETRY 1 → (timeout) → RETRY 2 → ... → RETRY 5
                                                                    ↓
                                                                 FAILED

Failure Handling

When max retries are exhausted:

  1. Mark unacknowledged recipients as DeliveryStatus.Failed
  2. Update metadata store with failed status
  3. Emit MESSAGE_FAILED event
  4. Remove from retry tracking

6. Encryption for Sensitive Announcements

Announcements containing messageDelivery or deliveryAck metadata are considered sensitive and can be encrypted per-peer.

Encryption Flow

1. Check if batch contains sensitive metadata
   ↓
2. If sensitive and ECIESService available:
   - Get peer's public key
   - Serialize announcements to JSON
   - Encrypt with ECIES (peer's public key)
   - Send as EncryptedBatchPayload
   ↓
3. If sensitive but no peer key:
   - Log warning
   - Send plaintext (fallback)
   ↓
4. If not sensitive:
   - Send plaintext

Encrypted Batch Payload

interface EncryptedBatchPayload {
  encryptedPayload: string;  // Base64-encoded ECIES ciphertext
  senderNodeId: string;      // Node ID of sender
}

7. Discovery Protocol (IDiscoveryProtocol)

Enables efficient block location across the network using Bloom filters and concurrent queries.

Discovery Flow

1. DiscoveryProtocol.discoverBlock(blockId)
   ↓
2. Check local cache (TTL: 60s default)
   - If cached and fresh, return immediately
   ↓
3. Get connected peer IDs
   ↓
4. Filter peers using Bloom filters
   - Query each peer's Bloom filter
   - Only query peers where filter.mightContain(blockId) = true
   - Reduces unnecessary network queries
   ↓
5. Query filtered peers with concurrency limit
   - Default: 10 concurrent queries
   - Measure latency per peer
   ↓
6. Build location records from successful queries
   - Sort by latency (lowest first)
   ↓
7. Cache results and return

Discovery Configuration

interface DiscoveryConfig {
  queryTimeoutMs: number;                    // Default: 5000ms
  maxConcurrentQueries: number;              // Default: 10
  cacheTtlMs: number;                        // Default: 60000ms (1min)
  bloomFilterFalsePositiveRate: number;      // Default: 0.01 (1%)
  bloomFilterHashCount: number;              // Default: 7
}

Discovery Result

interface DiscoveryResult {
  blockId: string;
  found: boolean;
  locations: ILocationRecord[];  // Sorted by latency
  queriedPeers: number;
  duration: number;
}

API Reference

GossipService API

Constructor

constructor(
  peerProvider: IPeerProvider,
  config?: GossipConfig,
  localUserIds?: Set<string>,
  eciesService?: ECIESService,
  localPrivateKey?: Buffer
)

Core Methods

**announceBlock(blockId: string): Promise**

  • Announce a new block to the network
  • Uses default fanout and TTL
  • Batched and sent to random peers

**announceRemoval(blockId: string): Promise**

  • Announce block removal to the network
  • Propagates with same fanout/TTL as add announcements

**announceMessage(blockIds: string[], metadata: MessageDeliveryMetadata): Promise**

  • Announce message blocks with delivery metadata
  • Applies priority-based fanout/TTL from config
  • Creates BlockAnnouncement for each blockId

**sendDeliveryAck(ack: DeliveryAckMetadata): Promise**

  • Send delivery acknowledgment through gossip
  • Creates ‘ack’ type BlockAnnouncement
  • Queues for batch sending

**handleAnnouncement(announcement: BlockAnnouncement): Promise**

  • Process incoming announcement from peer
  • Dispatches to appropriate handlers
  • Forwards with decremented TTL if applicable

**flushAnnouncements(): Promise**

  • Immediately send all pending announcements
  • Groups by fanout requirements
  • Encrypts sensitive batches per-peer

start(): void

  • Start the gossip service
  • Begins batch timer (default: 1000ms interval)

**stop(): Promise**

  • Stop the gossip service
  • Flushes pending announcements
  • Stops batch timer

Event Handlers

onAnnouncement(handler: AnnouncementHandler): void

  • Subscribe to general block announcements
  • Called for ‘add’/’remove’ without messageDelivery

onMessageDelivery(handler: (announcement: BlockAnnouncement) => void): void

  • Subscribe to message delivery events
  • Called when messageDelivery metadata matches local users

onDeliveryAck(handler: (announcement: BlockAnnouncement) => void): void

  • Subscribe to delivery acknowledgment events
  • Called when ‘ack’ type announcements are received

offAnnouncement(handler: AnnouncementHandler): void

  • Unsubscribe from general announcements

offMessageDelivery(handler: (announcement: BlockAnnouncement) => void): void

  • Unsubscribe from message delivery events

offDeliveryAck(handler: (announcement: BlockAnnouncement) => void): void

  • Unsubscribe from delivery ack events

GossipRetryService API

Constructor

constructor(
  gossipService: IGossipService,
  metadataStore: IDeliveryStatusStore,
  eventSystem: IMessageEventEmitter,
  config?: Partial<RetryConfig>
)

Core Methods

trackDelivery(messageId: string, blockIds: string[], metadata: MessageDeliveryMetadata): void

  • Register a new pending delivery for tracking
  • Sets all recipients to Announced status
  • Calculates first retry time

handleAck(ack: DeliveryAckMetadata): void

  • Process delivery acknowledgment
  • Updates recipient status
  • Removes from tracking if all recipients delivered

start(): void

  • Start the periodic retry timer
  • Checks for pending retries every 1 second

stop(): void

  • Stop the periodic retry timer

checkRetries(): void

  • Check all pending deliveries and retry/fail as needed
  • Public method for testing without real timers

getPendingDelivery(messageId: string): PendingDelivery | undefined

  • Get pending delivery state for inspection

getPendingCount(): number

  • Get count of pending deliveries

getConfig(): RetryConfig

  • Get current retry configuration

DiscoveryProtocol API

Constructor

constructor(
  networkProvider: IPeerNetworkProvider,
  config?: DiscoveryConfig
)

Core Methods

**discoverBlock(blockId: string): Promise**

  • Discover locations for a block across the network
  • Uses Bloom filter pre-checks
  • Returns locations sorted by latency

**queryPeer(peerId: string, blockId: string): Promise**

  • Query specific peer for a block
  • Direct query without Bloom filter pre-check
  • Returns query result with latency

getCachedLocations(blockId: string): ILocationRecord[] | null

  • Get cached discovery results
  • Returns null if not cached or expired

clearCache(blockId: string): void

  • Clear cache for specific block

clearAllCache(): void

  • Clear entire discovery cache

**getPeerBloomFilter(peerId: string): Promise**

  • Get Bloom filter from peer
  • Cached for efficiency

getConfig(): DiscoveryConfig

  • Get current discovery configuration

Performance Characteristics

Network Efficiency

Batching

  • Announcements batched within configurable interval (default: 1000ms)
  • Reduces network overhead by combining multiple announcements
  • Max batch size prevents oversized packets (default: 100)

Fanout

  • Block announcements: 3 peers (default)
  • Normal priority messages: 5 peers
  • High priority messages: 7 peers
  • Configurable per deployment

TTL (Time-to-Live)

  • Block announcements: 3 hops (default)
  • Normal priority messages: 5 hops
  • High priority messages: 7 hops
  • Prevents infinite propagation

Delivery Guarantees

Best-Effort Delivery

  • Gossip provides probabilistic delivery guarantees
  • Higher fanout/TTL increases delivery probability
  • Retry mechanism compensates for packet loss

Delivery Probability

  • With fanout=5, TTL=5: ~99.9% delivery probability
  • With fanout=7, TTL=7: ~99.99% delivery probability
  • Assumes 10% packet loss rate

Latency

  • Average delivery time: O(log N) where N = network size
  • High-priority messages: ~30% faster than normal priority
  • Retry adds 30s-240s for failed deliveries

Resource Usage

Memory

  • Pending announcements: O(batch size)
  • Retry tracking: O(pending deliveries × recipients)
  • Discovery cache: O(cached blocks × locations)
  • Bloom filter cache: O(connected peers)

Network Bandwidth

  • Announcement size: ~200 bytes (without encryption)
  • Encrypted announcement: ~400 bytes (ECIES overhead)
  • Batch size: up to 20KB (100 announcements)
  • Fanout multiplier: 3-7× per hop

CPU

  • Bloom filter checks: O(k) where k = hash count (default: 7)
  • ECIES encryption: ~5ms per batch
  • Fisher-Yates shuffle: O(n) where n = peer count

Security Considerations

Privacy Protection

Encrypted Announcements

  • Sensitive metadata encrypted per-peer using ECIES
  • Each peer receives uniquely encrypted batch
  • Prevents eavesdropping on message delivery info

Recipient Privacy

  • BCC recipients receive separate announcements
  • No cross-recipient information leakage
  • Each BCC copy encrypted with recipient’s key

Metadata Minimization

  • Only essential fields in announcements
  • No message content in gossip layer
  • Content stored separately as encrypted blocks

Attack Resistance

Sybil Attacks

  • Fanout limits prevent amplification
  • TTL prevents infinite propagation
  • Peer selection uses cryptographic randomness

Eclipse Attacks

  • Multiple independent gossip paths
  • Retry mechanism provides redundancy
  • Discovery protocol finds alternative routes

Denial of Service

  • Batch size limits prevent memory exhaustion
  • Concurrent query limits prevent resource exhaustion
  • TTL prevents network flooding

Authentication

Node Identity

  • Each announcement includes sender nodeId
  • ECIES encryption proves sender identity
  • Ack announcements include originalSenderNode

Message Integrity

  • Block IDs are cryptographic checksums (SHA3-512)
  • Announcements reference immutable blocks
  • Tampering detected via checksum mismatch

Integration Examples

Basic Message Sending

// Initialize services
const gossipService = new GossipService(peerProvider, config);
const messageCBL = new MessageCBLService(cblService, checksumService, blockStore);
const messagePassingService = new MessagePassingService(
  messageCBL,
  metadataStore,
  eventSystem,
  gossipService
);

// Send a message
const result = await messagePassingService.sendMessage(
  Buffer.from('Hello, World!'),
  'sender-id',
  {
    messageType: 'chat',
    senderId: 'sender-id',
    recipients: ['recipient-1', 'recipient-2'],
    priority: MessagePriority.NORMAL,
    encryptionScheme: MessageEncryptionScheme.RECIPIENT_KEYS
  }
);

console.log(`Message sent: ${result.messageId}`);

Email Delivery via Gossip

// Configure email service with gossip delivery
const emailService = new EmailMessageService(
  messageCBL,
  emailMetadataStore,
  gossipService,
  config
);

// Send email
const result = await emailService.sendEmail({
  from: createMailbox('sender', 'example.com'),
  to: [createMailbox('recipient', 'example.com')],
  subject: 'Hello',
  textBody: 'Hello, World!',
  encryptionScheme: MessageEncryptionScheme.RECIPIENT_KEYS,
  recipientPublicKeys: new Map([
    ['recipient@example.com', recipientPublicKey]
  ])
});

// Email delivered via gossip protocol
// Acks received automatically

Handling Delivery Events

// Subscribe to message delivery events
gossipService.onMessageDelivery(async (announcement) => {
  const { messageId, recipientIds } = announcement.messageDelivery!;
  console.log(`Message ${messageId} delivered to ${recipientIds.join(', ')}`);
  
  // Retrieve and process message content
  const content = await messageCBL.getMessageContent(messageId);
  // ... process content
});

// Subscribe to delivery acknowledgments
gossipService.onDeliveryAck(async (announcement) => {
  const { messageId, recipientId, status } = announcement.deliveryAck!;
  console.log(`Ack received: ${messageId}${recipientId} (${status})`);
  
  // Update UI or trigger notifications
});

Block Discovery

// Initialize discovery protocol
const discoveryProtocol = new DiscoveryProtocol(networkProvider, config);

// Discover block locations
const result = await discoveryProtocol.discoverBlock(blockId);

if (result.found) {
  console.log(`Block found on ${result.locations.length} nodes`);
  console.log(`Best node: ${result.locations[0].nodeId} (${result.locations[0].latencyMs}ms)`);
  
  // Retrieve block from best location
  const block = await retrieveBlockFrom(result.locations[0].nodeId, blockId);
} else {
  console.log('Block not found on network');
}

Retry Management

// Initialize retry service
const retryService = new GossipRetryService(
  gossipService,
  metadataStore,
  eventSystem,
  {
    initialTimeoutMs: 30000,
    maxRetries: 5,
    backoffMultiplier: 2
  }
);

retryService.start();

// Track message delivery
retryService.trackDelivery(messageId, blockIds, deliveryMetadata);

// Acks handled automatically
// Retries triggered automatically on timeout
// Failed deliveries emit MESSAGE_FAILED event

Testing

Property-Based Tests

  • Announcement validation (1000+ iterations)
  • Gossip propagation correctness
  • Retry backoff calculations
  • Encryption round-trips
  • Discovery result consistency

Integration Tests

  • Multi-node gossip propagation
  • Cross-node message delivery
  • Ack routing back to sender
  • Retry exhaustion and failure handling
  • Discovery with Bloom filters

Performance Tests

  • Delivery latency percentiles
  • Network bandwidth usage
  • Memory usage under load
  • Concurrent query scaling
  • Cache hit rates

Future Enhancements

Planned Features

  • Adaptive fanout based on network conditions
  • Geographic routing preferences
  • Bandwidth-aware peer selection
  • Gossip compression for large batches
  • Persistent retry state across restarts

Optimization Opportunities

  • Bloom filter synchronization protocol
  • Delta-based announcement batches
  • Multicast-aware routing
  • Predictive caching based on access patterns
  • Hierarchical gossip for large networks

References