Binding consumers
audience: ai
The oracle exposes a family of Stream<PriceTick>
endpoints, one per supported token pair. A consumer
coalition that wants oracle prices does three things,
in order: reference the oracle in its own
CoalitionConfig, compose a TicketValidator that
admits the oracle’s Measurements, and subscribe to
the streams it cares about. This chapter walks all
three from the consumer side; the oracle operator
does not participate in the handshake beyond
publishing ORACLE.content_hash() and
ORACLE_MEASUREMENTS.
Referencing the oracle
A consumer coalition (for instance, searcher-α from
the web3 example) references
the oracle through its own OrganismRef pointer:
use coalition::{OrganismRef, MeasurementsPin};
pub const ORACLE_CONSUMED: OrganismRef<'static> =
OrganismRef {
role: "oracle",
stable_id: ORACLE_STABLE_ID, // from the oracle's release page
content_hash: Some(ORACLE_CONTENT_HASH), // pinned
};
The reference is to the same organism the oracle
operator publishes. The stable_id and
content_hash come from the oracle operator’s
release page (setup); nothing is
negotiated out-of-band. If the consumer chooses to
follow rotations, it pins only the stable_id and
tracks content_hash updates through the
retirement chain (see
sustainability). If the
consumer pins both, a Measurements rotation requires
a consumer-side republish to remain bonded.
Composing the TicketValidator
The consumer’s TicketValidator admits the oracle’s
Measurements in its TDX arm:
use mosaik::tickets::{TicketValidator, And, Or};
use mosaik::tee::tdx::AdmitsMeasurements;
pub fn oracle_consumer_validator()
-> TicketValidator<'static>
{
TicketValidator::compose(
// Consumer's own ACL for who runs this searcher.
searcher_alpha::SELF_ACL,
// Admits any peer whose self-quote matches the
// oracle's published Measurements.
AdmitsMeasurements::equal(ORACLE_MEASUREMENTS),
)
}
AdmitsMeasurements::equal is the simplest
composition: the consumer accepts exactly the
declared Measurements set and nothing else. A
consumer that is willing to follow staged rotations
may use AdmitsMeasurements::in_set(&[MR_OLD, MR_NEW]) across a rotation window; see
sustainability.
First subscription
The stream endpoint for a given pair is addressed by
the oracle’s stable_id and the pair identifier:
use mosaik::streams::{StreamId, Subscription};
let network: Arc<Network> = /* from coalition bootstrap */;
let pair = TokenPair::new("USDC", "ETH");
let stream_id = StreamId::derive(
ORACLE_CONSUMED.stable_id(),
&pair.preimage(),
&PRICE_TICK_SCHEMA_V1,
);
let mut subscription: Subscription<PriceTick> =
network.subscribe(stream_id, oracle_consumer_validator()).await?;
while let Some(tick) = subscription.next().await {
// PriceTick::verify re-checks the oracle's quote
// on the stream's bond plus the commit's schema.
tick.verify(&ORACLE_MEASUREMENTS)?;
handle_tick(tick);
}
Two properties of the subscription are worth naming:
- Admission is one-sided. The oracle’s bond ACL admits any subscriber; the consumer’s validator admits any peer whose Measurements match. The bond either forms or it does not; there is no handshake step the oracle operator participates in.
PriceTick::verifyre-checks the oracle’s self-quote that was folded into the bond at subscription time. It does not re-quote per tick; TDX quotes are bond-level. Per-tick tamper detection is covered by the oracle’s signing key (see publication).
What the consumer can and cannot assume
- Prices are post-aggregation. The tick is what
the oracle’s declared
AggregationPolicyIdproduced after reading its sources (aggregation). The consumer does not see per-source quotes; only the aggregate, thesource_set_digest, and the staleness flag. - Cadence is nominal. The oracle publishes at the nominal cadence when all sources are fresh and quorate. When a source degrades, the oracle may skip a tick or publish a stale-flagged tick; both are covered under aggregation.
- Trust reduces to one set of bytes. The
consumer’s trust in the oracle is the admission
of
ORACLE_MEASUREMENTS. No reputation layer, no chain of signers, no multi-party commit. A consumer who wants reputation-gated oracle admission composes that on top — but the minimal shape does not require it.
Forward
Chapter 3 (source-reads) inverts the viewpoint: what the oracle itself reads, inside its enclave, to produce the ticks the consumer just subscribed to.