Skip to content

refactor: reduced amount of block hashes computed#834

Open
ZocoLini wants to merge 1 commit into
devfrom
perf/block-headers
Open

refactor: reduced amount of block hashes computed#834
ZocoLini wants to merge 1 commit into
devfrom
perf/block-headers

Conversation

@ZocoLini

@ZocoLini ZocoLini commented Jul 1, 2026

Copy link
Copy Markdown
Collaborator

The Block header storage now only works with Hashed block headers, avoiding block hash recomputation
Method that require the hash ask for it si the caller can supply an already computed one

This PR improves dash-spv performance and, somehow, gives stability to the benchmark I am using

@ZocoLini ZocoLini requested a review from xdustinface July 1, 2026 15:06
@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR migrates dash-spv's header storage APIs from raw BlockHeader to HashedBlockHeader, updating the BlockHeaderStorage trait and its implementations, sync managers/pipelines to use hashed headers/blocks with hash() instead of block_hash(), and adds an explicit block_hash parameter to WalletInterface::process_block_for_wallets across all call sites and mocks.

Changes

Storage layer HashedBlockHeader migration

Layer / File(s) Summary
BlockHeaderStorage trait and disk implementations
dash-spv/src/storage/block_headers.rs, dash-spv/src/storage/mod.rs
Trait methods and PersistentBlockHeaderStorage/DiskStorageManager implementations switch to HashedBlockHeader for store/load/get, removing store_hashed_headers*; tests use a hashed_batch helper and hash()-based lookups.
Storage benchmark
dash-spv/benches/storage.rs
Bench header generation and reverse-index lookup use HashedBlockHeader.

Sync managers/pipelines adopt hashed headers and blocks

Layer / File(s) Summary
Client genesis/checkpoint init
dash-spv/src/client/lifecycle.rs
Checkpoint and genesis headers are wrapped as HashedBlockHeader before storing.
Block headers sync manager
dash-spv/src/sync/block_headers/manager.rs
Storage write uses unified store_headers; tests build hashed genesis vectors.
Blocks pipeline and manager
dash-spv/src/sync/blocks/pipeline.rs, dash-spv/src/sync/blocks/manager.rs, dash-spv/src/sync/blocks/sync_manager.rs
Pipeline buffers/returns HashedBlock; manager and sync_manager route hashed blocks through wallet processing and storage.
Chainlock, filter headers, filters, masternodes
dash-spv/src/sync/chainlock/manager.rs, dash-spv/src/sync/filter_headers/pipeline.rs, dash-spv/src/sync/filters/manager.rs, dash-spv/src/sync/filters/pipeline.rs, dash-spv/src/sync/masternodes/sync_manager.rs, dash-spv/src/sync/masternodes/manager.rs
Hash derivation switches from block_hash() to hash(); tests preload storage with HashedBlockHeader-mapped headers across many scenarios.

WalletInterface process_block_for_wallets explicit block_hash

Layer / File(s) Summary
Trait/implementation signature change
key-wallet-manager/src/wallet_interface.rs, key-wallet-manager/src/process_block.rs
process_block_for_wallets gains a block_hash: BlockHash parameter used to build BlockInfo.
Mock implementations
key-wallet-manager/src/test_utils/mock_wallet.rs
MockWallet, NonMatchingMockWallet, MultiMockWallet add unused _block_hash parameter.
Call sites and tests
key-wallet-manager/src/process_block.rs, key-wallet-manager/src/event_tests.rs, key-wallet-manager/tests/spv_integration_tests.rs
All test/integration call sites pass block.block_hash() explicitly.

Estimated code review effort: 3 (Moderate) | ~30 minutes

Possibly related PRs

  • dashpay/rust-dashcore#790: Both PRs modify dash-spv/src/storage/block_headers.rs's BlockHeaderStorage/PersistentBlockHeaderStorage API at the storage layer.

Suggested labels: ready-for-review

Suggested reviewers: xdustinface

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title matches the PR’s main goal of reducing repeated block-hash computation, and it is concise and specific.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch perf/block-headers

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

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot 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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
dash-spv/src/storage/block_headers.rs (1)

165-169: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Remove stale hash mappings on height rewrites.
SegmentCache::insert only blocks overwrites with debug_assert!, so release builds can replace an existing header at the same height. Clear the old hash -> height entries for the overwritten range before inserting the replacement batch, or add a runtime reject if rewrites should never happen.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@dash-spv/src/storage/block_headers.rs` around lines 165 - 169, The stale hash
mappings are left behind when `SegmentCache::insert` overwrites headers at an
existing height in release builds. Update `BlockHeaders::store_items_at_height`
to remove any old `header_hash_index` entries for the overwritten height range
before calling `store_items_at_height`, or add a runtime check to reject
rewrites if they are not allowed; use the existing `header_hash_index` and
`store_items_at_height` logic to locate and fix the replacement path.
🧹 Nitpick comments (2)
key-wallet-manager/src/wallet_interface.rs (1)

68-74: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Document the block_hash/block invariant.

The new block_hash parameter is caller-supplied and must correspond to block's actual hash for correct BlockInfo construction downstream, but nothing in the trait doc states this contract. Since implementers no longer independently verify the hash (that's the point of the optimization), a mismatch would silently corrupt stored BlockInfo/event data.

Consider adding a doc line clarifying the invariant, e.g. "block_hash must be the hash of block (callers typically already have it from HashedBlock/HashedBlockHeader and should avoid recomputing it)."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@key-wallet-manager/src/wallet_interface.rs` around lines 68 - 74, Document
the new caller-supplied block_hash contract on process_block_for_wallets: it
must always match the actual hash of block, since implementers now rely on that
value for BlockInfo/event construction and no longer re-verify it. Update the
trait documentation near process_block_for_wallets in wallet_interface.rs to
state this invariant clearly, and mention that callers should pass the hash
already available from HashedBlock or HashedBlockHeader rather than recomputing
it.
key-wallet-manager/src/process_block.rs (1)

20-31: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Guard the block_hash invariant with a debug assertion.

block_hash is now trusted verbatim to build BlockInfo, which is persisted into TransactionRecord.context and surfaced in BlockProcessed events. If a caller ever passes a hash that doesn't match block, this will silently corrupt that context with no compile-time or runtime signal. A debug_assert_eq! costs nothing in release builds (preserving the perf goal of this PR) while catching integration bugs during development/tests.

🛡️ Proposed guard
     ) -> BlockProcessingResult {
         let mut result = BlockProcessingResult::default();
         if wallets.is_empty() {
             return result;
         }
+        debug_assert_eq!(
+            block_hash,
+            block.block_hash(),
+            "block_hash must match block.block_hash()"
+        );
         let info = BlockInfo::new(height, block_hash, block.header.time);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@key-wallet-manager/src/process_block.rs` around lines 20 - 31, Add a
debug-time invariant check in process_block_for_wallets before constructing
BlockInfo: verify the provided block_hash matches the hash derived from block
and fail fast in debug builds if it does not. Keep the check close to the
BlockInfo::new call so the trusted hash used for TransactionRecord.context and
BlockProcessed stays validated without affecting release performance.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@dash-spv/src/storage/block_headers.rs`:
- Around line 165-169: The stale hash mappings are left behind when
`SegmentCache::insert` overwrites headers at an existing height in release
builds. Update `BlockHeaders::store_items_at_height` to remove any old
`header_hash_index` entries for the overwritten height range before calling
`store_items_at_height`, or add a runtime check to reject rewrites if they are
not allowed; use the existing `header_hash_index` and `store_items_at_height`
logic to locate and fix the replacement path.

---

Nitpick comments:
In `@key-wallet-manager/src/process_block.rs`:
- Around line 20-31: Add a debug-time invariant check in
process_block_for_wallets before constructing BlockInfo: verify the provided
block_hash matches the hash derived from block and fail fast in debug builds if
it does not. Keep the check close to the BlockInfo::new call so the trusted hash
used for TransactionRecord.context and BlockProcessed stays validated without
affecting release performance.

In `@key-wallet-manager/src/wallet_interface.rs`:
- Around line 68-74: Document the new caller-supplied block_hash contract on
process_block_for_wallets: it must always match the actual hash of block, since
implementers now rely on that value for BlockInfo/event construction and no
longer re-verify it. Update the trait documentation near
process_block_for_wallets in wallet_interface.rs to state this invariant
clearly, and mention that callers should pass the hash already available from
HashedBlock or HashedBlockHeader rather than recomputing it.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a24b8ce7-a969-4e56-b98d-520ab6f54572

📥 Commits

Reviewing files that changed from the base of the PR and between 78d1002 and 118471d.

📒 Files selected for processing (19)
  • dash-spv/benches/storage.rs
  • dash-spv/src/client/lifecycle.rs
  • dash-spv/src/storage/block_headers.rs
  • dash-spv/src/storage/mod.rs
  • dash-spv/src/sync/block_headers/manager.rs
  • dash-spv/src/sync/blocks/manager.rs
  • dash-spv/src/sync/blocks/pipeline.rs
  • dash-spv/src/sync/blocks/sync_manager.rs
  • dash-spv/src/sync/chainlock/manager.rs
  • dash-spv/src/sync/filter_headers/pipeline.rs
  • dash-spv/src/sync/filters/manager.rs
  • dash-spv/src/sync/filters/pipeline.rs
  • dash-spv/src/sync/masternodes/manager.rs
  • dash-spv/src/sync/masternodes/sync_manager.rs
  • key-wallet-manager/src/event_tests.rs
  • key-wallet-manager/src/process_block.rs
  • key-wallet-manager/src/test_utils/mock_wallet.rs
  • key-wallet-manager/src/wallet_interface.rs
  • key-wallet-manager/tests/spv_integration_tests.rs

@codecov

codecov Bot commented Jul 1, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.13900% with 10 lines in your changes missing coverage. Please review.
✅ Project coverage is 72.93%. Comparing base (03096dd) to head (118471d).
⚠️ Report is 2 commits behind head on dev.

Files with missing lines Patch % Lines
dash-spv/src/client/lifecycle.rs 50.00% 4 Missing ⚠️
dash-spv/src/sync/masternodes/sync_manager.rs 20.00% 4 Missing ⚠️
dash-spv/src/sync/filter_headers/pipeline.rs 66.66% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##              dev     #834      +/-   ##
==========================================
- Coverage   73.16%   72.93%   -0.23%     
==========================================
  Files         323      323              
  Lines       72438    72569     +131     
==========================================
- Hits        52999    52931      -68     
- Misses      19439    19638     +199     
Flag Coverage Δ
core 76.94% <ø> (ø)
ffi 45.31% <ø> (-2.40%) ⬇️
rpc 20.00% <ø> (ø)
spv 90.56% <96.03%> (+0.23%) ⬆️
wallet 71.78% <100.00%> (+<0.01%) ⬆️
Files with missing lines Coverage Δ
dash-spv/src/storage/block_headers.rs 96.70% <100.00%> (-0.11%) ⬇️
dash-spv/src/storage/mod.rs 86.34% <100.00%> (+1.31%) ⬆️
dash-spv/src/sync/block_headers/manager.rs 90.17% <100.00%> (+0.14%) ⬆️
dash-spv/src/sync/blocks/manager.rs 97.04% <100.00%> (+0.10%) ⬆️
dash-spv/src/sync/blocks/pipeline.rs 97.09% <100.00%> (+0.01%) ⬆️
dash-spv/src/sync/blocks/sync_manager.rs 82.35% <ø> (ø)
dash-spv/src/sync/chainlock/manager.rs 93.49% <100.00%> (ø)
dash-spv/src/sync/filters/manager.rs 97.54% <100.00%> (-0.04%) ⬇️
dash-spv/src/sync/filters/pipeline.rs 97.99% <100.00%> (+0.17%) ⬆️
dash-spv/src/sync/masternodes/manager.rs 93.50% <100.00%> (+0.11%) ⬆️
... and 5 more

... and 19 files with indirect coverage changes

@ZocoLini ZocoLini changed the title perf: reduced amount of block hashes computed refactor: reduced amount of block hashes computed Jul 1, 2026
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.

1 participant