Hashgraph-like Consensus
A lightweight Rust library for making binary decisions in peer-to-peer or gossipsub networks. Perfect for group governance, voting systems, or any scenario where you need distributed agreement.
Features
- Fast - Reaches consensus in O(log n) rounds
- Byzantine fault tolerant - Correct even if up to 1/3 of peers are malicious
- Pluggable storage - In-memory by default; implement
ConsensusStoragefor persistence - Network-agnostic - Works with both Gossipsub (fixed 2-round) and P2P (dynamic rounds) topologies
- Event-driven - Subscribe to consensus outcomes via a broadcast event bus
- Cryptographic integrity - Votes are signed with secp256k1 and chained in a hashgraph structure
Based on the Hashgraph-like Consensus Protocol RFC.
Installation
Add to your Cargo.toml:
[]
= { = "https://github.com/vacp2p/hashgraph-like-consensus" }
Quick Start
use ;
use PrivateKeySigner;
async
Core Concepts
Scopes and Proposals
A scope groups related proposals together and carries default configuration (network type, threshold, timeout). Proposals inherit scope defaults unless overridden individually.
Scope (group / channel)
├── ScopeConfig (defaults for all proposals)
└── Proposals
├── Proposal 1 → Session (inherits scope config)
├── Proposal 2 → Session (inherits scope config)
└── Proposal 3 → Session (overrides scope config)
Network Types
| Type | Rounds | Behavior |
|---|---|---|
| Gossipsub (default) | Fixed 2 rounds | Round 1 = proposal broadcast, Round 2 = all votes |
| P2P | Dynamic ceil(2n/3) |
Each vote advances the round by one |
API Reference
Creating a Service
use DefaultConsensusService;
// Default: in-memory storage, 10 max sessions per scope
let service = default;
// Custom session limit
let service = new_with_max_sessions;
// Fully custom: plug in your own storage and event bus
let service = new_with_components;
Configuring a Scope
use ;
use Duration;
let service = default;
let scope = from;
// Initialize with the builder
service
.scope
.await?
.with_network_type
.with_threshold
.with_timeout
.with_liveness_criteria
.initialize
.await?;
// Update later (single field)
service
.scope
.await?
.with_threshold
.update
.await?;
Built-in presets are also available:
// High confidence (threshold = 0.9)
service.scope.await?.strict_consensus.initialize.await?;
// Low latency (threshold = 0.6, timeout = 30 s)
service.scope.await?.fast_consensus.initialize.await?;
Working with Proposals
// Create a proposal
let proposal = service
.create_proposal
.await?;
// Process a proposal received from the network
service.process_incoming_proposal.await?;
// List active proposals
let active: = service.get_active_proposals.await?;
// List finalized proposals (proposal_id -> result)
let finalized: = service.get_reached_proposals.await?;
Casting and Processing Votes
// Cast your vote (yes = true, no = false)
let vote = service.cast_vote.await?;
// Cast a vote and get the updated proposal (useful for gossiping)
let proposal = service
.cast_vote_and_get_proposal
.await?;
// Process a vote received from the network
service.process_incoming_vote.await?;
Checking Results
// Get the final consensus result (Ok(true) = YES, Ok(false) = NO)
let result: bool = service.get_consensus_result.await?;
// Check if enough votes have been collected
let enough: bool = service
.has_sufficient_votes_for_proposal
.await?;
Subscribing to Events
use ConsensusEvent;
let mut rx = service.subscribe_to_events;
spawn;
Statistics
let stats = service.get_scope_stats.await;
println!;
Advanced Usage
Custom Storage
Implement the ConsensusStorage trait to persist proposals to a database:
use ConsensusStorage;
Custom Event Bus
Implement ConsensusEventBus for alternative event delivery:
use ConsensusEventBus;
Utility Functions
The utils module provides low-level helpers:
| Function | Description |
|---|---|
validate_proposal() |
Validate a proposal and its votes |
validate_vote() |
Verify a vote's signature and structure |
validate_vote_chain() |
Ensure parent/received hash chains are correct |
has_sufficient_votes() |
Quick threshold check (count-based) |
calculate_consensus_result() |
Determine result from collected votes using threshold and liveness rules |
Building
# Build
# Run tests
# Generate docs
Note: Requires a working
protoc(Protocol Buffers compiler) since the library generates code from.protofiles at build time.