Rates Engine v0.5.0-rc.73
Pre-release[v0.5.0-rc.73] — 2026-05-23
Added
-
All 19 RedStone feeds now decode (#53). The decoder matched
feed_ids against the crypto allow-list (IsKnownCrypto). The
on-chainfeed_id()strings — captured 2026-05-22 — are not the
display names for 5 of 19 feeds, so EUROC (feed_idEUROC/EUR)
silently never decoded and the 11 RWA / tokenized-BTC feeds were
all dropped.internal/sources/redstone/feeds.goreplaces the
allow-list match with an explicit 19-entry registry keyed on the
exact feed_id, each mapped to a canonical(base, quote)pair.
Tokenized real-world assets (BENJI, GILTS, CETES, KTB, TESOURO,
USTRY, SPXU, iBENJI) decode as the newrwaAssetType
(ADR-0028); SolvBTC variants arecrypto. The quote is now
per-feed — EUROC lands as EUR-denominated instead of being
mislabelled USD. RedStone staysClassOracle/IncludeInVWAP= false, so NAV-quoted RWA references never feed market VWAP. -
CCTP-Stellar bridge ingest (#40). Circle's CCTP v2 is now a
wired source. The decoder for the four contract events
(deposit_for_burn,mint_and_withdraw,message_sent,
message_received) had shipped earlier; this completes the
source — a stateless topicDecodergated on the three known
CCTP contracts, aconsumer.Eventprojection, dispatcher
registration, and persistence to a newcctp_eventshypertable
(migration 0038). CCTP isClass=ClassBridge: bridge flow, never
contributes to VWAP.deposit_for_burn/mint_and_withdraware
USDC supply exits / entries beyond the classic trustline channel.
Enable by adding"cctp"toingestion.enabled_sources;
BackfillSafestaysfalsepending the WASM-history audit. -
Rozo-Stellar bridge ingest (#41). Rozo's v1 intent-bridge is
now a wired source. The decoder for the two v1 Payment events
(payment,flush) had shipped earlier; this completes the
source — a stateless topicDecodergated on the three live v1
Payment contracts, aconsumer.Eventprojection, dispatcher
registration, and persistence to a newrozo_eventshypertable
(migration 0039, fully typed — no jsonb blob).Class=ClassBridge,
never VWAP. Enable by adding"rozo"to
ingestion.enabled_sources;BackfillSafestaysfalsepending
the WASM-history audit. v2 Forwarder / IntentBridge stay
unwired — they are pre-mainnet. -
trades_pair_source_ts_idxcomposite index (#30). Migration
0037 adds(base_asset, quote_asset, source, ts DESC, ledger DESC)
ontrades.Store.LatestTradePerSource(behind/v1/observations)
runsSELECT DISTINCT ON (source) … ORDER BY source, ts DESC, ledger DESC; with only the pre-existing pair index that degraded
to an O(rows_in_pair) scan-then-sort. The new index orders exactly
as the query does within the(base_asset, quote_asset)prefix, so
the planner walks it as an O(num_sources) skip-scan. On an
already-populated node build itCONCURRENTLYby hand first — see
the migration header. -
cagg-broad-recomputeoperator procedure (#5). A one-shot
procedure doc for refreshing every continuous aggregate over the
preserved raw range. Necessary after a retention change (0031
trades / 0040 oracle_updates) or any backfill that lands rows
older than the CAGG's current oldest bucket. Lists the per-grain
CALL refresh_continuous_aggregate(...)commands for trades,
oracle, and pools-per-source CAGGs, the live-monitoring queries,
estimated runtime on r1, and explicit anti-conditions (don't run
during peak ingest / paired with other heavy r1 jobs / when
datazpool is over 85%). -
Monthly
galexie-archive-trimsystemd unit (#7, ADR-0027 §5).
The monthly trim cadence that ages newly-cold ledgers out of local
MinIO into the AWS public bucket.compute-trim-cutoff.shderives
the cutoff (indexer cursor − 90 days of ledgers) at run time, the
service invokesratesengine-ops trim-galexie-archive -older-than-ledger ${CUTOFF} -verify-upstream -commit, the timer
fires on the 1st of each month at 03:17 UTC. The Ansible role
installs the unit but does not enable it — per
feedback_cold_tier_premature_enablethe monthly trim is
destructive before §3 (cold-tiering on) + §4 (bulk-trim done);
the operator runssystemctl enable --now galexie-archive-trim.timerby hand once that rollout completes. -
ratesengine_ledgerstream_tier_both_missingpage-grade alert
(#7). ADR-0027's cold-tier failure mode (an LCM that is missing
from BOTH the local hot tier AND the AWS public bucket cold tier)
now alerts at page severity, with a runbook covering the
rehydrate-from-peer / disable-trim-timer / fix-config decision
tree. The metric was already exported by
internal/ledgerstream/tiered.go; the rule, the R1 overlay and
the runbook close the operational surface so an operator
enabling cold-tiering (§3) plus the bulk trim (§4) has the safety
net in place. The alert is silent until cold-tiering is enabled
(the metric stays at zero before then). -
ratesengine_source_matched_events_totalPrometheus metric.
Per-source counter of inputs a decoder'sMatches()claimed —
the denominator of decoder error-rate. Mirrors the
decoder_stats_5m.events_seenfix below onto Prometheus so the
live dashboardrate(decode_errors[5m]) / rate(matched_events[5m])
works without joining against the downstreamsource_events_total
(which counts decoder OUTPUTS, not INPUTS — different thing).
Wired intopipeline.emitDispatcherMetricDeltasalongside the
existing decode_errors / orphan_events deltas.
Changed
oracle_updatesretention removed (#14). Migration 0040 drops
the 90-day retention policy on theoracle_updateshypertable.
Sister to migration 0031 which did the same fortrades: every
raw oracle observation is now preserved indefinitely. The 0034
CAGGs (oracle_prices_1m…oracle_prices_1mo) are unchanged;
the migration header documents the per-grain
refresh_continuous_aggregateoperator call that re-backfills
them over the full raw range so the API serves long-form oracle
history.
Fixed
-
AWS-SDK checksum-warning log flood (#62). Since
aws-sdk-go-v2/configv1.29.0 the SDK's default response-checksum
mode iswhen_supported: it tries to validate a checksum on every
S3 GET and, when the response carries none, logsResponse has no supported checksum. Not validating response payload.at WARN.
galexie's MinIO GetObject responses carry no such checksum, so a
verify-archive chain walk (~1200 ledgers/s) emitted that line per
read — ballooning/tmp/va-full.logto 1.65 GB and burying the
real verify-archive failure under noise.ratesengine-indexerand
ratesengine-opsnow defaultAWS_RESPONSE_CHECKSUM_VALIDATIONto
when_requiredat process start (operator-set values are
respected), so the SDK validates only when the operation requires
it — S3 GetObject does not. -
RedStone EUROC feed never decoded (#53). The EUROC feed's
on-chain feed_id isEUROC/EUR, which never matched the crypto
allow-list entryEUROC, so the feed was silently skipped since
launch. Fixed by the explicit feed registry above; EUROC now lands
as an EUR-denominated observation. -
decoder_stats_5m.events_seenalways 0. The statsflush
flusher stampedEventsSeen: 0on every row with adispatcher. Stats doesn't expose per-source events_seen yet; fill when added
TODO. Per-source decoder error-rate (errors/events) was therefore
uncomputable — the numerator existed, the denominator was always
zero. The dispatcher now bumpseventsSeen[name]++in every
Matches→Decode site (events, contract calls, entry changes,
classic ops), exposes it viaStats.EventsSeen, and the flusher
writes the per-bucket delta todecoder_stats_5m. Bumped
pre-Decode so a decoder that matches then errors still counts —
exactly the shape that makes error-rate meaningful. -
SDEX density structurally locked at 99.99999%. The
sourceGenesisLedgermap declared SDEX's earliest-possible ledger
as 1 — but Stellar's network-genesis ledger carries zero
operations by design (it is the genesis spec record), so no SDEX
trade can ever live in ledger 1. The density denominator therefore
counted an unreachable ledger; the metric was structurally
prevented from ever reaching 100 % no matter how complete the
indexer was.#51's gap-fill verification surfaced it exactly:
62,688,969 / 62,688,970with the missing one being ledger 1.
Fixed to"sdex": 2— the earliest ledger that can actually carry
an SDEX operation. (Soroban sources already used exact first-WASM-
deploy ledgers and were untouched.) -
verify-archive -workers Nsilently dropped when-to=0. The
default-to=0(treat as "unbounded/live") fedsplitRange(from, 0, N)which hit itsto <= fromguard and returned a single chunk —
an N-way parallel chain walk silently degraded to a serial one.
Hit by a manual-from 2 -to 0 -workers 6bootstrap that crawled
~22h instead of ~4h, and would hit every fresh-state bootstrap of
the systemd-from-last-verifiedtimer for the same reason.
Fixed: whento == 0 && workers > 1we now query
datastore.FindLatestLedgerSequenceonce at start, adopt that as
the upper bound for the split, and log the resolution so it's
visible.to=0withworkers ≤ 1keeps its existing live-tail
semantics.