Skip to content

fix(rpc): verifychain false failures on chains with spends - #21

Merged
secsovereign merged 5 commits into
mainfrom
cursor/fix-verifychain-de0a
Oct 6, 2026
Merged

secsovereign merged 5 commits into
mainfrom
cursor/fix-verifychain-de0a

Conversation

@secsovereign

@secsovereign secsovereign commented Oct 6, 2026 •

Copy link
Copy Markdown
Member

Summary

Fix verifychain RPC returning false/invalid on valid chains containing non-coinbase spends.

Root cause: verify_chain was loading the current tip UTXO set and then validating blocks that were already applied to that set - causing spends to fail because inputs were already consumed and outputs already existed.

Changes

Levels 0-3: Header/Merkle/Linkage Only

  • Removed UTXO validation from levels ≤3 (matches Bitcoin Core semantics)
  • Level 0: Block exists check
  • Level 1: Block deserializable
  • Level 2: Merkle root verification
  • Level 3: Header linkage (prev_block_hash)

Level 4: Full UTXO Validation with Undo Log Rewind

  • Rewinds UTXO set using undo logs with one-pass-per-entry disconnect semantics matching blvm_consensus::reorganization::disconnect_block:
    for entry in undo_log.entries.iter() {
        if entry.new_utxo.is_some() { remove }
        if entry.previous_utxo.is_some() { restore }
    }
  • This correctly handles same-block create→spend (restore wins over remove)
  • Uses per-block height MTP via headers_before_height_for_mtp(height) (not tip-relative)

Tests

  • test_verify_chain_with_spends_returns_true: Levels 1-3 pass on chain with spends
  • test_verify_chain_level4_with_undo_logs: Level 4 with proper undo log rewind (feature-gated with production)

Closes #10

Open in Web Open in Cursor 

cursoragent and others added 2 commits October 6, 2026 21:41
The verifychain RPC was incorrectly returning false/invalid on valid chains
containing non-coinbase spends. The issue was that verify_chain loaded the
current tip UTXO set and then tried to validate blocks that were already
applied to that set.

Changes:
- Levels 0-3: Only perform header/merkle/linkage checks, no UTXO validation
- Level 4: Properly rewind UTXO set using undo logs before reconnecting blocks
- Add detailed docstring explaining Bitcoin Core checklevel semantics
- Feature-gate level 4 UTXO validation under 'production' feature

Test:
- Add test_verify_chain_with_spends_returns_true that creates a chain with
  non-coinbase spends and verifies that verifychain returns true at all levels

Closes #10

Co-authored-by: Secure Sovereign <secsovereign@users.noreply.github.com>
Level 4 undo log rewind:
- Use correct disconnect order: remove new_utxo first, then restore previous_utxo
- This matches blvm_consensus::reorganization disconnect_block semantics

Level 4 MTP fix:
- Use headers_before_height_for_mtp(height) for per-block MTP
- Previously used tip-relative MTP which was incorrect during replay

Test improvements:
- Fix BIP34 height encoding (height 0 = OP_0 + padding)
- Simplify level 4 test to use coinbase-only blocks (avoids 100-block
  maturity requirement for spending coinbase outputs)
- Test verifies undo log rewind + block replay mechanics

Closes #10

Co-authored-by: Secure Sovereign <secsovereign@users.noreply.github.com>
@secsovereign
secsovereign marked this pull request as ready for review October 6, 2026 22:07
cursoragent and others added 3 commits October 6, 2026 22:09
Co-authored-by: Secure Sovereign <secsovereign@users.noreply.github.com>
Change from two-pass (all removes then all restores) to one-pass-per-entry
matching blvm_consensus::reorganization::disconnect_block exactly:

  for entry in undo_log.entries.iter() {
      if entry.new_utxo.is_some() { remove }
      if entry.previous_utxo.is_some() { restore }
  }

This correctly handles same-block create→spend: restore wins over remove
when operating on the same outpoint.

Co-authored-by: Secure Sovereign <secsovereign@users.noreply.github.com>
Co-authored-by: Secure Sovereign <secsovereign@users.noreply.github.com>
@secsovereign
secsovereign merged commit 098218d into main Oct 6, 2026
12 checks passed
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.

Implement verifychain RPC method

2 participants