Repository navigation
Conversation
Payout decisions rest on median, weighted quorum and anomaly thresholds, but there was no consensus module to test and nothing beyond hand-written examples. This adds a pure consensus module and checks its invariants over generated adversarial inputs with fast-check. src/oracle/consensus/consensus.ts - median(), meetsQuorum(), deviationTolerance()/isAnomalous(), and evaluateConsensus() which screens invalid/stale/duplicate sources, rejects outliers around the median, enforces a minimum source count and a weighted quorum, and returns a trust tier plus a deterministic 64-bit decision id. - Duplicated source ids are invalid in every copy (no double voting), and every source that reported counts toward the quorum denominator, so bad data cannot lower the bar. consensus.property.spec.ts asserts, among others: - median: bounded by min/max, order-independent, monotone, exact under translation, stays inside the honest range while honest values outnumber adversarial ones, rejects non-finite input - quorum: scale-invariant, monotone in agreeing weight and in ratio, never passes with zero/non-finite total weight - anomaly threshold: symmetric, monotone in distance and tolerance - evaluateConsensus: never throws on hostile input (NaN, Infinity, duplicates, empty ids), order-independent, deterministic, only agrees when count and weighted quorum are met, never counts stale data, and a minority cannot pull the value outside honest range ± tolerance The suite caught a real bug during development: averaging the middle pair as a/2 + b/2 underflows on subnormals and returned 0 for [5e-324 x4]. That case is now a regression example. Also restores package.json, which was committed empty in Refract-Protocol#165. Contents are rebuilt from the package-lock.json root entry (which already lists fast-check) plus the previous scripts and Jest config, so `npm ci` works again. Adds `test:property`, `dev` and `typecheck` scripts (the latter two are already documented in the README). The Jest config now runs ESM-only transitive deps of @stellar/stellar-sdk v16 (@noble/*, uint8array-extras) through babel-jest, using the plugin already in devDependencies; this also un-breaks the existing scval-encoders suite. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On-chain readings were a bare i128, so consumers and auditors could not tell a corroborated value from a single-source one without trusting the backend. oracle-encoding.ts now packs provenance into a u128 that is published alongside the value. Layout (MSB first): version (4) | trust tier (4) | agreeing source count (8) | reserved (8) | source timestamp, Unix seconds (40) | consensus decision id (64). Version 0 is never valid, so zero means "no provenance". - packProvenance / unpackProvenance with strict validation: unknown versions, set reserved bits, out-of-range fields and inconsistent tier/count pairs (e.g. Corroborated with one source) are rejected. Unverified readings cannot be encoded at all. - provenanceFromDecision maps a ConsensusDecision to provenance; the source timestamp is the earliest agreeing observation, floored to seconds, so a value never looks fresher than its oldest input. - encodeReadingForChain + buildUpdateReadingArgs produce ScVal args for update_reading(coverage_type: u32, value: i128, provenance: u128). The contract has to accept the third argument before the relayer switches over. - OracleReading gains an optional `provenance`. The decision id is kept as 16 hex chars rather than a bigint so readings stay JSON-safe for the WebSocket feed. - Golden XDR fixture for the u128 argument, added to the regenerate script (existing fixtures are unchanged). - docs/oracle-provenance.md documents the layout for contract authors and auditors. Tests cover the documented bit layout, a fast-check round-trip over all valid provenance, every rejection path, decision → provenance mapping, the ScVal types and the golden fixture. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Oracle polling, consensus and claim settlement ran inside the API process, so request traffic and API restarts could delay or interrupt payouts. They now run in a separate worker; the API only serves reads and the WebSocket feed. Process roles (src/runtime/process-role.ts) - PROCESS_ROLE=api | worker | all. OracleScheduler and ClaimScheduler do nothing unless the role runs the pipeline. - Unset means `all` (one process, old behaviour) so existing deployments keep paying out until they are split; main.ts logs a warning in that case and refuses PROCESS_ROLE=worker. Worker (src/worker.ts, src/worker/) - Nest application context (no HTTP app) built from WorkerModule: data layer, Stellar, metrics, alerting, reading bus, policy/oracle/claim modules. No throttler, API-key guard or request-serving modules. - Tiny node:http listener on WORKER_HEALTH_PORT (default 4002): /health returns 503 when a pipeline stage has not succeeded within WORKER_STALE_AFTER_MS (PipelineHeartbeat), so the orchestrator can restart the worker alone; /metrics exposes Prometheus metrics. - Graceful shutdown shared with main.ts (runtime/graceful-shutdown.ts); ClaimScheduler still drains an in-flight settlement first. Worker → API channel (src/oracle/reading-bus.ts) - ReadingBus with a Redis implementation (latest reading per coverage type in a hash + pub/sub for live updates) and an in-memory one for PROCESS_ROLE=all / sandbox. A split role without Redis fails at boot instead of serving a frozen feed. Messages are validated on receipt. - OracleScheduler publishes readings to the bus; OracleFeedRelay (API) subscribes and broadcasts non-low readings via OracleGateway, which gets back the broadcastAlert() / welcome message its spec expects. Deployment - docker-compose: `backend` runs with PROCESS_ROLE=api, new `worker` service runs dist/worker.js with its own healthcheck; both share one env anchor. - npm scripts start:worker, start:worker:dev, start:worker:prod. - README documents the tiers and the one-worker-per-relayer-key rule. Pre-existing breakage fixed in files touched here: - app.module.ts: removed a truncated import line and a duplicated imports block left by a bad merge (the file did not parse). - claim.scheduler.ts: removed two stray closing braces (did not parse). - oracle.gateway.ts: OnModuleDestroy is imported from @nestjs/common. Note: oracle.module.ts / claim.module.ts / oracle.service.ts are empty on main, so neither entrypoint boots until those are restored. When they are, OracleModule should import OracleFeedModule rather than declare OracleGateway itself. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@agudajohn793 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
…(Simple agent) - docker-compose.yml: merged [markers] — model resolved the conflict markers - package.json: merged [markers] — model resolved the conflict markers - src/app.module.ts: merged [markers] — model resolved the conflict markers - src/claim/claim.scheduler.ts: merged [markers] — model resolved the conflict markers - src/main.ts: merged [markers] — model resolved the conflict markers - src/metrics/metrics.service.ts: merged [markers] — model resolved the conflict markers - src/oracle/oracle-encoding.ts: merged [markers] — model resolved the conflict markers - src/oracle/oracle-reading.ts: merged [markers] — model resolved the conflict markers - src/oracle/oracle.gateway.ts: merged [markers] — model resolved the conflict markers - src/oracle/oracle.scheduler.ts: merged [markers] — model resolved the conflict markers Co-authored-by: Simple Agent <agent@simple.dev>
…(Simple agent) - package.json: merged [markers] — model resolved the conflict markers - src/claim/claim.scheduler.ts: merged [markers] — model resolved the conflict markers Co-authored-by: Simple Agent <agent@simple.dev>
…(Simple agent) - package.json: merged [markers] — model resolved the conflict markers - src/claim/claim.scheduler.ts: merged [markers] — model resolved the conflict markers Co-authored-by: Simple Agent <agent@simple.dev>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #247
Closes #248
Closes #249
Closes #250
Summary
Type of change
Checklist
.envvalues committedNotes for reviewers