Refactored into multiple modules
This commit is contained in:
94
crates/oracle-demo/src/oracle/network_crdt.rs
Normal file
94
crates/oracle-demo/src/oracle/network_crdt.rs
Normal file
@@ -0,0 +1,94 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::{utils, AssetPair, OracleId, PriceAttestation};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct OracleNetworkCRDT {
|
||||
pub(crate) attestations: HashMap<String, PriceAttestation>,
|
||||
pub(crate) oracle_scores: HashMap<OracleId, f64>,
|
||||
}
|
||||
|
||||
impl OracleNetworkCRDT {
|
||||
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()))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user