Context
Recent discussions highlighted that many nodes which 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 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 we detect unobfuscated blocks at start time we suggest this new option in a warning.
At startup, we iterate over all undo and block files (grouping the block and undo files for more uniform iteration), read them with the old XOR key and write them back with the new key (<name>.reobfuscated). The implementation actually combines the two keys and reads directly into the new obfuscated version to only do a single iteration over the data. This works if the original blocks aren’t obfuscated or if the new blocks aren’t or if both are.
After successful write, we immediately delete the old file. Once all files are staged, we rename them back and atomically swap xor.dat.reobfuscated → xor.dat and continue operation.
We log the old and new keys and print progress roughly per-percent as files complete (i.e. max 100 progress logs).
Constraints
- Re-obfuscation resumes automatically (detected via
xor.dat.reobfuscated) even without the flag. In worst-case a crash should only force us to redo previous work. - Single-threaded, processing one file at a time to keep code simple and avoid complexity of interleaving renames and key swaps across threads.
- Fast in practice with sequential read/modify/write per blockfile - after recent obfuscation vectorization, this path is very quick.
Reproducer
0cmake -B build -DENABLE_IPC=ON -DBUILD_GUI=ON
1cmake --build build -j$(nproc)
2# command line
3./build/bin/bitcoind -reobfuscate-blocks -stopatheight=1
4# same with GUI
5./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: