Skip to content

fix(sdk): verify quorum proofs without blocking the executor - #5720

Merged
PastaPastaPasta merged 9 commits into
v5.1-devfrom
fix/verify-quorum-proofs-without-blocking
Nov 3, 2026
Merged

PastaPastaPasta merged 9 commits into
v5.1-devfrom
fix/verify-quorum-proofs-without-blocking

Conversation

@PastaPastaPasta

@PastaPastaPasta PastaPastaPasta commented Nov 2, 2026 •

Copy link
Copy Markdown
Member

Issue being fixed or feature implemented

Fixes #5706. VerifiedHttpContextProvider verified a relay's DIP 175 proof in a single poll of its async fetch. A relay can answer with a valid chain through every ChainLock quorum since the state it was asked from. On testnet today that is about 960 links, roughly 4 s of BLS work natively and about 10 s in wasm. The whole time, the proof stalled one Tokio worker: every task on a current-thread runtime, including the fetch's own deadline timer. In a browser it stalled the event loop. This needs fixing before the provider is exposed to browsers (#5652).

What was done?

  • dash-core-proof: verify one link at a time.
    • bootstrap::start decodes the envelope and makes every check that comes before the first link.
    • Verification::verify_link verifies one link.
    • finish verifies any links left, then the target, the coinbase and the records.
    • bootstrap::verify is now start(..)?.finish(), and QuorumProofChain::verify uses the same steps. Both paths make the same checks in the same order, so they accept and reject exactly the same proofs. The stale-target check still comes before any signature work.
  • Provider: verify in slices and yield in between.
    • The fetch verifies links until 10 ms have passed, then yields to the executor before the next link. An honest proof of a few links is checked without yielding.
    • Natively it yields with a 1 ms Tokio timer. Every caller of a fetch polls the same Shared future within one turn of its task. tokio::task::yield_now is ready on its second poll, and outside a scheduler's context, such as a multi-thread runtime's block_on future, its wake isn't even deferred. With it, a few callers could drive the whole verification in one turn. A timer stays pending until the timer driver fires it, however often it is polled. Slices are 10 ms, so a long proof takes about a tenth longer.
    • In the browser it yields with a MessageChannel message: a task of its own, so timers, input and rendering run in between. Hidden tabs don't throttle it the way they throttle setTimeout. A zero-delay timer is the fallback.
    • Verification stops at the fetch's 70 s deadline, without blaming the relay. The deadline is checked before every link and before a verified result is accepted. In the browser the fetch runs on a local task that outlives its callers, so nothing else would stop a long verification. Natively, dropping the fetch stops it at the next yield.
  • Rejected: verifying on a separate thread (a std thread plus a oneshot natively, a Web Worker in the browser).
    • Natively, a thread doesn't stop when the fetch is dropped. Repeated cancellations could pile up verifier threads, and the proving place would have to stay held until each thread exits.
    • A Web Worker needs a second wasm instance and bundler support in every app that uses the SDK.
    • Cooperative slicing has neither problem, is the same on both targets, and keeps the crate independent of the runtime's threading.
  • Rejected for now: refusing chains with far more links than their height span needs. Core doesn't promise short chains, and a chain through every ChainLock quorum is already within any bound that counts one link per DKG interval.

How Has This Been Tested?

  • dash-core-proof:

    • Link-by-link verification gives the same state and records as one call on the real mainnet and testnet fixtures.
    • The same holds on every 61st-byte flip (both the error and the state must match), on truncations, and on a stale target.
    • A synthetic 40-link chain verifies one link at a time, and a tampered link 20 fails exactly at its step.
    • All 34 tests pass.
  • Provider, natively:

    • should_let_other_tasks_run_while_a_proof_verifies: a current-thread runtime, the real 4-link testnet proof and a slice of zero. Another task runs before verification ends.
    • should_stop_verifying_at_the_fetchs_deadline and should_stop_verifying_at_the_deadline_without_a_yield: verification stops and nothing is cached, whether or not it yields.
    • should_let_other_tasks_run_while_callers_share_a_fetch_from_block_on: the 30-caller, one-turn check as a multi-thread runtime's block_on future.
    • should_let_other_tasks_run_while_many_callers_share_a_verifying_fetch: 30 callers share one verifying fetch. None completes within one turn of their task, and another task runs before verification ends.
    • should_not_end_a_yield_before_the_executor_comes_back: a yield polled twice in one turn stays pending.
    • The first test fails if verification never yields. The shared-fetch tests fail with a plain yield_now, and the block_on one also fails with a yield that waits for Tokio's deferred wake. The deadline tests fail without the per-link checks. All 121 tests pass.
  • Provider, wasm (wasm-bindgen-test under Node):

    • should_let_browser_timers_fire_while_a_proof_verifies: a setTimeout(0) set before judging fires before verification ends. It fails if verification never yields.
    • All 7 wasm tests pass.
  • Timings for the 4-link testnet proof (the debug wasm number includes the yields):

    Build Total Per link
    Native, release (as measured for fix(sdk): verify quorum proofs off the async executor in VerifiedHttpContextProvider #5706) — about 4 ms
    wasm, debug about 210 ms —
    wasm, release 41 to 55 ms about 10 to 14 ms
  • cargo clippy -D warnings is clean natively (--all-features --all-targets) and for wasm32-unknown-unknown.

  • Not in CI yet: the wasm tests still run only locally. feat(sdk): let wasm-sdk and evo-sdk opt into the verified quorum context provider #5652 adds a wasm32 CI job for this crate.

Remaining limit: the chain's header budget (4,096 ancestors) can all sit on one link, which is then verified in one step. That is one BLS check plus up to 4,096 X11 hashes, which I estimate at about 10–20 ms natively and up to roughly 100 ms in wasm. It is bounded and happens at most once per proof.

Breaking Changes

None. bootstrap::start and bootstrap::Verification are additions, and bootstrap::verify is unchanged.

Checklist:

  • I have performed a self-review of my own code
  • My Rust, FFI, WASM, Swift or Kotlin changes follow the coding conventions
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated relevant unit/integration/functional/e2e tests
  • I have added "!" to the title and described breaking changes in the corresponding section if my code contains any
  • I have made corresponding changes to the documentation if needed
  • If I added or changed GroveDB structure, I described it in the area's structure.rs, regenerated grovedb-structure.json, and checked the structure viewer link posted on this pull request
  • If I added or changed a system contract's document schemas, I checked the contract viewer link posted on this pull request

For repository code-owners and collaborators only

  • I have assigned this pull request to a milestone

🤖 Generated with Claude Code

PR Hygiene · 4a95215

  • Bots — thepastaclaw ✓
  • Self-review — post /self-reviewed
  • Reviewer requests paused — your 5 review slots are occupied; this PR is excluded from reviewers' queues. Required approvals still count without a slot.
  • Build green
  • Approvals
    • files with no dedicated owner (packages/rs-core-proof/src/bootstrap.rs, packages/rs-core-proof/src/chain.rs, packages/rs-core-proof/tests/synthetic.rs and 4 more) — QuantumExplorer or shumkov

When every merge requirement is met, the PR Hygiene check passes. Reviewer limits do not block merging; other required GitHub checks and protections still apply.

Summary by CodeRabbit

  • New Features
    • Proof verification now processes long chains incrementally, yielding between steps so other tasks and browser activity can continue.
    • Verification can complete automatically after processing any remaining chain links.
  • Bug Fixes
    • Proof checks that exceed the fetch deadline are now reported as timeouts rather than relay failures.

PastaPastaPasta and others added 5 commits November 2, 2026 13:39
`bootstrap::start` decodes an envelope and makes every check before the
first link; `Verification::verify_link` verifies one link, and `finish`
verifies any left, then the target and the records. An async caller can
yield between links instead of spending a long chain's BLS work in one
poll. `verify` is now `start` followed by `finish`, so both paths make the
same checks in the same order.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
A relay can answer a proof request with a valid chain through every
ChainLock quorum since the state it was asked from: about 960 links on
testnet today, 4 s of BLS work natively and more in a browser. The
provider verified it in one poll, stalling a Tokio worker (every task on
a current-thread runtime, including the fetch's own deadline) or the
browser's event loop.

The fetch now verifies one link at a time and yields to the executor
after every 10 ms of verification: Tokio's `yield_now`, which runs due
timers first, natively, and a zero-delay browser timer in wasm, so the
event loop's timers, input and rendering run in between. Dropping the
fetch stops verification at the next yield, so abandoned fetches leave
no work behind.

Fixes #5706

Co-Authored-By: Claude Opus 5.5 <[email protected]>
`QuorumProofChain::finish` now verifies any links left before the
target, so `verify` and `Verification::finish` share one loop, and the
progress carries the network instead of a cloned checkpoint. The checks
and their order are unchanged.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
…in browsers

In a browser the proof fetch runs on a local task that outlives its
callers, so nothing stopped a long verification, and hidden tabs throttle
timers to one wake-up a second or less: a zero-delay timer per link
would stretch even an honest proof to seconds and let a hostile one hold
a proving place for minutes. Verification now ends at the fetch's
deadline without blaming the relay, and the browser yield resumes on a
`MessageChannel` message, which is not throttled, falling back to a
timer. No yield follows the last link.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@coderabbitai

coderabbitai Bot commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review.

Recent review info
Run configuration
Commits

Reviewing files that changed from the base of the PR and between f1dbc27 and 4a95215.

Files selected for processing: 7
  • packages/rs-core-proof/src/bootstrap.rs
  • packages/rs-core-proof/src/chain.rs
  • packages/rs-core-proof/tests/synthetic.rs
  • packages/rs-core-proof/tests/verification.rs
  • packages/rs-sdk-trusted-context-provider/Cargo.toml
  • packages/rs-sdk-trusted-context-provider/src/proof_fetches.rs
  • packages/rs-sdk-trusted-context-provider/src/verified_provider.rs

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

Walkthrough

Proof-chain verification can now proceed link by link before finalization. The trusted context provider uses this flow, yields during verification on native and browser targets, and checks the fetch deadline. Tests cover verification results, yields, and deadline outcomes.

Changes: Incremental proof verification

Layer / File(s) Summary
Core verification flow
packages/rs-core-proof/src/chain.rs, packages/rs-core-proof/src/bootstrap.rs, packages/rs-core-proof/tests/*
The chain and bootstrap APIs now support starting verification, verifying links individually, and finishing verification. Tests compare stepwise results and errors with one-call verification.
Provider scheduling and deadline handling
packages/rs-sdk-trusted-context-provider/src/proof_fetches.rs, packages/rs-sdk-trusted-context-provider/Cargo.toml, packages/rs-sdk-trusted-context-provider/src/verified_provider.rs
The provider verifies links in time slices and yields through a native timer or browser MessageChannel. It reports when verification reaches the fetch deadline. Tests cover executor progress, shared verification, and deadline handling.

Estimated code review effort: 4 (Complex) | ~45 minutes

Change: Bug fix · Severity of issue fixed: Medium

Sequence Diagram(s)

sequenceDiagram
  participant ProofFetches
  participant Bootstrap as bootstrap::start
  participant Verification
  participant ExecutorYield
  ProofFetches->>Bootstrap: start proof verification
  Bootstrap-->>ProofFetches: return Verification
  loop While links remain
    ProofFetches->>Verification: verify_link
    ProofFetches->>ExecutorYield: yield after verification slice
    ExecutorYield-->>ProofFetches: resume verification
  end
  ProofFetches->>Verification: finish
Loading

Possibly related issues

Possibly related PRs

  • dashpay/platform#5521: This PR extends the core proof verifier and its one-call verification APIs with incremental verification.
  • dashpay/platform#5523: This PR changes the proof-fetch verification path introduced by this PR.

Suggested reviewers: thepastaclaw

Merge Risk: Minimal · up to 4a952

No actionable issue is established for the incremental verification or provider scheduling changes. The PR is mergeable after normal checks.

Pre-merge checks: Passed 5
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly and concisely describes the main change: adding non-blocking quorum-proof verification for the SDK executor.
Linked Issues check Passed The changes satisfy the coding requirements in directly linked issue #5706. bootstrap::start, Verification::verify_link, and finish enable link-by-link verification. ProofFetches limits verifi…
Out of Scope Changes check Passed The changed core-proof APIs and implementations support incremental verification required by #5706. The provider scheduling code, deadline handling, documentation, and added tests validate that behavi…
Docstring Coverage Passed Docstring coverage is 88.89% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentati…
Full details: Linked Issues check

Explanation

The changes satisfy the coding requirements in directly linked issue #5706. bootstrap::start, Verification::verify_link, and finish enable link-by-link verification. ProofFetches limits verification slices, yields between slices on native and wasm targets, and checks the fetch deadline before links and result acceptance. The provider therefore does not block the executor or browser event loop during long proof verification. The regression tests cover timer progress, current-thread execution, shared fetches, deadlines, and browser timers. The optional chain-length bound is not required by #5706.

Full details: Out of Scope Changes check

Explanation

The changed core-proof APIs and implementations support incremental verification required by #5706. The provider scheduling code, deadline handling, documentation, and added tests validate that behavior. The synthetic and fixture-equivalence tests support the required proof-verification changes. No unrelated change is demonstrated.

Full details: Docstring Coverage

Explanation

Docstring coverage is 88.89% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 18 functions across 6 files. (1 skipped: 1 unsupported.)

Finishing Touches
Generate docstrings
  • Commit to this branch
  • Create a new PR
Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

Share

@github-actions github-actions Bot added this to the v5.1.0 milestone Nov 2, 2026
@github-actions

github-actions Bot commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

Waiting for bot review — thepastaclaw not yet. Wait for the missing reviews, or a writer can post /skip-bots to proceed without them; blocking findings still need addressing.
Full checklist in the description.

@github-actions github-actions Bot added the waiting-bots Waiting for the review bots to report on this head label Nov 2, 2026
@thepastaclaw

thepastaclaw commented Nov 2, 2026 •

Copy link
Copy Markdown
Collaborator

✅ Final review complete — no blockers (commit 4a95215) · triage: critical

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Final validation — Phase 1 + Phase 2

The incremental verifier preserves the previous proof checks and their ordering, but native shared-fetch callers can bypass the intended scheduling boundary and keep verification running within one executor poll. The zero-link coverage claim is contradicted by an existing test exercising the refactored synchronous entry point. This was a static verification at the exact requested head; no builds or tests were run, and Rust workspace CI remains pending.

🔴 1 blocking

Review provenance

Source: reviewer 1: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 2: gpt-6.1-sol (agent: phase2-reviewer, role: architecture-layering); reviewer 3: gpt-6.1-sol (agent: phase2-reviewer, role: ffi-engineer); reviewer 4: gpt-6.1-sol (agent: phase2-reviewer, role: rust-quality); reviewer 5: gpt-6.1-sol (agent: phase2-reviewer, role: security-auditor); reviewer 6: muse-spark-1.3-contributor (agent: phase1-reviewer, role: general); reviewer 7: muse-spark-1.3-contributor (agent: phase1-reviewer, role: rust-quality); final verifier: gpt-6.1-sol (agent: sol-verifier, role: final-verifier)

  • Triage: critical by gpt-6.1-sol (effort low) — The intricate refactor in chain.rs (QuorumProofChain::start, verify_link and finish) and bootstrap.rs changes how cryptographic proof verification maintains and advances trusted signer state across incremental steps.
  • Phase 1 reviewers: muse-spark-1.3-contributor — general (completed, effort xhigh); agent phase1-reviewer, muse-spark-1.3-contributor — rust-quality (completed, effort xhigh); agent phase1-reviewer
  • Phase 1 model: muse-spark-1.3-contributor — not quota-gated; passed over gemini-3.8-flash-high (antigravity quota lookup failed), glm-5.3-flash (not used above high effort; tier asks max)
  • Single stage: Phase 1 and Phase 2 reviewed this head side by side, with no blocker gate between them (triage tier)
  • Fresh verifier: gpt-6.1-sol — final-verifier; agent sol-verifier
  • Phase 2 reviewers: gpt-6.1-sol — general (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — architecture-layering (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — ffi-engineer (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — rust-quality (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — security-auditor (completed, effort xhigh); agent phase2-reviewer
🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `packages/rs-sdk-trusted-context-provider/src/proof_fetches.rs`:
- [BLOCKING] packages/rs-sdk-trusted-context-provider/src/proof_fetches.rs:1334-1337: Shared fetch callers can resume verification before the executor yields
  Native verification runs inside a `Shared` future returned by `start`, and multiple callers can poll its clones within one parent-task poll. In the locked dependencies, Tokio 1.52.3's `yield_now()` returns `Pending` once and then `Ready` on the next poll, without waiting for its deferred wake. Meanwhile, futures-util 0.3.32's `Shared::poll` resets its state to `IDLE` after `Pending`, allowing another clone to immediately poll the inner future. Consequently, `join_all` with 30 callers can process approximately 30 verification slices in one parent-task poll: each subsequent caller completes the preceding yield and starts another slice. That permits hundreds of milliseconds of BLS work without returning control to a current-thread runtime's timers or unrelated tasks. The existing concurrency limits restrict distinct fetches, not callers sharing one fetch. This leaves the executor-stall problem present on the production shared-fetch path; the new native regression test invokes `judge` directly and does not exercise sharing. Gate continuation on a scheduler-driven completion that remains pending under additional polls, and add a regression with multiple shared-fetch callers proving that another task runs before verification finishes.

@github-actions

github-actions Bot commented Nov 2, 2026

Copy link
Copy Markdown
Contributor

Your move: thepastaclaw requested changes on this head; dismiss the review or push a fix; thepastaclaw left review threads unresolved; resolve them.
Full checklist in the description.

@github-actions github-actions Bot added waiting-self-review Waiting for the author to post /self-reviewed and removed waiting-bots Waiting for the review bots to report on this head labels Nov 2, 2026
…r turns

Tokio's `yield_now` is ready on its second poll whether or not its
deferred wake has come. A fetch is `Shared`, and every caller's clone
polls it within one turn of the callers' task, so with a few callers a
whole proof was verified in one turn again. The native yield now waits
for that deferred wake itself and stays pending under further polls.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@github-actions

github-actions Bot commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

Your move: thepastaclaw requested changes on this head; dismiss the review or push a fix; thepastaclaw left review threads unresolved; resolve them.
Full checklist in the description.

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-review — Final validation — Phase 1 + Phase 2

At ca3670c, the incremental verifier preserves authentication checks and keeps scheduling in the provider, but the shared-fetch yield fix remains incomplete for multithread-runtime entry futures. One blocking scheduling issue and one non-blocking deadline gap remain after independently inspecting the complete diff and locked dependency implementations. Validation was static only; current CI still has Rust workspace runner selection pending, so Rust build/test completion is not established.

🔴 1 blocking | 🟡 1 suggestion(s)

1 carried-forward finding(s) already raised on this PR; not re-posting as new inline comments.

Review provenance

Source: reviewer 1: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 2: gpt-6.1-sol (agent: phase2-reviewer, role: architecture-layering); reviewer 3: gpt-6.1-sol (agent: phase2-reviewer, role: ffi-engineer); reviewer 4: gpt-6.1-sol (agent: phase2-reviewer, role: rust-quality); reviewer 5: gpt-6.1-sol (agent: phase2-reviewer, role: security-auditor); reviewer 6: muse-spark-1.3-contributor (agent: phase1-reviewer, role: general); reviewer 7: muse-spark-1.3-contributor (agent: phase1-reviewer, role: rust-quality); reviewer 8: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 9: gpt-6.1-sol (agent: phase2-reviewer, role: architecture-layering); reviewer 10: gpt-6.1-sol (agent: phase2-reviewer, role: ffi-engineer); reviewer 11: gpt-6.1-sol (agent: phase2-reviewer, role: rust-quality); reviewer 12: gpt-6.1-sol (agent: phase2-reviewer, role: security-auditor); final verifier: gpt-6.1-sol (agent: sol-verifier, role: final-verifier)

  • Triage: critical by gpt-6.1-sol (effort low) — The intricate refactor changes cryptographic proof verification control flow in bootstrap::Verification and QuorumProofChain::{verify_link,finish}, while adding shared-future scheduling and cancellation behavior across native and browser executors.
  • Phase 1 reviewers: muse-spark-1.3-contributor — general (completed, effort xhigh); agent phase1-reviewer, muse-spark-1.3-contributor — rust-quality (completed, effort xhigh); agent phase1-reviewer
  • Phase 1 model: muse-spark-1.3-contributor — not quota-gated; passed over gemini-3.8-flash-high (antigravity quota lookup failed), glm-5.3-flash (not used above high effort; tier asks max)
  • Single stage: Phase 1 and Phase 2 reviewed this head side by side, with no blocker gate between them (triage tier)
  • Fresh final gate: an independent Phase-2 review ran after iterative findings were reconciled
  • Fresh verifier: gpt-6.1-sol — final-verifier; agent sol-verifier
  • Phase 2 reviewers: gpt-6.1-sol — general (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — architecture-layering (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — ffi-engineer (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — rust-quality (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — security-auditor (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — general (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — architecture-layering (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — ffi-engineer (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — rust-quality (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — security-auditor (completed, effort xhigh); agent phase2-reviewer
🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `packages/rs-sdk-trusted-context-provider/src/proof_fetches.rs`:
- [SUGGESTION] packages/rs-sdk-trusted-context-provider/src/proof_fetches.rs:1100-1109: Enforce the verification deadline on paths that do not yield
  The only deadline check follows an inter-slice yield. Zero-link and one-link proofs never reach it, nor do longer proofs that fit within one slice. These paths can start verification with an expired deadline or cross it during the final link or finish, then publish the verified key anyway. The surrounding fetch checks its deadline before awaiting a response, not immediately before judging it, and the Proven branch returns without another deadline check. This is a bounded deadline-contract gap rather than an unbounded verification stall. Check expiry before starting verification and before accepting its completed result, independently of whether a yield occurs. Add an already-expired regression with a no-yield slice configuration that asserts OutOfTime and an unchanged cache; the existing regression forces a yield and misses this branch.
- [BLOCKING] packages/rs-sdk-trusted-context-provider/src/proof_fetches.rs:1354-1358: Shared fetch callers can resume verification before the executor yields
  (existing thread: https://github.com/dashpay/platform/pull/5720#discussion_r4447444582)
  The custom waker fixes the current-thread case covered by the new regressions, but receiving that wake does not always establish an executor turn. In locked Tokio 1.52.3, MultiThread::block_on enters the runtime without installing a scheduler context; runtime::context::defer therefore invokes wake_by_ref synchronously. This includes the normal default #[tokio::main] body. The first poll here consequently sets turn.came before returning Pending, and another Shared clone polled by the same parent immediately resumes verification. Locked futures-util 0.3.32 resets Shared to IDLE after Pending, and join_all with 30 callers polls all 30 within one parent poll, allowing roughly 30 verification slices without returning control. Worker tasks can continue, but sibling futures, cancellation branches, and LocalSet tasks driven on this thread remain blocked. Make verification continuation safe in this entry-future context, for example by giving verification its own cancellable scheduled task and sharing only its result. Add both repeated-poll and shared-fetch regressions under a multithread runtime, leaving the test body on its block_on thread rather than spawning it.

PastaPastaPasta and others added 2 commits November 2, 2026 15:16
…deadline

Outside a scheduler's context, such as a multi-thread runtime's
`block_on` future, Tokio does not defer `yield_now`'s wake, so the
callers sharing a fetch could still resume verification slice after
slice within one turn. The native yield is now a 1 ms timer, which stays
pending until the timer driver fires it however often it is polled.

The deadline is now checked before every link and before a verified
result is accepted, so proofs that never yield are held to it too.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@github-actions

github-actions Bot commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

Your move: thepastaclaw left review threads unresolved; resolve them.
Full checklist in the description.

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-review — Final validation — Phase 1 + Phase 2

At c994596, the complete diff preserves verification checks and their order while adding cooperative scheduling; both prior findings are fixed. One non-blocking test-coverage gap remains: the deadline regressions start already expired and do not exercise expiration during verification. Validation was static only; current CI still has runner selection and changed-package determination pending, so build and test results are not yet established.

🟡 1 suggestion(s)

Review provenance

Source: reviewer 1: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 2: gpt-6.1-sol (agent: phase2-reviewer, role: architecture-layering); reviewer 3: gpt-6.1-sol (agent: phase2-reviewer, role: ffi-engineer); reviewer 4: gpt-6.1-sol (agent: phase2-reviewer, role: rust-quality); reviewer 5: gpt-6.1-sol (agent: phase2-reviewer, role: security-auditor); reviewer 6: muse-spark-1.3-contributor (agent: phase1-reviewer, role: general); reviewer 7: muse-spark-1.3-contributor (agent: phase1-reviewer, role: rust-quality); reviewer 8: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 9: gpt-6.1-sol (agent: phase2-reviewer, role: architecture-layering); reviewer 10: gpt-6.1-sol (agent: phase2-reviewer, role: ffi-engineer); reviewer 11: gpt-6.1-sol (agent: phase2-reviewer, role: rust-quality); reviewer 12: gpt-6.1-sol (agent: phase2-reviewer, role: security-auditor); final verifier: gpt-6.1-sol (agent: sol-verifier, role: final-verifier)

  • Triage: critical by gpt-6.1-sol (effort low) — The intricate change restructures cryptographic proof verification in QuorumProofChain::{start, verify_link, finish} in packages/rs-core-proof/src/chain.rs and adds shared asynchronous verification, yielding, and deadline handling.
  • Phase 1 reviewers: muse-spark-1.3-contributor — general (completed, effort xhigh); agent phase1-reviewer, muse-spark-1.3-contributor — rust-quality (completed, effort xhigh); agent phase1-reviewer
  • Phase 1 model: muse-spark-1.3-contributor — not quota-gated; passed over gemini-3.8-flash-high (antigravity quota lookup failed), glm-5.3-flash (not used above high effort; tier asks max)
  • Single stage: Phase 1 and Phase 2 reviewed this head side by side, with no blocker gate between them (triage tier)
  • Fresh final gate: an independent Phase-2 review ran after iterative findings were reconciled
  • Fresh verifier: gpt-6.1-sol — final-verifier; agent sol-verifier
  • Phase 2 reviewers: gpt-6.1-sol — general (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — architecture-layering (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — ffi-engineer (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — rust-quality (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — security-auditor (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — general (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — architecture-layering (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — ffi-engineer (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — rust-quality (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — security-auditor (completed, effort xhigh); agent phase2-reviewer
🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `packages/rs-sdk-trusted-context-provider/src/proof_fetches.rs`:
- [SUGGESTION] packages/rs-sdk-trusted-context-provider/src/proof_fetches.rs:2180-2186: Exercise deadline expiration after verification has started
  This test and `should_stop_verifying_at_the_deadline_without_a_yield` both pass `Duration::ZERO`, so the four-link fixture returns at the first per-link deadline check, before verifying any link or yielding. Removing all per-link deadline checks would still let both tests pass because the final check would reject the completed valid proof; removing only the final check would also leave both passing. They therefore do not protect stopping an in-progress proof after expiry or rejecting a result whose final verification step crosses the deadline. Add deterministic coverage that starts with a live deadline, reaches an inter-link yield, expires before resumption, and verifies that subsequent links are not processed. Also exercise expiry during finalization to protect the completed-result guard. A controllable clock or test hook can distinguish these paths without depending on BLS execution speed.

@github-actions

github-actions Bot commented Nov 2, 2026

Copy link
Copy Markdown
Contributor

Your move: thepastaclaw left review threads unresolved; resolve them.
Full checklist in the description.

`verify` takes its clock as a parameter, `Instant::now` outside tests,
so the tests can let the deadline pass at a chosen reading: during the
first yield, which must stop the proof before its next link, and at the
check of the finished result, which must reject it.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@github-actions

github-actions Bot commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

Waiting for bot review — thepastaclaw not yet. Wait for the missing reviews, or a writer can post /skip-bots to proceed without them; blocking findings still need addressing.
Full checklist in the description.

@github-actions github-actions Bot added waiting-bots Waiting for the review bots to report on this head and removed waiting-self-review Waiting for the author to post /self-reviewed labels Nov 2, 2026

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-review — Final validation — Phase 1 + Phase 2

Reviewed the complete diff at 4a95215 and found no remaining actionable issues. Incremental verification preserves the original proof checks and their order, and all three prior findings are addressed. This was a static review with no builds or tests run locally; current head-matched CI has Rust workspace tests pending and no failed code checks.

🔴 0 blocking | 🟡 0 suggestion(s) | 💬 0 nitpick(s)

Review provenance

Source: reviewer 1: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 2: gpt-6.1-sol (agent: phase2-reviewer, role: architecture-layering); reviewer 3: gpt-6.1-sol (agent: phase2-reviewer, role: ffi-engineer); reviewer 4: gpt-6.1-sol (agent: phase2-reviewer, role: rust-quality); reviewer 5: gpt-6.1-sol (agent: phase2-reviewer, role: security-auditor); reviewer 6: muse-spark-1.3-contributor (agent: phase1-reviewer, role: general); reviewer 7: muse-spark-1.3-contributor (agent: phase1-reviewer, role: rust-quality); reviewer 8: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 9: gpt-6.1-sol (agent: phase2-reviewer, role: architecture-layering); reviewer 10: gpt-6.1-sol (agent: phase2-reviewer, role: ffi-engineer); reviewer 11: gpt-6.1-sol (agent: phase2-reviewer, role: rust-quality); reviewer 12: gpt-6.1-sol (agent: phase2-reviewer, role: security-auditor); final verifier: gpt-6.1-sol (agent: sol-verifier, role: final-verifier)

  • Triage: critical by gpt-6.1-sol (effort low) — The intricate change refactors cryptographic proof acceptance in packages/rs-core-proof/src/chain.rs through start, verify_link and finish, while integrating incremental verification with shared asynchronous fetches and deadlines.
  • Phase 1 reviewers: muse-spark-1.3-contributor — general (completed, effort xhigh); agent phase1-reviewer, muse-spark-1.3-contributor — rust-quality (completed, effort xhigh); agent phase1-reviewer
  • Phase 1 model: muse-spark-1.3-contributor — not quota-gated; passed over gemini-3.8-flash-high (antigravity quota lookup failed), glm-5.3-flash (not used above high effort; tier asks max)
  • Single stage: Phase 1 and Phase 2 reviewed this head side by side, with no blocker gate between them (triage tier)
  • Fresh final gate: an independent Phase-2 review ran after iterative findings were reconciled
  • Fresh verifier: gpt-6.1-sol — final-verifier; agent sol-verifier
  • Phase 2 reviewers: gpt-6.1-sol — general (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — architecture-layering (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — ffi-engineer (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — rust-quality (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — security-auditor (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — general (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — architecture-layering (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — ffi-engineer (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — rust-quality (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — security-auditor (completed, effort xhigh); agent phase2-reviewer
🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify the current code and confirm that no unresolved issues remain.

No unresolved findings remain from the prior review on this head.

@github-actions

github-actions Bot commented Nov 2, 2026

Copy link
Copy Markdown
Contributor

Bots are done — your move: post /self-reviewed.
Full checklist in the description.

@github-actions github-actions Bot added the waiting-self-review Waiting for the author to post /self-reviewed label Nov 2, 2026
@github-actions github-actions Bot removed the waiting-bots Waiting for the review bots to report on this head label Nov 2, 2026

@PastaPastaPasta PastaPastaPasta left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only touches experimental opt-in feature; approved; merging

@PastaPastaPasta
PastaPastaPasta merged commit 3620ce2 into v5.1-dev Nov 3, 2026
28 of 29 checks passed
@PastaPastaPasta
PastaPastaPasta deleted the fix/verify-quorum-proofs-without-blocking branch November 3, 2026 17:12
shumkov added a commit that referenced this pull request Nov 3, 2026
Brings in #5489, #5526 and #5720, which landed on v5.1-dev after this
branch started. #5526 adds token-market-contract at 5.0.1; it takes the
merged version, 5.0.3, in its package.json and in Cargo.lock, so the
lockfile stays current and yarn constraints pass once this merges.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@shumkov shumkov mentioned this pull request Nov 3, 2026
13 of 22 tasks
shumkov added a commit that referenced this pull request Nov 6, 2026
Brings in the rust-dashcore pin c9aeac0d (DGW, the coinbase checks,
masternode-sync liveness, the private sync module, the FFI removal), the
verified quorum context provider (#5523, #5720) and its SDK opt-in
(#5721).

Semantic resolutions:

- rs-sdk-trusted-context-provider: keeps this branch's `local` module next
  to v5.1-dev's `proof_fetches` and `proof_transport`. System contracts
  have one owner, `system_contracts`: `LocalContextResolver::data_contract`
  calls `system_data_contract`, and the table copied into `local.rs` is
  gone, so the resolver now also serves the decision-proposals and
  token-market contracts from protocol 15.
- The token-market gate (`is_inactive_system_contract`) holds on every
  path: in `LocalContextResolver::data_contract` before the known
  contracts, and in `TrustedHttpContextProvider::get_data_contract` before
  the resolver and the fallback provider. New tests pin each gate; each
  was seen red with only its own gate removed.
- `platform_activation_height` keeps the dash-context-provider copy;
  `system_contracts` re-exports it.
- rs-sdk: keeps the fixed `context_provider: Arc<dyn ContextProvider>` and
  the removal of `Sdk::set_context_provider`, and v5.1-dev's
  `SdkBuilder::build` checks of the provider's network and proof
  requirement. The two setter tests now test the builder, through both
  `with_context_provider` and `with_context_provider_arc`; both go red
  without the build check. The balance checker, `read_contract` example
  and `quorum_key` test drop the setter calls.
- platform-wallet `spv/runtime.rs`: takes v5.1-dev's dash-spv adaptations
  (`SyncProgress`/`SyncState` from the crate root, infallible
  `PeerNetworkManager::new`) and keeps this branch's byte-reversed quorum
  lookup key, `is_ready` (running, headers and masternodes `Synced`), the
  verified-only lookup, and the rejection of quorum types that name no
  LLMQ type, now matched as `LlmqtypeUnknown(_)`.
- `VerifiedHttpContextProvider`'s docs no longer point at the removed
  setter.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

waiting-self-review Waiting for the author to post /self-reviewed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(sdk): verify quorum proofs off the async executor in VerifiedHttpContextProvider

2 participants