use std::sync::Arc;
use tokio::sync::RwLock;
use serde::{Deserialize, Serialize};
pub mod bridge;
pub mod consensus;
pub mod evm;
pub mod ledger;
pub mod wallet;
pub use bridge::*;
pub use consensus::*;
pub use evm::*;
pub use ledger::*;
pub use wallet::*;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MiningConfig {
pub network: NetworkType,
pub enabled: bool,
pub auto_start: bool,
pub offer_gpu: bool,
pub offer_cpu: bool,
pub max_gpu_usage: f32, pub max_cpu_usage: f32, pub reserved_ram_gb: f32,
pub wallet_address: String,
pub wallet_private_key: Option<String>,
pub payout_threshold: f64,
pub auto_withdraw: bool,
pub withdrawal_address: Option<String>,
pub benchmark_on_start: bool,
pub adaptive_performance: bool,
pub min_job_reward: f64,
pub rpc_endpoints: Vec<String>,
pub p2p_port: u16,
pub api_port: u16,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum NetworkType {
HanzoMainnet, HanzoTestnet, ZooMainnet, ZooTestnet, Custom(String), }
impl NetworkType {
pub fn rpc_endpoint(&self) -> String {
match self {
Self::HanzoMainnet => "https://rpc.hanzo.network".to_string(),
Self::HanzoTestnet => "https://rpc.hanzo-test.network".to_string(),
Self::ZooMainnet => "https://rpc.zoo.network".to_string(),
Self::ZooTestnet => "https://rpc.zoo-test.network".to_string(),
Self::Custom(endpoint) => endpoint.clone(),
}
}
pub fn chain_id(&self) -> u64 {
match self {
Self::HanzoMainnet => 36963, Self::HanzoTestnet => 36964, Self::ZooMainnet => 200200, Self::ZooTestnet => 200201, Self::Custom(_) => 0,
}
}
pub fn native_token(&self) -> &str {
match self {
Self::HanzoMainnet | Self::HanzoTestnet => "HAI", Self::ZooMainnet | Self::ZooTestnet => "ZOO", Self::Custom(_) => "TOKEN",
}
}
}
impl Default for MiningConfig {
fn default() -> Self {
Self {
network: NetworkType::HanzoMainnet,
enabled: true,
auto_start: true,
offer_gpu: true,
offer_cpu: true,
max_gpu_usage: 0.8, max_cpu_usage: 0.6, reserved_ram_gb: 4.0,
wallet_address: String::new(),
wallet_private_key: None,
payout_threshold: 10.0, auto_withdraw: true,
withdrawal_address: None,
benchmark_on_start: true,
adaptive_performance: true,
min_job_reward: 0.001,
rpc_endpoints: vec![
"https://rpc.hanzo.network".to_string(),
"https://rpc2.hanzo.network".to_string(),
],
p2p_port: 3691, api_port: 3690, }
}
}
pub struct MiningManager {
config: Arc<RwLock<MiningConfig>>,
is_mining: Arc<RwLock<bool>>,
current_jobs: Arc<RwLock<Vec<ComputeJob>>>,
total_earned: Arc<RwLock<f64>>,
performance_stats: Arc<RwLock<PerformanceStats>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ComputeJob {
pub job_id: String,
pub job_type: JobType,
pub requester: String,
pub reward: f64,
pub deadline: u64,
pub input_data: Vec<u8>,
pub status: JobStatus,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum JobType {
Embedding(EmbeddingJob),
Reranking(RerankingJob),
Inference(InferenceJob),
Training(TrainingJob),
Custom(Vec<u8>),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EmbeddingJob {
pub model: String,
pub texts: Vec<String>,
pub batch_size: usize,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RerankingJob {
pub model: String,
pub query: String,
pub documents: Vec<String>,
pub top_k: usize,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct InferenceJob {
pub model: String,
pub prompt: String,
pub max_tokens: usize,
pub temperature: f32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TrainingJob {
pub model: String,
pub dataset_url: String,
pub epochs: usize,
pub checkpoint_interval: usize,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum JobStatus {
Pending,
Running,
Completed,
Failed,
Cancelled,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PerformanceStats {
pub gpu_tflops: f32,
pub cpu_gflops: f32,
pub ram_gb: f32,
pub vram_gb: f32,
pub network_mbps: f32,
pub jobs_completed: u64,
pub jobs_failed: u64,
pub uptime_hours: f64,
pub reputation_score: f64,
}
impl MiningManager {
pub fn new(config: MiningConfig) -> Self {
Self {
config: Arc::new(RwLock::new(config)),
is_mining: Arc::new(RwLock::new(false)),
current_jobs: Arc::new(RwLock::new(Vec::new())),
total_earned: Arc::new(RwLock::new(0.0)),
performance_stats: Arc::new(RwLock::new(PerformanceStats::default())),
}
}
pub async fn start_mining(&self) -> Result<(), Box<dyn std::error::Error>> {
let config = self.config.read().await;
if !config.enabled {
return Err("Mining is disabled in config".into());
}
println!("🚀 Starting AI mining on {}", config.network.rpc_endpoint());
println!("⛏️ Offering: GPU={}, CPU={}", config.offer_gpu, config.offer_cpu);
println!("💰 Wallet: {}", config.wallet_address);
*self.is_mining.write().await = true;
self.connect_to_network(&config).await?;
if config.benchmark_on_start {
self.run_benchmark().await?;
}
self.start_job_listener().await;
Ok(())
}
pub async fn stop_mining(&self) -> Result<(), Box<dyn std::error::Error>> {
println!("⛔ Stopping AI mining...");
*self.is_mining.write().await = false;
let mut jobs = self.current_jobs.write().await;
for job in jobs.iter_mut() {
job.status = JobStatus::Cancelled;
}
Ok(())
}
async fn connect_to_network(&self, config: &MiningConfig) -> Result<(), Box<dyn std::error::Error>> {
println!("🔗 Connecting to {} network...", match &config.network {
NetworkType::HanzoMainnet => "Hanzo Mainnet",
NetworkType::HanzoTestnet => "Hanzo Testnet",
NetworkType::ZooMainnet => "Zoo Mainnet",
NetworkType::ZooTestnet => "Zoo Testnet",
NetworkType::Custom(url) => url,
});
Ok(())
}
async fn run_benchmark(&self) -> Result<(), Box<dyn std::error::Error>> {
println!("📊 Running performance benchmark...");
let mut stats = self.performance_stats.write().await;
if self.config.read().await.offer_gpu {
stats.gpu_tflops = self.benchmark_gpu().await?;
println!(" GPU: {:.2} TFLOPS", stats.gpu_tflops);
}
if self.config.read().await.offer_cpu {
stats.cpu_gflops = self.benchmark_cpu().await?;
println!(" CPU: {:.2} GFLOPS", stats.cpu_gflops);
}
stats.ram_gb = self.get_available_ram();
println!(" RAM: {:.2} GB available", stats.ram_gb);
if self.config.read().await.offer_gpu {
stats.vram_gb = self.get_available_vram();
println!(" VRAM: {:.2} GB available", stats.vram_gb);
}
stats.network_mbps = self.benchmark_network().await?;
println!(" Network: {:.2} Mbps", stats.network_mbps);
Ok(())
}
async fn start_job_listener(&self) {
let is_mining = self.is_mining.clone();
let _current_jobs = self.current_jobs.clone();
let config = self.config.clone();
tokio::spawn(async move {
while *is_mining.read().await {
tokio::time::sleep(tokio::time::Duration::from_secs(10)).await;
let cfg = config.read().await;
if !cfg.enabled {
continue;
}
println!("👀 Checking for new compute jobs...");
}
});
}
pub async fn execute_job(&self, job: ComputeJob) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
println!("🔧 Executing job: {}", job.job_id);
let result = match job.job_type {
JobType::Embedding(ref params) => {
self.execute_embedding_job(params).await?
}
JobType::Reranking(ref params) => {
self.execute_reranking_job(params).await?
}
JobType::Inference(ref params) => {
self.execute_inference_job(params).await?
}
JobType::Training(ref params) => {
self.execute_training_job(params).await?
}
JobType::Custom(ref data) => {
self.execute_custom_job(data).await?
}
};
let mut stats = self.performance_stats.write().await;
stats.jobs_completed += 1;
*self.total_earned.write().await += job.reward;
println!("💰 Earned {} {} for job {}", job.reward,
self.config.read().await.network.native_token(), job.job_id);
Ok(result)
}
async fn execute_embedding_job(&self, params: &EmbeddingJob) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
println!(" Generating embeddings with model: {}", params.model);
Ok(vec![])
}
async fn execute_reranking_job(&self, params: &RerankingJob) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
println!(" Reranking {} documents", params.documents.len());
Ok(vec![])
}
async fn execute_inference_job(&self, params: &InferenceJob) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
println!(" Running inference with model: {}", params.model);
Ok(vec![])
}
async fn execute_training_job(&self, params: &TrainingJob) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
println!(" Training model: {} for {} epochs", params.model, params.epochs);
Ok(vec![])
}
async fn execute_custom_job(&self, data: &[u8]) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
println!(" Executing custom job ({} bytes)", data.len());
Ok(vec![])
}
pub async fn get_stats(&self) -> MiningStats {
MiningStats {
is_mining: *self.is_mining.read().await,
network: self.config.read().await.network.clone(),
total_earned: *self.total_earned.read().await,
current_jobs: self.current_jobs.read().await.len(),
performance: self.performance_stats.read().await.clone(),
}
}
async fn benchmark_gpu(&self) -> Result<f32, Box<dyn std::error::Error>> {
Ok(15.7) }
async fn benchmark_cpu(&self) -> Result<f32, Box<dyn std::error::Error>> {
Ok(450.0) }
fn get_available_ram(&self) -> f32 {
16.0 }
fn get_available_vram(&self) -> f32 {
10.0 }
async fn benchmark_network(&self) -> Result<f32, Box<dyn std::error::Error>> {
Ok(100.0) }
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MiningStats {
pub is_mining: bool,
pub network: NetworkType,
pub total_earned: f64,
pub current_jobs: usize,
pub performance: PerformanceStats,
}
impl Default for PerformanceStats {
fn default() -> Self {
Self {
gpu_tflops: 0.0,
cpu_gflops: 0.0,
ram_gb: 0.0,
vram_gb: 0.0,
network_mbps: 0.0,
jobs_completed: 0,
jobs_failed: 0,
uptime_hours: 0.0,
reputation_score: 100.0,
}
}
}
pub async fn init_mining() -> Result<MiningManager, Box<dyn std::error::Error>> {
let config_path = dirs::home_dir()
.expect("Could not find home directory")
.join(".hanzo/config/mining.toml");
let config = if config_path.exists() {
let contents = std::fs::read_to_string(&config_path)?;
toml::from_str(&contents)?
} else {
let config = MiningConfig::default();
std::fs::create_dir_all(config_path.parent().unwrap())?;
std::fs::write(&config_path, toml::to_string_pretty(&config)?)?;
config
};
let manager = MiningManager::new(config);
if manager.config.read().await.auto_start {
let _ = manager.start_mining().await;
}
Ok(manager)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_network_endpoints() {
assert_eq!(NetworkType::HanzoMainnet.rpc_endpoint(), "https://rpc.hanzo.network");
assert_eq!(NetworkType::ZooMainnet.rpc_endpoint(), "https://rpc.zoo.network");
assert_eq!(NetworkType::HanzoMainnet.native_token(), "HAI");
assert_eq!(NetworkType::ZooMainnet.native_token(), "ZOO");
assert_eq!(NetworkType::HanzoMainnet.chain_id(), 36963);
assert_eq!(NetworkType::ZooMainnet.chain_id(), 200200);
}
#[tokio::test]
async fn test_mining_manager() {
let config = MiningConfig {
enabled: false, ..Default::default()
};
let manager = MiningManager::new(config);
let stats = manager.get_stats().await;
assert!(!stats.is_mining);
assert_eq!(stats.total_earned, 0.0);
}
}