paritytech / paritytech/web3-storage

Challenge responder: `--challenge-poll-interval 0` makes a decode-drift miss unrecoverable

Open
#321 0 comments 0 reactions 1 assignee View on GitHub

@ilchu is already working on this.

Since Jul 27, 2026.

Dominant language
Rust
Stars
12
Forks
3
Avg merge
2d 2h
Merged PRs (30d)
33

Description

A provider can disable the challenge responder's reconciliation scan with --challenge-poll-interval 0 (ChallengeResponderParams, provider-node/src/cli.rs), which sets safety_net = false in ChallengeResponder::run_loop and makes the periodic scan_and_respond arm a permanent no-op. The node is then purely event-driven, and one class of missed event has no recovery path at all.

The gap

chain_events::decode_block_events decodes each block's events through the static storage-subxt bindings. When an event matches by pallet and name but its field shape has drifted from the bindings — the normal consequence of a runtime upgrade that changes ChallengeCreateddecode logs a warn! and returns None. No BlockEvent is constructed, so nothing is broadcast and no coordinator ever sees it.

Nothing re-announces that event. The other ways an event can be missed do self-heal:

Gap Recovery
Receiver falls behind EVENT_CHANNEL_CAPACITY Lagged → full scan
Reconnect or node restart Resubscribed → bootstrap scan
Stale or duplicated event replayed point-read returns Ok(None), no-op
Event fails to decode against the bindings none

With the safety net enabled (the 300s default) the periodic Challenges scan covers it. With poll_interval = 0 the provider silently stops responding to challenges, with only a log line to show for it, and gets slashed.

Why this is worth a guard rather than documentation

The failure is silent, the trigger is a routine runtime upgrade, and the penalty is stake. An operator setting 0 is opting out of the backstop for the one duty where missing it is slashable — most likely without realising that a decode failure is unrecoverable, since the flag's help text presents the scan as covering "events lost to edge cases".

Options

  • Reject or clamp 0 for --challenge-poll-interval specifically, keeping it allowed for --replica-poll-interval (a missed sync costs revenue, not stake).
  • Keep 0 accepted but warn! loudly at startup that challenge responses then depend entirely on event decoding.
  • Escalate decode failures instead: have decode trigger a reconciliation scan when an event matched by name but failed to decode, which closes the gap independently of poll_interval.

The third is the most targeted — it turns the one unrecoverable case into a recoverable one — but it needs decode_block_events to report drift back to the coordinators rather than just logging.

Context

Came out of review discussion on #291, where the same poll_interval = 0 config also made dropped-while-paused events unrecoverable. That half is fixed in #291 (events now stay queued while paused); this issue is the remaining, independent gap.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.