Skip to content

fix: create missing Pool on demand to avoid null-Pool abort#249

Merged
rickstaa merged 1 commit into
mainfrom
fix/create-or-load-pool
Jul 21, 2026
Merged

fix: create missing Pool on demand to avoid null-Pool abort#249
rickstaa merged 1 commit into
mainfrom
fix/create-or-load-pool

Conversation

@rickstaa

@rickstaa rickstaa commented Jul 20, 2026

Copy link
Copy Markdown
Member

Problem

reward() aborts on a null Pool (the halt at block 144056642) and ticketBroker silently drops the fees when a round's Pool was never built. newRound builds Pools by walking the on-chain pool with an eth_call enumeration, which is non-deterministic and can come up short. See #248 for the root cause.

Fix

Add createOrLoadPool(round, transcoderAddress) and use it in newRound, reward, and ticketBroker, so the Pool is always built through one code path and no handler aborts on a null Pool.

  • Single writer — the helper is the only place a Pool is created, setting the round snapshot (totalStake/rewardCut/feeShare) once. Handlers only add their own accumulator (rewardrewardTokens, ticketBrokerfees), never re-touching the snapshot.
  • No ! — the helper returns a non-null Pool and defaults the non-nullable fields if the Transcoder is ever missing, so save() can't abort (matches The Graph's unexpected-null linter guidance).
  • Unchanged on a full sync — the transcoder always exists (from Bond/register logs), so Pools get real values. The default branch is a failsafe.

Notes

@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This change adds a shared createOrLoadPool helper and updates round initialization, reward processing, and ticket redemption to use it for deterministic Pool creation, loading, field updates, and persistence.

Changes

Pool lifecycle centralization

Layer / File(s) Summary
Shared pool creation and loading
utils/helpers.ts
Adds createOrLoadPool, which loads an existing pool or initializes and saves one using round and transcoder data.
Round pool initialization
src/mappings/roundsManager.ts
Replaces inline Pool construction in newRound with the shared helper.
Reward and ticket pool updates
src/mappings/bondingManager.ts, src/mappings/ticketBroker.ts
Uses the shared helper for pool retrieval and applies reward, fee-share, reward-cut, and fee updates directly to the returned pool.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

  • livepeer/subgraph#246: Addresses null Pool handling by creating pools on demand when storage loading returns null.

Sequence Diagram(s)

sequenceDiagram
  participant RoundHandler
  participant RewardHandler
  participant TicketHandler
  participant createOrLoadPool
  participant PoolStore

  RoundHandler->>createOrLoadPool: Initialize pool for active transcoder
  RewardHandler->>createOrLoadPool: Retrieve pool for reward
  TicketHandler->>createOrLoadPool: Retrieve pool for ticket fees
  createOrLoadPool->>PoolStore: Load or save pool
  createOrLoadPool-->>RewardHandler: Pool entity for reward updates
  createOrLoadPool-->>TicketHandler: Pool entity for fee updates
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title is concise and accurately summarizes the main change: creating missing Pools on demand to prevent null-Pool aborts.
Description check ✅ Passed The description covers the problem, fix, context, and dependencies, but it omits the template checklist and an explicit Fixes # line.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/create-or-load-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

github-actions Bot commented Jul 20, 2026

Copy link
Copy Markdown

🚀 Subgraph Studio preview deployed

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/mappings/ticketBroker.ts (1)

68-71: 🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Fix erroneous reserve deduction due to premature zeroing of deposit.

broadcaster.deposit is reassigned to ZERO_BD before it is subtracted from faceValue to calculate the difference. Consequently, the difference evaluates to the entire faceValue, leading to an over-deduction from the broadcaster's reserve. Calculate the difference before resetting the deposit.

🐛 Proposed fix
   if (faceValue.gt(broadcaster.deposit)) {
-    broadcaster.deposit = ZERO_BD;
-
-    let difference = faceValue.minus(broadcaster.deposit);
+    let difference = faceValue.minus(broadcaster.deposit);
+    broadcaster.deposit = ZERO_BD;
     if (difference.gt(broadcaster.reserve)) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/mappings/ticketBroker.ts` around lines 68 - 71, In the
insufficient-deposit branch, calculate difference using the original
broadcaster.deposit before assigning ZERO_BD. Update the sequence around
broadcaster.deposit and difference so the reserve deduction reflects only the
uncovered amount, then reset broadcaster.deposit to ZERO_BD.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/mappings/ticketBroker.ts`:
- Around line 68-71: In the insufficient-deposit branch, calculate difference
using the original broadcaster.deposit before assigning ZERO_BD. Update the
sequence around broadcaster.deposit and difference so the reserve deduction
reflects only the uncovered amount, then reset broadcaster.deposit to ZERO_BD.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 54c63cbb-bd7c-462a-8efc-e8566a4022c1

📥 Commits

Reviewing files that changed from the base of the PR and between 2eac27f and 38d1b9a.

📒 Files selected for processing (4)
  • src/mappings/bondingManager.ts
  • src/mappings/roundsManager.ts
  • src/mappings/ticketBroker.ts
  • utils/helpers.ts

@rickstaa
rickstaa force-pushed the fix/create-or-load-pool branch 16 times, most recently from f7a9b2b to 4e6ab06 Compare July 20, 2026 21:57
Defensive patch. newRound() builds a Pool per active transcoder via a non-deterministic eth_call enumeration that can miss one, leaving reward() to abort on the null Pool and ticketBroker to drop fees. createOrLoadPool() rebuilds the missing Pool on demand in newRound(), reward(), and ticketBroker() so no handler aborts.

The deterministic root fix is tracked in #248.
@rickstaa
rickstaa force-pushed the fix/create-or-load-pool branch from 4e6ab06 to 7c6b016 Compare July 20, 2026 22:00
@rickstaa rickstaa changed the title fix: createOrLoadPool helper — always-present Pool across newRound, reward, ticketBroker fix: create missing Pool on demand to avoid null-Pool abort Jul 20, 2026
@rickstaa
rickstaa merged commit 00c74c1 into main Jul 21, 2026
2 of 3 checks passed
@rickstaa
rickstaa deleted the fix/create-or-load-pool branch July 21, 2026 07:00
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