Conversation
`blockchain` and `filedao` each declared their own `ErrInvalidTipHeight` sentinel with the same message. The block store raises the `filedao` one when it refuses a block whose height is not `tip + 1`, and `CommitBlock` propagates it verbatim, but callers compare against the `blockchain` one. In `rolldposCtx.Commit` that mismatch turns an expected outcome into an error: when block sync has already committed height H and the consensus round then commits its own block at H, the comparison misses the skip branch, logs "error when committing the block", and returns an error, so the FSM waits out the round TTL instead of moving on. There is no finality or state impact -- the block store still refuses the block. Alias `blockchain.ErrInvalidTipHeight` to the `filedao` sentinel so both names refer to one error, and match it with `errors.Is` in `rolldposCtx.Commit` so the branch keeps working if the storage error is ever wrapped. Fixes iotexproject#5010 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
❌ Your project check has failed because the head coverage (62.67%) is below the target coverage (85.00%). You can increase the head coverage or adjust the target coverage. Additional details and impacted files@@ Coverage Diff @@
## master #5014 +/- ##
===========================================
- Coverage 74.83% 62.67% -12.16%
===========================================
Files 378 502 +124
Lines 31624 50114 +18490
===========================================
+ Hits 23666 31410 +7744
- Misses 6747 14969 +8222
- Partials 1211 3735 +2524 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
The patch left the paused and generic-error branches of `rolldposCtx.Commit` uncovered, and the block sync callback, whose already-committed-height branch the alias unmasks, had no direct coverage at all because it lives in a closure inside `buildBlockSyncer`. Factor the three rolldpos commit cases onto a shared fixture and add the paused and failing-commit ones, so every branch of the commit switch is exercised. Extract the block sync retry loop into `commitSyncedBlock`, keeping the classification logic and the `Calibrate` skip as they were, and cover its outcomes with the block store's height rejection among them. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Thanks for the review. Addressed the two actionable points in 31e12d0.
Block-sync callback behavior change lacks direct coverage — also real, and it was the more interesting gap. The alias unmasks the The extraction is a relocation only. One thing worth a look during review: the original returned
Full |
|



Description
blockchain/filedao/filedao.goandblockchain/blockchain.goeach declared their ownErrInvalidTipHeightsentinel with the same message. The block store raises thefiledaoone when it refuses a block whose height is nottip + 1, andblockchain.CommitBlockpropagates it verbatim — but callers compare against theblockchainone, so the comparison never matches.In
rolldposCtx.Committhat turns an expected outcome into an error path: if block sync has already committed height H and the consensus round then callsCommitBlockfor its own block at H, the switch missesblockchain.ErrInvalidTipHeight(which returnstrue, nil), falls through todefault, logserror when committing the block, and returns an error. The FSM then stays in its pre-commit state until the round TTL expires instead of recognising the height as done.chainservice/builder.go:690has the same comparison, but it is masked there because the precedingValidateBlockreturns theblockchainvariable first.There is no finality or state impact — the block store guard still refuses the second block. This is a robustness fix.
Fixes #5010
Changes
blockchain.ErrInvalidTipHeightnow aliasesfiledao.ErrInvalidTipHeight, so both names refer to a single sentinel and a height rejection from the block store matches what callers switch on. (blockchainalready importsfiledao; the reverse direction would be an import cycle.)rolldposCtx.Commitmatches witherrors.Isinstead oferrors.Causeequality, so the skip branch keeps working if the storage error is ever wrapped, and the skip intent is documented in a comment.Tests
TestCommitAlreadyCommittedHeight(consensus/scheme/rolldpos): drives the reported scenario end to end on a real chain — the round registers its own block at H, block sync commits a different block at H, then the round collects a majority of COMMIT endorsements and callsCommit. Asserts(true, nil)and that the block-sync block is still the tip. Fails onmasterwitherror when committing a block/invalid tip height.TestCommitBlockInvalidTipHeight(blockchain): pins the contract at the layer where it broke — a height rejection from the block store must satisfyerrors.Is(err, blockchain.ErrInvalidTipHeight). Fails onmaster.Full
./blockchain/... ./consensus/... ./chainservice/...run is green apart fromTestBlockIndexerChecker_CheckIndexer, which fails identically on unmodifiedmaster.🤖 Generated with Claude Code