Watch SAC events by topic filter with cursor-paged drains; restore periodic topology re-sync - #16
Merged
Merged
Conversation
…ins; restore periodic topology re-sync. The mainnet XLM SAC emits hundreds of events per ledger, so the unfiltered contractId subscription returned pages that never spanned a full ledger while the poll cursor jumped to latestLedger, dropping every Moonlight event; scans are now one filter per call, endLedger-windowed with processing-limit halving, and consumption advances only across RPC-scanned positions.
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.
Problem
The mainnet dashboard showed nothing from the 2026-07-30 T3 demo run (Councils Cheshire/Salem, Provider Orion, deposit/send/withdraw) despite a healthy watcher and correct council-platform registrations.
Root cause (all measured against mainnet):
getEventspage never spanned even one ledger, andpollTickthen setlastLedgerSeen = res.latestLedger— jumping the cursor ~15 minutes of ledgers per 5s tick and silently dropping every Moonlight event (provider_added, deposits, settlements). The cold-start/back-fill walks had the same flood problem:lastLedgerInPage + 1stepping plus a 50-page cap bounded a "24h" walk to ~2 minutes of mainnet ledgers.contract_initialized(pending 120s, then permanently blacklisted), or piggybacked onprovider_added— which the flood dropped. Salem stayed name-only (no channel/provider/jurisdiction) for hours after council-platform had everything.Changes
transferpatterns pinned to known channel addresses (deposit + settlement) andfeepatterns pinned to registered PP keys (bundles), one filter pergetEventscall. Patterns verified against the real mainnet events (transfer = 4 topics, fee = 2).scannedTo + 1), neverlatestLedgerjumps. Handles both measured RPC behaviors: bounded scans that return a below-head cursor with a partial page, and-32001 processing limitrejections (windowedendLedgerrequests, halving on rejection). Store dedup is now id-based beyond the 20-entry ring so designed re-read overlap can't double-count.provider_addedpiggyback refresh kept for fast linkage.moonlight.network.v2, v2 snapshot shape,channel_bundlekind, new sync architecture (hourly re-sync text was stale).Verification
deno task check/lint/fmt:check/testgreen (58 tests; new coverage for the query builder, windowed/cursor drain semantics, processing-limit fallbacks, and store dedup).council_formed,provider_added(Orion), the 18:59:32Z deposit (20.05 XLM,00c81d08…), 19:00:21Z bundle (f69effe0…), 19:01:06Z settlement (775ddecc…), plus the later 20:48–21:07Z cycles — 11 events,eventsLast24h: 11,activePPs: 1, and Salem's topology complete (channelCCLT…, Provider Orion, AU). Cold start walks the full 24h in ~7 windowed requests per filter and completes in ~40s; the 5s forward tick resumes at the head cursor in one request per filter.Deploying this to
moonlight-mainnet-network-dashboard(tagged main push) and restarting is what makes the mainnet dashboard pick the run up — the run must be within the 24h window at record time (or re-run the demo actions), since the no-persistence design is unchanged.