Skip to content

fix: unblock indexing — nullable Transaction.to + reward Pool guard#247

Open
rickstaa wants to merge 2 commits into
mainfrom
fix/nullable-to-and-reward-pool
Open

fix: unblock indexing — nullable Transaction.to + reward Pool guard#247
rickstaa wants to merge 2 commits into
mainfrom
fix/nullable-to-and-reward-pool

Conversation

@rickstaa

Copy link
Copy Markdown
Member

Single PR to unblock the Livepeer subgraph in one deploy. Combines two independent fixes (also open separately as #245 and #246):

1. Transaction.to nullable (#245)

Fixes the deterministic halt at block 485100965 — a Tenderize unlock deployed via a constructor has no recipient, so event.transaction.to is null, but Transaction.to was String!:

missing value for non-nullable field `to`  (handler: earningsClaimed)

Change: schema.graphql Transaction.to: String!String. Matches graph-ts (to: Address | null) and Ethereum (a creation tx to is null). No mapping change.

2. Pool guard in reward() (#246)

Stops reward() hard-aborting on a missing Pool at block 144056642:

unexpected null in handler `reward`  (bondingManager.ts:499)

Change: create the Pool on demand when Pool.load() is null.

Why combined

Grafting is disabled, so any redeploy triggers a full resync. On that resync, block 144056642 (reward) comes before 485100965 (to), so both fixes are needed for the subgraph to sync cleanly past the current halt. Deploy this branch to fix production in one shot.

Validation

Both reproduced and fixed locally against an Arbitrum One archive RPC — the pre-fix build aborts at 485100965 and 144056642, this branch indexes past both. yarn codegen + yarn build pass.

Full root-cause notes in #245 (deterministic to bug) and #246 (defensive Pool guard).

🤖 Generated with Claude Code

rickstaa added 2 commits July 20, 2026 17:15
Contract-creation txs have no recipient, so `event.transaction.to` is null and
graph-node aborted on the non-nullable `Transaction.to`. `null` is the correct
value (matches graph-ts `Address | null`); no mapping change needed.
reward() loaded the round's Pool with `Pool.load()` and dereferenced it via
`pool!`, which aborts the subgraph if the Pool is missing (observed at block
144056642: "unexpected null in handler `reward`" at bondingManager.ts:499).

Pools are created per active transcoder in newRound() from on-chain calls
(getFirstTranscoderInPool / getNextTranscoderInPool). If that set comes back
empty — the call reverted, or an incomplete archive node on a resync — no Pool
exists for a transcoder that later calls reward(). Create the Pool on demand so
a missing Pool can never hard-halt indexing.
@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@rickstaa, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 58 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 59137e03-a824-422b-8a52-85303c6da137

📥 Commits

Reviewing files that changed from the base of the PR and between 2eac27f and 82d79b6.

📒 Files selected for processing (2)
  • schema.graphql
  • src/mappings/bondingManager.ts
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/nullable-to-and-reward-pool

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown

🚀 Subgraph Studio preview deployed

Item Details
Version label pr-247-4aa21cd-29754385784
Query endpoint https://api.studio.thegraph.com/query/31909/livepeer-ci/pr-247-4aa21cd-29754385784
curl -H 'Content-Type: application/json' \
  -d '{"query":"{ protocol(id: \"0\") { inflation } }"}' \
  https://api.studio.thegraph.com/query/31909/livepeer-ci/pr-247-4aa21cd-29754385784

rickstaa added a commit to livepeer/explorer that referenced this pull request Jul 21, 2026
…h resyncs (#749)

Stopgap while the subgraph resyncs from scratch (livepeer/subgraph#247), which
leaves the manually surfaced LIP-118 poll showing 0% support and 0% participation
even for people who already voted.

Revert this and #734 once the subgraph has reindexed the poll.
---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Copilot <copilot-pull-request-reviewer[bot]@users.noreply.github.com>
rickstaa added a commit to livepeer/explorer that referenced this pull request Jul 21, 2026
Stopgap while the subgraph resyncs from scratch (livepeer/subgraph#247). The
withdrawal list comes from the subgraph, so locks created after indexing stalled
are missing from it: an unbond appears to do nothing, and a user with no
acknowledgement may reasonably unbond again, moving more stake out for a second
full unbonding period. Once such a lock matures it is also withdrawable on-chain
while remaining invisible in the UI.

Lock ids are sequential and never reused, so anything the subgraph has not seen
sits above its highest known id. Add /api/unbonding-locks/[address], which reads
that tail from the contract, and append it to the subgraph's list rather than
replacing it. The round comes from /api/current-round with it, since a stale
round files a matured lock as pending and hides its withdraw button.

Only fetched when the subgraph reports degraded and the user is viewing their own
account, so a healthy subgraph behaves exactly as before, with no extra request.
The scan is bounded to 200 ids so a direct call cannot ask for an unbounded read.

This is a bandaid, not a feature: it duplicates state the subgraph owns and
should be reverted once indexing has recovered. It also disables itself as that
happens, since the ids it fetches are those above what the subgraph reports.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: CodeRabbit <coderabbitai[bot]@users.noreply.github.com>
rickstaa added a commit to livepeer/explorer that referenced this pull request Jul 21, 2026
)

Stopgap while the subgraph resyncs from scratch (livepeer/subgraph#247). Locks
created after indexing stalled are missing from the withdrawal list, so an
unbond appears to do nothing, and a matured lock stays invisible while being
withdrawable on-chain.

Lock ids are sequential and never reused, so anything the subgraph has not seen
sits above its highest known id. Add /api/unbonding-locks/[address] to read that
tail from the contract and append it to the subgraph's list rather than
replacing it, with the round from /api/current-round since a stale round hides a
matured lock's withdraw button.

Only fetched when the subgraph reports degraded and on the user's own account,
capped at 200 ids.

Revert once the subgraph has reindexed.

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: CodeRabbit <coderabbitai[bot]@users.noreply.github.com>
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