Context: Recent discussions highlighted that many nodes that synced before Bitcoin Core v28 have their block and undo files stored effectively in the clear (zero XOR key). This patch adds a simple, resumable maintenance tool to obfuscate previously raw block files, rotate an existing key to a fresh random one, or de-obfuscate (set key to zero) if consciously chosen, all without requiring a resync. The operation can be cancelled and restarted safely.
Implementation: The new startup option -reobfuscate-blocks[=VALUE] accepts either 16 hex characters as an exact 8-byte XOR key (little-endian in-memory layout) or a boolean to generate a random 64-bit key. e.g. -reobfuscate-blocks=0000000000000000 sets the key to zero, effectively removing obfuscation.
If unobfuscated blocks are detected at start time, a warning suggests this new option.
At startup, we iterate over all undo and block files (grouping them for more uniform iteration), read them with the old XOR key, and write them back with the new key (as <name>.reobfuscated). The implementation combines the two keys and reads directly into the new obfuscated version to do only a single pass over the data. This works whether the original blocks are obfuscated, the new blocks are not, or neither are.
After a successful write, the old file is deleted immediately. Once all files are staged, they are renamed back, and xor.dat.reobfuscated is atomically swapped to xor.dat before the operation continues.
Progress is logged roughly per-percent as files complete (i.e. max 100 progress log lines).
Constraints:
- Re-obfuscation resumes automatically (detected via
xor.dat.reobfuscated) even without the flag. In the worst case, a crash should only force redoing previous work. - Single-threaded, processing one file at a time to keep code simple and avoid the complexity of interleaving renames and key swaps across threads.
- Fast in practice with sequential read/modify/write per block file - after recent obfuscation vectorization, this path is very quick.
Reproducer:
cmake -B build -DBUILD_GUI=ON && cmake --build build -j$(nproc)
# command line
./build/bin/bitcoind -reobfuscate-blocks -stopatheight=1
# same with GUI
./build/bin/bitcoin-qt -reobfuscate-blocks -stopatheight=1
Single-threaded Performance:
| cpu | hdd/ssd | block count | size | files | time (min) | blocks/min |
|---|---|---|---|---|---|---|
| Apple M4 Max laptop | SSD | ~909k | ~707 GB | 9,982 | 8.4 | 146,613 |
| Intel Core i9 | SSD | ~909k | ~725 GB | 10,238 | 23.1 | 39,351 |
| Raspberry Pi 5 | SSD | ~914k | ~728 GB | 10,276 | 72.78 | 12,558 |
| Intel Core i7 | HDD | ~909k | ~720 GB | 10,156 | 208.7 | 4,356 |
| Raspberry Pi 4B | HDD | ~915k | ~730 GB | 10,304 | 1467 | 624 |
Similar work: