Soroban contract integration health checks and Stellar provider dependency graph - #1074
Merged
mijinummi merged 1 commit intoAug 28, 2026
Conversation
…graph Closes MDTechLabs#1067 and MDTechLabs#1068. 60 new tests, all passing. Both features are new directories — no existing source file is touched. ## MDTechLabs#1067 — Soroban contract integration health `src/contracts/health/soroban/` runs four checks in order, because each is only meaningful if the previous one passed: 1. **Availability** — is the contract there? 2. **Network** — did the *expected* network answer? 3. **Interface** — are the methods the integration calls actually present? 4. **Read** — do safe reads succeed, and return something sensible? Three decisions worth review: **When the contract is absent, the later checks are skipped rather than failed.** Reporting "interface check failed" for a contract that does not exist buries the one fact that matters, and each skip records why. **A wrong network is `unhealthy`, not a warning.** A contract answering from testnet when the integration is configured for mainnet is worse than one that does not answer at all — the integration looks fine while reading someone else's state. **Severity is graded rather than binary.** A missing method or a wrong network means the integration cannot work, so `unhealthy`. A failing read on an otherwise correct contract is `degraded` — the wiring is right and the fault may be transient, and those warrant different responses. Every probe is bounded by a timeout. An integration that never answers is not healthy, and without a bound the health check would hang along with it. `src/monitoring/contracts/` aggregates results across integrations and keeps a short history, because one failing check cannot distinguish an RPC blip from an integration broken since deploy. `isPersistentlyFailing` is that distinction. A sweep that throws for one contract yields `unknown` for that one rather than failing the sweep — one unreachable integration must not hide the status of the others. An empty monitor reports `unknown`, not `healthy`: saying "healthy" when nothing is registered would hide a misconfiguration. ## MDTechLabs#1068 — Stellar bridge provider dependency graph `src/providers/dependencies/stellar/` models what each provider needs — RPC, Horizon, contracts, liquidity sources, APIs — and derives provider health from it. The problem is attribution. The symptom is "provider X is down"; the cause is usually one shared RPC endpoint or price API sitting underneath several providers. The graph makes that a lookup rather than an investigation: record the dependency unhealthy once and every dependent provider reports the reason rather than a bare failure. Grading, which is the point of the model: - a **critical** dependency unhealthy → provider **unhealthy**; it cannot serve - a critical dependency degraded, or a **non-critical** one unhealthy → provider **degraded**; it serves, worse - a critical dependency that has never reported → **unknown** That last one is deliberate. Claiming health for something never checked is how a dashboard ends up lying, so `healthyProviderIds` excludes unknown providers rather than handing them traffic. A provider declaring a dependency that is not registered is rejected at registration — it would otherwise have nothing to check and silently report healthy. `impactOf` answers "is this endpoint safe to take out of rotation?" without recording a failure first. `src/providers/health/` rolls this into a fleet view whose `rootCauses` groups failures by the dependency responsible, widest blast radius first: five providers failing for one reason is one problem, not five. ## Verification pnpm exec jest tests/contracts tests/providers 60 passed pnpm run build green (CI's gate) eslint on every new src file clean tsc --noEmit clean Note on staging: `node_modules` is tracked in this repository (13,336 files), and installing dependencies locally modifies thousands of them. Only the 13 files above are staged; nothing under `node_modules` is included.
|
@Cybermaxi7 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! 🚀 |
4 tasks
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 #1067
Closes #1068
60 new tests, all passing.
pnpm run buildgreen. Both features are new directories — no existing source file is touched.#1067 — Soroban contract integration health
src/contracts/health/soroban/runs four checks in order, because each is only meaningful if the previous one passed:Three decisions worth a reviewer's eye:
When the contract is absent, the later checks are skipped rather than failed. Reporting "interface check failed" for a contract that doesn't exist buries the one fact that matters. Each skip records why it was skipped, so nothing looks silently unrun.
A wrong network is
unhealthy, not a warning. A contract answering from testnet when the integration is configured for mainnet is worse than one that doesn't answer — the integration looks fine while reading someone else's state, and everything downstream trusts it.Severity is graded, not binary. A missing method or a wrong network means the integration cannot work →
unhealthy. A failing read on an otherwise correct contract →degraded: the wiring is right and the fault may well be transient. Those warrant different responses, and collapsing them loses the distinction.Every probe is bounded by a timeout. An integration that never answers is not healthy, and without a bound the health check would hang along with it — there are tests for a hanging availability probe and a hanging read.
readProbesaccept an optionalexpectassertion, because a read that returns something is weaker evidence than a read that returns something sensible — a contract can answer while being wired to the wrong asset.Monitoring
src/monitoring/contracts/aggregates results and keeps a short history. History matters: a single failing check cannot tell an RPC blip from an integration that's been broken since deploy, andisPersistentlyFailingis exactly that distinction.unknownfor that one rather than failing the sweep — one unreachable integration must not hide the status of the others.unknown, nothealthy. Saying "healthy" when nothing is registered would hide a misconfiguration where the contracts were never wired up.#1068 — Stellar bridge provider dependency graph
src/providers/dependencies/stellar/models what each provider needs — RPC, Horizon, contracts, liquidity sources, APIs — and derives provider health from it.The problem is attribution. The symptom is "provider X is down"; the cause is usually one shared RPC endpoint or price API sitting underneath several providers. The graph turns that from an investigation into a lookup: record the dependency unhealthy once, and every dependent provider reports the reason rather than a bare failure.
The grading is the substance of the model:
That last case is deliberate. Claiming health for something never checked is how a dashboard ends up lying, so
healthyProviderIdsexcludes unknown providers rather than handing them traffic."Critical" here means the provider cannot serve without it — not merely "important". A price API going down degrades quote quality; an RPC endpoint going down stops the provider dead, and reporting those identically makes the signal useless.
Two things that fall out of the model:
impactOfanswers "is this endpoint safe to take out of rotation?" without recording a failure first.src/providers/health/rolls this into a fleet view.rootCausesgroups failures by the dependency responsible, widest blast radius first: five providers failing for one reason is one problem, not five, and that's the view an operator actually wants at 3am.Verification
Two notes for the maintainers
node_modulesis tracked in this repository — 13,336 files. Installing dependencies locally modifies or restructures thousands of them, which makesgit add -Aactively dangerous here. Only the 13 source and test files are in this commit; nothing undernode_modulesis included. Worth.gitignore-ing separately, but that's a large, disruptive change and not mine to make inside a feature PR.CI doesn't run the TypeScript tests. The workflow does
pnpm install,pnpm run build, thencargo test— sojestnever runs on a PR, and neither these 60 tests nor any existing suite gates a merge. Addingpnpm testto that job would be a one-line change; happy to open it separately.Separately, and unrelated to this PR: the root
pnpm-lock.yamlislockfileVersion: 6.0(pnpm 8 format) whilepackageManagerpinspnpm@10.30.2. Locally, pnpm 10 refuses it withERR_PNPM_LOCKFILE_BREAKING_CHANGEunder--frozen-lockfile; CI resolves a version that accepts it, so this isn't breaking your pipeline today, but a contributor followingpackageManagerwill hit it. I left the lockfile untouched rather than regenerate it into this PR.