Skip to content

fix: Bound tx validation and add spawn blocking calls - #2488

Merged
sergerad merged 2 commits into
sergerad-trace-fixesfrom
sergerad-validator-perf
Aug 19, 2026
Merged

fix: Bound tx validation and add spawn blocking calls#2488
sergerad merged 2 commits into
sergerad-trace-fixesfrom
sergerad-validator-perf

Conversation

@sergerad

@sergerad sergerad commented Aug 19, 2026

Copy link
Copy Markdown
Collaborator

Summary

Under load, the validator's SignBlock RPC was spiking from ~30ms to ~300ms, with the tracing added in #2487 showing the time spread uniformly across the request rather than concentrated in any one span — the signature of CPU starvation, not lock contention. Each submitted transaction runs proof verification and full VM re-execution on unbounded blocking threads, oversubscribing every core, while the Golden seal (secp256k1 ops) and the CPU-heavy parts of block signing ran directly on async workers.

The two paths have asymmetric failure modes: a delayed block signature stalls the whole chain, while a delayed transaction validation only slows admission — the RPC submits every transaction to every validator before it may enter the mempool, so blocks are proposed exclusively from already-validated transactions and signing never waits on validation. Signing must therefore always have CPU headroom; validation is the correct place to apply backpressure.

Changes:

  • Bounded validation concurrency: SubmitProvenTransaction now acquires a permit from a semaphore sized to available_parallelism - 2 (minimum 1) before validating, converting CPU oversubscription into visible queueing. The permit is acquired after the already-validated short-circuit, so duplicate submissions never wait. The wait is instrumented as an acquire_validation_permit span.
  • CPU work off the async workers: the Golden seal (secp256k1 group ops), into_header_and_body (account/nullifier/note tree roots plus chain and transaction commitments — hashing proportional to block contents), and full-block serialization now run via spawn_blocking_in_current_span, with panics propagated via resume_unwind (same convention as tx_validation).
  • decode span: SignBlock::decode now times ProposedBlock deserialization, closing the last un-instrumented sync segment of the request path.

Verified against a local multi-validator run: the rpc span's self-time drops to ~0% (fully attributed), the offloaded work still reports under validate_block (the helper carries the span across the thread hop), and the uncontended acquire_validation_permit adds no measurable latency. Behavior note: under sustained validation overload, submissions now queue (and eventually hit the request timeout) instead of silently degrading block signing — backpressure lands on submitters, which already handle it.

Changelog

changelog = "none"
reason    = "Internal change only."

@sergerad sergerad changed the title Bound tx validation and add spawn blocking calls fix: Bound tx validation and add spawn blocking calls Aug 19, 2026

@kkovaacs kkovaacs 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.

Looks good to me % a small nit.

Comment thread bin/validator/src/server/validator_service/sign_block.rs Outdated

@Mirko-von-Leipzig Mirko-von-Leipzig 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.

Thank you; good findings. I initially thought it would be database write lock contention.

(signed_block, bytes)
})
.await
.unwrap_or_else(|e| std::panic::resume_unwind(e.into_panic()));

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.

@kkovaacs a fairly common pattern - should we make this part of the spawn function itself?

Comment thread bin/validator/src/server/validator_service/mod.rs Outdated
Comment thread bin/validator/src/server/validator_service/sign_block.rs Outdated

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.

This is one of the points where I wish we had more powerful tracing. It would be sensible to always have decode, encode and handle instrumented by the trait itself.

However that is not helpful because our macros need introspection of the function body to work properly.

Nothing actionable; just a complaint into the void :)

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.

Perhaps for a different PR, but I think this exhibits my point that most of our RPC work is actually not async, but rather blocking.

Our database calls are actually sync under the hood; we're just twisting ourselves into pretzels jumping between sync and async multiple times.

@sergerad
sergerad force-pushed the sergerad-validator-perf branch from 07d2747 to 897f5dc Compare August 19, 2026 21:29
@sergerad
sergerad merged commit e85abd3 into next Aug 19, 2026
31 of 50 checks passed
@sergerad
sergerad deleted the sergerad-validator-perf branch August 19, 2026 21:40
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.

3 participants