A production-ready Go implementation of the HotStuff-2 Byzantine Fault Tolerant consensus protocol.
- Two-phase BFT consensus - Optimistic responsiveness with 2 network delays
- Linear view-change - O(n) data per message during leader changes (O(n²) total messages, amortized O(n))
- Formally verified - TLA+ model checked (12 safety invariants, 4 liveness properties)
- Dual signature schemes - Ed25519 (O(n) multi-sig) and BLS12-381 (O(1) aggregate sig)
- Configurable block time - Target block time from milliseconds to minutes
- Adaptive pacemaker - Exponential backoff timeouts for liveness
- Generic design - Supports custom hash types and block structures
- Payload-agnostic - Opaque block payload supports any execution model (transactions, DAG refs, rollup batches)
- Byzantine testing - Twins framework for fault injection scenarios
See HotStuff-2 in action with real consensus running on a simulated network:
go run demo/main.go
# Open http://localhost:8080 in your browserFeatures:
- Real-time visualization of nodes and message passing
- Fault injection (crash nodes, create network partitions)
- Configurable block time (optimistic vs 1-second target)
- Event log with CSV export
- Support for 4-16 node networks (f=1 to f=5)
See demo/README.md for details.
package main
import (
"time"
"github.com/edgedlt/hotstuff2"
"github.com/edgedlt/hotstuff2/timer"
"go.uber.org/zap"
)
func main() {
// Configure consensus
cfg, _ := hotstuff2.NewConfig[MyHash](
hotstuff2.WithMyIndex[MyHash](0),
hotstuff2.WithValidators[MyHash](validators),
hotstuff2.WithPrivateKey[MyHash](privateKey),
hotstuff2.WithStorage[MyHash](storage),
hotstuff2.WithNetwork[MyHash](network),
hotstuff2.WithExecutor[MyHash](executor),
hotstuff2.WithTimer[MyHash](timer.NewRealTimer()),
hotstuff2.WithLogger[MyHash](zap.NewProduction()),
// Optional: Configure target block time (default is optimistically responsive)
hotstuff2.WithTargetBlockTime[MyHash](5 * time.Second),
)
// Create and start consensus
hs, _ := hotstuff2.NewHotStuff2(cfg, func(block hotstuff2.Block[MyHash]) {
log.Printf("Committed block %d", block.Height())
})
hs.Start()
defer hs.Stop()
}See the Integration Guide for complete documentation.
go get github.com/edgedlt/hotstuff2Requirements: Go 1.23+
hotstuff2/
├── hotstuff2.go # Core consensus state machine
├── config.go # Configuration with functional options
├── context.go # Consensus state management
├── types.go # Core interfaces (Hash, Block, Storage, Network)
├── vote.go # Vote creation and verification
├── quorum_cert.go # Quorum certificate aggregation
├── pacemaker.go # View synchronization and timeouts
├── payload.go # Message serialization
├── timer/ # Timer implementations (Real, Mock, Adaptive)
├── internal/crypto/ # Ed25519 (multi-sig) and BLS12-381 (aggregate sig)
├── twins/ # Byzantine fault injection testing
└── formal-models/tla/ # TLA+ formal specification
Implement these interfaces to integrate with your blockchain:
// Your hash type
type Hash interface {
Bytes() []byte
Equals(other Hash) bool
String() string
}
// Your block type (payload is opaque - consensus doesn't interpret it)
type Block[H Hash] interface {
Hash() H
Height() uint32
PrevHash() H
Payload() []byte // Opaque: transactions, DAG refs, rollup batches, etc.
ProposerIndex() uint16
Timestamp() uint64
Bytes() []byte
}
// Persistent storage (safety-critical)
type Storage[H Hash] interface {
GetBlock(hash H) (Block[H], error)
PutBlock(block Block[H]) error
GetLastBlock() (Block[H], error)
GetQC(nodeHash H) (QuorumCertificate[H], error)
PutQC(qc QuorumCertificate[H]) error
GetHighestLockedQC() (QuorumCertificate[H], error)
PutHighestLockedQC(qc QuorumCertificate[H]) error
GetView() (uint32, error)
PutView(view uint32) error
Close() error
}
// Network message delivery
type Network[H Hash] interface {
Broadcast(payload ConsensusPayload[H])
SendTo(validatorIndex uint16, payload ConsensusPayload[H])
Receive() <-chan ConsensusPayload[H]
Close() error
}
// Block execution
type Executor[H Hash] interface {
Execute(block Block[H]) (stateHash H, err error)
Verify(block Block[H]) error
GetStateHash() H
CreateBlock(height uint32, prevHash H, proposerIndex uint16) (Block[H], error)
}HotStuff-2 achieves consensus in two phases:
- Propose: Leader broadcasts block with justification QC
- Vote: Replicas vote if proposal satisfies SafeNode rule
- QC Formation: Leader aggregates 2f+1 votes into QC
- Commit: Two consecutive QCs commit the first block (two-chain rule)
Safety: Replicas only vote for proposals that extend their locked QC or have a higher justification QC.
Liveness: Adaptive timeouts with exponential backoff ensure progress under partial synchrony.
For details, see the Protocol Guide.
HotStuff-2's efficient view-change protocol enables scaling to hundreds of validators. During normal operation, communication is O(n) messages per view. View changes require O(n²) messages but occur rarely, keeping amortized complexity low. This makes HotStuff-2 suitable for both consortium networks and public proof-of-stake chains.
| Validators | Max Faults | Quorum | Use Case |
|---|---|---|---|
| 4 | 1 | 3 | Development, small teams |
| 21 | 7 | 15 | Consortium networks |
| 100 | 33 | 67 | Mid-size PoS chains |
| 200+ | 66+ | 134+ | Large validator sets |
Byzantine fault tolerance: f < n/3 (tolerates up to f Byzantine validators)
The protocol is formally verified using TLA+ model checking:
Safety Invariants (12 properties verified):
- Agreement: No conflicting commits at same height
- Validity: Only proposed blocks can be committed
- No double voting: At most one vote per view per replica
- QC integrity: Quorum certificates require 2f+1 distinct signers
Liveness Properties (4 properties verified under fairness):
- Eventually some block commits
- View synchronization achieved
- Progress guaranteed under partial synchrony
Verification Results:
- 2.6M states explored
- 790K distinct states
- All properties verified
See formal-models/tla/ for the TLA+ specification.
# Run all tests
go test ./...
# Run with race detection
go test -race ./...
# Run benchmarks
go test -bench=. -benchmem
# Run specific benchmark suite
./bench.sh quick- Unit tests: Individual component testing
- Integration tests: Multi-node consensus scenarios
- Twins tests: Byzantine fault injection (100+ scenarios)
- Benchmarks: Performance validation
Benchmarked on AMD Ryzen 9 5900X, Go 1.24:
| Operation | Ed25519 | BLS12-381 | Notes |
|---|---|---|---|
| Sign | 50.2K ops/sec (20μs) | 7.3K ops/sec (137μs) | Ed25519 ~7x faster |
| Verify | 21.4K ops/sec (47μs) | 914 ops/sec (1.1ms) | Ed25519 ~23x faster |
| Aggregate | N/A | 190.7K ops/sec (5μs) | BLS-only, O(1) signatures |
| Operation | 4 nodes | 7 nodes | 10 nodes | 22 nodes |
|---|---|---|---|---|
| QC Formation | 506ns | 682ns | 864ns | 2.5μs |
| QC Validation | 47μs | 47μs | 47μs | 47μs |
| Validators | Recommended | QC Size | Rationale |
|---|---|---|---|
| 4-22 | Ed25519 | O(n) | Faster verification |
| 25-100 | Either | - | Consider bandwidth needs |
| 100+ | BLS | O(1) | 75% bandwidth savings |
Run benchmarks:
./bench.sh quick # Quick benchmarks
./bench.sh full # Full suite with HTML reportSee bench/README.md for benchmark documentation.
| Document | Description |
|---|---|
| Protocol Guide | Algorithm explanation (quick overview + deep dive) |
| Integration Guide | How to integrate HotStuff-2 into your protocol |
| Interactive Demo | Web-based demo with network simulation and fault injection |
| TLA+ Specification | Formal verification details |
| Implementation Mapping | TLA+ to Go code mapping |
| Twins Testing | Byzantine fault injection framework |
| Benchmarks | Performance testing guide |
HotStuff-2 is suitable for any blockchain requiring BFT consensus with fast finality:
Public Networks
- Proof-of-stake L1 chains
- Validator-based L2 networks
- Cross-chain bridge committees
Consortium & Enterprise
- Multi-organization networks
- Financial settlement systems
- Supply chain coordination
Why HotStuff-2?
- Sub-second finality (no probabilistic confirmation)
- Scales to hundreds of validators
- Tolerates up to 1/3 Byzantine faults
- Efficient view-change on leader failure
Contributions welcome! Please:
- Fork the repository
- Create a feature branch
- Add tests for new functionality
- Ensure all tests pass (
go test ./...) - Submit a pull request
- HotStuff-2 Paper - Protocol specification
- Original HotStuff - Foundation protocol
- nspcc-dev/dbft - Architecture inspiration
- HotStuff-2 paper authors for the algorithm design
- nspcc-dev/dbft for interface patterns
- relab/hotstuff for Twins testing approach
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.