fix: keep best-effort candidate-roster export failures from escaping the handle path - #26901
ruslanvelkov-beep wants to merge 4 commits into
Conversation
…the handle path Signed-off-by: Ruslan Velkov <ruslan.velkov@limechain.tech>
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
Codecov Report✅ All modified and coverable lines are covered by tests. @@ Coverage Diff @@
## main #26901 +/- ##
============================================
+ Coverage 71.25% 71.27% +0.02%
- Complexity 11906 11907 +1
============================================
Files 2596 2596
Lines 109552 109555 +3
Branches 12364 12365 +1
============================================
+ Hits 78061 78087 +26
+ Misses 27447 27433 -14
+ Partials 4044 4035 -9
... and 8 files with indirect coverage changes 🚀 New features to boost your workflow:
|
🚨 TestLens detected 1 failed test 🚨Here is what you can do:
Failed Jobs without Test Failures❌ 600: [FLOW] PR Checks / CI Complete Test Summary600: [FLOW] PR Checks / MATS / HAPI Tests / hapi-tests-misc / HAPI Tests (Misc) > :test-clients:testSubprocessConcurrent
🏷️ Commit: 443a13c Test FailuresLedgerIdPublicationTimestampTest > ledgerIdPublicationIsNotBackdatedWithinItsBlock() > as written (:test-clients:testSubprocessConcurrent in 600: [FLOW] PR Checks / MATS / HAPI Tests / hapi-tests-misc / HAPI Tests (Misc))Rerun ControlsNote Checks are currently running using the configuration below. Select tests to mute in this pull request: 🔲 LedgerIdPublicationTimestampTest > ledgerIdPublicationIsNotBackdatedWithinItsBlock() Reuse successful test results: 🔲 ♻️ Only rerun the tests that failed or were muted before Click the checkbox to trigger a rerun: 🔲 Rerun jobs Learn more about TestLens at testlens.app/docs. |
Description
At
PREPARE_UPGRADE,PlatformStateUpdates.doExport(...)resolves the export path and calls the roster export helper with no exception handling — unlike theputCandidateRostercall just above it, which is wrapped. The export is a best-effort operator convenience and is not consensus state, but an unchecked exception from it escapeshandleTxBody; the enclosing dispatch then catches it and rolls back the stack, discarding the candidate roster already applied on that node while peers whose export succeeded keep it — a node-local, configuration/environment-dependent divergence.Escaping cases include a malformed configured path (
InvalidPathException), a path resolving to a filesystem root (NullPointerException), and an I/O failure during the write surfacing asUncheckedIOException(e.g. a full disk).DiskStartupNetworks.tryToExportonly catchesIOException, so these unchecked types are not absorbed there.This wraps
doExportin atry/catchthat logs and swallows any failure, so a best-effort export can never affect committed state — matching the existing treatment ofputCandidateRoster.Notes for reviewer
catch(Exception)covers every reachable unchecked type; anIOError(Error) fromtoAbsolutePathis intentionally not caught.Tests
PlatformStateUpdatesTest(16, all green) adds cases for: export-helper failure, malformed path, root path, disk-full-during-write, and a forcedcreateTempFileIllegalArgumentException— each asserting the failure is swallowed and the candidate roster stays committed.Checklist