Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Aggregation in the enclave

audience: ai

Each tick, for each supported pair, the enclave collects the fresh quotes from the source-availability snapshot (wrapping), runs the declared aggregation policy, and produces one PriceTick. The aggregation policy is the rung where “in-enclave” stops being a plumbing detail and starts being the thing the consumers’ trust reduces to.

The PriceTick commit shape

pub struct PriceTick {
    /// Enclave-local wall clock at aggregation moment.
    pub timestamp_ms:      u64,

    /// Ordered pair (base, quote). ETH/USDC, BTC/USDC, etc.
    pub pair:              TokenPair,

    /// The aggregated price in fixed-point units of quote per base.
    pub price:             FixedPrice,

    /// Confidence band — max(abs(source_i - price)) among
    /// contributing sources, in quote-per-base units.
    pub confidence:        FixedPrice,

    /// blake3 of the ordered list of contributing SourceIds.
    /// Consumers cross-reference against the published SOURCE_CATALOG
    /// to know which sources voted for this tick.
    pub source_set_digest: [u8; 32],

    /// Number of sources that contributed. Below a declared
    /// minimum, the tick carries the `stale` flag.
    pub source_count:      u8,

    /// Set when one or more declared sources were unavailable
    /// and the tick is being published with degraded quorum.
    pub stale:             bool,

    /// Monotonic sequence number within the stream. Gaps
    /// indicate the oracle skipped a tick (e.g. no quorum).
    pub seq:               u64,
}

The enclave signs every PriceTick with its long-term signing key (bound to MR_TD via the first quote folded into the Stream’s bond; see publication). Per-tick quotes would be expensive and unnecessary — the consumer verified the quote once at subscription time; the per-tick signature binds each commit back to the same measured guest.

Aggregation policies

OracleParameters.aggregation_policy is an identifier selecting one of a small catalog of policies. The catalog is part of the oracle image, so adding a new policy is a new Measurements set.

pub enum AggregationPolicyId {
    /// Weighted median across fresh sources. Outliers
    /// beyond `k * MAD` are dropped before the median.
    WeightedMedian { k: u16, weights: &'static [SourceWeight] },

    /// Volume-weighted average across CEX sources plus
    /// pool-weighted on-chain reads. Weights published
    /// with the image.
    Vwap { weights: &'static [SourceWeight] },

    /// Minimum required quorum before any output; below
    /// the threshold, no tick.
    QuorumFloor {
        inner:       &'static AggregationPolicyId,
        min_sources: u8,
    },
}

All three forms are specified inside the enclave image. The parameters (k, weights, min_sources) are folded into Measurements via the image content; a consumer who wants to audit the policy reproduces the image from its published build recipe and reads the constants.

The selected policy operates on the fresh snapshot:

pub fn aggregate(
    policy: &AggregationPolicyId,
    fresh:  &[(SourceId, Quote)],
) -> AggregationOutcome {
    match policy {
        AggregationPolicyId::WeightedMedian { k, weights } => {
            let filtered = mad_filter(fresh, *k);
            let price = weighted_median(&filtered, weights);
            AggregationOutcome::Published {
                price,
                confidence:       max_dev(&filtered, price),
                source_count:     filtered.len() as u8,
                contributing_ids: filtered.iter().map(|(id, _)| *id).collect(),
            }
        }
        AggregationPolicyId::Vwap { weights } => { /* … */ }
        AggregationPolicyId::QuorumFloor { inner, min_sources } => {
            if fresh.len() < *min_sources as usize {
                AggregationOutcome::Skip
            } else {
                aggregate(inner, fresh)
            }
        }
    }
}

Outlier rejection

Outlier rejection uses Median Absolute Deviation (MAD). For a snapshot of fresh quotes q_1 … q_n:

  • m = median(q_1 … q_n)
  • MAD = median(|q_i - m|)
  • filtered = { q_i : |q_i - m| ≤ k * MAD }

MAD is robust against asymmetric outlier distributions in a way that standard-deviation filters are not. The threshold k is a published image constant; higher k lets more variance through (useful during volatile periods); lower k is stricter.

A degenerate case: if MAD = 0 (two or more sources agree exactly), any non-agreeing source is rejected. The Rust implementation folds a small absolute floor to avoid this pathology on identical-tick snapshots.

Confidence and the stale flag

confidence is the max deviation among contributing sources from the published price. A confidence band much larger than usual tells a consumer that the sources disagreed this tick; the consumer can choose to act on a wide band.

The stale flag is set when:

  • source_count < min_sources on a QuorumFloor-wrapped policy (no publication at all; gap in seq).
  • One or more sources declared in the catalog are reconnecting at aggregation time; the tick is published with stale: true if remaining sources still meet quorum.

A consumer that distinguishes fresh from stale ticks gets both liveness (keep seeing prices) and safety (know when to widen spreads or halt).

Determinism inside the enclave

Aggregation is deterministic given the fresh snapshot and the policy. Two honest oracle replicas running the same image with the same source catalog and the same upstream feeds at the same moment produce the same tick. This is useful for:

  • Multi-operator fleets (sustainability) — several operators publishing the same stream with the same ticks, letting consumers follow over when one retires.
  • Audit replay — an operator rebuilding the image from the declared constants and replaying captured upstream feeds reproduces the historical stream.

Network timing and TCP message ordering differ across replicas; exact bit-for-bit replay across operators is therefore approximate at tick-level. Over a window, the ticks converge to the same aggregated prices modulo sub-cadence de-synchronisation.

What the pipeline never does

  • It never publishes a tick from a single source without the stale flag. Single-source ticks are either skipped or flagged.
  • It never publishes the raw per-source quotes. Only the aggregate, the confidence, and the source-set digest leave the enclave.
  • It never adjusts the policy at runtime. Policy identifiers and their parameters are part of OracleParameters, part of the oracle’s content hash, part of Measurements. An operator who wants a new policy publishes a new image.

Forward

Chapter 6 (publication) specifies the mosaik surface the aggregated ticks flow through: one Stream<PriceTick> per supported pair, signed by the enclave, readable by anyone who admitted the oracle’s Measurements.