Skip to main content

tenzro_consensus/
lib.rs

1//! HotStuff-2 BFT Consensus Engine for Tenzro Network
2//!
3//! This crate implements the HotStuff-2 consensus protocol, a two-phase BFT
4//! consensus algorithm with O(n) linear communication complexity per view.
5//!
6//! # Overview
7//!
8//! HotStuff-2 provides:
9//! - **Fast Finality**: Two-phase protocol (PREPARE → COMMIT → DECIDE)
10//! - **Linear Communication**: O(n) message complexity per view
11//! - **Optimistic Responsiveness**: Commits in network delay time under good conditions
12//! - **TEE Integration**: Validators with TEE attestation get priority in leader selection
13//! - **Robust Liveness**: Automatic view changes on timeout
14//!
15//! # Architecture
16//!
17//! The consensus engine consists of several key components:
18//!
19//! - **HotStuff2Engine**: Main consensus engine implementing the protocol
20//! - **ValidatorSet**: Manages the set of validators and their voting power
21//! - **EpochManager**: Handles epoch transitions and validator set updates
22//! - **VoteCollector**: Collects votes and forms quorum certificates
23//! - **BlockProposer**: Creates block proposals with transaction selection
24//! - **Mempool**: Transaction pool with priority ordering
25//! - **FinalityTracker**: Tracks finalized blocks and sends notifications
26//!
27//! # Protocol Flow
28//!
29//! 1. **PREPARE Phase**:
30//!    - Leader proposes a block
31//!    - Validators vote on the proposal
32//!    - Prepare QC formed when 2f+1 votes collected
33//!
34//! 2. **COMMIT Phase**:
35//!    - Leader shares prepare QC
36//!    - Validators vote to commit
37//!    - Commit QC formed when 2f+1 votes collected
38//!
39//! 3. **DECIDE Phase**:
40//!    - Block is finalized
41//!    - Transactions removed from mempool
42//!    - Advance to next height
43//!
44//! # TEE Integration
45//!
46//! Validators with valid TEE attestation receive priority in leader selection,
47//! providing hardware-rooted trust. The leader selection algorithm gives
48//! TEE-attested validators 2x voting weight for leader selection while
49//! maintaining standard voting power for consensus.
50//!
51//! # Examples
52//!
53//! ```no_run
54//! use tenzro_consensus::{
55//!     HotStuff2Engine, ConsensusConfig, ConsensusEngine,
56//!     EpochManager, ValidatorInfo,
57//! };
58//! use tenzro_crypto::pq::MlDsaSigningKey;
59//! use tenzro_crypto::{KeyPair, KeyType};
60//! use tenzro_types::primitives::Address;
61//!
62//! #[tokio::main]
63//! async fn main() -> tenzro_consensus::Result<()> {
64//!     // Generate validator triple keypair (Ed25519 classical + ML-DSA-65 PQ
65//!     // + BLS12-381 for HotStuff-2 vote-signature aggregation)
66//!     let keypair = KeyPair::generate(KeyType::Ed25519)?;
67//!     let pq_key = MlDsaSigningKey::generate();
68//!     let bls_key = tenzro_crypto::bls::BlsKeyPair::generate()?;
69//!
70//!     // Convert address (tenzro_crypto::Address is 20 bytes, tenzro_types::Address is 32 bytes)
71//!     let crypto_addr = keypair.address();
72//!     let mut addr_bytes = [0u8; 32];
73//!     addr_bytes[..20].copy_from_slice(crypto_addr.as_bytes());
74//!     let address = Address::new(addr_bytes);
75//!
76//!     // Create validators with mandatory PQ + BLS verifying keys
77//!     let validators = vec![
78//!         ValidatorInfo::new(
79//!             address,
80//!             keypair.public_key().clone(),
81//!             pq_key.verifying_key_bytes().to_vec(),
82//!             bls_key.public_key().to_bytes().to_vec(),
83//!             1000,
84//!         ),
85//!     ];
86//!
87//!     // Create epoch manager
88//!     let epoch_manager = EpochManager::new(validators, 10000)?;
89//!
90//!     // Create consensus engine
91//!     let config = ConsensusConfig::default()
92//!         .with_block_time(400)
93//!         .with_view_timeout(2000);
94//!
95//!     let mut engine = HotStuff2Engine::new(keypair, pq_key, bls_key, config, epoch_manager);
96//!
97//!     // Start consensus
98//!     engine.start().await?;
99//!
100//!     // Engine now participates in consensus...
101//!
102//!     Ok(())
103//! }
104//! ```
105
106pub mod admission;
107pub mod config;
108pub mod epoch_manager;
109pub mod error;
110pub mod finality;
111pub mod hotstuff2;
112pub mod leader_reputation;
113pub mod mempool;
114pub mod proposer;
115pub mod timeout;
116pub mod traits;
117pub mod validator;
118pub mod vote_state;
119pub mod voter;
120
121// Re-export commonly used types
122pub use admission::{
123    AdmissionConfig, AdmissionController, AdmissionDecision, BucketSnapshot,
124    DefaultLaneResolver, Lane, LaneResolver, LaneStats,
125};
126pub use config::{BftThreshold, ConsensusConfig, ProposerElectionKind};
127pub use epoch_manager::{Epoch, EpochManager, EpochStateStore, EpochStats};
128pub use error::{ConsensusError, Result};
129pub use finality::{FinalityNotification, FinalityTracker, ForkChoice};
130pub use hotstuff2::{
131    BlockProvider, ConsensusOutMessage, HotStuff2Engine, Phase, StateRootProvider,
132};
133pub use leader_reputation::{
134    proposer_window, reputation_seed, voter_window, LeaderReputation, ProposerHistory,
135    ProposerRecord, ValidatorWeights, VoterHistory, VoterRecord, ACTIVE_WEIGHT, FAILED_WEIGHT,
136    FAILURE_THRESHOLD_PERCENT, INACTIVE_WEIGHT, NO_TEE_MULTIPLIER_BPS, TEE_MULTIPLIER_BPS,
137};
138pub use mempool::{Mempool, MempoolStats};
139pub use proposer::BlockProposer;
140pub use timeout::{
141    CollectOutcome, NecCollectOutcome, NecSigner, NoEndorsementCertificate, NoEndorsementCollector,
142    NoEndorsementMsg, TcSigner, TimeoutCertificate, TimeoutCollector, TimeoutMsg,
143    NO_ENDORSEMENT_CERTIFICATE_FORMAT_VERSION, NO_ENDORSEMENT_MSG_FORMAT_VERSION,
144    TIMEOUT_CERTIFICATE_FORMAT_VERSION, TIMEOUT_MSG_FORMAT_VERSION,
145};
146pub use traits::{ConsensusEngine, ConsensusNetwork, SlashingCallback, StateManager};
147pub use validator::{
148    EquivocationDetector, EquivocationEvidence, ProposerElection, ReputationProposer,
149    RoundRobinProposer, ValidatorInfo, ValidatorSet, ValidatorStatus,
150};
151pub use vote_state::{
152    open_default_file_store, FileVoteStateStore, LastSignState, MemoryVoteStateStore,
153    VoteStateStore, VoteStep, VrsDecision,
154};
155pub use voter::{bls_payload_for_vote, QuorumCertificate, Vote, VoteCollector, VoteType};
156
157#[cfg(test)]
158mod tests {
159    use super::*;
160    use tenzro_crypto::bls::BlsKeyPair;
161    use tenzro_crypto::pq::MlDsaSigningKey;
162    use tenzro_crypto::{KeyPair, KeyType};
163
164    #[test]
165    fn test_crate_version() {
166        // Basic smoke test to ensure the crate compiles
167        let config = ConsensusConfig::default();
168        assert_eq!(config.block_time_ms, 400);
169    }
170
171    fn convert_address(crypto_addr: tenzro_crypto::Address) -> tenzro_types::primitives::Address {
172        let mut addr_bytes = [0u8; 32];
173        addr_bytes[..20].copy_from_slice(crypto_addr.as_bytes());
174        tenzro_types::primitives::Address::new(addr_bytes)
175    }
176
177    #[test]
178    fn test_validator_creation() {
179        let keypair = KeyPair::generate(KeyType::Ed25519).unwrap();
180        let address = convert_address(keypair.address());
181        let pq = MlDsaSigningKey::generate();
182        let bls = BlsKeyPair::generate().unwrap();
183        let validator = ValidatorInfo::new(
184            address,
185            keypair.public_key().clone(),
186            pq.verifying_key_bytes().to_vec(),
187            bls.public_key().to_bytes().to_vec(),
188            1000,
189        );
190
191        assert_eq!(validator.stake, 1000);
192        assert!(validator.is_active());
193    }
194
195    #[test]
196    fn test_epoch_manager_creation() {
197        let keypair = KeyPair::generate(KeyType::Ed25519).unwrap();
198        let address = convert_address(keypair.address());
199        let pq = MlDsaSigningKey::generate();
200        let bls = BlsKeyPair::generate().unwrap();
201        let validators = vec![
202            ValidatorInfo::new(
203                address,
204                keypair.public_key().clone(),
205                pq.verifying_key_bytes().to_vec(),
206                bls.public_key().to_bytes().to_vec(),
207                1000,
208            ),
209        ];
210
211        let epoch_manager = EpochManager::new(validators, 100).unwrap();
212        let epoch = epoch_manager.current_epoch();
213
214        assert_eq!(epoch.number, 0);
215        assert_eq!(epoch.duration(), 100);
216    }
217
218    #[tokio::test]
219    async fn test_consensus_engine_creation() {
220        let keypair = KeyPair::generate(KeyType::Ed25519).unwrap();
221        let address = convert_address(keypair.address());
222        let pq = MlDsaSigningKey::generate();
223        let bls = BlsKeyPair::generate().unwrap();
224        let validators = vec![
225            ValidatorInfo::new(
226                address,
227                keypair.public_key().clone(),
228                pq.verifying_key_bytes().to_vec(),
229                bls.public_key().to_bytes().to_vec(),
230                1000,
231            ),
232        ];
233
234        let config = ConsensusConfig::default();
235        let epoch_manager = EpochManager::new(validators, 100).unwrap();
236        let pq_engine = MlDsaSigningKey::generate();
237        let bls_engine = BlsKeyPair::generate().unwrap();
238        let engine = HotStuff2Engine::new(keypair, pq_engine, bls_engine, config, epoch_manager);
239
240        assert_eq!(engine.finalized_height().await, tenzro_types::primitives::BlockHeight::from(0));
241    }
242}