ethereum-optimism / ethereum-optimism/optimism
kona-sp1-proposer: stop extending descendants of dynamically blacklisted games
- Dominant language
- Go
- Stars
- 6.5k
- Forks
- 4k
- Avg merge
- 2d 38m
- Merged PRs (30d)
- 164
Description
## Summary
The proposer checks only the selected immediate parent for blacklist/retirement standing before creating a game. A previously cached ancestor may become blacklisted while an unblacklisted descendant remains canonical. The proposer can then continue extending that descendant even though it deliberately refuses to defend the blacklisted ancestor.
If the ancestor later resolves `CHALLENGER_WINS`, every subsequently bonded descendant is invalidated.
## Observed failure
This occurred on the `zk-proofs-1` devnet:
- Game 11 was challenged and then explicitly blacklisted.
- Games 12–14 already existed when game 11 was blacklisted.
- Game 15 was created from game 14 after the blacklist, and the proposer continued extending that branch through game 107.
- The proposer correctly skipped defense of game 11 because it was blacklisted.
- When game 11's prove deadline expired, it resolved `CHALLENGER_WINS`, invalidating the full descendant branch.
Blacklisting transaction: `0x5733c3653b1ba3b01146d7f25afaead159b025487ca346d9b046e5e97b9f98b4` on Sepolia.
## Current behavior
`spawn_game_creation_task` freshly checks `isGameBlacklisted` and `isGameRetired` only for the selected immediate parent. If that parent is disallowed, it removes the parent's cached subtree and defers creation.
However:
- Cached games do not have blacklist/retirement standing refreshed as part of normal discovery.
- `select_canonical_head` does not evaluate standing across a game's ancestry.
- Blacklisting marks one game address only; existing descendants remain individually unblacklisted.
- An unblacklisted descendant of a blacklisted ancestor can therefore remain canonical and be extended.
Retirement is less exposed in the common case because advancing `retirementTimestamp` retires every already-created game, including the branch tip. The complete ancestry invariant should nevertheless cover both blacklist and retirement standing.
## Recommended behavior fix
1. Periodically refresh blacklist/retirement standing for cached parent-eligible games. Refreshing only `GameStatus` is insufficient because blacklisting does not change game status.
2. Compute parent eligibility across the entire ancestry:
```text
eligible(game) =
game standing allowed
AND parent eligible
AND parent not CHALLENGER_WINS
```
3. When an ancestor becomes blacklisted or retired:
- Immediately quarantine its entire subtree from canonical-head selection and creation.
- Clear proof-generation progress for games the proposer will no longer defend.
- Recompute the canonical head from another branch or the anchor.
4. Keep lifecycle tracking separate from parent eligibility. Simply deleting games from the only cache risks losing resolution, refund, and bond-claim work.
5. Immediately before submitting `create()`, freshly recheck the selected game's complete ancestry to cover a blacklist occurring after the prior sync.
The ancestry-standing check should use the registry relevant to each game's lifecycle/defense policy. The existing latest-state check against the currently registered registry should remain as the separate immediate-parent contract-admissibility guard.
## Component ownership
The primary fix belongs in `kona-sp1-proposer`: challenger behavior cannot prevent the proposer from bonding additional games on a doomed branch.
ethereum-optimism/optimism#21445 is complementary defense-in-depth: `op-challenger` should challenge children whose ancestry is locally invalid so proposer bonds have a recipient. It does not replace parent-eligibility enforcement in the proposer.
## Acceptance criteria
- A game is parent-eligible only when its complete known ancestry is parent-eligible.
- A newly blacklisted ancestor quarantines all descendants from canonical-head selection on the next sync.
- A retired ancestor receives equivalent handling.
- An alternate valid branch or anchor is selected when available.
- Resolution, refund, and bond lifecycle tracking survives removal from the parent-eligible DAG.
- A latest-state ancestry check runs before `create()` submission.
- Regression coverage includes:
- Cache a root and descendants.
- Blacklist the root after discovery.
- Verify the descendant tip is not selected or extended.
- Verify an alternate branch or anchor is selected.
- Verify lifecycle tracking remains intact.
## Related issues and changes
- ethereum-optimism/optimism#22116 covers descendants of pending/unknown ancestors. That state must remain pending and retryable; blacklist/retirement requires active subtree quarantine after an onchain state change.
- ethereum-optimism/optimism#22086 and ethereum-optimism/optimism#22097 added the current immediate-parent blacklist/retirement guard.
- ethereum-optimism/optimism#21445 covers complementary `op-challenger` behavior.
- ethereum-optimism/optimism#22589 covers invalid anchor states, not dynamic ancestor standing.
Contributor guide
Assessment
This issue has not been assessed yet.