Skip to content

Fix median plugin deadlock when TX fails silently#131

Open
cl-efornaciari wants to merge 1 commit intosmartcontractkit:masterfrom
cl-efornaciari:feature/DF-22948/fix-median-deadlock
Open

Fix median plugin deadlock when TX fails silently#131
cl-efornaciari wants to merge 1 commit intosmartcontractkit:masterfrom
cl-efornaciari:feature/DF-22948/fix-median-deadlock

Conversation

@cl-efornaciari
Copy link

@cl-efornaciari cl-efornaciari commented Feb 26, 2026

Summary

  • Fixes a deadlock in the median reporting plugin where ShouldAcceptFinalizedReport permanently rejects new reports after a TX fails silently
  • When latestAcceptedEpochRound is advanced optimistically but the TX never lands on-chain, nothingPending evaluates to false permanently. For stable/pegged feeds with no price deviation, this creates an unrecoverable deadlock
  • Adds a pendingTooOld check: if a pending report has not landed on-chain within DeltaC (heartbeat timeout), treat it as expired and accept new reports. No new config parameters required

Affected chains: Solana, Starknet, Fantom, Matic, BSC, Moonbeam

Ticket: DF-22948

Changes

  • median.go: Add latestAcceptedAt timestamp field, add pendingTooOld condition to acceptance logic, enhanced debug logging
  • median_test.go: New test file with 5 tests covering deadlock recovery, pending check preservation, deviation bypass, normal flow, and stale report rejection

Test plan

  • TestShouldAcceptFinalizedReport_PendingTooOldRecovery -- verifies recovery after DeltaC expiry
  • TestShouldAcceptFinalizedReport_PendingCheckStillWorksWithinDeltaC -- confirms pending optimization still active within window
  • TestShouldAcceptFinalizedReport_VolatileFeedCanRecover -- deviation bypass works immediately
  • TestShouldAcceptFinalizedReport_NormalFlow -- happy path (TX lands on-chain)
  • TestShouldAcceptFinalizedReport_StaleReportRejected -- stale reports still rejected

When ShouldAcceptFinalizedReport accepts a report, it advances
latestAcceptedEpochRound optimistically before the TX is confirmed
on-chain. If the TX fails silently (e.g. fees too low), the on-chain
state never advances but latestAcceptedEpochRound remains stuck ahead,
causing nothingPending to permanently evaluate to false. For stable
feeds with no price deviation, this creates an unrecoverable deadlock
that can only be resolved by restarting the node.

Add a pendingTooOld check: if a previously accepted report has been
pending for longer than DeltaC without landing on-chain, treat it as
expired and allow new reports to be accepted. This reuses the existing
DeltaC config parameter (heartbeat timeout) as the expiry threshold,
requiring no new configuration.

Affected chains: Solana, Starknet, Fantom, Matic, BSC, Moonbeam.
Ticket: DF-22948
@cl-efornaciari cl-efornaciari requested a review from a team as a code owner February 26, 2026 00:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant