Files
bft-crdt-experiment/docs/use-case-2-oracle-networks.md

11 KiB

Use Case 2: Decentralized Oracle Networks Without Consensus

The Oracle Problem

Blockchain smart contracts need external data but face a fundamental dilemma:

Current Oracle Challenges

  1. Consensus Overhead

    • Chainlink nodes must reach consensus on each price update
    • Requires multiple rounds of communication
    • Gas costs scale with number of oracles
    • Updates limited by consensus frequency
  2. Single Point of Manipulation

    • Consensus produces ONE "official" price
    • Attackers know exactly what to target
    • Flash loan attacks can manipulate prices
    • Time-based attacks exploit update delays
  3. Economic Inefficiency

    • Oracles paid per consensus round
    • Can't update continuously due to costs
    • Trade-off between security (more oracles) and cost
    • Subsidies required for less popular feeds

The BFT-CRDT Oracle Solution

Instead of consensus, use eventual consistency with on-chain aggregation:

Traditional Oracle Network:
[Data Sources] → [Oracle Nodes] → [Consensus Protocol] → [Single Price] → [Smart Contract]
                                   ↓                      ↓
                                [Expensive]          [Attack Target]

BFT-CRDT Oracle Network:
[Data Sources] → [Oracle Nodes] → [BFT-CRDT Network] → [All Prices] → [Smart Contract]
                     ↓                ↓                     ↓              ↓
                [Independent]    [No consensus]    [Time-windowed]    [Aggregates]

Key Innovation: Consensus-Free Price Discovery

  • Oracles submit prices independently whenever they want
  • No coordination or communication between oracles
  • Smart contracts see ALL prices within a time window
  • Aggregation happens on-chain with custom logic

Detailed Architecture

Data Flow

// 1. Oracle observes price from data source
let price_observation = PriceData {
    oracle_id: "oracle_1",
    asset_pair: "ETH/USD",
    price: 2531_47,
    confidence: 99,
    source: "binance",
    observed_at: timestamp,
};

// 2. Oracle creates signed attestation
let attestation = OracleAttestation {
    data: price_observation,
    merkle_proof: proof_from_source,
    signature: oracle.sign(&price_observation),
};

// 3. Submit to BFT-CRDT network (no consensus needed)
crdt_network.submit(attestation);

// 4. Smart contract queries all recent attestations
let prices = crdt_network.get_attestations(
    asset_pair: "ETH/USD",
    time_window: Duration::from_secs(300), // 5 minutes
);

// 5. Smart contract applies custom aggregation
let final_price = aggregate_with_outlier_detection(prices);

CRDT Structure

pub struct OracleCRDT {
    // All price attestations
    attestations: Map<AttestationId, OracleAttestation>,
    
    // Index by asset and time
    price_index: BTreeMap<(AssetPair, Timestamp), Vec<AttestationId>>,
    
    // Oracle reputation tracking
    oracle_performance: Map<OracleId, PerformanceMetrics>,
    
    // Detected anomalies
    anomalies: Set<AnomalyReport>,
}

pub struct OracleAttestation {
    pub id: AttestationId,
    pub oracle_id: OracleId,
    pub asset_pair: AssetPair,
    pub price: u128,
    pub confidence: u8,
    pub sources: Vec<DataSource>,
    pub timestamp: Timestamp,
    pub proof: SourceProof,
    pub signature: Signature,
}

pub struct SourceProof {
    // Proof that price came from claimed source
    pub source_signature: Option<Signature>,
    pub api_attestation: Option<TLSProof>,
    pub merkle_path: Option<MerklePath>,
}

Merge Rules

impl Merge for OracleCRDT {
    fn merge(&mut self, other: &Self) {
        // 1. Merge attestations (no conflicts possible)
        for (id, attestation) in &other.attestations {
            if !self.attestations.contains_key(id) {
                if self.verify_attestation(attestation) {
                    self.add_attestation(attestation.clone());
                }
            }
        }
        
        // 2. Update performance metrics
        self.update_oracle_performance(&other.oracle_performance);
        
        // 3. Merge anomaly reports
        self.anomalies.extend(&other.anomalies);
    }
}

Smart Contract Integration

On-Chain Aggregation

contract PriceAggregator {
    struct PriceData {
        uint128 price;
        uint8 confidence;
        address oracle;
        uint256 timestamp;
    }
    
    function getPrice(
        string calldata assetPair,
        uint256 maxAge
    ) external view returns (uint128) {
        // Get all prices from CRDT oracle network
        PriceData[] memory prices = oracleNetwork.getPrices(
            assetPair,
            block.timestamp - maxAge,
            block.timestamp
        );
        
        require(prices.length >= MIN_SOURCES, "Insufficient data");
        
        // Apply custom aggregation logic
        return calculateWeightedMedian(prices);
    }
    
    function calculateWeightedMedian(
        PriceData[] memory prices
    ) internal pure returns (uint128) {
        // Sort by price
        sortPrices(prices);
        
        // Remove outliers (> 2 std dev)
        uint256 validCount = removeOutliers(prices);
        
        // Weight by confidence and recency
        uint256[] memory weights = calculateWeights(prices, validCount);
        
        // Find weighted median
        return findWeightedMedian(prices, weights, validCount);
    }
}

Advanced Aggregation Strategies

library OracleAggregation {
    // Time-Weighted Average Price (TWAP)
    function calculateTWAP(
        PriceData[] memory prices,
        uint256 duration
    ) internal pure returns (uint128) {
        uint256 weightedSum = 0;
        uint256 totalWeight = 0;
        
        for (uint i = 0; i < prices.length; i++) {
            uint256 timeWeight = duration - (block.timestamp - prices[i].timestamp);
            weightedSum += prices[i].price * timeWeight;
            totalWeight += timeWeight;
        }
        
        return uint128(weightedSum / totalWeight);
    }
    
    // Volatility-Adjusted Price
    function getVolAdjustedPrice(
        PriceData[] memory prices
    ) internal pure returns (uint128 price, uint128 confidence) {
        uint128 median = getMedian(prices);
        uint128 stdDev = getStandardDeviation(prices, median);
        
        // Higher volatility = lower confidence
        confidence = stdDev < median / 100 ? 99 : 50;
        
        // Use trimmed mean for volatile periods
        if (stdDev > median / 50) {
            price = getTrimmedMean(prices, 10); // Trim 10% each side
        } else {
            price = median;
        }
    }
}

Security Advantages

1. No Single Point of Attack

  • No "official" price to manipulate
  • Attackers must compromise multiple oracles
  • Each oracle failure has limited impact

2. Transparent Price Discovery

// Anyone can audit all price submissions
function auditPriceHistory(
    string calldata assetPair,
    uint256 startTime,
    uint256 endTime
) external view returns (PriceData[] memory) {
    return oracleNetwork.getAllPrices(assetPair, startTime, endTime);
}

3. Economic Attack Resistance

  • No consensus rounds to game
  • Continuous submissions prevent timing attacks
  • Outlier detection catches manipulated prices

4. Oracle Reputation System

pub struct OracleReputation {
    pub total_submissions: u64,
    pub accuracy_score: u8, // 0-100
    pub average_deviation: u128,
    pub downtime_periods: Vec<(Timestamp, Timestamp)>,
    pub suspicious_patterns: Vec<SuspiciousPattern>,
}

impl OracleCRDT {
    fn update_reputation(&mut self, oracle_id: &OracleId) {
        let submissions = self.get_oracle_submissions(oracle_id);
        let market_prices = self.calculate_market_consensus(submissions);
        
        // Track how often oracle deviates from market
        let deviation = calculate_average_deviation(submissions, market_prices);
        
        // Detect suspicious patterns
        let patterns = detect_patterns(submissions);
        
        self.oracle_performance.get_mut(oracle_id).unwrap().update(
            deviation,
            patterns,
        );
    }
}

Use Cases

1. DeFi Lending Protocols

contract LendingProtocol {
    function getCollateralValue(
        address asset,
        uint256 amount
    ) public view returns (uint256) {
        // Get prices from last 5 minutes
        uint128 price = priceAggregator.getPrice(
            getAssetPair(asset),
            300 // 5 minutes
        );
        
        // Use conservative estimate for collateral
        return (amount * price * 80) / 100; // 80% of market price
    }
}

2. Derivatives and Options

contract OptionsProtocol {
    function getSettlementPrice(
        string calldata assetPair,
        uint256 expiryTime
    ) external view returns (uint128) {
        // Get all prices within 1 hour of expiry
        PriceData[] memory prices = oracleNetwork.getPrices(
            assetPair,
            expiryTime - 1800, // 30 min before
            expiryTime + 1800  // 30 min after
        );
        
        // Use TWAP for fair settlement
        return calculateTWAP(prices, 3600);
    }
}

3. Stablecoin Protocols

contract StablecoinProtocol {
    function getMintPrice() public view returns (uint128) {
        // Aggregate multiple fiat sources
        uint128 usdPrice = getAggregatePrice("USD", 600);
        uint128 eurPrice = getAggregatePrice("EUR", 600);
        uint128 gbpPrice = getAggregatePrice("GBP", 600);
        
        // Weight by liquidity
        return (usdPrice * 60 + eurPrice * 30 + gbpPrice * 10) / 100;
    }
}

4. Cross-Chain Price Feeds

// Relay prices to multiple chains without consensus
impl OracleCRDT {
    fn relay_to_chain(&self, chain_id: ChainId, asset_pair: AssetPair) {
        let prices = self.get_recent_prices(asset_pair, Duration::from_secs(300));
        
        let message = CrossChainPriceUpdate {
            prices: prices,
            merkle_root: self.calculate_merkle_root(&prices),
            timestamp: now(),
        };
        
        // Send via BFT-CRDT cross-chain relay
        self.cross_chain_relay.send(chain_id, message);
    }
}

Performance Analysis

Throughput

  • Traditional: ~0.1 updates/second (limited by consensus)
  • BFT-CRDT: ~100 updates/second per oracle (no coordination)

Latency

  • Traditional: 10-60 seconds (consensus rounds)
  • BFT-CRDT: <1 second (direct submission)

Cost Comparison

System Cost per Update Updates per Hour Monthly Cost
Chainlink $5-50 60 $216k-2.16M
BFT-CRDT $0.10 3600 $260k

Note: BFT-CRDT has higher total cost but provides 60x more data

Data Richness

Traditional Oracle (per hour):
- 60 consensus prices
- Single value per update
- No individual oracle data

BFT-CRDT Oracle (per hour):
- 3,600 individual submissions