diff options
| author | bitflash-maintainer <noreply@bitflash.invalid> | 2026-09-05 22:46:52 +0000 |
|---|---|---|
| committer | bitflash-maintainer <noreply@bitflash.invalid> | 2026-09-05 22:46:52 +0000 |
| commit | ceae3d076b5ad11ee84729ae43f14e9312896646 (patch) | |
| tree | 7e9132aa871fdc01cb95268d2f5ea3bb11853ddf /docs/storage.md | |
| parent | be63e83d79e7e00e6b8ca889a70e6a19886aa1d8 (diff) | |
| parent | 66e0b9158d050c46b1ff2509faeee3f4573cac1c (diff) | |
Bring main onto the line this project actually ships
main had drifted to a history with no ancestor in common with the tree we
build and deploy. It sat at be63e83 (2026-08-09) with 28 commits; the shipped
line, deploy/soak-2026-08-21, had 383. The two shared nothing -- git
merge-base returns no result at all -- so anyone cloning this repository
landed on a default branch that was neither current nor related to the
running node.
The 28 commits on main were audited before this merge: every one is already
present in the tree by content, including the two that are hardest to see
because they were rewritten afterwards -- the payout reorg-safety work
(PayoutBlockStillOnChain, since evolved to re-check on every retry rather
than once at maturity) and the nostr relay certificate verification
(SSL_set1_host, now with a Windows root-store path). Nothing on main is lost
by this merge.
Recorded as a merge rather than a force-push: main only ever moves forward,
its old history stays reachable as the first parent, and this is revertible.
The tree is taken wholesale from the merged branch, so main's content is now
exactly what was built and tested.
What this brings onto main:
- compactblock: BIP152-style compact block relay ported from upstream 1.2.23,
primitives and unit test only, with the RAND_bytes failure path closed and
the reconstruction allocation bounded.
- upstream/main 17741d9: isolated testnet parameters and genesis, optional
2 MB large pages for RandomX. Mainnet genesis verified byte-identical
through upstream's BuildGenesisBlock() refactor.
- deploy: every image built on bookworm so binaries run on Debian 12, and the
container build now honours the RandomX and libsecp256k1 pins it had been
silently ignoring since before 1.2.15.
Gates at this tree: 15/15 selftests, compactblock's 17 checks, consensus
constants unchanged against e4f898c apart from the pre-existing
MAX_BLOCK_SIZE_GEN, mainnet genesis intact, money-log check ok.
Diffstat (limited to 'docs/storage.md')
| -rw-r--r-- | docs/storage.md | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/docs/storage.md b/docs/storage.md new file mode 100644 index 0000000..c7de4e7 --- /dev/null +++ b/docs/storage.md | |||
| @@ -0,0 +1,159 @@ | |||
| 1 | # Bitflash Storage Inventory | ||
| 2 | |||
| 3 | This document records the Berkeley DB surface that still exists in Bitflash. | ||
| 4 | It is a migration map, not a promise that all stores should move at once. | ||
| 5 | |||
| 6 | The immediate priority is `wallet.dat`: it holds spend authority and recovery | ||
| 7 | metadata. `blkindex.dat` can be rebuilt from block files, so it is important for | ||
| 8 | startup correctness but less dangerous than wallet storage. | ||
| 9 | |||
| 10 | ## Berkeley DB Environment | ||
| 11 | |||
| 12 | All `CDB` stores use one Berkeley DB environment rooted at: | ||
| 13 | |||
| 14 | ```text | ||
| 15 | <datadir>/database/ | ||
| 16 | ``` | ||
| 17 | |||
| 18 | The environment creates log files such as: | ||
| 19 | |||
| 20 | ```text | ||
| 21 | database/log.0000000001 | ||
| 22 | ``` | ||
| 23 | |||
| 24 | Those logs are part of the legacy BDB risk model. They are not user-facing | ||
| 25 | wallet files, but they can contain historical records while the environment is | ||
| 26 | live. Wallet encryption already rewrites `wallet.dat` and purges BDB environment | ||
| 27 | logs after the encrypted file is installed. | ||
| 28 | |||
| 29 | ## Common Records | ||
| 30 | |||
| 31 | Every `CDB` file can carry: | ||
| 32 | |||
| 33 | | Key | Value | Purpose | | ||
| 34 | |---|---|---| | ||
| 35 | | `"version"` | `int` | Database format version written when a DB is opened in create mode. | | ||
| 36 | |||
| 37 | Keys and values are serialized with the existing `CDataStream` format. A future | ||
| 38 | SQLite migration must preserve byte-for-byte value semantics until a higher | ||
| 39 | level schema migration is intentionally introduced. | ||
| 40 | |||
| 41 | ## `wallet.dat` | ||
| 42 | |||
| 43 | `wallet.dat` is accessed through `CWalletDB`. | ||
| 44 | Read-only tooling should go through `ScanWalletRecords()` instead of opening a | ||
| 45 | Berkeley DB cursor directly. That keeps migration checks, audits, and future | ||
| 46 | backends behind one record-stream boundary. Wallet rewrite code should also use | ||
| 47 | that boundary when it needs to copy existing records into a newly written | ||
| 48 | wallet file. | ||
| 49 | |||
| 50 | | Key shape | Value | Secret? | Meaning | | ||
| 51 | |---|---|---:|---| | ||
| 52 | | `("name", address)` | `string` | No | Address book label. | | ||
| 53 | | `("tx", txid)` | `CWalletTx` | No | Wallet transaction state, including spend flags and metadata. | | ||
| 54 | | `("key", pubkey)` | `CPrivKey` | Yes | Plain private key record for unencrypted wallets or old backups. | | ||
| 55 | | `"defaultkey"` | `vector<unsigned char>` | No | Default public key shown by the wallet. | | ||
| 56 | | `"hdmaster"` | `vector<unsigned char>` | Yes | Plain BIP32 master private key material. | | ||
| 57 | | `"hdchaincode"` | `vector<unsigned char>` | Yes | Plain BIP32 chain code. | | ||
| 58 | | `"hdnext"` | `unsigned int` | No | Legacy deterministic derivation next index. | | ||
| 59 | | `"hdschema"` | `int` | No | Deterministic derivation schema (`legacy` or `bip44`). | | ||
| 60 | | `"hdcointype"` | `unsigned int` | No | BIP44 coin type. Bitflash is `4346950`. | | ||
| 61 | | `"hdreceivenext"` | `unsigned int` | No | BIP44 external receive-chain next index. | | ||
| 62 | | `"hdchangenext"` | `unsigned int` | No | BIP44 internal change-chain next index. | | ||
| 63 | | `("mkey", id)` | `CWalletMasterKey` | Sensitive | Encrypted wallet master-key metadata. | | ||
| 64 | | `("ckey", pubkey)` | `vector<unsigned char>` | Yes | Private key encrypted under the wallet master key. | | ||
| 65 | | `"cryptedhdmaster"` | `vector<unsigned char>` | Yes | Encrypted BIP32 master private key material. | | ||
| 66 | | `"cryptedhdchaincode"` | `vector<unsigned char>` | Yes | Encrypted BIP32 chain code. | | ||
| 67 | | `"walletminversion"` | `int` | No | Minimum wallet format version required to open this wallet safely. | | ||
| 68 | | `("pool", index)` | `vector<unsigned char>` | No | Public key reserved in the key pool. The private key lives in `key`/`ckey`. | | ||
| 69 | | `("setting", name)` | typed setting value | Usually no | Wallet/UI settings such as mining mode, fees, and backup timestamps. | | ||
| 70 | |||
| 71 | ### Wallet Migration Rules | ||
| 72 | |||
| 73 | A future wallet backend must keep these properties: | ||
| 74 | |||
| 75 | 1. Unknown future wallet formats fail closed with a clear message. | ||
| 76 | 2. Encrypted wallets must encrypt private keys and HD seed material. | ||
| 77 | 3. A locked encrypted wallet may expose public keys and balances, but not | ||
| 78 | private keys or decrypted HD seed material. | ||
| 79 | 4. `-backupwallet` must produce a wallet file that opens in a different datadir | ||
| 80 | without copying `database/`, and must not leave a half-written final backup | ||
| 81 | path if the copy or install step fails. | ||
| 82 | 5. `-recoveryaudit` must distinguish: | ||
| 83 | - no recovery phrase installed; | ||
| 84 | - recovery phrase present; | ||
| 85 | - recovery phrase encrypted and locked, requiring unlock before coverage can | ||
| 86 | be audited. | ||
| 87 | |||
| 88 | ## SQLite Wallet Store | ||
| 89 | |||
| 90 | Since v1.2.20 SQLite is the default wallet backend. It is a byte-preserving | ||
| 91 | record store, not a new wallet format -- the same serialized `CDataStream` bytes | ||
| 92 | `wallet.dat` uses: | ||
| 93 | |||
| 94 | ```sql | ||
| 95 | CREATE TABLE wallet_records ( | ||
| 96 | key BLOB PRIMARY KEY NOT NULL, | ||
| 97 | value BLOB NOT NULL | ||
| 98 | ); | ||
| 99 | PRAGMA user_version=1; | ||
| 100 | ``` | ||
| 101 | |||
| 102 | A fresh data directory starts on `wallet.sqlite`. An existing `wallet.dat` keeps | ||
| 103 | running on Berkeley DB until it is converted: the GUI offers a one-click | ||
| 104 | conversion on first run, and `-walletbackend=sqlite` / `-walletbackend=bdb` | ||
| 105 | (recorded in a plain-text `wallet-backend` marker file in the datadir) select a | ||
| 106 | backend explicitly. Conversion never modifies `wallet.dat`; it stays as a | ||
| 107 | fallback, and the change takes effect on restart. | ||
| 108 | |||
| 109 | Every wallet operation runs on either backend: read, write, erase, key-pool and | ||
| 110 | HD-seed writes (the two halves of the seed bracketed in one SQLite transaction), | ||
| 111 | `-backupwallet` (checkpoint then copy the self-contained file), `-encryptwallet` | ||
| 112 | (an atomic rebuild-and-swap in one transaction), and the `-walletstorageaudit` / | ||
| 113 | `-walletstoragecheck` diagnostics, which read the active backend's file. | ||
| 114 | |||
| 115 | The migration tooling remains available for scripted use. `-walletsqliteexport=FILE` | ||
| 116 | streams every raw `wallet.dat` record through `ScanWalletRecords()` into a SQLite | ||
| 117 | file in one transaction, refusing to overwrite. `-walletsqliteverify=FILE` | ||
| 118 | compares the two streams and prints only counts. `-walletsqliteloadcheck=FILE` | ||
| 119 | parses an export with the same record types the loader uses. | ||
| 120 | `-walletsqliterestore=FILE` rebuilds a `wallet.dat` from an export in an empty | ||
| 121 | data directory. Failed exports and restores remove their incomplete output. | ||
| 122 | |||
| 123 | ## `blkindex.dat` | ||
| 124 | |||
| 125 | `blkindex.dat` is accessed through `CTxDB`. | ||
| 126 | |||
| 127 | | Key shape | Value | Rebuildable? | Meaning | | ||
| 128 | |---|---|---:|---| | ||
| 129 | | `("tx", txid)` | `CTxIndex` | Yes | Transaction disk position and spent-output index state. | | ||
| 130 | | `("owner", hash160, CDiskTxPos)` | `int height` | Yes | Legacy owner transaction index cursor range. | | ||
| 131 | | `("blockindex", blockhash)` | `CDiskBlockIndex` | Yes | Block index entry. | | ||
| 132 | | `"hashBestChain"` | `uint256` | Yes | Current best-chain tip hash. | | ||
| 133 | |||
| 134 | `blkindex.dat` can be rebuilt from `blk*.dat` plus consensus validation. A | ||
| 135 | future migration may therefore prefer a rebuild path over a byte-preserving | ||
| 136 | conversion path. | ||
| 137 | |||
| 138 | ## Other Legacy Stores | ||
| 139 | |||
| 140 | None. Upstream still documents `reviews.dat` (`CReviewDB`) and `market.dat` | ||
| 141 | (`CMarketDB`) here; this fork deleted the 2009 marketplace outright, along | ||
| 142 | with `CReviewDB`, `market.cpp` and `market.h`, so neither file is opened or | ||
| 143 | created by this tree. A datadir carrying them from an older build is simply | ||
| 144 | ignored. | ||
| 145 | |||
| 146 | The old IP address database (`addr.dat`) has been removed. Peer discovery is | ||
| 147 | handled by Nostr, `.btf`, rendezvous relays, and direct onion peers. | ||
| 148 | |||
| 149 | ## Migration Order (shipped in v1.2.20) | ||
| 150 | |||
| 151 | 1. Storage self-tests were added around Berkeley DB behavior first. | ||
| 152 | 2. The SQLite backend landed behind an explicit flag, then behind a | ||
| 153 | `wallet-backend` marker and a GUI conversion wizard. | ||
| 154 | 3. BDB-to-SQLite migration is a one-way copy that leaves `wallet.dat` as a backup. | ||
| 155 | 4. SQLite became the default for new wallets only after cross-version restore, | ||
| 156 | encryption, backup, and recovery-audit tests passed -- and a live coin-proof | ||
| 157 | of receive, spend, restart, and encrypt on real mainnet funds. | ||
| 158 | 5. Treat `blkindex.dat` separately; it is safer to rebuild than to migrate under | ||
| 159 | pressure. | ||