diff options
| author | bitflash-maintainer <noreply@bitflash.invalid> | 2026-09-01 17:14:12 +0000 |
|---|---|---|
| committer | bitflash-maintainer <noreply@bitflash.invalid> | 2026-09-01 17:14:12 +0000 |
| commit | b4f0bc693ef7175702f82bcb2110b627922e8cbd (patch) | |
| tree | 73435feb1a076dfba94d8143d7d7b7784908c82f /src/main_gui.cpp | |
| parent | a1d867ecbcfc9e218408d0a11863a450243a01f9 (diff) | |
| parent | 6aa3dade77632f13189d2a3ef29897f29a5f9572 (diff) | |
Merge upstream v1.2.20 into the fork
Merges upstream tag v1.2.20 (6aa3dade) into our 1.2.19+sec tree. The merge
base is bc3de30's descendant 9e39a50 -- upstream's own v1.2.19 -- so this is
an ordinary three-way merge, not a replay. Five conflict blocks in four
files, all resolved below.
No consensus change. CheckBlock, ConnectBlock, DisconnectBlock, ConnectInputs,
AcceptBlock, AcceptTransaction, GetNextWorkRequired and GetBlockValue hash
identical to v1.2.19; script.cpp and script.h are byte-identical on both
sides. main.cpp is +3 lines and main.h +2, all wallet-backend plumbing.
rpc.cpp is untouched, so the payout ledger arrives unchanged.
Makefile, VERSION. OURS, renumbered. 1.2.20+sec, for the same reason 1.2.19
carried +sec: this tree is not the upstream release of that number and the
string names every release artifact.
Makefile, AppImage recipe. OURS for the AppDir path, THEIRS for the bundled
library. Upstream's hunk reverts the icon paths to a hardcoded
/tmp/bitflash.AppDir, which is the local-user pre-placement hazard the fork
moved out of /tmp in the first place; taking their side wholesale would have
reintroduced it silently, inside a conflict about something else. The AppDir
stays $(APPDIR), and libsqlite3.so.0 joins the bundled list, which the new
backend genuinely needs.
src/Makefile, src/makefile.mingw, HEADERS. BOTH. Ours drops market.h,
theirs adds wallet_sqlite.h; the resolution does both. NODE_OBJS auto-merged
correctly in both files -- obj/wallet_sqlite.o present, obj/market.o still
gone -- and was verified rather than assumed, because that line has trapped
this fork before.
src/selftest.cpp, known-tests list. BOTH, union. Upstream adds eight
wallet-storage tests, we keep payout-ledger. The dispatch chain itself
auto-merged and still routes payout-ledger to RunPayoutLedgerSelfTest.
Hardening verified intact after merge: the TLS 1.2 floor in nostr.cpp, the
/rvrelay pin, opt-in managed Tor, strict sig3-on-onion descriptor
verification, and the marketplace removal. Upstream shipped no build logs or
__pycache__ this time; the three added files are docs/storage.md and
src/wallet_sqlite.{cpp,h}.
The SQLite backend this release introduces is NOT enabled here. An existing
wallet.dat resolves to Berkeley DB on every branch of the new selection
logic, and the conversion wizard is GUI-only and not compiled into the
headless node. The review findings that gate ever turning it on -- the
non-atomic backend marker, the connection-wide WriteHDMaster transaction,
and the encrypt-swap crash window -- are recorded on the tracker, not fixed
here.
Diffstat (limited to 'src/main_gui.cpp')
| -rw-r--r-- | src/main_gui.cpp | 306 |
1 files changed, 297 insertions, 9 deletions
diff --git a/src/main_gui.cpp b/src/main_gui.cpp index 211e1e2..2743429 100644 --- a/src/main_gui.cpp +++ b/src/main_gui.cpp | |||
| @@ -113,8 +113,12 @@ static void PrintUsage() | |||
| 113 | printf(" /debug\n"); | 113 | printf(" /debug\n"); |
| 114 | printf(" /gen\n"); | 114 | printf(" /gen\n"); |
| 115 | printf(" /nogui or /daemon\n"); | 115 | printf(" /nogui or /daemon\n"); |
| 116 | printf(" /selftest=wallet-keypool, wallet-hd, wallet-format, wallet-crypto, wallet-encrypt,\n"); | 116 | printf(" /selftest=wallet-keypool, wallet-hd, wallet-format, wallet-storage-sanity,\n"); |
| 117 | printf(" net-message, consensus-limits, pool-stratum, parse-money, socks5-proxy, or managed-tor\n"); | 117 | printf(" db-env-reopen, wallet-sqlite, wallet-sqlite-migration,\n"); |
| 118 | printf(" wallet-crypto, wallet-encrypt, wallet-portability,\n"); | ||
| 119 | printf(" net-message,\n"); | ||
| 120 | printf(" consensus-limits, pool-stratum,\n"); | ||
| 121 | printf(" parse-money, socks5-proxy, or managed-tor\n"); | ||
| 118 | printf("\n"); | 122 | printf("\n"); |
| 119 | printf("Mining mode:\n"); | 123 | printf("Mining mode:\n"); |
| 120 | printf(" /operator\n"); | 124 | printf(" /operator\n"); |
| @@ -175,6 +179,23 @@ static void PrintUsage() | |||
| 175 | printf(" /recoveryaudit (show how much spendable balance is\n"); | 179 | printf(" /recoveryaudit (show how much spendable balance is\n"); |
| 176 | printf(" covered by the recovery phrase;\n"); | 180 | printf(" covered by the recovery phrase;\n"); |
| 177 | printf(" exits 2 when wallet.dat is still needed)\n"); | 181 | printf(" exits 2 when wallet.dat is still needed)\n"); |
| 182 | printf(" /walletstorageaudit (count wallet.dat record types without\n"); | ||
| 183 | printf(" printing wallet values, then exit)\n"); | ||
| 184 | printf(" /walletstorageauditjson=FILE\n"); | ||
| 185 | printf(" (write the same audit as deterministic JSON)\n"); | ||
| 186 | printf(" /walletstoragecheck (fail closed on inconsistent or unsafe\n"); | ||
| 187 | printf(" wallet.dat storage state)\n"); | ||
| 188 | printf(" /walletsqliteexport=FILE (copy raw wallet.dat records into an\n"); | ||
| 189 | printf(" SQLite store, then exit)\n"); | ||
| 190 | printf(" /walletsqliteverify=FILE (compare wallet.dat with a SQLite export,\n"); | ||
| 191 | printf(" printing counts only, then exit)\n"); | ||
| 192 | printf(" /walletsqliterestore=FILE (rebuild wallet.dat from a SQLite export in\n"); | ||
| 193 | printf(" an empty data directory, then exit)\n"); | ||
| 194 | printf(" /walletsqliteloadcheck=FILE\n"); | ||
| 195 | printf(" (parse a SQLite export like the wallet loader)\n"); | ||
| 196 | printf(" /walletsqlite=FILE (stage-load a SQLite wallet export, then exit)\n"); | ||
| 197 | printf(" /walletbackend=sqlite (opt-in: run the node on <datadir>/wallet.sqlite\n"); | ||
| 198 | printf(" instead of wallet.dat; export one first)\n"); | ||
| 178 | printf(" /rescan (walk the chain for coins this wallet owns\n"); | 199 | printf(" /rescan (walk the chain for coins this wallet owns\n"); |
| 179 | printf(" but never recorded, then exit)\n"); | 200 | printf(" but never recorded, then exit)\n"); |
| 180 | printf("\n"); | 201 | printf("\n"); |
| @@ -530,10 +551,119 @@ int main(int argc, char* argv[]) | |||
| 530 | 551 | ||
| 531 | ParseStartupArguments(argc, argv); | 552 | ParseStartupArguments(argc, argv); |
| 532 | 553 | ||
| 554 | #ifdef _WIN32 | ||
| 555 | // Set by the GUI "Restart Now" button: give the previous instance a moment | ||
| 556 | // to release the network port and the block-index files before this one | ||
| 557 | // opens them, so a relaunch does not race the process it is replacing. | ||
| 558 | if (arg(argc, argv, "/restartwait") || arg(argc, argv, "-restartwait")) | ||
| 559 | Sleep(2500); | ||
| 560 | #endif | ||
| 561 | |||
| 562 | // Hidden self-test helper. It must run before LoadWallet(): several | ||
| 563 | // storage-sanity scenarios deliberately make wallet.dat unsafe to load. | ||
| 564 | string strSelfTestMutateWallet = | ||
| 565 | argval2(argc, argv, "/selftestmutatewallet", "-selftestmutatewallet"); | ||
| 566 | if (!strSelfTestMutateWallet.empty()) | ||
| 567 | return RunSelfTestMutateWallet(strSelfTestMutateWallet); | ||
| 568 | |||
| 533 | string strSelfTest = argval2(argc, argv, "/selftest", "-selftest"); | 569 | string strSelfTest = argval2(argc, argv, "/selftest", "-selftest"); |
| 534 | if (!strSelfTest.empty()) | 570 | if (!strSelfTest.empty()) |
| 535 | return RunSelfTest(strSelfTest); | 571 | return RunSelfTest(strSelfTest); |
| 536 | 572 | ||
| 573 | // Storage diagnostics must run before LoadWallet(). Their job is to | ||
| 574 | // explain wallet.dat states that the normal wallet loader may refuse. | ||
| 575 | string strWalletStorageAuditJson = | ||
| 576 | argval2(argc, argv, "/walletstorageauditjson", "-walletstorageauditjson"); | ||
| 577 | bool fDiagWantsAudit = arg(argc,argv,"/walletstorageaudit") || | ||
| 578 | arg(argc,argv,"-walletstorageaudit") || | ||
| 579 | !strWalletStorageAuditJson.empty(); | ||
| 580 | bool fDiagWantsCheck = arg(argc,argv,"/walletstoragecheck") || | ||
| 581 | arg(argc,argv,"-walletstoragecheck"); | ||
| 582 | |||
| 583 | // These diagnostics normally read wallet.dat. Under -walletbackend=sqlite | ||
| 584 | // the live wallet is wallet.sqlite, so open it read-only as the active | ||
| 585 | // store and let the same scan walk the right file. This runs before the | ||
| 586 | // normal backend resolution further down, so validate the value here too. | ||
| 587 | string strDiagBackend = argval2(argc, argv, "/walletbackend", "-walletbackend"); | ||
| 588 | if ((fDiagWantsAudit || fDiagWantsCheck) && !strDiagBackend.empty() && | ||
| 589 | strDiagBackend != "sqlite" && strDiagBackend != "bdb") | ||
| 590 | { | ||
| 591 | AttachTerminal(); | ||
| 592 | fprintf(stderr, "Unknown wallet backend '%s'. Use -walletbackend=sqlite " | ||
| 593 | "or -walletbackend=bdb.\n", strDiagBackend.c_str()); | ||
| 594 | return 1; | ||
| 595 | } | ||
| 596 | bool fDiagSQLite = (strDiagBackend == "sqlite") && | ||
| 597 | (fDiagWantsAudit || fDiagWantsCheck); | ||
| 598 | if (fDiagSQLite) | ||
| 599 | { | ||
| 600 | AttachTerminal(); | ||
| 601 | string strSQLitePath = GetAppDir() + "/wallet.sqlite"; | ||
| 602 | string strOpenErr; | ||
| 603 | if (!WalletSQLiteRuntimeOpenReadOnly(strSQLitePath, strOpenErr)) | ||
| 604 | { | ||
| 605 | fprintf(stderr, "Cannot open the SQLite wallet for diagnostics: %s\n", | ||
| 606 | strOpenErr.c_str()); | ||
| 607 | return 1; | ||
| 608 | } | ||
| 609 | } | ||
| 610 | |||
| 611 | if (fDiagWantsAudit) | ||
| 612 | { | ||
| 613 | int nRet = CmdWalletStorageAudit(strWalletStorageAuditJson); | ||
| 614 | if (fDiagSQLite) | ||
| 615 | WalletSQLiteRuntimeClose(); | ||
| 616 | else | ||
| 617 | DBFlush(true); | ||
| 618 | return nRet; | ||
| 619 | } | ||
| 620 | |||
| 621 | if (fDiagWantsCheck) | ||
| 622 | { | ||
| 623 | int nRet = CmdWalletStorageCheck(); | ||
| 624 | if (fDiagSQLite) | ||
| 625 | WalletSQLiteRuntimeClose(); | ||
| 626 | else | ||
| 627 | DBFlush(true); | ||
| 628 | return nRet; | ||
| 629 | } | ||
| 630 | |||
| 631 | string strWalletSQLiteExport = | ||
| 632 | argval2(argc, argv, "/walletsqliteexport", "-walletsqliteexport"); | ||
| 633 | if (!strWalletSQLiteExport.empty()) | ||
| 634 | { | ||
| 635 | int nRet = CmdWalletSQLiteExport(strWalletSQLiteExport); | ||
| 636 | DBFlush(true); | ||
| 637 | return nRet; | ||
| 638 | } | ||
| 639 | |||
| 640 | string strWalletSQLiteVerify = | ||
| 641 | argval2(argc, argv, "/walletsqliteverify", "-walletsqliteverify"); | ||
| 642 | if (!strWalletSQLiteVerify.empty()) | ||
| 643 | { | ||
| 644 | int nRet = CmdWalletSQLiteVerify(strWalletSQLiteVerify); | ||
| 645 | DBFlush(true); | ||
| 646 | return nRet; | ||
| 647 | } | ||
| 648 | |||
| 649 | string strWalletSQLiteRestore = | ||
| 650 | argval2(argc, argv, "/walletsqliterestore", "-walletsqliterestore"); | ||
| 651 | if (!strWalletSQLiteRestore.empty()) | ||
| 652 | { | ||
| 653 | int nRet = CmdWalletSQLiteRestore(strWalletSQLiteRestore); | ||
| 654 | DBFlush(true); | ||
| 655 | return nRet; | ||
| 656 | } | ||
| 657 | |||
| 658 | string strWalletSQLiteLoadCheck = | ||
| 659 | argval2(argc, argv, "/walletsqliteloadcheck", "-walletsqliteloadcheck"); | ||
| 660 | if (!strWalletSQLiteLoadCheck.empty()) | ||
| 661 | { | ||
| 662 | int nRet = CmdWalletSQLiteLoadCheck(strWalletSQLiteLoadCheck); | ||
| 663 | DBFlush(true); | ||
| 664 | return nRet; | ||
| 665 | } | ||
| 666 | |||
| 537 | // Berkeley DB reports failure by throwing, and CDB's constructor lets it | 667 | // Berkeley DB reports failure by throwing, and CDB's constructor lets it |
| 538 | // through. Nothing on this path caught anything, so an unreadable | 668 | // through. Nothing on this path caught anything, so an unreadable |
| 539 | // blkindex.dat or wallet.dat -- one written by another platform's Berkeley | 669 | // blkindex.dat or wallet.dat -- one written by another platform's Berkeley |
| @@ -578,18 +708,171 @@ int main(int argc, char* argv[]) | |||
| 578 | printf("Loading wallet...\n"); | 708 | printf("Loading wallet...\n"); |
| 579 | try | 709 | try |
| 580 | { | 710 | { |
| 581 | if (!LoadWallet()) | 711 | string strWalletBackend = |
| 712 | argval2(argc, argv, "/walletbackend", "-walletbackend"); | ||
| 713 | string strWalletSQLite = | ||
| 714 | argval2(argc, argv, "/walletsqlite", "-walletsqlite"); | ||
| 715 | |||
| 716 | // A misspelled backend must not fall through to Berkeley DB silently -- | ||
| 717 | // someone who typed -walletbackend=sqlit meant to run on SQLite, and | ||
| 718 | // opening wallet.dat instead of telling them is the wrong surprise. | ||
| 719 | if (!strWalletBackend.empty() && | ||
| 720 | strWalletBackend != "sqlite" && strWalletBackend != "bdb") | ||
| 582 | { | 721 | { |
| 583 | // LoadWallet() explains itself into strWalletLoadError when it | 722 | AttachTerminal(); |
| 584 | // knows why -- an unsupported wallet format, for one, which is the | 723 | FatalStartupError(fHeadlessStartup, |
| 585 | // case this whole path exists to make visible. | 724 | strprintf("Unknown wallet backend '%s'.", strWalletBackend.c_str()), |
| 586 | FatalStartupError(fHeadlessStartup, "Cannot open wallet.dat.", | 725 | "Use -walletbackend=sqlite for the SQLite backend, or " |
| 587 | strWalletLoadError); | 726 | "-walletbackend=bdb for the Berkeley DB wallet.dat."); |
| 588 | return 1; | 727 | return 1; |
| 589 | } | 728 | } |
| 590 | 729 | ||
| 730 | if (strWalletBackend == "sqlite") | ||
| 731 | { | ||
| 732 | // Explicit opt-in via the flag. The node runs on | ||
| 733 | // <datadir>/wallet.sqlite and never opens wallet.dat, but the user | ||
| 734 | // has to have exported one first -- there is no silent migration, | ||
| 735 | // and wallet.dat is left | ||
| 736 | // exactly where it is so a plain restart goes back to it. | ||
| 737 | AttachTerminal(); | ||
| 738 | string strSQLitePath = GetAppDir() + "/wallet.sqlite"; | ||
| 739 | if (!FileExists(strSQLitePath.c_str())) | ||
| 740 | { | ||
| 741 | string strGuide = strprintf( | ||
| 742 | "No SQLite wallet was found at\n" | ||
| 743 | " %s\n\n" | ||
| 744 | "The SQLite wallet backend is opt-in and needs an exported\n" | ||
| 745 | "wallet first. Your Berkeley DB wallet.dat is not touched by\n" | ||
| 746 | "any of this.\n\n" | ||
| 747 | " Step 1 Export your existing wallet to SQLite:\n" | ||
| 748 | " bitflash -walletsqliteexport=\"%s\"\n" | ||
| 749 | " Step 2 Start again with the SQLite backend:\n" | ||
| 750 | " bitflash -walletbackend=sqlite\n\n" | ||
| 751 | "To go back to Berkeley DB at any time, just start without\n" | ||
| 752 | "-walletbackend=sqlite. wallet.dat is still your wallet.", | ||
| 753 | strSQLitePath.c_str(), strSQLitePath.c_str()); | ||
| 754 | FatalStartupError(fHeadlessStartup, | ||
| 755 | "The SQLite wallet backend needs an exported wallet first.", | ||
| 756 | strGuide); | ||
| 757 | return 1; | ||
| 758 | } | ||
| 759 | |||
| 760 | if (!LoadWalletFromSQLiteRuntime(strSQLitePath)) | ||
| 761 | { | ||
| 762 | FatalStartupError(fHeadlessStartup, | ||
| 763 | "Cannot open the SQLite wallet backend.", | ||
| 764 | strWalletLoadError); | ||
| 765 | return 1; | ||
| 766 | } | ||
| 767 | |||
| 768 | fprintf(stderr, | ||
| 769 | "Wallet backend: SQLite\n" | ||
| 770 | " %s\n" | ||
| 771 | "Your Berkeley DB wallet.dat is left untouched. Restart without\n" | ||
| 772 | "-walletbackend=sqlite to go back to it.\n", | ||
| 773 | strSQLitePath.c_str()); | ||
| 774 | fflush(stderr); | ||
| 775 | // Fall through and run the node normally: every CWalletDB read, | ||
| 776 | // write, and erase now routes to this SQLite file. | ||
| 777 | } | ||
| 778 | else if (!strWalletSQLite.empty()) | ||
| 779 | { | ||
| 780 | AttachTerminal(); | ||
| 781 | if (!LoadWalletFromSQLite(strWalletSQLite)) | ||
| 782 | { | ||
| 783 | FatalStartupError(fHeadlessStartup, | ||
| 784 | "Cannot open SQLite wallet export.", | ||
| 785 | strWalletLoadError); | ||
| 786 | return 1; | ||
| 787 | } | ||
| 788 | |||
| 789 | fprintf(stderr, "SQLite wallet loaded: read-only staging backend\n"); | ||
| 790 | fprintf(stderr, "SQLite runtime writes are not enabled yet; exiting before " | ||
| 791 | "network, mining, GUI, or wallet mutation starts.\n"); | ||
| 792 | fflush(stderr); | ||
| 793 | DBFlush(true); | ||
| 794 | return 0; | ||
| 795 | } | ||
| 796 | else if (strWalletBackend == "bdb") | ||
| 797 | { | ||
| 798 | // Explicit -walletbackend=bdb overrides the marker and the default: | ||
| 799 | // force Berkeley DB (LoadWallet creates wallet.dat if none exists). | ||
| 800 | if (!LoadWallet()) | ||
| 801 | { | ||
| 802 | FatalStartupError(fHeadlessStartup, "Cannot open wallet.dat.", | ||
| 803 | strWalletLoadError); | ||
| 804 | return 1; | ||
| 805 | } | ||
| 806 | } | ||
| 807 | else | ||
| 808 | { | ||
| 809 | // No explicit -walletbackend on the command line. Resolve it from | ||
| 810 | // the persistent marker, then defaults: an existing wallet.sqlite | ||
| 811 | // stays on SQLite, an existing wallet.dat stays on Berkeley DB (the | ||
| 812 | // GUI offers to convert), and a fresh install starts on SQLite -- | ||
| 813 | // the new default. wallet.dat is never touched by any of this. | ||
| 814 | string strSQLitePath = GetAppDir() + "/wallet.sqlite"; | ||
| 815 | bool fSQLiteExists = FileExists(strSQLitePath.c_str()); | ||
| 816 | bool fWalletDatExists = FileExists((GetAppDir() + "/wallet.dat").c_str()); | ||
| 817 | string strMarker = ReadWalletBackendMarker(); | ||
| 818 | |||
| 819 | bool fUseSQLite = false; | ||
| 820 | bool fCreateSQLite = false; | ||
| 821 | if (strMarker == "sqlite") | ||
| 822 | { | ||
| 823 | if (fSQLiteExists) fUseSQLite = true; | ||
| 824 | else if (fWalletDatExists) fUseSQLite = false; // marker stale; real wallet is BDB | ||
| 825 | else { fUseSQLite = true; fCreateSQLite = true; } | ||
| 826 | } | ||
| 827 | else if (strMarker == "bdb") | ||
| 828 | { | ||
| 829 | fUseSQLite = false; | ||
| 830 | } | ||
| 831 | else // no marker recorded yet | ||
| 832 | { | ||
| 833 | if (fSQLiteExists && !fWalletDatExists) fUseSQLite = true; | ||
| 834 | else if (fWalletDatExists) fUseSQLite = false; | ||
| 835 | else { fUseSQLite = true; fCreateSQLite = true; } | ||
| 836 | } | ||
| 837 | |||
| 838 | if (fUseSQLite) | ||
| 839 | { | ||
| 840 | AttachTerminal(); | ||
| 841 | bool fOk = fCreateSQLite | ||
| 842 | ? CreateNewSQLiteWallet(strSQLitePath) | ||
| 843 | : LoadWalletFromSQLiteRuntime(strSQLitePath); | ||
| 844 | if (!fOk) | ||
| 845 | { | ||
| 846 | FatalStartupError(fHeadlessStartup, | ||
| 847 | fCreateSQLite ? "Cannot create the SQLite wallet." | ||
| 848 | : "Cannot open the SQLite wallet.", | ||
| 849 | strWalletLoadError); | ||
| 850 | return 1; | ||
| 851 | } | ||
| 852 | // Record the choice so it is stable from here on. | ||
| 853 | if (ReadWalletBackendMarker() != "sqlite") | ||
| 854 | WriteWalletBackendMarker("sqlite"); | ||
| 855 | fprintf(stderr, "Wallet backend: SQLite\n %s\n%s", | ||
| 856 | strSQLitePath.c_str(), | ||
| 857 | fCreateSQLite ? "A new wallet was created here.\n" : ""); | ||
| 858 | fflush(stderr); | ||
| 859 | // Fall through and run the node; CWalletDB routes to this file. | ||
| 860 | } | ||
| 861 | else if (!LoadWallet()) | ||
| 862 | { | ||
| 863 | // LoadWallet() explains itself into strWalletLoadError when it | ||
| 864 | // knows why -- an unsupported wallet format, for one, which is | ||
| 865 | // the case this whole path exists to make visible. | ||
| 866 | FatalStartupError(fHeadlessStartup, "Cannot open wallet.dat.", | ||
| 867 | strWalletLoadError); | ||
| 868 | return 1; | ||
| 869 | } | ||
| 870 | } | ||
| 871 | |||
| 591 | // After the block index, so there is a chain to compare the wallet | 872 | // After the block index, so there is a chain to compare the wallet |
| 592 | // against, and before anything reports a balance. | 873 | // against, and before anything reports a balance. Works on either |
| 874 | // backend: RescanSpentFlags writes corrected flags through CWalletDB, | ||
| 875 | // which routes to SQLite when that backend is active. | ||
| 593 | RescanSpentFlags(); | 876 | RescanSpentFlags(); |
| 594 | } | 877 | } |
| 595 | catch (const std::exception& e) | 878 | catch (const std::exception& e) |
| @@ -858,6 +1141,10 @@ int main(int argc, char* argv[]) | |||
| 858 | // called here, which is why a wallet.dat copied elsewhere would not | 1141 | // called here, which is why a wallet.dat copied elsewhere would not |
| 859 | // open -- issue #40. Not optional. | 1142 | // open -- issue #40. Not optional. |
| 860 | DBFlush(true); | 1143 | DBFlush(true); |
| 1144 | // Checkpoint and close the SQLite wallet backend if one is active. A | ||
| 1145 | // no-op on the Berkeley DB path. Safe to kill before this runs: WAL + | ||
| 1146 | // synchronous=FULL already made every committed write durable. | ||
| 1147 | WalletSQLiteRuntimeClose(); | ||
| 861 | #ifdef _WIN32 | 1148 | #ifdef _WIN32 |
| 862 | // wallet.dat is safely flushed and closed now; let a pending console | 1149 | // wallet.dat is safely flushed and closed now; let a pending console |
| 863 | // control handler (CLOSE/LOGOFF/SHUTDOWN) return so the OS can finish. | 1150 | // control handler (CLOSE/LOGOFF/SHUTDOWN) return so the OS can finish. |
| @@ -874,6 +1161,7 @@ int main(int argc, char* argv[]) | |||
| 874 | StopNode(); | 1161 | StopNode(); |
| 875 | BtfStopManagedTor(); | 1162 | BtfStopManagedTor(); |
| 876 | DBFlush(true); | 1163 | DBFlush(true); |
| 1164 | WalletSQLiteRuntimeClose(); | ||
| 877 | return ret; | 1165 | return ret; |
| 878 | #endif | 1166 | #endif |
| 879 | } | 1167 | } |