diff options
| author | Bitflash <admin@bitflash.network> | 2026-08-18 10:28:04 -0300 |
|---|---|---|
| committer | Bitflash <admin@bitflash.network> | 2026-08-18 10:28:04 -0300 |
| commit | 243b635267b6d34ef3b4b50ed559f743db161ad7 (patch) | |
| tree | 914f2851ce35919230c51ca083d3a964d6722408 /src/db.cpp | |
| parent | a6eb8dab830be3135c054ae3ae442886f1867b4e (diff) | |
| parent | 00c7aaed74e57da18598faa6751b7720598de3bd (diff) | |
Merge pull request 'wallet: run the node on a SQLite backend (opt-in)' (#59) from wallet-sqlite-activate into main
Diffstat (limited to 'src/db.cpp')
| -rw-r--r-- | src/db.cpp | 107 |
1 files changed, 107 insertions, 0 deletions
| @@ -124,6 +124,13 @@ void WalletSQLiteRuntimeClose() | |||
| 124 | { | 124 | { |
| 125 | if (pWalletSQLiteRuntime) | 125 | if (pWalletSQLiteRuntime) |
| 126 | { | 126 | { |
| 127 | // Fold the write-ahead log into the main file on the way out. WAL + | ||
| 128 | // synchronous=FULL already makes every committed write durable across a | ||
| 129 | // kill, so this is housekeeping, not the thing that protects the data: | ||
| 130 | // if it fails, or the node is killed before it runs, the wallet is | ||
| 131 | // still whole. Best effort, never throws. | ||
| 132 | string strCheckpointError; | ||
| 133 | pWalletSQLiteRuntime->Checkpoint(strCheckpointError); | ||
| 127 | delete pWalletSQLiteRuntime; | 134 | delete pWalletSQLiteRuntime; |
| 128 | pWalletSQLiteRuntime = NULL; | 135 | pWalletSQLiteRuntime = NULL; |
| 129 | } | 136 | } |
| @@ -1426,6 +1433,106 @@ bool LoadWalletFromSQLite(const string& strPath) | |||
| 1426 | return FinishLoadedWallet(visitor.vchDefaultKey, false); | 1433 | return FinishLoadedWallet(visitor.vchDefaultKey, false); |
| 1427 | } | 1434 | } |
| 1428 | 1435 | ||
| 1436 | // Open a SQLite wallet read-write and keep it open as the active runtime | ||
| 1437 | // backend, then load its records into memory the same way LoadWalletFromSQLite | ||
| 1438 | // does. Unlike the read-only staging path, this leaves pWalletSQLiteRuntime set | ||
| 1439 | // so every later CWalletDB read/write/erase routes to this file for the life of | ||
| 1440 | // the process. The Berkeley DB wallet.dat is never opened. | ||
| 1441 | bool LoadWalletFromSQLiteRuntime(const string& strPath) | ||
| 1442 | { | ||
| 1443 | strWalletLoadError.clear(); | ||
| 1444 | |||
| 1445 | if (!FileExists(strPath.c_str())) | ||
| 1446 | { | ||
| 1447 | strWalletLoadError = strprintf("SQLite wallet does not exist: %s", | ||
| 1448 | strPath.c_str()); | ||
| 1449 | printf("LoadWallet: %s\n", strWalletLoadError.c_str()); | ||
| 1450 | return false; | ||
| 1451 | } | ||
| 1452 | |||
| 1453 | string strError; | ||
| 1454 | if (!WalletSQLiteRuntimeOpen(strPath, strError)) | ||
| 1455 | { | ||
| 1456 | strWalletLoadError = strError; | ||
| 1457 | printf("LoadWallet: cannot open SQLite wallet backend: %s\n", | ||
| 1458 | strError.c_str()); | ||
| 1459 | return false; | ||
| 1460 | } | ||
| 1461 | |||
| 1462 | CSQLiteWalletRuntimeLoadVisitor visitor; | ||
| 1463 | try | ||
| 1464 | { | ||
| 1465 | CRITICAL_BLOCK(cs_mapKeys) | ||
| 1466 | CRITICAL_BLOCK(cs_mapWallet) | ||
| 1467 | { | ||
| 1468 | if (!pWalletSQLiteRuntime->ScanRecords(visitor, strError)) | ||
| 1469 | { | ||
| 1470 | WalletSQLiteRuntimeClose(); | ||
| 1471 | if (strWalletLoadError.empty()) | ||
| 1472 | strWalletLoadError = strError; | ||
| 1473 | printf("LoadWallet: SQLite wallet backend could not be read. " | ||
| 1474 | "Failed while handling a '%s' record: %s\n", | ||
| 1475 | visitor.strLastType.c_str(), strError.c_str()); | ||
| 1476 | return false; | ||
| 1477 | } | ||
| 1478 | } | ||
| 1479 | } | ||
| 1480 | catch (const std::exception& e) | ||
| 1481 | { | ||
| 1482 | WalletSQLiteRuntimeClose(); | ||
| 1483 | strWalletLoadError = strprintf( | ||
| 1484 | "SQLite wallet backend could not be read while handling a '%s' record: %s", | ||
| 1485 | visitor.strLastType.c_str(), e.what()); | ||
| 1486 | printf("LoadWallet: %s\n", strWalletLoadError.c_str()); | ||
| 1487 | return false; | ||
| 1488 | } | ||
| 1489 | catch (...) | ||
| 1490 | { | ||
| 1491 | WalletSQLiteRuntimeClose(); | ||
| 1492 | strWalletLoadError = strprintf( | ||
| 1493 | "SQLite wallet backend could not be read while handling a '%s' record", | ||
| 1494 | visitor.strLastType.c_str()); | ||
| 1495 | printf("LoadWallet: %s\n", strWalletLoadError.c_str()); | ||
| 1496 | return false; | ||
| 1497 | } | ||
| 1498 | |||
| 1499 | // Refuse an empty or non-wallet SQLite file up front, with a message that | ||
| 1500 | // names the likely cause. FinishLoadedWallet below already rejects a | ||
| 1501 | // missing default key (it is the fMayCreateDefaultKey=false path), but its | ||
| 1502 | // wording -- "no usable default public key" -- reads as corruption when the | ||
| 1503 | // real story is usually "this file was never an exported wallet". A blank | ||
| 1504 | // wallet.sqlite left by a typo or a half-run export should say so. | ||
| 1505 | if (visitor.vchDefaultKey.empty()) | ||
| 1506 | { | ||
| 1507 | WalletSQLiteRuntimeClose(); | ||
| 1508 | strWalletLoadError = | ||
| 1509 | "SQLite wallet has no default key record; it may be empty or not a " | ||
| 1510 | "wallet export. Create it with -walletsqliteexport."; | ||
| 1511 | printf("LoadWallet: %s\n", strWalletLoadError.c_str()); | ||
| 1512 | return false; | ||
| 1513 | } | ||
| 1514 | |||
| 1515 | if (!ReconcileLoadedWalletMetadata(visitor.fHaveStoredMineMode, | ||
| 1516 | visitor.fHaveStoredHDCoinType)) | ||
| 1517 | { | ||
| 1518 | WalletSQLiteRuntimeClose(); | ||
| 1519 | if (strWalletLoadError.empty()) | ||
| 1520 | strWalletLoadError = "SQLite wallet metadata is not supported by this build"; | ||
| 1521 | return false; | ||
| 1522 | } | ||
| 1523 | |||
| 1524 | // Never fabricate a default key: an export always carries one, and a file | ||
| 1525 | // that does not is refused with the wallet left open to no writes rather | ||
| 1526 | // than quietly minted into a new identity. | ||
| 1527 | if (!FinishLoadedWallet(visitor.vchDefaultKey, false)) | ||
| 1528 | { | ||
| 1529 | WalletSQLiteRuntimeClose(); | ||
| 1530 | return false; | ||
| 1531 | } | ||
| 1532 | |||
| 1533 | return true; | ||
| 1534 | } | ||
| 1535 | |||
| 1429 | 1536 | ||
| 1430 | // Write a copy of wallet.dat that can be opened anywhere. | 1537 | // Write a copy of wallet.dat that can be opened anywhere. |
| 1431 | // | 1538 | // |