Repository navigation
Conversation
…instead of ignoring a deep rollback onRollback ignored a rollback when the cursor was more than 2160 slots ahead of the rollback point. 2160 is k, the security parameter, which counts blocks, not slots. On mainnet and preprod that refused every rollback deeper than about 36 minutes. After an ignored rollback the session went on and wrote the blocks that follow the rollback point on top of newer data. - The limit is now 3k/f slots (129600 on mainnet and preprod): k blocks always fit in that window, so no valid rollback is refused. - A rollback deeper than that is refused and the sync restarts from the cursor, instead of carrying on with that session. - No cursor yet: nothing to roll back (was a NullPointerException). Part of #1328. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…fallback Review: 3k/f slots refused valid one-block rollbacks across a gap on sparse devnets (k=10, f=1 gives 30 slots), and allowed rollbacks of up to ~3k blocks on mainnet. Look up the rollback point's block number in the cursor table and compare with k. Fall back to 3k/f slots only when the point has no cursor row (range-fetch batches write one row per batch; old rows are cleaned up). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Initial automated review · Aster Hi @satran004, thanks for the PR! 🙏 This is an automatic first check by an AI reviewer. It does not replace maintainer review and may be wrong. Reviewed commit: No issues found in this first check. Not tested: Code was read only; builds, tests, and rollback fault-injection scenarios were not run. |
Fault-injection re-test resultWe ran the same 104 fault scenarios again on preprod (benchmark-vm): 43 during the initial sync and 61 at the tip. This time the build had all the fix PRs together: main + #1330, #1331, #1313, #1332, #1271, #1333, #1266 (branch
Details and the full list of findings: #1328 This PR in the test
|
The slot check is used only when the rollback point has no cursor row. It is not the deepest valid rollback in slots: after a long run of empty slots a rollback of fewer than k blocks can be deeper. Say so in the javadoc, and add a test that such a rollback takes the refuse-and-restart path instead of being applied. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MJrQUCWhJpLCQR5Asv7nDb
|
|
Updated after an external review of the 2.0.x backport #1341: 2348452. Each finding, its verdict and its test are in the reply on #1339. |
|
Verdict: APPROVED reviewer1 — original-PR review at The rollback fix and tests match approved #1341. The The numbered findings refer to the counterpart review of #1341. No additional blocking finding remains. Validation on combined main: core 244 passed, 1 skipped at |
|
Fault-injection rerun on For this PR:
The baseline is unpatched |
|
LGTM. Block-based depth check and restarting instead of ignoring look right, and #1341 matches. |



Part of #1328.
Problem
BlockFetchService.onRollbackignored a rollback when the cursor was more than 2160 slots ahead of the rollback point. But 2160 isk, the security parameter, andkcounts blocks. On mainnet and preprod, 2160 slots is only about 36 minutes, whilekblocks is about 12 hours. So every rollback deeper than about 36 minutes was ignored.Ignoring a rollback is not harmless. The session keeps going and writes the blocks that come after the rollback point on top of newer data. In the fault-injection test, an old session intersected 13,581 slots (about 680 blocks) behind the cursor. Its rollback was ignored, and it wrote an old block again. That left 11 spent outputs in
address_utxo_unspent.What changes
k.kblocks (129,600 slots on mainnet and preprod). A point can lack a row for two reasons: the range fetch writes one cursor row per batch, and old rows are cleaned up.Tests
New unit tests:
kblocks is applied, andk + 1is refused and restarts;All core tests pass. The rollback fault scenarios (RB01–RB11) will be re-run on preprod with all PRs of #1328, and the results will be posted here.
Note: the restart after a refused rollback is a normal restart request. With #1330, a request that is dropped by the debounce is retried.
🤖 Generated with Claude Code