use std::error::Error;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use std::time::{Duration, SystemTime, UNIX_EPOCH};
use async_trait::async_trait;
use serde::{Serialize, Deserialize};
use log::{debug, info, warn, error};
use thiserror::Error;
#[derive(Error, Debug)]
pub enum BlockchainError {
#[error("Network error: {0}")]
NetworkError(String),
#[error("Configuration error: {0}")]
ConfigError(String),
#[error("Synchronization error: {0}")]
SyncError(String),
#[error("Block processing error: {0}")]
BlockProcessingError(String),
#[error("Transaction error: {0}")]
TransactionError(String),
#[error("Validation error: {0}")]
ValidationError(String),
#[error("Storage error: {0}")]
StorageError(String),
#[error("RPC error: {0}")]
RpcError(String),
#[error("Serialization error: {0}")]
SerializationError(String),
#[error("Not found: {0}")]
NotFoundError(String),
#[error("IO error: {0}")]
IoError(#[from] std::io::Error),
#[error("Timeout: {0}")]
TimeoutError(String),
#[error("Internal error: {0}")]
InternalError(String),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BlockchainMetrics {
pub block_count: u64,
pub tx_count: u64,
pub utxo_set_size: u64,
pub difficulty: f64,
pub hash_rate: f64,
pub network_weight: Option<f64>,
pub block_propagation_time: u64,
pub mempool_size: u64,
pub mempool_tx_count: u64,
pub fee_estimates: HashMap<u16, u64>,
pub timestamp: u64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BlockchainState {
pub chain_id: String,
pub network: String,
pub protocol_version: u32,
pub best_block_hash: String,
pub best_block_height: u64,
pub median_time_past: u64,
pub initial_block_download: bool,
pub sync_progress: f64,
pub chain_work: String,
pub size_on_disk: u64,
pub connection_count: u32,
pub verification_progress: f64,
pub pruned: bool,
pub prune_height: Option<u64>,
pub last_checkpoint: Option<u64>,
pub warnings: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PeerInfo {
pub id: u64,
pub addr: String,
pub services: u64,
pub last_send: u64,
pub last_recv: u64,
pub conn_time: u64,
pub ping_time: Option<f64>,
pub version: u32,
pub subver: String,
pub inbound: bool,
pub start_height: u64,
pub ban_score: u32,
pub sync_node: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MempoolStatus {
pub tx_count: u64,
pub size: u64,
pub memory_usage: u64,
pub min_fee_per_kb: u64,
pub max_fee_per_kb: u64,
pub avg_fee_per_kb: u64,
pub max_ancestors: u16,
pub fullrbf: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BlockInfo {
pub hash: String,
pub height: u64,
pub version: u32,
pub time: u64,
pub mediantime: u64,
pub nonce: u32,
pub difficulty: f64,
pub previousblockhash: String,
pub nextblockhash: Option<String>,
pub chainwork: String,
pub tx_count: u64,
pub size: u64,
pub weight: u64,
pub strippedsize: u64,
pub merkleroot: String,
pub bits: String,
pub valid: bool,
pub confirmations: u64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TransactionInfo {
pub txid: String,
pub hash: String,
pub version: u32,
pub size: u64,
pub vsize: u64,
pub weight: u64,
pub locktime: u32,
pub timestamp: Option<u64>,
pub blockhash: Option<String>,
pub blockheight: Option<u64>,
pub confirmations: Option<u64>,
pub fee: Option<u64>,
pub fee_per_vbyte: Option<f64>,
pub rbf: bool,
}
#[async_trait]
pub trait NodePort {
async fn get_blockchain_state(&self) -> Result<BlockchainState, BlockchainError>;
async fn get_metrics(&self) -> Result<BlockchainMetrics, BlockchainError>;
async fn get_block_by_hash(&self, hash: &str) -> Result<BlockInfo, BlockchainError>;
async fn get_block_by_height(&self, height: u64) -> Result<BlockInfo, BlockchainError>;
async fn get_raw_block(&self, hash: &str) -> Result<Vec<u8>, BlockchainError>;
async fn get_transaction(&self, txid: &str) -> Result<TransactionInfo, BlockchainError>;
async fn get_raw_transaction(&self, txid: &str) -> Result<Vec<u8>, BlockchainError>;
async fn broadcast_transaction(&self, tx__data: &[u8]) -> Result<String, BlockchainError>;
async fn get_mempool_status(&self) -> Result<MempoolStatus, BlockchainError>;
async fn get_mempool_transactions(&self) -> Result<Vec<String>, BlockchainError>;
async fn estimate_fee(&self, confirmation_target: u16) -> Result<u64, BlockchainError>;
async fn get_peer_info(&self) -> Result<Vec<PeerInfo>, BlockchainError>;
async fn get_difficulty(&self) -> Result<f64, BlockchainError>;
async fn get_network_hashrate(&self) -> Result<f64, BlockchainError>;
async fn is_in_mempool(&self, txid: &str) -> Result<bool, BlockchainError>;
async fn get_utxo(&self, txid: &str, vout: u32) -> Result<Option<UtxoInfo>, BlockchainError>;
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UtxoInfo {
pub txid: String,
pub vout: u32,
pub amount: u64,
pub script_pubkey: String,
pub script_pubkey_asm: String,
pub script_type: String,
pub confirmations: u64,
pub coinbase: bool,
}
#[async_trait]
pub trait WalletPort {
async fn create_transaction(&self, params: TransactionParams) -> Result<String, BlockchainError>;
async fn sign_transaction(&self, tx: &str, privkeys: Option<Vec<String>>) -> Result<String, BlockchainError>;
async fn analyze_transaction(&self, tx: &str) -> Result<TransactionAnalysis, BlockchainError>;
async fn get_address_balance(&self, address: &str) -> Result<AddressBalance, BlockchainError>;
async fn get_address_transactions(&self, address: &str, limit: Option<u32>) -> Result<Vec<String>, BlockchainError>;
async fn get_address_utxos(&self, address: &str) -> Result<Vec<UtxoInfo>, BlockchainError>;
async fn import_private_key(&self, privkey: &str) -> Result<(), BlockchainError>;
async fn export_private_keys(&self) -> Result<Vec<String>, BlockchainError>;
async fn create_raw_transaction(&self, inputs: Vec<TxInput>, outputs: HashMap<String, f64>) -> Result<String, BlockchainError>;
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TxInput {
pub txid: String,
pub vout: u32,
pub sequence: Option<u32>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TransactionParams {
pub inputs: Option<Vec<TxInput>>,
pub outputs: HashMap<String, f64>,
pub fee_rate: Option<u64>,
pub locktime: Option<u32>,
pub rbf: Option<bool>,
pub change_address: Option<String>,
pub op_return_data: Option<Vec<u8>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TransactionAnalysis {
pub txid: String,
pub size: u64,
pub vsize: u64,
pub weight: u64,
pub fee: Option<u64>,
pub fee_rate: Option<f64>,
pub inputs: Vec<TxAnalysisInput>,
pub outputs: Vec<TxAnalysisOutput>,
pub input_amount: Option<u64>,
pub output_amount: u64,
pub is_coinbase: bool,
pub is_rbf: bool,
pub is_fully_signed: bool,
pub locktime: u32,
pub sigops: u32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TxAnalysisInput {
pub txid: String,
pub vout: u32,
pub amount: Option<u64>,
pub address: Option<String>,
pub script_sig: String,
pub witness: Option<Vec<String>>,
pub sequence: u32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TxAnalysisOutput {
pub n: u32,
pub amount: u64,
pub address: Option<String>,
pub script_pubkey: String,
pub script_type: String,
pub is_op_return: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AddressBalance {
pub confirmed: u64,
pub unconfirmed: u64,
pub total: u64,
pub tx_count: u64,
pub utxo_count: u64,
}
#[async_trait]
pub trait SmartContractPort {
async fn deploy_contract(&self, bytecode: &str, abi: &str, params: &[String]) -> Result<String, BlockchainError>;
async fn call_contract(&self, address: &str, abi: &str, method: &str, params: &[String]) -> Result<String, BlockchainError>;
async fn send_to_contract(&self, address: &str, abi: &str, method: &str, params: &[String], value: Option<u64>) -> Result<String, BlockchainError>;
async fn get_contract_events(&self, address: &str, abi: &str, event: &str, from_block: Option<u64>, to_block: Option<u64>) -> Result<Vec<ContractEvent>, BlockchainError>;
async fn get_contract_bytecode(&self, address: &str) -> Result<String, BlockchainError>;
async fn get_contract_balance(&self, address: &str) -> Result<u64, BlockchainError>;
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ContractEvent {
pub address: String,
pub block_hash: String,
pub block_number: u64,
pub transaction_hash: String,
pub transaction_index: u32,
pub log_index: u32,
pub event: String,
pub parameters: HashMap<String, String>,
}
#[async_trait]
pub trait MetricsPort {
async fn start_metrics(&self) -> Result<(), BlockchainError>;
async fn stop_metrics(&self) -> Result<(), BlockchainError>;
async fn get_latest_metrics(&self) -> Result<BlockchainMetrics, BlockchainError>;
async fn get_historical_metrics(&self, start_time: u64, end_time: u64, interval: u64) -> Result<Vec<BlockchainMetrics>, BlockchainError>;
async fn get_metric(&self, name: &str, start_time: u64, end_time: u64, interval: u64) -> Result<Vec<(u64, f64)>, BlockchainError>;
async fn set_metric_alert(&self, name: &str, threshold: f64, comparison: AlertComparison) -> Result<(), BlockchainError>;
async fn remove_metric_alert(&self, name: &str) -> Result<(), BlockchainError>;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum AlertComparison {
GreaterThan,
GreaterThanOrEqual,
LessThan,
LessThanOrEqual,
Equal,
NotEqual,
}
#[async_trait]
pub trait SecurityPort {
async fn is_block_valid(&self, hash: &str) -> Result<bool, BlockchainError>;
async fn get_difficulty_history(&self, blocks: u32) -> Result<Vec<(u64, f64)>, BlockchainError>;
async fn detect_chain_split(&self) -> Result<Option<ChainSplitInfo>, BlockchainError>;
async fn detect_unusual_transactions(&self) -> Result<Vec<UnusualTransaction>, BlockchainError>;
async fn monitor_fee_spikes(&self, threshold: f64) -> Result<bool, BlockchainError>;
async fn monitor_hashrate_change(&self, window: u32, threshold: f64) -> Result<Option<f64>, BlockchainError>;
async fn is_address_malicious(&self, address: &str) -> Result<bool, BlockchainError>;
async fn report_security_incident(&self, incident_type: &str, details: &str) -> Result<(), BlockchainError>;
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ChainSplitInfo {
pub split_height: u64,
pub main_chain_hash: String,
pub split_chain_hash: String,
pub main_chain_length: u32,
pub split_chain_length: u32,
pub work_difference: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UnusualTransaction {
pub txid: String,
pub reason: String,
pub severity: u8,
pub details: HashMap<String, String>,
}
pub struct BlockchainCore {
adapters: HashMap<String, Box<dyn BlockchainAdapter>>,
active_adapter: String,
metrics: Arc<Mutex<Option<BlockchainMetrics>>>,
state: Arc<Mutex<Option<BlockchainState>>>,
metrics_interval: Duration,
sync_interval: Duration,
}
impl BlockchainCore {
pub fn new() -> Self {
Self {
adapters: HashMap::new(),
active_adapter: String::new(),
metrics: Arc::new(Mutex::new(None)),
state: Arc::new(Mutex::new(None)),
metrics_interval: Duration::from_secs(60),
sync_interval: Duration::from_secs(10),
}
}
pub fn register_adapter(&mut self, name: &str, adapter: Box<dyn BlockchainAdapter>) {
self.adapters.insert(name.to_string(), adapter);
if self.active_adapter.is_empty() {
self.active_adapter = name.to_string();
}
}
pub fn set_active_adapter(&mut self, name: &str) -> Result<(), BlockchainError> {
if !self.adapters.contains_key(name) {
return Err(BlockchainError::ConfigError(format!("Adapter '{}' not found", name)));
}
self.active_adapter = name.to_string();
Ok(())
}
pub fn get_active_adapter(&self) -> Result<&Box<dyn BlockchainAdapter>, BlockchainError> {
self.adapters.get(&self.active_adapter)
.ok_or_else(|| BlockchainError::ConfigError("No active adapter set".to_string()))
}
pub async fn init(&self) -> Result<(), BlockchainError> {
let adapter = self.get_active_adapter()?;
adapter.init().await?;
let state = adapter.get_blockchain_state().await?;
let mut state_lock = self.state.lock()
.map_err(|_| BlockchainError::InternalError("Failed to lock state mutex".to_string()))?;
*state_lock = Some(state);
let metrics = adapter.get_metrics().await?;
let mut metrics_lock = self.metrics.lock()
.map_err(|_| BlockchainError::InternalError("Failed to lock metrics mutex".to_string()))?;
*metrics_lock = Some(metrics);
Ok(())
}
pub async fn start_sync(&self) -> Result<(), BlockchainError> {
let adapter = self.get_active_adapter()?;
let state_arc = self.state.clone();
let metrics_arc = self.metrics.clone();
let sync_interval = self.sync_interval;
let metrics_interval = self.metrics_interval;
let adapter_arc = Arc::new(adapter);
tokio::spawn(async move {
let mut last_metrics_update = SystemTime::now();
loop {
match adapter_arc.get_blockchain_state().await {
Ok(new_state) => {
let mut state_lock = match state_arc.lock() {
Ok(lock) => lock,
Err(e) => {
error!("Failed to lock state mutex: {}", e);
continue;
}
};
*state_lock = Some(new_state);
},
Err(e) => {
error!("Failed to update blockchain state: {}", e);
}
}
if last_metrics_update.elapsed().unwrap_or(Duration::from_secs(0)) >= metrics_interval {
match adapter_arc.get_metrics().await {
Ok(new_metrics) => {
let mut metrics_lock = match metrics_arc.lock() {
Ok(lock) => lock,
Err(e) => {
error!("Failed to lock metrics mutex: {}", e);
continue;
}
};
*metrics_lock = Some(new_metrics);
last_metrics_update = SystemTime::now();
},
Err(e) => {
error!("Failed to update blockchain metrics: {}", e);
}
}
}
tokio::time::sleep(sync_interval).await;
}
});
Ok(())
}
pub fn get_latest_state(&self) -> Result<BlockchainState, BlockchainError> {
let state_lock = self.state.lock()
.map_err(|_| BlockchainError::InternalError("Failed to lock state mutex".to_string()))?;
state_lock.clone()
.ok_or_else(|| BlockchainError::InternalError("Blockchain state not initialized".to_string()))
}
pub fn get_latest_metrics(&self) -> Result<BlockchainMetrics, BlockchainError> {
let metrics_lock = self.metrics.lock()
.map_err(|_| BlockchainError::InternalError("Failed to lock metrics mutex".to_string()))?;
metrics_lock.clone()
.ok_or_else(|| BlockchainError::InternalError("Blockchain metrics not initialized".to_string()))
}
}
#[async_trait]
pub trait BlockchainAdapter: NodePort + WalletPort + SmartContractPort + MetricsPort + SecurityPort + Send + Sync {
async fn init(&self) -> Result<(), BlockchainError>;
fn get_name(&self) -> &str;
fn get_blockchain(&self) -> &str;
fn get_version(&self) -> &str;
fn get_features(&self) -> Vec<String>;
fn supports_feature(&self, feature: &str) -> bool {
self.get_features().iter().any(|f| f == feature)
}
}
pub mod bitcoin;
pub mod ethereum;
pub mod polkadot;
pub mod utils;