diff options
| author | bitflash <dev@bitflash.network> | 2026-08-18 16:14:19 -0300 |
|---|---|---|
| committer | bitflash <dev@bitflash.network> | 2026-08-18 16:14:19 -0300 |
| commit | 3f94ec0649f935d00de49ad7b55026317dc64a27 (patch) | |
| tree | e67ff06c8341889cf90cbbc3b835507a90510b64 /src/db.cpp | |
| parent | f3fb7ce6759ac98a7cc39d586fc2824982c74acd (diff) | |
wallet: make SQLite the default backend for new wallets
A fresh install with no wallet.dat now starts on the SQLite backend and
creates wallet.sqlite, instead of a Berkeley DB wallet.dat. The choice is
recorded in a plain-text <datadir>/wallet-backend marker so it survives a
restart without a command-line flag.
Backend resolution when no -walletbackend is given: an existing
wallet.sqlite (or a "sqlite" marker) stays on SQLite; an existing
wallet.dat stays on Berkeley DB -- nothing is converted behind the user;
a fresh datadir starts on SQLite. An explicit -walletbackend=bdb or a
"bdb" marker forces Berkeley DB and overrides the default.
Adds CreateNewSQLiteWallet() (WalletSQLiteRuntimeOpen gains fMustExist so
the create path can make a new file) which mints the first default key
straight into the SQLite store via the same FinishLoadedWallet() call the
Berkeley DB create path uses, then cleans up on failure. Marker read/write
helpers are plain text, hand-editable.
New wallet-backend-default self-test proves the resolution in child
processes (fresh->SQLite+marker, existing wallet.dat->BDB, "bdb"
marker->BDB, explicit flag->wallet.dat). The three wallet.dat-specific
suites now ask for -walletbackend=bdb explicitly, since a flagless fresh
datadir is SQLite now. All wallet suites pass.
Diffstat (limited to 'src/db.cpp')
| -rw-r--r-- | src/db.cpp | 91 |
1 files changed, 89 insertions, 2 deletions
| @@ -101,10 +101,13 @@ bool WalletSQLiteRuntimeActive() | |||
| 101 | return pWalletSQLiteRuntime != NULL; | 101 | return pWalletSQLiteRuntime != NULL; |
| 102 | } | 102 | } |
| 103 | 103 | ||
| 104 | bool WalletSQLiteRuntimeOpen(const string& strPath, string& strErrorRet) | 104 | bool WalletSQLiteRuntimeOpen(const string& strPath, string& strErrorRet, bool fMustExist) |
| 105 | { | 105 | { |
| 106 | strErrorRet.clear(); | 106 | strErrorRet.clear(); |
| 107 | if (!FileExists(strPath.c_str())) | 107 | // Callers that load an existing wallet want the clear "does not exist" |
| 108 | // message rather than silently creating a blank one; the create path passes | ||
| 109 | // fMustExist=false so Open() (SQLITE_OPEN_CREATE) can make a fresh file. | ||
| 110 | if (fMustExist && !FileExists(strPath.c_str())) | ||
| 108 | { | 111 | { |
| 109 | strErrorRet = strprintf("SQLite wallet does not exist: %s", | 112 | strErrorRet = strprintf("SQLite wallet does not exist: %s", |
| 110 | strPath.c_str()); | 113 | strPath.c_str()); |
| @@ -230,6 +233,47 @@ bool WalletSQLiteRuntimeCheckpoint(string& strErrorRet) | |||
| 230 | return pWalletSQLiteRuntime->Checkpoint(strErrorRet); | 233 | return pWalletSQLiteRuntime->Checkpoint(strErrorRet); |
| 231 | } | 234 | } |
| 232 | 235 | ||
| 236 | // The persistent record of which backend this datadir uses, so the choice | ||
| 237 | // survives a restart without a command-line flag. A plain text file holding | ||
| 238 | // "sqlite" or "bdb" -- visible and hand-editable on purpose, no hidden state. | ||
| 239 | static string WalletBackendMarkerPath() | ||
| 240 | { | ||
| 241 | return GetAppDir() + "/wallet-backend"; | ||
| 242 | } | ||
| 243 | |||
| 244 | string ReadWalletBackendMarker() | ||
| 245 | { | ||
| 246 | FILE* pf = fopen(WalletBackendMarkerPath().c_str(), "rb"); | ||
| 247 | if (!pf) | ||
| 248 | return ""; | ||
| 249 | char buf[16] = {0}; | ||
| 250 | size_t n = fread(buf, 1, sizeof(buf) - 1, pf); | ||
| 251 | fclose(pf); | ||
| 252 | string s(buf, n); | ||
| 253 | while (!s.empty() && isspace((unsigned char)s[s.size() - 1])) | ||
| 254 | s.erase(s.size() - 1); | ||
| 255 | while (!s.empty() && isspace((unsigned char)s[0])) | ||
| 256 | s.erase(0, 1); | ||
| 257 | if (s == "sqlite" || s == "bdb") | ||
| 258 | return s; | ||
| 259 | return ""; | ||
| 260 | } | ||
| 261 | |||
| 262 | bool WriteWalletBackendMarker(const string& strBackend) | ||
| 263 | { | ||
| 264 | if (strBackend != "sqlite" && strBackend != "bdb") | ||
| 265 | return false; | ||
| 266 | FILE* pf = fopen(WalletBackendMarkerPath().c_str(), "wb"); | ||
| 267 | if (!pf) | ||
| 268 | return false; | ||
| 269 | bool fOk = fwrite(strBackend.c_str(), 1, strBackend.size(), pf) == strBackend.size(); | ||
| 270 | if (fputc('\n', pf) == EOF) | ||
| 271 | fOk = false; | ||
| 272 | if (fclose(pf) != 0) | ||
| 273 | fOk = false; | ||
| 274 | return fOk; | ||
| 275 | } | ||
| 276 | |||
| 233 | 277 | ||
| 234 | CDB::CDB(const char* pszFile, const char* pszMode, bool fTxn) : pdb(NULL) | 278 | CDB::CDB(const char* pszFile, const char* pszMode, bool fTxn) : pdb(NULL) |
| 235 | { | 279 | { |
| @@ -1609,6 +1653,49 @@ bool LoadWalletFromSQLiteRuntime(const string& strPath) | |||
| 1609 | return true; | 1653 | return true; |
| 1610 | } | 1654 | } |
| 1611 | 1655 | ||
| 1656 | // Create a brand-new wallet directly in the SQLite backend. For a fresh install | ||
| 1657 | // where SQLite is the default there is no wallet.dat to export from, so open a | ||
| 1658 | // new wallet.sqlite (Open() creates the file and its schema) and let | ||
| 1659 | // FinishLoadedWallet mint the first default key straight into it -- the same | ||
| 1660 | // call the Berkeley DB create path uses, so a new wallet is identical either | ||
| 1661 | // way. Refuses to touch an existing file, and cleans up on failure so a broken | ||
| 1662 | // half-initialised wallet.sqlite is never left for the next start to load. | ||
| 1663 | bool CreateNewSQLiteWallet(const string& strPath) | ||
| 1664 | { | ||
| 1665 | strWalletLoadError.clear(); | ||
| 1666 | |||
| 1667 | if (FileExists(strPath.c_str())) | ||
| 1668 | { | ||
| 1669 | strWalletLoadError = strprintf("SQLite wallet already exists: %s", | ||
| 1670 | strPath.c_str()); | ||
| 1671 | printf("CreateNewSQLiteWallet: %s\n", strWalletLoadError.c_str()); | ||
| 1672 | return false; | ||
| 1673 | } | ||
| 1674 | |||
| 1675 | string strError; | ||
| 1676 | if (!WalletSQLiteRuntimeOpen(strPath, strError, false)) | ||
| 1677 | { | ||
| 1678 | strWalletLoadError = strError; | ||
| 1679 | printf("CreateNewSQLiteWallet: cannot create SQLite wallet: %s\n", | ||
| 1680 | strError.c_str()); | ||
| 1681 | return false; | ||
| 1682 | } | ||
| 1683 | |||
| 1684 | vector<unsigned char> vchNoDefaultKey; | ||
| 1685 | if (!FinishLoadedWallet(vchNoDefaultKey, true)) | ||
| 1686 | { | ||
| 1687 | WalletSQLiteRuntimeClose(); | ||
| 1688 | remove(strPath.c_str()); | ||
| 1689 | remove((strPath + "-wal").c_str()); | ||
| 1690 | remove((strPath + "-shm").c_str()); | ||
| 1691 | if (strWalletLoadError.empty()) | ||
| 1692 | strWalletLoadError = "could not initialise the new SQLite wallet"; | ||
| 1693 | return false; | ||
| 1694 | } | ||
| 1695 | |||
| 1696 | return true; | ||
| 1697 | } | ||
| 1698 | |||
| 1612 | 1699 | ||
| 1613 | // Write a copy of wallet.dat that can be opened anywhere. | 1700 | // Write a copy of wallet.dat that can be opened anywhere. |
| 1614 | // | 1701 | // |