Skip to content

Move signature verification out of the write transaction and parallelize it - #5103

Open
RickiNano wants to merge 4 commits into
nanocurrency:developfrom
RickiNano:mt-block-processor
Open

Move signature verification out of the write transaction and parallelize it#5103
RickiNano wants to merge 4 commits into
nanocurrency:developfrom
RickiNano:mt-block-processor

Conversation

@RickiNano

Copy link
Copy Markdown
Contributor

Block signature verification currently runs serially inside the ledger write transaction: the block processor opens a write tx per batch and each ledger.process() call does its ed25519 checks while holding it. This PR moves that CPU work out of the transaction and onto a small worker pool, so batches are pre-validated in parallel before the write tx is opened.

Benefits

  • Higher block throughput. Serial signature work now spread across up to 4 threads
  • Shorter write transaction hold times. The write tx now spends its time on actual store reads/writes instead of signature validation
  • Zero behavioral change. Results are bit-identical to today: same checks, same order of ledger application, same result codes, same notification order. A duplicate block with a bad signature still returns old, forks and rollbacks are untouched.

How it works

  • block_context gains a nano::signature_verification result (unknown / valid / valid_epoch / invalid), defaulting to unknown.
  • process_batch() fans the batch out across a dedicated nano::thread_pool between next_batch() and tx_begin_write(). Workers verify state blocks (against the account owner first, then the epoch signer for epoch links — the same order the ledger processor uses) and open blocks. Legacy send/receive/change blocks need a frontier lookup to determine the signer, so they stay unknown and are verified inline as today; they are effectively extinct on the live network.
  • ledger.process() accepts the verification result (defaulting to unknown, so all existing callers keep today's behavior). Inside ledger_processor, a new validate_signature() helper consumes the pre-computed result where it is conclusive and falls back to validate_message() where it isn't. Debug builds re-verify every skipped check via debug_assert.
  • Pre-verified invalid blocks are still rejected at the existing check site inside the transaction (not short-circuited earlier), preserving today's result-code precedence.

Co-authored with Claude Fable

@gr0vity-dev-bot

gr0vity-dev-bot commented Jul 8, 2026

Copy link
Copy Markdown

Test Results for Commit 8f2c2b4

Pull Request 5103: Results
Overall Status:

Test Case Results

  • 5n4pr_conf_10k_bintree: PASS (Duration: 111s)
  • 5n4pr_conf_10k_change: PASS (Duration: 134s)
  • 5n4pr_conf_change_dependant: PASS (Duration: 114s)
  • 5n4pr_conf_change_independant: PASS (Duration: 117s)
  • 5n4pr_conf_send_dependant: PASS (Duration: 106s)
  • 5n4pr_conf_send_independant: PASS (Duration: 144s)
  • 5n4pr_rocks_10k_bintree: PASS (Duration: 112s)
  • 5n4pr_rocks_10k_change: PASS (Duration: 186s)

Last updated: 2026-07-09 23:23:52 UTC

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR reduces ledger write-transaction hold time by pre-validating block signatures outside the transaction and (for eligible block types) doing that work in parallel, then threading the pre-validation result into ledger.process()/ledger_processor so the in-tx signature check can be skipped when conclusive.

Changes:

  • Add nano::signature_verification and plumb it through ledger::process() into ledger_processor.
  • Add a configurable verification worker pool to block_processor to pre-validate signatures for each batch before opening the write transaction.
  • Add config + stats + TOML coverage for the new verification_threads setting and blocks_verified stat.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
nano/secure/ledger.hpp Extends ledger::process() API to accept optional pre-validation result.
nano/secure/ledger.cpp Passes pre-validation result into ledger_processor.
nano/secure/ledger_processor.hpp Extends ledger_processor to store a pre-validation result and adds validate_signature() helper.
nano/secure/ledger_processor.cpp Implements validate_signature() and routes relevant signature checks through it.
nano/secure/common.hpp Introduces signature_verification enum used for pre-validation.
nano/node/block_processor.hpp Adds verification_threads config and declares batch verification helpers/pool.
nano/node/block_processor.cpp Implements parallel batch signature verification, config serialization, and stats reporting.
nano/node/block_context.hpp Stores per-block pre-validation result in block_context.
nano/lib/stats_enums.hpp Adds blocks_verified stat detail.
nano/core_test/toml.cpp Extends TOML config tests to include verification_threads.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread nano/secure/ledger_processor.cpp Outdated
Comment thread nano/node/block_processor.cpp
@RickiNano

Copy link
Copy Markdown
Contributor Author

I need to rebase this branch on develop to fix the conflicts

@RickiNano
RickiNano force-pushed the mt-block-processor branch from af03151 to 8f2c2b4 Compare July 9, 2026 20:26
@RickiNano

Copy link
Copy Markdown
Contributor Author

Rebased and ready for review @pwojcikdev

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