Skip to content

fix: count validating attesters from each rollup's own active set - #129

Merged
aminsammara merged 1 commit into
mainfrom
amin/summary-enumerate-active
Nov 5, 2026
Merged

aminsammara merged 1 commit into
mainfrom
amin/summary-enumerate-active

Conversation

@aminsammara

Copy link
Copy Markdown
Collaborator

Follow-up to #128, which is now in prod. The staking summary undercounts active attesters, and the dashboard headline currently reads 507M instead of about 630M.

What's wrong

live API chain
v6 validating 2,541 3,157 (getActiveAttesterCount)
v5 validating 0 50
activeValueLocked 507.06M 630.25M

The reader only asks about attesters in the indexer's deposit table, and that table is missing about 670 attesters that are validating on chain:

  • all 50 on v5, which deposited between blocks 26,229,331 and 26,253,638;
  • about 616 on v6.

Why the indexer lacks those deposits is a separate investigation. The old event-count summary was already off by about 99 stakes and 113 exits, which points the same way.

Fix

  • Each rollup's active set is read from chain with getActiveAttesterCount + getAttesterAtIndex and merged into the attesters the reader checks.
  • Validating counts and active stake are now complete whatever the indexer holds.
  • Exiting and zombie attesters have already left the active set, so for those the indexer's list is still the only source.

Deploy

  • The two calls are in a new ROLLUP_ACTIVE_SET_ABI, not ROLLUP_ABI. That keeps Ponder's build fingerprint identical to what's deployed.
  • ponder.config.ts, ponder.schema.ts and src/events are unchanged from origin/main.
  • So this deploys as a plain image swap on the current schema atp-indexer-si-v2, with no new_schema and no rebuild.

Checks

  • yarn jest: 40 tests pass, including a new case for validating attesters the indexer never saw.
  • yarn typecheck: clean.
  • Live mainnet check, deliberately passing only 1,000 of the 7,246 known attesters: v6 = 3,157 validating / 630.25M, v5 = 50 / 10M. Both match chain exactly. A full read takes about 10s.

After #128 went to prod the summary reported 2,541 validating attesters on the canonical rollup
while getActiveAttesterCount said 3,157, and 0 on v5 where the chain has 50. Active stake read
507M against the ~630M the GSE holds, and that is the dashboard's headline number.

The reader only asked about attesters in the indexer's deposit table, and that table is missing
about 670 attesters that are validating on chain (all 50 on v5, which deposited between blocks
26,229,331 and 26,253,638, and ~616 on v6). Why the indexer lacks them is a separate question; the
summary should not depend on it for the active set, which the rollup can list itself.

Each rollup's active set is now read with getActiveAttesterCount and getAttesterAtIndex and merged
into the attesters asked about, so validating counts and stake are complete whatever the indexer
holds. Exiting and zombie attesters have left the active set, so for those the indexer's list is
still the only source.

The two calls live in a separate ABI rather than ROLLUP_ABI: ponder.config.ts gives ROLLUP_ABI to
the Rollup contract, so extending it changes Ponder's build fingerprint and would force another
schema rebuild on deploy for a function no handler uses.
@aminsammara
aminsammara requested a review from a team as a code owner November 4, 2026 14:25
@aminsammara
aminsammara merged commit f76298a into main Nov 5, 2026
5 checks passed
aminsammara added a commit that referenced this pull request Nov 5, 2026
… down (#130)

The #129 deploy went out as an in-place image swap on atp-indexer-si-v2. Ponder fingerprints
the whole src/ tree, not just ponder.config.ts, so the new image refused to start on a schema
an older build created. box-deploy.sh then exited without restoring the previous image, which
left the prod API returning 502.

Redeploying with a fresh schema could not fix it either. The si-v3 rebuild completed, but the
script finds the old schema by asking the serving container, and that container was
crash-looping. CURRENT came back empty, psql ran against "".atp_position, the failing command
substitution tripped set -e, and the script died before the flip.

Three changes:
- current_schema falls back to docker-compose.override.yml, which this script writes and
  which records what the box was serving, whenever the container can't answer.
- A failed /ready after an image swap restores the previous image instead of leaving the box
  down.
- psql_count tolerates a schema that doesn't exist. The parity check then compares against 0
  rather than killing the script.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant