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

Wrapping source feeds

audience: ai

The oracle’s trust model collapses if any of its sources is read outside the enclave. This chapter specifies how each source class from source-reads is terminated inside the TDX guest so that the only code that touches cleartext prices is the code whose MR_TD the consumers admitted.

The enclave boundary

The oracle process runs in a TDX guest. Its Measurements cover MR_TD (the guest’s initial memory image), MR_CONFIG_ID (the guest’s folded configuration, including the source-catalog digest), and the owner set (MR_OWNER, MR_OWNER_CONFIG). Nothing outside the guest can observe or inject into the subscriptions below.

┌─────────────────────────────────────────────────┐
│ TDX guest — measured by ORACLE_MEASUREMENTS     │
│                                                 │
│  ┌──────────────┐  ┌──────────────────────────┐ │
│  │ CEX clients  │  │ on-chain readers          │ │
│  │ (TLS-pinned) │  │ (archive / light client)  │ │
│  └──────┬───────┘  └───────────┬──────────────┘ │
│         │                      │                │
│         ▼                      ▼                │
│    ┌────────────────────────────────────────┐   │
│    │ aggregation + publication pipeline      │   │
│    └───────────────────┬────────────────────┘   │
│                        │                        │
│                        ▼                        │
│             ┌──────────────────────┐            │
│             │ mosaik Stream commits │            │
│             │ (signed by enclave)   │            │
│             └──────────────────────┘            │
└─────────────────────────────────────────────────┘
          ▲                               │
          │ host I/O (opaque)             │ signed commits
          │                               ▼
     untrusted host                 consumer subscribers

Host I/O crosses the boundary only as ciphertext or as TLS bytes whose endpoints are pinned inside the enclave. Nothing else is trusted.

CEX spot feeds

Each Source::CexSpot entry is a WebSocket subscription terminated by a TLS client built into the oracle image. The client:

  • Pins SPKI. The TLS handshake checks the leaf certificate’s SPKI against tls_spki from source-reads. Any mismatch is a hard-fail; the source transitions to reconnecting and does not recover until a matching handshake.
  • Ignores the host’s resolver. Hostnames are resolved inside the enclave (DoH to a pinned resolver, or the resolver identity is folded into the Measurements alongside the SPKI pin).
  • Rejects downgrade. TLS 1.3 only; any negotiation past a declared cipher-suite set is a hard-fail.

A single shared TlsClient inside the enclave holds an (exchange, pair) → WebSocket map; each message arriving is stamped with an enclave-local timestamp and forwarded to the aggregation pipeline.

pub struct TlsClient {
    config: Arc<rustls::ClientConfig>,  // pinned SPKI verifier
}

impl TlsClient {
    pub async fn subscribe(
        &self,
        source: &Source,
    ) -> Result<BoxStream<'static, RawQuote>, SourceError> {
        match source {
            Source::CexSpot { endpoint, symbol, tls_spki, .. } => {
                let stream = self.connect_ws(endpoint, *tls_spki).await?;
                Ok(stream.map(|msg| parse_raw_quote(symbol, msg)).boxed())
            }
            _ => unreachable!("non-CEX sources handled elsewhere"),
        }
    }
}

On-chain AMM reads

Source::OnChainAmm entries read AMM pool slots (Uniswap V3 slot0, Curve get_virtual_price, etc.) through one of two paths:

  • Archive node. The operator runs an archive node (e.g. reth --full or geth --syncmode snap) whose RPC endpoint is accessible only from the enclave’s network namespace. The client authenticates the RPC session with a mutual TLS pair whose CA cert is folded into the oracle’s Measurements; the archive node’s identity is therefore transitively part of the oracle’s trust model. An operator who runs their archive node honestly delivers honest reads; a dishonest or compromised archive node shows up as quorum disagreement if quorum > 1.
  • Light client. The enclave runs an Ethereum consensus light client that verifies every execution-layer read against a sync-committee- signed head. Under honest-majority assumptions on the consensus layer, the reads are trustless. Slower than archive; strictly stronger trust story.
pub struct OnChainReader {
    archive:     Option<Arc<ArchiveClient>>,    // mTLS-pinned
    light:       Option<Arc<LightClient>>,      // consensus-verified
}

impl OnChainReader {
    pub async fn read(
        &self,
        source: &Source,
    ) -> Result<Quote, SourceError> {
        match source {
            Source::OnChainAmm { read_mode, .. } => match read_mode {
                OnChainReadMode::ArchiveNode => self.read_archive(source).await,
                OnChainReadMode::LightClient => self.read_light(source).await,
            },
            _ => unreachable!(),
        }
    }
}

The choice between archive and light client is the oracle operator’s. Most operators run archive in production (latency) and light in a verifier role (cross-check); some catalog entries mark a source quorum: 2 meaning both an archive read and a light-client read must agree within a tolerance before the source contributes.

Peer oracle sources

Source::OnChainOracle entries subscribe to another mosaik oracle exactly the way a consumer does (binding). The enclave’s TicketValidator composes the peer oracle’s Measurements alongside its own; the resulting streams feed into the aggregation pipeline like any other source.

The composition is transitive: the oracle’s Measurements cover a code path that admits another oracle’s Measurements. A consumer of this oracle who wants to audit the peer set can do so by reading SOURCE_CATALOG (its digest is in the content hash) and verifying each referenced oracle’s published Measurements.

Source-availability reporting

The aggregation pipeline is supplied with a live per-source availability map:

pub struct Availability {
    pub fresh:       HashSet<SourceId>,
    pub stale:       HashSet<SourceId>,
    pub reconnecting:HashSet<SourceId>,
}

Availability is updated on every message arrival and every reconnect-timeout. The aggregation policy (aggregation) reads this snapshot each tick to decide whether to publish, skip, or flag.

What the enclave never does

  • It never accepts unpinned TLS. A non-matching SPKI is a hard-fail.
  • It never leaks raw source quotes outside the guest. Only aggregated ticks leave the enclave, and only through the signed mosaik stream commits in publication.
  • It never imports source data through the host OS. File-backed cache, shared memory, and host syscalls other than network I/O are not used. Any cache is in-guest RAM only.

Forward

Chapter 5 (aggregation) specifies what the in-enclave pipeline does with the fresh quotes once they arrive.