Skip to main content

hanzo_mining/
ledger.rs

1//! Global AI Mining Ledger - Powered by Lux Consensus
2//!
3//! This module implements the global ledger for AI coin mining, using Lux's
4//! quantum-safe consensus protocol for transaction finality. The ledger tracks:
5//!
6//! - Mining rewards earned across the network
7//! - Data sharing contributions
8//! - Compute provisioning
9//! - Model hosting rewards
10//! - Cross-chain teleport transfers
11//!
12//! ## Architecture
13//!
14//! The mining ledger operates as an overlay on the Lux consensus layer:
15//! - Lux provides BFT consensus with 2-round finality
16//! - Quantum-safe signatures (ML-DSA) for all transactions
17//! - Sub-second block times with 69% quorum threshold
18//!
19//! ## Usage
20//!
21//! ```ignore
22//! use hanzo_mining::ledger::{MiningLedger, LedgerConfig};
23//! use hanzo_mining::wallet::MiningWallet;
24//!
25//! // Create quantum-safe wallet
26//! let wallet = MiningWallet::generate_quantum_safe().await?;
27//!
28//! // Connect to global ledger
29//! let ledger = MiningLedger::connect(LedgerConfig::mainnet()).await?;
30//!
31//! // Submit mining reward claim
32//! let tx = ledger.claim_reward(&wallet, reward_proof).await?;
33//! ```
34
35use crate::{NetworkType, PerformanceStats, MiningRewardType};
36use crate::evm::{TeleportDestination, TeleportTransfer, TeleportStatus};
37use serde::{Deserialize, Serialize};
38use std::collections::HashMap;
39use std::sync::Arc;
40use tokio::sync::RwLock;
41
42/// Lux consensus network IDs
43pub const LUX_MAINNET_NETWORK_ID: u32 = 1;
44pub const LUX_TESTNET_NETWORK_ID: u32 = 5;
45
46/// AI Protocol network IDs (overlay on Lux)
47pub const AI_MAINNET_ID: u32 = 36963;
48pub const AI_TESTNET_ID: u32 = 36964;
49
50/// Block production parameters
51pub const BLOCK_TIME_MS: u64 = 500;      // 500ms block time
52pub const QUORUM_THRESHOLD: f64 = 0.69;   // 69% BFT threshold
53pub const FINALITY_ROUNDS: u32 = 2;       // 2-round finality
54
55/// Ledger configuration
56#[derive(Debug, Clone, Serialize, Deserialize)]
57pub struct LedgerConfig {
58    /// Network type
59    pub network: NetworkType,
60    /// Lux consensus RPC endpoint
61    pub consensus_rpc: String,
62    /// P2P bootstrap peers
63    pub bootstrap_peers: Vec<String>,
64    /// Block time in milliseconds
65    pub block_time_ms: u64,
66    /// Enable quantum-safe mode
67    pub quantum_safe: bool,
68    /// Security level (NIST 2, 3, or 5)
69    pub security_level: u8,
70}
71
72impl LedgerConfig {
73    pub fn mainnet() -> Self {
74        Self {
75            network: NetworkType::HanzoMainnet,
76            consensus_rpc: "https://consensus.hanzo.network".to_string(),
77            bootstrap_peers: vec![
78                "/dns4/boot1.hanzo.network/tcp/3691".to_string(),
79                "/dns4/boot2.hanzo.network/tcp/3691".to_string(),
80                "/dns4/boot3.hanzo.network/tcp/3691".to_string(),
81            ],
82            block_time_ms: BLOCK_TIME_MS,
83            quantum_safe: true,
84            security_level: 3, // NIST Level 3 (ML-DSA-65)
85        }
86    }
87
88    pub fn testnet() -> Self {
89        Self {
90            network: NetworkType::HanzoTestnet,
91            consensus_rpc: "https://consensus.hanzo-test.network".to_string(),
92            bootstrap_peers: vec![
93                "/dns4/boot1.hanzo-test.network/tcp/3691".to_string(),
94            ],
95            block_time_ms: BLOCK_TIME_MS,
96            quantum_safe: true,
97            security_level: 3,
98        }
99    }
100
101    pub fn zoo_mainnet() -> Self {
102        Self {
103            network: NetworkType::ZooMainnet,
104            consensus_rpc: "https://consensus.zoo.network".to_string(),
105            bootstrap_peers: vec![
106                "/dns4/boot1.zoo.network/tcp/3691".to_string(),
107                "/dns4/boot2.zoo.network/tcp/3691".to_string(),
108            ],
109            block_time_ms: BLOCK_TIME_MS,
110            quantum_safe: true,
111            security_level: 3,
112        }
113    }
114}
115
116/// Block header in the mining ledger
117#[derive(Debug, Clone, Serialize, Deserialize)]
118pub struct BlockHeader {
119    /// Block height
120    pub height: u64,
121    /// Previous block hash (Blake3)
122    pub parent_hash: [u8; 32],
123    /// Block hash
124    pub hash: [u8; 32],
125    /// Timestamp (Unix ms)
126    pub timestamp: u64,
127    /// Proposer's quantum-safe public key
128    pub proposer: Vec<u8>,
129    /// Merkle root of transactions
130    pub tx_root: [u8; 32],
131    /// Merkle root of state
132    pub state_root: [u8; 32],
133    /// Number of transactions
134    pub tx_count: u32,
135}
136
137/// Mining transaction types
138#[derive(Debug, Clone, Serialize, Deserialize)]
139pub enum MiningTransaction {
140    /// Register as a miner on the network
141    RegisterMiner {
142        /// Quantum-safe public key
143        public_key: Vec<u8>,
144        /// Miner capabilities
145        capabilities: Vec<u8>,
146        /// Performance stats
147        stats: PerformanceStats,
148        /// Signature (ML-DSA)
149        signature: Vec<u8>,
150    },
151    /// Submit proof of work/contribution
152    SubmitProof {
153        /// Miner public key
154        miner: Vec<u8>,
155        /// Type of contribution
156        reward_type: MiningRewardType,
157        /// Proof data (varies by type)
158        proof: Vec<u8>,
159        /// Signature
160        signature: Vec<u8>,
161    },
162    /// Claim accumulated rewards
163    ClaimReward {
164        /// Miner public key
165        miner: Vec<u8>,
166        /// Reward amount (in wei)
167        amount: u128,
168        /// Recipient address
169        recipient: String,
170        /// Merkle proof of rewards
171        proof: Vec<u8>,
172        /// Signature
173        signature: Vec<u8>,
174    },
175    /// Teleport AI coins to EVM chain
176    TeleportOut {
177        /// Source miner
178        from: Vec<u8>,
179        /// Destination chain
180        destination: TeleportDestination,
181        /// Destination address
182        to_address: String,
183        /// Amount to teleport
184        amount: u128,
185        /// Signature
186        signature: Vec<u8>,
187    },
188    /// Receive teleported coins from EVM
189    TeleportIn {
190        /// Source chain
191        source_chain: u64,
192        /// Source transaction hash
193        source_tx: String,
194        /// Recipient public key
195        recipient: Vec<u8>,
196        /// Amount received
197        amount: u128,
198        /// Relay signature
199        relay_signature: Vec<u8>,
200    },
201    /// Update miner status/capabilities
202    UpdateMiner {
203        /// Miner public key
204        miner: Vec<u8>,
205        /// New capabilities
206        capabilities: Option<Vec<u8>>,
207        /// New performance stats
208        stats: Option<PerformanceStats>,
209        /// Signature
210        signature: Vec<u8>,
211    },
212    /// Validator vote for consensus
213    Vote {
214        /// Voter's public key
215        voter: Vec<u8>,
216        /// Block being voted on
217        block_hash: [u8; 32],
218        /// Vote type (preference, commit, cancel)
219        vote_type: VoteType,
220        /// Quantum-safe signature
221        signature: Vec<u8>,
222    },
223}
224
225/// Vote types for consensus
226#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
227pub enum VoteType {
228    /// Preference vote
229    Preference,
230    /// Commit vote (finalizes block)
231    Commit,
232    /// Cancel vote (rejects block)
233    Cancel,
234}
235
236/// Transaction status
237#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
238pub enum TransactionStatus {
239    /// Transaction is pending
240    Pending,
241    /// Transaction is in mempool
242    InMempool,
243    /// Transaction is included in block
244    Included { block_height: u64 },
245    /// Transaction is finalized
246    Finalized { block_height: u64 },
247    /// Transaction failed
248    Failed { reason: String },
249}
250
251/// Miner state in the ledger
252#[derive(Debug, Clone, Serialize, Deserialize)]
253pub struct MinerState {
254    /// Quantum-safe public key
255    pub public_key: Vec<u8>,
256    /// Address (derived from public key)
257    pub address: String,
258    /// Total rewards earned (in wei)
259    pub total_earned: u128,
260    /// Pending rewards (claimable)
261    pub pending_rewards: u128,
262    /// Registration block
263    pub registered_at: u64,
264    /// Last active block
265    pub last_active: u64,
266    /// Reputation score (0-100)
267    pub reputation: u64,
268    /// Jobs completed
269    pub jobs_completed: u64,
270    /// Performance stats
271    pub stats: PerformanceStats,
272    /// Active capabilities
273    pub capabilities: Vec<u8>,
274}
275
276/// Global mining ledger client
277pub struct MiningLedger {
278    /// Configuration
279    config: LedgerConfig,
280    /// Current block height
281    current_height: Arc<RwLock<u64>>,
282    /// Local miner states cache
283    miners: Arc<RwLock<HashMap<String, MinerState>>>,
284    /// Pending transactions
285    pending_txs: Arc<RwLock<Vec<(String, MiningTransaction)>>>,
286    /// Connected to network
287    connected: Arc<RwLock<bool>>,
288    /// HTTP client for RPC
289    http_client: reqwest::Client,
290}
291
292impl MiningLedger {
293    /// Connect to the global mining ledger
294    pub async fn connect(config: LedgerConfig) -> Result<Self, LedgerError> {
295        let ledger = Self {
296            config,
297            current_height: Arc::new(RwLock::new(0)),
298            miners: Arc::new(RwLock::new(HashMap::new())),
299            pending_txs: Arc::new(RwLock::new(Vec::new())),
300            connected: Arc::new(RwLock::new(false)),
301            http_client: reqwest::Client::new(),
302        };
303
304        // Connect to consensus network
305        ledger.sync_state().await?;
306        *ledger.connected.write().await = true;
307
308        Ok(ledger)
309    }
310
311    /// Sync local state with network
312    async fn sync_state(&self) -> Result<(), LedgerError> {
313        // Get current block height from consensus RPC
314        let height = self.get_block_height().await?;
315        *self.current_height.write().await = height;
316        Ok(())
317    }
318
319    /// Get current block height
320    pub async fn get_block_height(&self) -> Result<u64, LedgerError> {
321        let response = self.rpc_call("ledger.getHeight", serde_json::json!({})).await?;
322        let height = response.get("height")
323            .and_then(|h| h.as_u64())
324            .unwrap_or(0);
325        Ok(height)
326    }
327
328    /// Register a new miner
329    pub async fn register_miner(
330        &self,
331        public_key: &[u8],
332        capabilities: &[u8],
333        stats: &PerformanceStats,
334        signature: &[u8],
335    ) -> Result<String, LedgerError> {
336        let tx = MiningTransaction::RegisterMiner {
337            public_key: public_key.to_vec(),
338            capabilities: capabilities.to_vec(),
339            stats: stats.clone(),
340            signature: signature.to_vec(),
341        };
342
343        self.submit_transaction(tx).await
344    }
345
346    /// Submit a mining proof
347    pub async fn submit_proof(
348        &self,
349        miner: &[u8],
350        reward_type: MiningRewardType,
351        proof: &[u8],
352        signature: &[u8],
353    ) -> Result<String, LedgerError> {
354        let tx = MiningTransaction::SubmitProof {
355            miner: miner.to_vec(),
356            reward_type,
357            proof: proof.to_vec(),
358            signature: signature.to_vec(),
359        };
360
361        self.submit_transaction(tx).await
362    }
363
364    /// Claim accumulated rewards
365    pub async fn claim_rewards(
366        &self,
367        miner: &[u8],
368        amount: u128,
369        recipient: &str,
370        proof: &[u8],
371        signature: &[u8],
372    ) -> Result<String, LedgerError> {
373        let tx = MiningTransaction::ClaimReward {
374            miner: miner.to_vec(),
375            amount,
376            recipient: recipient.to_string(),
377            proof: proof.to_vec(),
378            signature: signature.to_vec(),
379        };
380
381        self.submit_transaction(tx).await
382    }
383
384    /// Teleport AI coins to an EVM chain
385    pub async fn teleport_out(
386        &self,
387        from: &[u8],
388        destination: TeleportDestination,
389        to_address: &str,
390        amount: u128,
391        signature: &[u8],
392    ) -> Result<TeleportTransfer, LedgerError> {
393        let tx = MiningTransaction::TeleportOut {
394            from: from.to_vec(),
395            destination: destination.clone(),
396            to_address: to_address.to_string(),
397            amount,
398            signature: signature.to_vec(),
399        };
400
401        let tx_hash = self.submit_transaction(tx).await?;
402
403        Ok(TeleportTransfer {
404            teleport_id: tx_hash.clone(),
405            amount,
406            from_address: hex::encode(from),
407            to_address: to_address.to_string(),
408            destination,
409            status: TeleportStatus::Initiated,
410            protocol_tx: Some(tx_hash),
411            evm_tx: None,
412            initiated_at: std::time::SystemTime::now()
413                .duration_since(std::time::UNIX_EPOCH)
414                .unwrap()
415                .as_secs(),
416            completed_at: None,
417        })
418    }
419
420    /// Get miner state from ledger
421    pub async fn get_miner_state(&self, address: &str) -> Result<Option<MinerState>, LedgerError> {
422        // Check local cache first
423        if let Some(state) = self.miners.read().await.get(address) {
424            return Ok(Some(state.clone()));
425        }
426
427        // Fetch from network
428        let response = self.rpc_call(
429            "ledger.getMiner",
430            serde_json::json!({ "address": address }),
431        ).await?;
432
433        if response.is_null() {
434            return Ok(None);
435        }
436
437        let state: MinerState = serde_json::from_value(response)
438            .map_err(|e| LedgerError::InvalidResponse(e.to_string()))?;
439
440        // Cache locally
441        self.miners.write().await.insert(address.to_string(), state.clone());
442
443        Ok(Some(state))
444    }
445
446    /// Get pending rewards for a miner
447    pub async fn get_pending_rewards(&self, miner: &[u8]) -> Result<u128, LedgerError> {
448        let address = derive_address_from_pubkey(miner);
449
450        let response = self.rpc_call(
451            "ledger.getPendingRewards",
452            serde_json::json!({ "address": address }),
453        ).await?;
454
455        let rewards = response.get("rewards")
456            .and_then(|r| r.as_str())
457            .and_then(|s| s.parse::<u128>().ok())
458            .unwrap_or(0);
459
460        Ok(rewards)
461    }
462
463    /// Get teleport transfer status
464    pub async fn get_teleport_status(&self, teleport_id: &str) -> Result<TeleportStatus, LedgerError> {
465        let response = self.rpc_call(
466            "ledger.getTeleportStatus",
467            serde_json::json!({ "id": teleport_id }),
468        ).await?;
469
470        let status_str = response.get("status")
471            .and_then(|s| s.as_str())
472            .unwrap_or("unknown");
473
474        let status = match status_str {
475            "initiated" => TeleportStatus::Initiated,
476            "pending_confirmation" => TeleportStatus::PendingConfirmation,
477            "processing" => TeleportStatus::Processing,
478            "minting" => TeleportStatus::Minting,
479            "completed" => TeleportStatus::Completed,
480            other => TeleportStatus::Failed(format!("Unknown status: {}", other)),
481        };
482
483        Ok(status)
484    }
485
486    /// Submit a consensus vote
487    pub async fn submit_vote(
488        &self,
489        voter: &[u8],
490        block_hash: [u8; 32],
491        vote_type: VoteType,
492        signature: &[u8],
493    ) -> Result<(), LedgerError> {
494        let tx = MiningTransaction::Vote {
495            voter: voter.to_vec(),
496            block_hash,
497            vote_type,
498            signature: signature.to_vec(),
499        };
500
501        self.submit_transaction(tx).await?;
502        Ok(())
503    }
504
505    /// Get transaction status
506    pub async fn get_transaction_status(&self, tx_hash: &str) -> Result<TransactionStatus, LedgerError> {
507        let response = self.rpc_call(
508            "ledger.getTransactionStatus",
509            serde_json::json!({ "hash": tx_hash }),
510        ).await?;
511
512        let status_str = response.get("status")
513            .and_then(|s| s.as_str())
514            .unwrap_or("unknown");
515
516        let status = match status_str {
517            "pending" => TransactionStatus::Pending,
518            "mempool" => TransactionStatus::InMempool,
519            "included" => {
520                let height = response.get("block_height")
521                    .and_then(|h| h.as_u64())
522                    .unwrap_or(0);
523                TransactionStatus::Included { block_height: height }
524            }
525            "finalized" => {
526                let height = response.get("block_height")
527                    .and_then(|h| h.as_u64())
528                    .unwrap_or(0);
529                TransactionStatus::Finalized { block_height: height }
530            }
531            _ => {
532                let reason = response.get("reason")
533                    .and_then(|r| r.as_str())
534                    .unwrap_or("Unknown error")
535                    .to_string();
536                TransactionStatus::Failed { reason }
537            }
538        };
539
540        Ok(status)
541    }
542
543    /// Subscribe to new blocks
544    pub async fn subscribe_blocks(&self, callback: impl Fn(BlockHeader) + Send + Sync + 'static) {
545        let connected = self.connected.clone();
546        let height = self.current_height.clone();
547        let rpc_url = self.config.consensus_rpc.clone();
548
549        tokio::spawn(async move {
550            let client = reqwest::Client::new();
551            let mut last_height = 0u64;
552
553            while *connected.read().await {
554                // Poll for new blocks
555                tokio::time::sleep(tokio::time::Duration::from_millis(BLOCK_TIME_MS)).await;
556
557                let current = *height.read().await;
558                if current > last_height {
559                    // Fetch new block headers
560                    if let Ok(response) = client.post(&rpc_url)
561                        .json(&serde_json::json!({
562                            "jsonrpc": "2.0",
563                            "method": "ledger.getBlock",
564                            "params": { "height": current },
565                            "id": 1
566                        }))
567                        .send()
568                        .await
569                    {
570                        if let Ok(json) = response.json::<serde_json::Value>().await {
571                            if let Ok(header) = serde_json::from_value::<BlockHeader>(
572                                json.get("result").cloned().unwrap_or_default()
573                            ) {
574                                callback(header);
575                            }
576                        }
577                    }
578                    last_height = current;
579                }
580            }
581        });
582    }
583
584    /// Internal: Submit transaction to network
585    async fn submit_transaction(&self, tx: MiningTransaction) -> Result<String, LedgerError> {
586        let tx_bytes = serde_json::to_vec(&tx)
587            .map_err(|e| LedgerError::SerializationError(e.to_string()))?;
588
589        let tx_hash = hex::encode(blake3::hash(&tx_bytes).as_bytes());
590
591        // Add to pending
592        self.pending_txs.write().await.push((tx_hash.clone(), tx.clone()));
593
594        // Submit to network
595        let response = self.rpc_call(
596            "ledger.submitTransaction",
597            serde_json::json!({
598                "tx": hex::encode(&tx_bytes),
599            }),
600        ).await?;
601
602        let network_hash = response.get("hash")
603            .and_then(|h| h.as_str())
604            .unwrap_or(&tx_hash)
605            .to_string();
606
607        Ok(network_hash)
608    }
609
610    /// Internal: Make RPC call
611    async fn rpc_call(&self, method: &str, params: serde_json::Value) -> Result<serde_json::Value, LedgerError> {
612        let request = serde_json::json!({
613            "jsonrpc": "2.0",
614            "method": method,
615            "params": params,
616            "id": 1
617        });
618
619        let response = self.http_client
620            .post(&self.config.consensus_rpc)
621            .json(&request)
622            .send()
623            .await
624            .map_err(|e| LedgerError::NetworkError(e.to_string()))?;
625
626        let json: serde_json::Value = response.json().await
627            .map_err(|e| LedgerError::NetworkError(e.to_string()))?;
628
629        if let Some(error) = json.get("error") {
630            return Err(LedgerError::RpcError(error.to_string()));
631        }
632
633        Ok(json.get("result").cloned().unwrap_or_default())
634    }
635
636    /// Get ledger statistics
637    pub async fn get_stats(&self) -> LedgerStats {
638        LedgerStats {
639            network: self.config.network.clone(),
640            current_height: *self.current_height.read().await,
641            connected: *self.connected.read().await,
642            miners_cached: self.miners.read().await.len(),
643            pending_txs: self.pending_txs.read().await.len(),
644            quantum_safe: self.config.quantum_safe,
645        }
646    }
647}
648
649/// Ledger statistics
650#[derive(Debug, Clone, Serialize, Deserialize)]
651pub struct LedgerStats {
652    pub network: NetworkType,
653    pub current_height: u64,
654    pub connected: bool,
655    pub miners_cached: usize,
656    pub pending_txs: usize,
657    pub quantum_safe: bool,
658}
659
660/// Ledger errors
661#[derive(Debug, thiserror::Error)]
662pub enum LedgerError {
663    #[error("Network error: {0}")]
664    NetworkError(String),
665    #[error("RPC error: {0}")]
666    RpcError(String),
667    #[error("Invalid response: {0}")]
668    InvalidResponse(String),
669    #[error("Serialization error: {0}")]
670    SerializationError(String),
671    #[error("Transaction failed: {0}")]
672    TransactionFailed(String),
673    #[error("Not connected to network")]
674    NotConnected,
675    #[error("Invalid signature")]
676    InvalidSignature,
677    #[error("Insufficient balance")]
678    InsufficientBalance,
679}
680
681/// Derive address from quantum-safe public key
682pub fn derive_address_from_pubkey(pubkey: &[u8]) -> String {
683    let hash = blake3::hash(pubkey);
684    format!("0x{}", hex::encode(&hash.as_bytes()[..20]))
685}
686
687/// Verify a quantum-safe signature (placeholder - actual impl in hanzo-pqc)
688pub fn verify_quantum_signature(pubkey: &[u8], message: &[u8], signature: &[u8]) -> bool {
689    // This would use hanzo_pqc::signature::MlDsa for actual verification
690    // Placeholder for now
691    !pubkey.is_empty() && !message.is_empty() && !signature.is_empty()
692}
693
694#[cfg(test)]
695mod tests {
696    use super::*;
697
698    #[test]
699    fn test_ledger_config() {
700        let config = LedgerConfig::mainnet();
701        assert!(config.quantum_safe);
702        assert_eq!(config.security_level, 3);
703        assert!(!config.bootstrap_peers.is_empty());
704    }
705
706    #[test]
707    fn test_derive_address() {
708        let pubkey = vec![1u8; 32];
709        let address = derive_address_from_pubkey(&pubkey);
710        assert!(address.starts_with("0x"));
711        assert_eq!(address.len(), 42); // 0x + 40 hex chars
712    }
713
714    #[test]
715    fn test_vote_types() {
716        assert_eq!(VoteType::Preference, VoteType::Preference);
717        assert_ne!(VoteType::Commit, VoteType::Cancel);
718    }
719
720    #[test]
721    fn test_transaction_status() {
722        let status = TransactionStatus::Finalized { block_height: 100 };
723        match status {
724            TransactionStatus::Finalized { block_height } => {
725                assert_eq!(block_height, 100);
726            }
727            _ => panic!("Wrong status"),
728        }
729    }
730}