fix(settlement): keep transient tracker errors retryable (H-02 follow-up) - #412
Conversation
…rlane track_submission (H-02)
…dcaster tracker (H-02)
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthroughThis PR changes error handling in solver-settlement's Broadcaster and Hyperlane message trackers so that storage load failures propagate their typed ChangesError propagation fix
Estimated code review effort: 3 (Moderate) | ~25 minutes Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
…-up) (openintentsframework#412) * fix(settlement): keep transient tracker load errors retryable in hyperlane track_submission (H-02) * fix(settlement): keep transient tracker load errors retryable in broadcaster tracker (H-02) * fix(settlement): keep check_delivery tracker load errors retryable (H-02) (cherry picked from commit b64493a)
…o fork HyperlaneSettlement openintentsframework#412's check_delivery test constructs HyperlaneSettlement directly; add the fork-specific fields (network_kinds, starknet_clients, starknet_fee_token_addresses, allow_zero_hyperlane7683_settle_quote, solver_identities) so it compiles against this fork. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Summary
Follow-up to #410 for audit finding H-02 (transient settlement-callback failure permanently marks confirmed orders as failed).
#410 added the retryable
SettlementError::StorageUnavailable/BackendUnavailablevariants (classifiedRetryLaterbysettlement_failure_policy) and retyped the leaf tracker functions —SettlementMessageTracker::load/savenow mapStorageError::Backend→StorageUnavailable.But several intermediate tracker methods still wrapped that
loadin.map_err(|e| SettlementError::ValidationFailed(...))?, overwriting the retryable variant before it reached the engine.ValidationFailedis classifiedFailOrder(terminal), so a momentary storage/Redis fault after on-chain confirmation still moved the order toFailed— after which recovery excludes it, stranding solver capital. The recovery replay funnels through the same site, so recovery could not rescue it either.This PR removes those re-wraps so the typed error propagates via
?, keeping transient storage faults retryable. No new types, no policy change.Sites fixed (all 5 in the same class)
MessageTracker::track_submissionhyperlane.rsMessageTracker::check_deliveryhyperlane.rsBroadcasterMessageTracker::track_submissionbroadcaster.rsBroadcasterMessageTracker::store_proofbroadcaster.rsBroadcasterMessageTracker::mark_verifiedbroadcaster.rstrack_submissionruns on the PostFill confirm callback and the recovery replay (recover_post_fill_state), so it was a live strand.check_deliveryis reached viacan_claim, which currently swallows the error and returnsfalse— so it was not yet a live strand, but it is the identical shape and is fixed here to close the class and prevent a future refactor from silently re-arming it.The soft path at
broadcaster.rsbuffer_coverage_check(tracing::warn!on load error → returnsNone) is intentionally left untouched — it already degrades gracefully and never reaches the terminal policy.The change
Genuinely permanent conditions stay terminal: deserialization of corrupt persisted state maps to
StorageError::Serialization→ValidationFailed(unchanged), and config/decode/missing-chain errors keep theirValidationFailed. Only true backend/connection faults become retryable.Tests
Added 5 regression tests (one per fixed site) that inject a transient fault at the real
StorageInterface::get_bytesseam (MockStorageInterfacereturningStorageError::Backend) and assert the tracker method surfacesSettlementError::StorageUnavailable(_)rather thanValidationFailed. Each was confirmed RED (failing onValidationFailed) before the fix and GREEN after.Uses a test-only
solver-storage = { features = ["testing"] }dev-dependency (mirrors the existingsolver-servicepattern) to reachMockStorageInterface.Verification
cargo test -p solver-settlement→ 186 passed, 0 failed (181 baseline + 5 new)cargo fmt --all -- --check→ cleancargo clippy -p solver-settlement --all-features --all-targets -- -D warnings --allow deprecated→ cleanNet effect
A momentary RPC/storage/message-tracker fault in the cross-chain post-fill callback (Hyperlane or Broadcaster) now leaves the order non-terminal for recovery to re-drive, instead of stranding an on-chain-confirmed order in
Failed.Summary by CodeRabbit
Bug Fixes
Tests