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.
What is this?
This library helps groups of peers vote on proposals and reach consensus, even when some peers are offline or trying to cause trouble. It's based on the Hashgraph-like Consensus Protocol RFC, which means:
- Fast: Reaches consensus in O(log n) rounds, so it scales well
- Secure: Works correctly even if up to 1/3 of peers are malicious (Byzantine fault tolerant)
- Simple: Easy to embed in your application with a clean API
How it works
- Someone creates a proposal (like "Should we upgrade to version 2?")
- Peers vote yes or no, with each vote cryptographically signed
- Votes link together in a hashgraph structure (like a blockchain, but more efficient)
- Once enough votes are collected, consensus is reached and everyone knows the result
The library handles all the tricky parts: validating signatures, checking vote chains, managing timeouts, and determining when consensus is reached.
Quick start
use ;
use PrivateKeySigner;
use Duration;
async
API Overview
Configuring a Scope
Scope vs Proposal Relationship
)
)
)
)
)
Scopes carry defaults (network type, thresholds, timeouts) so you don't have to pass config on every proposal. Use the builder to initialize or update a scope:
use ;
async
Creating a Service
// Simple: use defaults (in-memory storage, 10 max sessions per scope)
let service = default;
// Custom: set your own session limit
let service = new_with_max_sessions;
// Advanced: plug in your own storage and event bus
let service = new_with_components;
Working with Proposals
Create a proposal - Start a new voting session:
let proposal = service.create_proposal.await?;
Process incoming proposals - When you receive a proposal from the network:
service.process_incoming_proposal.await?;
List proposals - See what's active or finalized:
let active = service.get_active_proposals.await;
let finalized = service.get_reached_proposals.await;
Casting Votes
Cast your vote - Vote yes or no on a proposal:
let vote = service.cast_vote.await?;
Vote and fetch proposal - Useful for the creator who wants to gossip the updated proposal:
let proposal = service.cast_vote_and_get_proposal.await?;
Picking a config for your transport
- Gossipsub (default):
ConsensusConfig::gossipsub()enforces the RFC’s two-round flow (round 1 = proposal, round 2 = everyone’s votes). - P2P: use
ConsensusConfig::p2p()to derive the round cap dynamically (ceil(2n/3) of expected voters) and advance one round per vote.
Pass configs via create_proposal_with_config (or helper methods) when you need explicit control.
Scope defaults are usually easier: set them once with
service.scope(&scope).await?.with_network_type(...)...initialize().await?,
then override per proposal only when needed.
Process incoming votes - When you receive votes from other peers:
service.process_incoming_vote.await?;
Checking Results
Get consensus result - See if a proposal has reached consensus:
if let Some = service.get_consensus_result.await
Check vote count - See if enough votes have been collected:
let enough_votes = service
.has_sufficient_votes_for_proposal
.await?;
Events
Subscribe to events - Get notified when consensus is reached or fails:
use ConsensusEvent;
let mut receiver = service.subscribe_to_events;
spawn;
Statistics
Get scope statistics - See how many proposals are active, finalized, etc:
let stats = service.get_scope_stats.await;
println!;
Advanced Usage
Custom storage - Want to persist proposals to a database? Implement the ConsensusStorage trait:
Custom events - Need different event handling? Implement ConsensusEventBus:
Utility functions - The utils module provides helpers for validation and ID generation:
validate_proposal()- Check if a proposal and its votes are validvalidate_vote()- Verify a single vote's signature and structurevalidate_vote_chain()- Ensure vote parent/received hash chains are correcthas_sufficient_votes()- Quick threshold check (count-based only)calculate_consensus_result(votes, expected_voters, consensus_threshold, liveness_criteria_yes)- Determine the result from collected votes (returnsSome(result)when consensus is reached, otherwiseNone), using the configured threshold and liveness rules
Learn More
This library implements the Hashgraph-like Consensus Protocol RFC. For details on how the protocol works, security guarantees, and edge cases, check out the RFC.