Skip to content

Keep HD change recoverable and bound message stalls - #109

Merged
Bitflash-sh merged 1 commit into
Bitflash-sh:mainfrom
mtg0001:wallet-change-and-message-stall-fixes
Aug 2, 2026
Merged

Keep HD change recoverable and bound message stalls#109
Bitflash-sh merged 1 commit into
Bitflash-sh:mainfrom
mtg0001:wallet-change-and-message-stall-fixes

Conversation

@mtg0001

@mtg0001 mtg0001 commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Send change from HD wallets to a newly derived phrase-backed key instead of reusing a spent input's key.
  • Make restore scan at least beyond the pre-generated key-pool window before treating an empty batch as the stopping point.
  • Stop the message parser from consuming and reinserting headers for incomplete payloads; it now waits in place without sleeping inside the shared message thread.
  • Cap protocol message headers at the serializer's MAX_SIZE and disconnect peers that keep an incomplete message pending too long.
  • Add a net-message self-test for complete, incomplete, stale incomplete, and oversized message headers.

Why

A wallet with a recovery phrase can still hold coins on pre-phrase keys. Reusing an input key for change silently moves value back to a key the phrase cannot reproduce. HD wallets should fail to create a transaction rather than create non-recoverable change.

The message parser also had a shared-thread stall: when a header announced more bytes than had arrived, it consumed the header, inserted it back at the front of the receive buffer, slept for 100 ms, and moved on. A peer that drips a large message can make every pass pay that cost and keep the connection alive by continuing to send bytes.

This PR deliberately leaves the block-size consensus cap out. That should be a separate change after a full resync from genesis with the proposed limit.

Testing

  • git diff --check
  • make -f makefile.mingw tests from MSYS2 UCRT64 in src/

@Bitflash-sh
Bitflash-sh merged commit ffcbdb5 into Bitflash-sh:main Aug 2, 2026
Bitflash-sh added a commit that referenced this pull request Aug 2, 2026
CheckBlock() validated block size against MAX_SIZE, the serializer's generic 32 MB guard rather than a block rule; MAX_BLOCK_SIZE did not exist in this tree at all, because Bitcoin's 1 MB cap arrived in 0.3.x, after the 0.1.0 this fork came from. A miner could produce a 32 MB block and every node would download, verify and store it.

Original work by mtg0001 in #110, rebased over #109 with the self-test conflict resolved, plus a comment explaining why the inherited count-against-bytes test stays.

Measured before choosing the number: 5709 blocks read from blk0001.dat give a largest block of 34,290 bytes and a median of 216, so 1 MB leaves 29x of headroom and rejects nothing that exists. A node built from this branch then synced genesis to 5706 on the live network with zero size-limit rejections and zero CheckBlock errors -- the same test that caught BIP30 rejecting a real block at height 859.
Bitflash-sh added a commit that referenced this pull request Aug 2, 2026
Restoring from a phrase gave up after the first batch of a hundred addresses that turned up nothing, and the wallet digs a wider gap than that by itself: a restore leaves nHDNext at the depth it scanned, the key pool derives KEYPOOL_SIZE more, and change takes the index after those. Measured on a real wallet with real coin -- restore, spend once, and the outputs land at indices 201 and 302; restoring again found only the first transaction and reported the spend as gone. With -restoredepth=500 the same wallet found both, which is what said this was reach and not loss.

Three quiet batches instead of one: 2 transaction(s) across 601 derived addresses on the same wallet, chain and phrase.

Worse after #109, not before it: change used to return to an input's key, a low index the scan had already passed. Making change recoverable moved it out to where the scan stopped looking.

Does not fix the gap growing with every restore -- pulling nHDNext back to the last used index is the structural answer and needs its own testing.
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.

2 participants