diff options
| author | Bitflash <btf01@proton.me> | 2026-08-02 14:04:42 -0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-08-02 14:04:42 -0300 |
| commit | 4b2416b7315d76a2abd1a0ac0b72b3d1ef0ff6c6 (patch) | |
| tree | f38b8b03fbf4b09f8d4ddf8856f297d9af792eac /src/net.cpp | |
| parent | 67271dda37e4b9764c59059caa2c8268f755d6e5 (diff) | |
Bump to 1.2.14 (#116)
A block had no size limit, spending could move coins onto a key your recovery phrase cannot reproduce, and one peer could hold up the whole node with a message it never finished sending. All three are fixed here, and all three were found by auditing the tree rather than by anyone hitting them.
## Blocks now have a size limit — and this one is consensus
`CheckBlock()` measured a block against `MAX_SIZE`, the serializer's generic 32 MB guard. There was no `MAX_BLOCK_SIZE` anywhere in the tree: Bitcoin's 1 MB cap arrived in 0.3.x, after the 0.1.0 this project came from, so the inheritance was simply missing. A miner could produce a 32 MB block and every node would download, verify and store it.
The cap is now **1 MB**, chosen against the chain rather than tradition. Reading all 5709 blocks out of `blk0001.dat`:
| | |
|---|---|
| largest block ever mined | 34,290 bytes |
| median | 216 bytes |
| p99 | 14,451 bytes |
1 MB leaves **29× of headroom** over the largest block this chain has ever carried, so nothing existing is rejected. A node built with the rule then synced genesis → 5706 on the live network with zero rejections, which is the same test that once caught BIP30 rejecting a real block at height 859.
**Because it is consensus, it matters that you upgrade.** Until most nodes have it, a block above 1 MB would be accepted by old nodes and rejected by new ones — which is how a chain splits. Nobody is mining such blocks today; the gap is worth closing before somebody does.
## Spending could put your change on a key the phrase cannot recover
When a wallet spends, the leftover goes back to you as *change*. This tree sent change to **the same key as one of the coins being spent** — 0.1.0 behaviour, and a privacy problem long tracked as #23.
With recovery phrases it became a way to lose money. If the coin being spent sat on a key created *before* the seed — the wallet's original default address, an imported key, anything older than `-newphrase` — then the change went back to that same pre-seed key. So spending quietly moved your balance onto a key the twelve words do not reproduce, in a wallet you believed the words covered.
Change now comes from a newly derived, phrase-backed key. **If that derivation fails, the transaction is refused rather than created**, because a failed send is recoverable and unrecoverable change is not. Wallets with no seed keep the old behaviour exactly.
Restore also now scans past the pre-generated key-pool window before accepting an empty batch as the end, so a restore cannot stop short while used addresses sit just beyond it.
## One peer could hold up the whole node
`ProcessMessages` runs in a single thread that serves every peer. When a message header announced more bytes than had arrived, the old code consumed the header, inserted it back at the *front* of the receive buffer — an O(n) memmove on a buffer that could hold 256 MB — and then slept 100 ms **inside that shared thread**. A peer that announced a large message and dripped bytes could make every pass pay both costs, forever, while looking perfectly active to the inactivity reaper.
The parser now reads the header from a copy without consuming it, never sleeps in the shared thread, and disconnects a peer that sits on an incomplete message for two minutes. The wire cap drops from 256 MB to `MAX_SIZE`.
## The rendezvous holds more than one registration
A node's registration at a rendezvous relay was consumed by the first caller, and registering again *replaced* the previous one — so a node was reachable to exactly one peer at a time and unreachable for the whole gap between being paired and registering again. Measured on a live node: descriptors resolved 53 times out of 54, its own registrations paired 11 out of 12, and **half of every outbound dial failed**.
All three relays now keep a queue per node and pair with the oldest registration still alive. **This is already deployed** — you get it without upgrading. The matching node-side change, which parks spare registrations, is deliberately **not** in this release: it measured worse in the field than the code it replaced and will not ship until that is explained.
## Restoring from a phrase now looks far enough
Found by proving the change fix above with real coin, and caused by it.
Restoring derived forward in batches of a hundred and stopped at the first batch that turned up nothing. The wallet digs a wider gap than that by itself: a restore leaves the derivation counter at the depth it scanned, the key pool derives a hundred more, and change takes the index after those. So the address used *after* a restore can sit two hundred indices past the last one used before it, with nothing in between.
On a real wallet: receive, restore, spend once — the outputs land at indices 201 and 302. Restoring again reported
```
Restored: 1 transaction(s) across 201 derived addresses
```
and the spend was invisible, both the payment and the change. The money was derived and covered by the phrase; the search stopped short of it. Three quiet batches instead of one, and the same wallet reports `2 transaction(s) across 601 derived addresses`.
Change returning to an input's key used to hide this, because that key sat at a low index the scan had already passed. Fixing recoverability moved change out to where the search stopped looking, so the two had to be fixed together.
The gap is self-inflicted and grows with each restore, so a long enough history can still outrun a fixed number of quiet batches. `-restoredepth=N` looks as far as you ask. The structural fix is tracked separately.
## A headless node can finally spend
`SendMoney()` has been in this tree since 0.1.0 and only the window ever called it, so a node without a screen could be paid and could never pay — it could hold a balance with no way to move it. Found while trying to prove the change fix, which needs a spend.
```
bitflash -sendto=ADDRESS,AMOUNT
```
Refuses an address that does not decode, an amount that is zero, negative or not a number, and a wallet whose chain is not loaded — all before touching the wallet. A transaction created while the node is stopped is not broadcast until the node starts.
## Also
- `-help` printed nothing at all on Windows. This tree remaps `printf` to the debug-log writer, and a `-mwindows` binary has no console, so the one command whose job is to tell you something returned 0 in silence.
- The README described a program from several releases ago — deterministic restore listed as an open issue, mining mode described as forgotten between restarts, and every flag written in the slash form that MSYS2 rewrites into a path.
- Diagnostics now report why a socket close failed, per error code and per site, and flag a handle handed back while some part of the program still claims it.
## Downloads
| File | Platform | Notes |
|------|----------|-------|
| `Bitflash-1.2.14-windows.zip` | Windows x86_64 | Extract and run |
| `Bitflash-1.2.14-x86_64.AppImage` | Linux x86_64 | Desktop/GUI — `chmod +x` and run |
| `bitflash-node-1.2.14-x86_64` | Linux x86_64 | Headless server node, no libGL or FUSE |
Verify with `sha256sum -c SHA256SUMS`.
Everything in [v1.2.13](https://github.com/Bitflash-sh/bitflash/releases/tag/v1.2.13) is included.
Diffstat (limited to 'src/net.cpp')
0 files changed, 0 insertions, 0 deletions