use std::collections::HashMap; use crate::{utils, AssetPair, OracleId, PriceAttestation}; #[derive(Clone)] pub(crate) struct NetworkCRDT { pub(crate) attestations: HashMap, pub(crate) oracle_scores: HashMap, } impl NetworkCRDT { pub(crate) fn new() -> Self { Self { attestations: HashMap::new(), oracle_scores: HashMap::new(), } } pub(crate) fn submit_attestation(&mut self, attestation: PriceAttestation) { self.attestations .insert(attestation.id.clone(), attestation.clone()); // Update oracle reputation let score = self .oracle_scores .entry(attestation.oracle_id.clone()) .or_insert(0.5); *score = (*score * 0.95) + 0.05; } pub(crate) fn merge(&mut self, other: &Self) { for (id, attestation) in &other.attestations { if !self.attestations.contains_key(id) { self.attestations.insert(id.clone(), attestation.clone()); } } for (oracle_id, score) in &other.oracle_scores { self.oracle_scores.insert(oracle_id.clone(), *score); } } pub(crate) fn get_aggregate_price( &self, asset_pair: &AssetPair, max_age: u64, ) -> Option<(f64, u8, usize)> { let now = utils::timestamp(); let min_time = now.saturating_sub(max_age); let mut prices = Vec::new(); for attestation in self.attestations.values() { if attestation.asset_pair == *asset_pair && attestation.timestamp >= min_time { let weight = self .oracle_scores .get(&attestation.oracle_id) .unwrap_or(&0.5); prices.push((attestation.price, attestation.confidence, *weight)); } } if prices.is_empty() { return None; } // Remove outliers prices.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap()); if prices.len() > 4 { let q1 = prices[prices.len() / 4].0; let q3 = prices[3 * prices.len() / 4].0; let iqr = q3 - q1; let lower = q1 - iqr * 1.5; let upper = q3 + iqr * 1.5; prices.retain(|(price, _, _)| *price >= lower && *price <= upper); } // Calculate weighted average let mut total_weight = 0.0; let mut weighted_sum = 0.0; let mut confidence_sum = 0.0; for (price, confidence, weight) in &prices { let w = (*confidence as f64 / 100.0) * weight; weighted_sum += price * w; confidence_sum += *confidence as f64 * w; total_weight += w; } let avg_price = weighted_sum / total_weight; let avg_confidence = (confidence_sum / total_weight) as u8; Some((avg_price, avg_confidence, prices.len())) } }