Challenge-saturation stress prototype#271
Draft
x3c41a wants to merge 1 commit into
Draft
Conversation
Create N challenges in one block (Utility.force_batch of challenge_offchain reusing a single uploaded commitment) so they share a deadline, leave them undefended, then measure the on_finalize slash sweep at that deadline block: System.BlockWeight per class, block time, ChallengeSlashed count, provider stake trajectory, and residual Challenges/NextChallengeIndex state. Emits a JSON result and a pre-flight estimate from the benchmarked weights. Second slice of #267 (challenge saturation). The provider-defends-all flavor is a follow-up.
x3c41a
marked this pull request as draft
July 7, 2026 09:28
This was referenced Jul 7, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Second slice of #267: a prototype that stresses the challenge-slash sweep at scale and measures it.
Stacked on #269 (storage-backed timeouts +
lower-timeouts.ts), which this needs soChallengeTimeoutcan be lowered to put the deadline minutes away instead of two days. Base retargets todevonce #269 merges.What it does
examples/papi/challenge-saturation.tscreates N challenges in a single block (oneUtility.force_batchofchallenge_offchain, all reusing one uploaded commitment so they share a deadline), leaves them undefended, waits for the deadline block, then measures both the creation block and theon_finalizesweep block: on-chainSystem.BlockWeightper class, block time,ChallengeSlashedcount, provider stake trajectory, and residualChallenges/NextChallengeIndexstate after the drain. It prints a pre-flight estimate from the benchmarked weights and emits a JSON result (--json).This is the "provider ignores all" flavor (the
on_finalizemass-slash path). The "provider defends all" flavor (per-challenge proof generation +respond_to_challenge) is a follow-up.Findings
Measured on local zombienet,
ChallengeTimeout=30, count 800:Two things this answers for the issue:
MaxChallengesPerDeadline = 1000is unreachable through the create path. All challenges sharing a deadline must be created in one block, and block inclusion is gated by the benchmarkedchallenge_offchainweight (~4148 bytes PoV each), which caps a single block at ~947. So you cannot actually line up 1,000 at one deadline via extrinsics. (Recorded creation PoV is far lower because the creates hit mostly the same storage; inclusion still gates on the benchmark.)These feed the #177 hardening decision (is the sweep a real DoS surface?) and #113 (2s blocks halve the per-block budget, so re-run after). Numbers reconcile end to end: created == slashed, stake fully slashed, no residual state.
Usage
Tested
Ran end to end on local zombienet + provider node at counts 25 and 800; both reconcile clean.
tsc --noEmitpasses. The script tops the provider stake back up on each run (every run slashes it to 0) so it is re-runnable on the same chain.