1use serde::{Deserialize, Serialize};
35use std::sync::Arc;
36use tokio::sync::RwLock;
37
38#[cfg(feature = "consensus")]
39use lux_consensus::{Block as LuxBlock, Chain, Config as LuxConfig, Engine, ID, Vote as LuxVote, VoteType as LuxVoteType};
40
41use crate::ledger::{BlockHeader, MiningTransaction, VoteType, LedgerError};
42
43pub const AI_CHAIN_MAINNET_ID: u64 = 36963;
45pub const AI_CHAIN_TESTNET_ID: u64 = 36964;
46
47pub const AI_CHAIN_BLOCK_TIME_MS: u64 = 500;
49pub const AI_CHAIN_QUORUM_THRESHOLD: f64 = 0.69;
50pub const AI_CHAIN_FINALITY_ROUNDS: u32 = 2;
51pub const AI_CHAIN_SAMPLE_SIZE: usize = 20;
52
53#[derive(Debug, Clone, Serialize, Deserialize)]
55pub struct ConsensusConfig {
56 pub network_id: u64,
58 pub quantum_resistant: bool,
60 pub security_level: u32,
62 pub sample_size: usize,
64 pub quorum_size: usize,
66 pub block_time_ms: u64,
68 pub gpu_acceleration: bool,
70 pub bootstrap_peers: Vec<String>,
72}
73
74impl ConsensusConfig {
75 pub fn ai_chain_mainnet() -> Self {
77 Self {
78 network_id: AI_CHAIN_MAINNET_ID,
79 quantum_resistant: true,
80 security_level: 3, sample_size: AI_CHAIN_SAMPLE_SIZE,
82 quorum_size: AI_CHAIN_SAMPLE_SIZE, block_time_ms: AI_CHAIN_BLOCK_TIME_MS,
84 gpu_acceleration: true,
85 bootstrap_peers: vec![
86 "/dns4/boot1.ai-chain.hanzo.network/tcp/3691".to_string(),
87 "/dns4/boot2.ai-chain.hanzo.network/tcp/3691".to_string(),
88 "/dns4/boot3.ai-chain.hanzo.network/tcp/3691".to_string(),
89 ],
90 }
91 }
92
93 pub fn ai_chain_testnet() -> Self {
95 Self {
96 network_id: AI_CHAIN_TESTNET_ID,
97 quantum_resistant: true,
98 security_level: 3,
99 sample_size: AI_CHAIN_SAMPLE_SIZE,
100 quorum_size: AI_CHAIN_SAMPLE_SIZE,
101 block_time_ms: AI_CHAIN_BLOCK_TIME_MS,
102 gpu_acceleration: false,
103 bootstrap_peers: vec![
104 "/dns4/boot1.ai-chain-test.hanzo.network/tcp/3691".to_string(),
105 ],
106 }
107 }
108
109 #[cfg(feature = "consensus")]
111 pub fn to_lux_config(&self) -> LuxConfig {
112 LuxConfig {
113 alpha: self.quorum_size,
114 k: self.sample_size,
115 max_outstanding: 10,
116 max_poll_delay: std::time::Duration::from_millis(self.block_time_ms),
117 network_timeout: std::time::Duration::from_secs(5),
118 max_message_size: 2 * 1024 * 1024,
119 security_level: self.security_level,
120 quantum_resistant: self.quantum_resistant,
121 gpu_acceleration: self.gpu_acceleration,
122 }
123 }
124}
125
126#[derive(Debug, Clone, Serialize, Deserialize)]
128pub struct AIChainBlock {
129 pub id: [u8; 32],
131 pub parent_id: [u8; 32],
133 pub height: u64,
135 pub timestamp: u64,
137 pub proposer: Vec<u8>,
139 pub transactions: Vec<MiningTransaction>,
141 pub tx_root: [u8; 32],
143 pub state_root: [u8; 32],
145 pub signature: Vec<u8>,
147}
148
149impl AIChainBlock {
150 pub fn new(
152 parent_id: [u8; 32],
153 height: u64,
154 proposer: Vec<u8>,
155 transactions: Vec<MiningTransaction>,
156 ) -> Self {
157 let timestamp = std::time::SystemTime::now()
158 .duration_since(std::time::UNIX_EPOCH)
159 .unwrap()
160 .as_millis() as u64;
161
162 let tx_root = compute_tx_root(&transactions);
164
165 let id = compute_block_id(parent_id, height, timestamp, &tx_root);
167
168 Self {
169 id,
170 parent_id,
171 height,
172 timestamp,
173 proposer,
174 transactions,
175 tx_root,
176 state_root: [0u8; 32], signature: Vec::new(),
178 }
179 }
180
181 pub fn sign(&mut self, signature: Vec<u8>) {
183 self.signature = signature;
184 }
185
186 pub fn to_header(&self) -> BlockHeader {
188 BlockHeader {
189 height: self.height,
190 parent_hash: self.parent_id,
191 hash: self.id,
192 timestamp: self.timestamp,
193 proposer: self.proposer.clone(),
194 tx_root: self.tx_root,
195 state_root: self.state_root,
196 tx_count: self.transactions.len() as u32,
197 }
198 }
199
200 #[cfg(feature = "consensus")]
202 pub fn to_lux_block(&self) -> LuxBlock {
203 let payload = serde_json::to_vec(&self.transactions).unwrap_or_default();
204 LuxBlock::new(
205 ID::from(self.id),
206 ID::from(self.parent_id),
207 self.height,
208 payload,
209 )
210 }
211}
212
213#[derive(Debug, Clone, Serialize, Deserialize)]
215pub struct AIChainVote {
216 pub block_id: [u8; 32],
218 pub vote_type: VoteType,
220 pub voter: Vec<u8>,
222 pub signature: Vec<u8>,
224}
225
226impl AIChainVote {
227 pub fn new(block_id: [u8; 32], vote_type: VoteType, voter: Vec<u8>) -> Self {
229 Self {
230 block_id,
231 vote_type,
232 voter,
233 signature: Vec::new(),
234 }
235 }
236
237 pub fn sign(&mut self, signature: Vec<u8>) {
239 self.signature = signature;
240 }
241
242 #[cfg(feature = "consensus")]
244 pub fn to_lux_vote(&self) -> LuxVote {
245 let lux_vote_type = match self.vote_type {
246 VoteType::Preference => LuxVoteType::Preference,
247 VoteType::Commit => LuxVoteType::Commit,
248 VoteType::Cancel => LuxVoteType::Cancel,
249 };
250
251 LuxVote::new(
252 ID::from(self.block_id),
253 lux_vote_type,
254 ID::new(self.voter.clone()),
255 )
256 .with_signature(self.signature.clone())
257 }
258}
259
260#[derive(Debug, Clone, PartialEq)]
262pub enum ConsensusMode {
263 #[cfg(feature = "consensus")]
265 Embedded,
266 Rpc { endpoint: String },
268}
269
270pub struct ConsensusEngine {
272 config: ConsensusConfig,
274 mode: ConsensusMode,
276 #[cfg(feature = "consensus")]
278 chain: Option<Chain>,
279 height: Arc<RwLock<u64>>,
281 running: Arc<RwLock<bool>>,
283 pending_blocks: Arc<RwLock<Vec<AIChainBlock>>>,
285 accepted_blocks: Arc<RwLock<Vec<[u8; 32]>>>,
287}
288
289impl ConsensusEngine {
290 pub fn new(config: ConsensusConfig) -> Result<Self, ConsensusError> {
292 #[cfg(feature = "consensus")]
293 {
294 let lux_config = config.to_lux_config();
295 let chain = Chain::new(lux_config);
296
297 Ok(Self {
298 config,
299 mode: ConsensusMode::Embedded,
300 chain: Some(chain),
301 height: Arc::new(RwLock::new(0)),
302 running: Arc::new(RwLock::new(false)),
303 pending_blocks: Arc::new(RwLock::new(Vec::new())),
304 accepted_blocks: Arc::new(RwLock::new(Vec::new())),
305 })
306 }
307
308 #[cfg(not(feature = "consensus"))]
309 {
310 Ok(Self {
311 config,
312 mode: ConsensusMode::Rpc {
313 endpoint: "https://consensus.hanzo.network".to_string(),
314 },
315 height: Arc::new(RwLock::new(0)),
316 running: Arc::new(RwLock::new(false)),
317 pending_blocks: Arc::new(RwLock::new(Vec::new())),
318 accepted_blocks: Arc::new(RwLock::new(Vec::new())),
319 })
320 }
321 }
322
323 pub fn with_rpc(config: ConsensusConfig, endpoint: String) -> Self {
325 Self {
326 config,
327 mode: ConsensusMode::Rpc { endpoint },
328 #[cfg(feature = "consensus")]
329 chain: None,
330 height: Arc::new(RwLock::new(0)),
331 running: Arc::new(RwLock::new(false)),
332 pending_blocks: Arc::new(RwLock::new(Vec::new())),
333 accepted_blocks: Arc::new(RwLock::new(Vec::new())),
334 }
335 }
336
337 pub async fn start(&mut self) -> Result<(), ConsensusError> {
339 #[cfg(feature = "consensus")]
340 if let Some(ref mut chain) = self.chain {
341 chain.start().map_err(|e| ConsensusError::EngineError(e.to_string()))?;
342 }
343
344 *self.running.write().await = true;
345 Ok(())
346 }
347
348 pub async fn stop(&mut self) -> Result<(), ConsensusError> {
350 #[cfg(feature = "consensus")]
351 if let Some(ref mut chain) = self.chain {
352 chain.stop().map_err(|e| ConsensusError::EngineError(e.to_string()))?;
353 }
354
355 *self.running.write().await = false;
356 Ok(())
357 }
358
359 pub async fn submit_block(&mut self, block: AIChainBlock) -> Result<(), ConsensusError> {
361 if !*self.running.read().await {
362 return Err(ConsensusError::NotRunning);
363 }
364
365 #[cfg(feature = "consensus")]
366 if let Some(ref mut chain) = self.chain {
367 let lux_block = block.to_lux_block();
368 chain.add(lux_block).map_err(|e| ConsensusError::EngineError(e.to_string()))?;
369 }
370
371 self.pending_blocks.write().await.push(block);
373
374 Ok(())
375 }
376
377 pub async fn record_vote(&mut self, vote: AIChainVote) -> Result<bool, ConsensusError> {
379 if !*self.running.read().await {
380 return Err(ConsensusError::NotRunning);
381 }
382
383 #[cfg(feature = "consensus")]
384 if let Some(ref mut chain) = self.chain {
385 let lux_vote = vote.to_lux_vote();
386 chain.record_vote(lux_vote).map_err(|e| ConsensusError::EngineError(e.to_string()))?;
387
388 let id = ID::from(vote.block_id);
390 if chain.is_accepted(&id) {
391 self.accepted_blocks.write().await.push(vote.block_id);
392 return Ok(true);
393 }
394 }
395
396 Ok(false)
397 }
398
399 pub async fn is_accepted(&self, block_id: &[u8; 32]) -> bool {
401 #[cfg(feature = "consensus")]
402 if let Some(ref chain) = self.chain {
403 let id = ID::from(*block_id);
404 return chain.is_accepted(&id);
405 }
406
407 self.accepted_blocks.read().await.contains(block_id)
408 }
409
410 pub async fn get_height(&self) -> u64 {
412 *self.height.read().await
413 }
414
415 pub fn mode(&self) -> &ConsensusMode {
417 &self.mode
418 }
419
420 pub fn config(&self) -> &ConsensusConfig {
422 &self.config
423 }
424
425 pub fn is_quantum_safe(&self) -> bool {
427 self.config.quantum_resistant
428 }
429}
430
431#[derive(Debug, thiserror::Error)]
433pub enum ConsensusError {
434 #[error("Consensus engine not running")]
435 NotRunning,
436 #[error("Block not found: {0}")]
437 BlockNotFound(String),
438 #[error("Invalid block: {0}")]
439 InvalidBlock(String),
440 #[error("Invalid vote: {0}")]
441 InvalidVote(String),
442 #[error("Engine error: {0}")]
443 EngineError(String),
444 #[error("Signature verification failed")]
445 SignatureError,
446 #[error("Network error: {0}")]
447 NetworkError(String),
448}
449
450impl From<ConsensusError> for LedgerError {
451 fn from(e: ConsensusError) -> Self {
452 LedgerError::TransactionFailed(e.to_string())
453 }
454}
455
456fn compute_tx_root(transactions: &[MiningTransaction]) -> [u8; 32] {
460 if transactions.is_empty() {
461 return [0u8; 32];
462 }
463
464 let tx_bytes: Vec<u8> = transactions
465 .iter()
466 .flat_map(|tx| serde_json::to_vec(tx).unwrap_or_default())
467 .collect();
468
469 *blake3::hash(&tx_bytes).as_bytes()
470}
471
472fn compute_block_id(
474 parent_id: [u8; 32],
475 height: u64,
476 timestamp: u64,
477 tx_root: &[u8; 32],
478) -> [u8; 32] {
479 let mut data = Vec::new();
480 data.extend_from_slice(&parent_id);
481 data.extend_from_slice(&height.to_le_bytes());
482 data.extend_from_slice(×tamp.to_le_bytes());
483 data.extend_from_slice(tx_root);
484 *blake3::hash(&data).as_bytes()
485}
486
487#[cfg(test)]
488mod tests {
489 use super::*;
490
491 #[test]
492 fn test_config_mainnet() {
493 let config = ConsensusConfig::ai_chain_mainnet();
494 assert_eq!(config.network_id, AI_CHAIN_MAINNET_ID);
495 assert!(config.quantum_resistant);
496 assert_eq!(config.security_level, 3);
497 assert_eq!(config.sample_size, 20);
498 assert!(!config.bootstrap_peers.is_empty());
499 }
500
501 #[test]
502 fn test_config_testnet() {
503 let config = ConsensusConfig::ai_chain_testnet();
504 assert_eq!(config.network_id, AI_CHAIN_TESTNET_ID);
505 assert!(config.quantum_resistant);
506 }
507
508 #[test]
509 fn test_block_creation() {
510 let parent = [0u8; 32];
511 let proposer = vec![1u8; 32];
512 let block = AIChainBlock::new(parent, 1, proposer.clone(), vec![]);
513
514 assert_eq!(block.height, 1);
515 assert_eq!(block.parent_id, parent);
516 assert_eq!(block.proposer, proposer);
517 assert!(block.timestamp > 0);
518 }
519
520 #[test]
521 fn test_vote_creation() {
522 let block_id = [1u8; 32];
523 let voter = vec![2u8; 32];
524 let vote = AIChainVote::new(block_id, VoteType::Preference, voter.clone());
525
526 assert_eq!(vote.block_id, block_id);
527 assert_eq!(vote.vote_type, VoteType::Preference);
528 assert_eq!(vote.voter, voter);
529 }
530
531 #[test]
532 fn test_compute_tx_root() {
533 let empty_root = compute_tx_root(&[]);
534 assert_eq!(empty_root, [0u8; 32]);
535 }
536
537 #[test]
538 fn test_compute_block_id() {
539 let parent = [0u8; 32];
540 let tx_root = [1u8; 32];
541 let id = compute_block_id(parent, 1, 1000, &tx_root);
542
543 let id2 = compute_block_id(parent, 1, 1000, &tx_root);
545 assert_eq!(id, id2);
546
547 let id3 = compute_block_id(parent, 2, 1000, &tx_root);
549 assert_ne!(id, id3);
550 }
551
552 #[tokio::test]
553 async fn test_engine_creation() {
554 let config = ConsensusConfig::ai_chain_testnet();
555 let engine = ConsensusEngine::new(config).unwrap();
556
557 assert!(engine.is_quantum_safe());
558 assert_eq!(engine.get_height().await, 0);
559 }
560
561 #[tokio::test]
562 async fn test_engine_start_stop() {
563 let config = ConsensusConfig::ai_chain_testnet();
564 let mut engine = ConsensusEngine::new(config).unwrap();
565
566 assert!(engine.start().await.is_ok());
567 assert!(engine.stop().await.is_ok());
568 }
569}