diff options
| author | bitflash-maintainer <noreply@bitflash.invalid> | 2026-09-03 22:33:20 +0000 |
|---|---|---|
| committer | bitflash-maintainer <noreply@bitflash.invalid> | 2026-09-03 22:33:20 +0000 |
| commit | b810d86752ddb2674118f737582c924bb9eb74c1 (patch) | |
| tree | 1ceadf421609a2e58da81103165a2fb7085387de /src/main_gui.cpp | |
| parent | db44eac5d347c229539946e8d61f1ff0d1f68001 (diff) | |
| parent | 5ef59833756da6f47274cb990eb874fb0ed99019 (diff) | |
merge: upstream 1.2.20 into deploy/all-2026-08-24
# Conflicts:
# Makefile
Diffstat (limited to 'src/main_gui.cpp')
| -rw-r--r-- | src/main_gui.cpp | 335 |
1 files changed, 326 insertions, 9 deletions
diff --git a/src/main_gui.cpp b/src/main_gui.cpp index 0e64985..dd001c8 100644 --- a/src/main_gui.cpp +++ b/src/main_gui.cpp | |||
| @@ -115,8 +115,12 @@ static void PrintUsage() | |||
| 115 | printf(" /maxdebugfilesize=N (roll debug.log at N MB, default 1024; 0 = never)\n"); | 115 | printf(" /maxdebugfilesize=N (roll debug.log at N MB, default 1024; 0 = never)\n"); |
| 116 | printf(" /gen\n"); | 116 | printf(" /gen\n"); |
| 117 | printf(" /nogui or /daemon\n"); | 117 | printf(" /nogui or /daemon\n"); |
| 118 | printf(" /selftest=wallet-keypool, wallet-hd, wallet-format, wallet-crypto, wallet-encrypt,\n"); | 118 | printf(" /selftest=wallet-keypool, wallet-hd, wallet-format, wallet-storage-sanity,\n"); |
| 119 | printf(" net-message, consensus-limits, pool-stratum, parse-money, socks5-proxy, or managed-tor\n"); | 119 | printf(" db-env-reopen, wallet-sqlite, wallet-sqlite-migration,\n"); |
| 120 | printf(" wallet-crypto, wallet-encrypt, wallet-portability,\n"); | ||
| 121 | printf(" net-message,\n"); | ||
| 122 | printf(" consensus-limits, pool-stratum,\n"); | ||
| 123 | printf(" parse-money, socks5-proxy, or managed-tor\n"); | ||
| 120 | printf("\n"); | 124 | printf("\n"); |
| 121 | printf("Mining mode:\n"); | 125 | printf("Mining mode:\n"); |
| 122 | printf(" /operator\n"); | 126 | printf(" /operator\n"); |
| @@ -177,6 +181,26 @@ static void PrintUsage() | |||
| 177 | printf(" /recoveryaudit (show how much spendable balance is\n"); | 181 | printf(" /recoveryaudit (show how much spendable balance is\n"); |
| 178 | printf(" covered by the recovery phrase;\n"); | 182 | printf(" covered by the recovery phrase;\n"); |
| 179 | printf(" exits 2 when wallet.dat is still needed)\n"); | 183 | printf(" exits 2 when wallet.dat is still needed)\n"); |
| 184 | printf(" /walletstorageaudit (count wallet.dat record types without\n"); | ||
| 185 | printf(" printing wallet values, then exit)\n"); | ||
| 186 | printf(" /walletstorageauditjson=FILE\n"); | ||
| 187 | printf(" (write the same audit as deterministic JSON)\n"); | ||
| 188 | printf(" /walletstoragecheck (fail closed on inconsistent or unsafe\n"); | ||
| 189 | printf(" wallet.dat storage state)\n"); | ||
| 190 | printf(" /walletsqliteexport=FILE (copy raw wallet.dat records into an\n"); | ||
| 191 | printf(" SQLite store, then exit)\n"); | ||
| 192 | printf(" /walletsqliteverify=FILE (compare wallet.dat with a SQLite export,\n"); | ||
| 193 | printf(" printing counts only, then exit)\n"); | ||
| 194 | printf(" /walletsqliterestore=FILE (rebuild wallet.dat from a SQLite export in\n"); | ||
| 195 | printf(" an empty data directory, then exit)\n"); | ||
| 196 | printf(" /walletsqliteloadcheck=FILE\n"); | ||
| 197 | printf(" (parse a SQLite export like the wallet loader)\n"); | ||
| 198 | printf(" /walletsqlite=FILE (stage-load a SQLite wallet export, then exit)\n"); | ||
| 199 | printf(" /walletbackend=sqlite (opt-in: run the node on <datadir>/wallet.sqlite\n"); | ||
| 200 | printf(" instead of wallet.dat; export one first)\n"); | ||
| 201 | printf(" /createwallet (headless only: permit creating a new wallet in a\n"); | ||
| 202 | printf(" datadir that has none -- otherwise refused, since\n"); | ||
| 203 | printf(" a missing wallet is usually a mount/backup fault)\n"); | ||
| 180 | printf(" /rescan (walk the chain for coins this wallet owns\n"); | 204 | printf(" /rescan (walk the chain for coins this wallet owns\n"); |
| 181 | printf(" but never recorded, then exit)\n"); | 205 | printf(" but never recorded, then exit)\n"); |
| 182 | printf("\n"); | 206 | printf("\n"); |
| @@ -580,10 +604,119 @@ int main(int argc, char* argv[]) | |||
| 580 | 604 | ||
| 581 | ParseStartupArguments(argc, argv); | 605 | ParseStartupArguments(argc, argv); |
| 582 | 606 | ||
| 607 | #ifdef _WIN32 | ||
| 608 | // Set by the GUI "Restart Now" button: give the previous instance a moment | ||
| 609 | // to release the network port and the block-index files before this one | ||
| 610 | // opens them, so a relaunch does not race the process it is replacing. | ||
| 611 | if (arg(argc, argv, "/restartwait") || arg(argc, argv, "-restartwait")) | ||
| 612 | Sleep(2500); | ||
| 613 | #endif | ||
| 614 | |||
| 615 | // Hidden self-test helper. It must run before LoadWallet(): several | ||
| 616 | // storage-sanity scenarios deliberately make wallet.dat unsafe to load. | ||
| 617 | string strSelfTestMutateWallet = | ||
| 618 | argval2(argc, argv, "/selftestmutatewallet", "-selftestmutatewallet"); | ||
| 619 | if (!strSelfTestMutateWallet.empty()) | ||
| 620 | return RunSelfTestMutateWallet(strSelfTestMutateWallet); | ||
| 621 | |||
| 583 | string strSelfTest = argval2(argc, argv, "/selftest", "-selftest"); | 622 | string strSelfTest = argval2(argc, argv, "/selftest", "-selftest"); |
| 584 | if (!strSelfTest.empty()) | 623 | if (!strSelfTest.empty()) |
| 585 | return RunSelfTest(strSelfTest); | 624 | return RunSelfTest(strSelfTest); |
| 586 | 625 | ||
| 626 | // Storage diagnostics must run before LoadWallet(). Their job is to | ||
| 627 | // explain wallet.dat states that the normal wallet loader may refuse. | ||
| 628 | string strWalletStorageAuditJson = | ||
| 629 | argval2(argc, argv, "/walletstorageauditjson", "-walletstorageauditjson"); | ||
| 630 | bool fDiagWantsAudit = arg(argc,argv,"/walletstorageaudit") || | ||
| 631 | arg(argc,argv,"-walletstorageaudit") || | ||
| 632 | !strWalletStorageAuditJson.empty(); | ||
| 633 | bool fDiagWantsCheck = arg(argc,argv,"/walletstoragecheck") || | ||
| 634 | arg(argc,argv,"-walletstoragecheck"); | ||
| 635 | |||
| 636 | // These diagnostics normally read wallet.dat. Under -walletbackend=sqlite | ||
| 637 | // the live wallet is wallet.sqlite, so open it read-only as the active | ||
| 638 | // store and let the same scan walk the right file. This runs before the | ||
| 639 | // normal backend resolution further down, so validate the value here too. | ||
| 640 | string strDiagBackend = argval2(argc, argv, "/walletbackend", "-walletbackend"); | ||
| 641 | if ((fDiagWantsAudit || fDiagWantsCheck) && !strDiagBackend.empty() && | ||
| 642 | strDiagBackend != "sqlite" && strDiagBackend != "bdb") | ||
| 643 | { | ||
| 644 | AttachTerminal(); | ||
| 645 | fprintf(stderr, "Unknown wallet backend '%s'. Use -walletbackend=sqlite " | ||
| 646 | "or -walletbackend=bdb.\n", strDiagBackend.c_str()); | ||
| 647 | return 1; | ||
| 648 | } | ||
| 649 | bool fDiagSQLite = (strDiagBackend == "sqlite") && | ||
| 650 | (fDiagWantsAudit || fDiagWantsCheck); | ||
| 651 | if (fDiagSQLite) | ||
| 652 | { | ||
| 653 | AttachTerminal(); | ||
| 654 | string strSQLitePath = GetAppDir() + "/wallet.sqlite"; | ||
| 655 | string strOpenErr; | ||
| 656 | if (!WalletSQLiteRuntimeOpenReadOnly(strSQLitePath, strOpenErr)) | ||
| 657 | { | ||
| 658 | fprintf(stderr, "Cannot open the SQLite wallet for diagnostics: %s\n", | ||
| 659 | strOpenErr.c_str()); | ||
| 660 | return 1; | ||
| 661 | } | ||
| 662 | } | ||
| 663 | |||
| 664 | if (fDiagWantsAudit) | ||
| 665 | { | ||
| 666 | int nRet = CmdWalletStorageAudit(strWalletStorageAuditJson); | ||
| 667 | if (fDiagSQLite) | ||
| 668 | WalletSQLiteRuntimeClose(); | ||
| 669 | else | ||
| 670 | DBFlush(true); | ||
| 671 | return nRet; | ||
| 672 | } | ||
| 673 | |||
| 674 | if (fDiagWantsCheck) | ||
| 675 | { | ||
| 676 | int nRet = CmdWalletStorageCheck(); | ||
| 677 | if (fDiagSQLite) | ||
| 678 | WalletSQLiteRuntimeClose(); | ||
| 679 | else | ||
| 680 | DBFlush(true); | ||
| 681 | return nRet; | ||
| 682 | } | ||
| 683 | |||
| 684 | string strWalletSQLiteExport = | ||
| 685 | argval2(argc, argv, "/walletsqliteexport", "-walletsqliteexport"); | ||
| 686 | if (!strWalletSQLiteExport.empty()) | ||
| 687 | { | ||
| 688 | int nRet = CmdWalletSQLiteExport(strWalletSQLiteExport); | ||
| 689 | DBFlush(true); | ||
| 690 | return nRet; | ||
| 691 | } | ||
| 692 | |||
| 693 | string strWalletSQLiteVerify = | ||
| 694 | argval2(argc, argv, "/walletsqliteverify", "-walletsqliteverify"); | ||
| 695 | if (!strWalletSQLiteVerify.empty()) | ||
| 696 | { | ||
| 697 | int nRet = CmdWalletSQLiteVerify(strWalletSQLiteVerify); | ||
| 698 | DBFlush(true); | ||
| 699 | return nRet; | ||
| 700 | } | ||
| 701 | |||
| 702 | string strWalletSQLiteRestore = | ||
| 703 | argval2(argc, argv, "/walletsqliterestore", "-walletsqliterestore"); | ||
| 704 | if (!strWalletSQLiteRestore.empty()) | ||
| 705 | { | ||
| 706 | int nRet = CmdWalletSQLiteRestore(strWalletSQLiteRestore); | ||
| 707 | DBFlush(true); | ||
| 708 | return nRet; | ||
| 709 | } | ||
| 710 | |||
| 711 | string strWalletSQLiteLoadCheck = | ||
| 712 | argval2(argc, argv, "/walletsqliteloadcheck", "-walletsqliteloadcheck"); | ||
| 713 | if (!strWalletSQLiteLoadCheck.empty()) | ||
| 714 | { | ||
| 715 | int nRet = CmdWalletSQLiteLoadCheck(strWalletSQLiteLoadCheck); | ||
| 716 | DBFlush(true); | ||
| 717 | return nRet; | ||
| 718 | } | ||
| 719 | |||
| 587 | // Berkeley DB reports failure by throwing, and CDB's constructor lets it | 720 | // Berkeley DB reports failure by throwing, and CDB's constructor lets it |
| 588 | // through. Nothing on this path caught anything, so an unreadable | 721 | // through. Nothing on this path caught anything, so an unreadable |
| 589 | // blkindex.dat or wallet.dat -- one written by another platform's Berkeley | 722 | // blkindex.dat or wallet.dat -- one written by another platform's Berkeley |
| @@ -628,18 +761,197 @@ int main(int argc, char* argv[]) | |||
| 628 | printf("Loading wallet...\n"); | 761 | printf("Loading wallet...\n"); |
| 629 | try | 762 | try |
| 630 | { | 763 | { |
| 631 | if (!LoadWallet()) | 764 | string strWalletBackend = |
| 765 | argval2(argc, argv, "/walletbackend", "-walletbackend"); | ||
| 766 | string strWalletSQLite = | ||
| 767 | argval2(argc, argv, "/walletsqlite", "-walletsqlite"); | ||
| 768 | |||
| 769 | // A misspelled backend must not fall through to Berkeley DB silently -- | ||
| 770 | // someone who typed -walletbackend=sqlit meant to run on SQLite, and | ||
| 771 | // opening wallet.dat instead of telling them is the wrong surprise. | ||
| 772 | if (!strWalletBackend.empty() && | ||
| 773 | strWalletBackend != "sqlite" && strWalletBackend != "bdb") | ||
| 632 | { | 774 | { |
| 633 | // LoadWallet() explains itself into strWalletLoadError when it | 775 | AttachTerminal(); |
| 634 | // knows why -- an unsupported wallet format, for one, which is the | 776 | FatalStartupError(fHeadlessStartup, |
| 635 | // case this whole path exists to make visible. | 777 | strprintf("Unknown wallet backend '%s'.", strWalletBackend.c_str()), |
| 636 | FatalStartupError(fHeadlessStartup, "Cannot open wallet.dat.", | 778 | "Use -walletbackend=sqlite for the SQLite backend, or " |
| 637 | strWalletLoadError); | 779 | "-walletbackend=bdb for the Berkeley DB wallet.dat."); |
| 638 | return 1; | 780 | return 1; |
| 639 | } | 781 | } |
| 640 | 782 | ||
| 783 | if (strWalletBackend == "sqlite") | ||
| 784 | { | ||
| 785 | // Explicit opt-in via the flag. The node runs on | ||
| 786 | // <datadir>/wallet.sqlite and never opens wallet.dat, but the user | ||
| 787 | // has to have exported one first -- there is no silent migration, | ||
| 788 | // and wallet.dat is left | ||
| 789 | // exactly where it is so a plain restart goes back to it. | ||
| 790 | AttachTerminal(); | ||
| 791 | string strSQLitePath = GetAppDir() + "/wallet.sqlite"; | ||
| 792 | if (!FileExists(strSQLitePath.c_str())) | ||
| 793 | { | ||
| 794 | string strGuide = strprintf( | ||
| 795 | "No SQLite wallet was found at\n" | ||
| 796 | " %s\n\n" | ||
| 797 | "The SQLite wallet backend is opt-in and needs an exported\n" | ||
| 798 | "wallet first. Your Berkeley DB wallet.dat is not touched by\n" | ||
| 799 | "any of this.\n\n" | ||
| 800 | " Step 1 Export your existing wallet to SQLite:\n" | ||
| 801 | " bitflash -walletsqliteexport=\"%s\"\n" | ||
| 802 | " Step 2 Start again with the SQLite backend:\n" | ||
| 803 | " bitflash -walletbackend=sqlite\n\n" | ||
| 804 | "To go back to Berkeley DB at any time, just start without\n" | ||
| 805 | "-walletbackend=sqlite. wallet.dat is still your wallet.", | ||
| 806 | strSQLitePath.c_str(), strSQLitePath.c_str()); | ||
| 807 | FatalStartupError(fHeadlessStartup, | ||
| 808 | "The SQLite wallet backend needs an exported wallet first.", | ||
| 809 | strGuide); | ||
| 810 | return 1; | ||
| 811 | } | ||
| 812 | |||
| 813 | if (!LoadWalletFromSQLiteRuntime(strSQLitePath)) | ||
| 814 | { | ||
| 815 | FatalStartupError(fHeadlessStartup, | ||
| 816 | "Cannot open the SQLite wallet backend.", | ||
| 817 | strWalletLoadError); | ||
| 818 | return 1; | ||
| 819 | } | ||
| 820 | |||
| 821 | fprintf(stderr, | ||
| 822 | "Wallet backend: SQLite\n" | ||
| 823 | " %s\n" | ||
| 824 | "Your Berkeley DB wallet.dat is left untouched. Restart without\n" | ||
| 825 | "-walletbackend=sqlite to go back to it.\n", | ||
| 826 | strSQLitePath.c_str()); | ||
| 827 | fflush(stderr); | ||
| 828 | // Fall through and run the node normally: every CWalletDB read, | ||
| 829 | // write, and erase now routes to this SQLite file. | ||
| 830 | } | ||
| 831 | else if (!strWalletSQLite.empty()) | ||
| 832 | { | ||
| 833 | AttachTerminal(); | ||
| 834 | if (!LoadWalletFromSQLite(strWalletSQLite)) | ||
| 835 | { | ||
| 836 | FatalStartupError(fHeadlessStartup, | ||
| 837 | "Cannot open SQLite wallet export.", | ||
| 838 | strWalletLoadError); | ||
| 839 | return 1; | ||
| 840 | } | ||
| 841 | |||
| 842 | fprintf(stderr, "SQLite wallet loaded: read-only staging backend\n"); | ||
| 843 | fprintf(stderr, "SQLite runtime writes are not enabled yet; exiting before " | ||
| 844 | "network, mining, GUI, or wallet mutation starts.\n"); | ||
| 845 | fflush(stderr); | ||
| 846 | DBFlush(true); | ||
| 847 | return 0; | ||
| 848 | } | ||
| 849 | else if (strWalletBackend == "bdb") | ||
| 850 | { | ||
| 851 | // Explicit -walletbackend=bdb overrides the marker and the default: | ||
| 852 | // force Berkeley DB (LoadWallet creates wallet.dat if none exists). | ||
| 853 | if (!LoadWallet()) | ||
| 854 | { | ||
| 855 | FatalStartupError(fHeadlessStartup, "Cannot open wallet.dat.", | ||
| 856 | strWalletLoadError); | ||
| 857 | return 1; | ||
| 858 | } | ||
| 859 | } | ||
| 860 | else | ||
| 861 | { | ||
| 862 | // No explicit -walletbackend on the command line. Resolve it from | ||
| 863 | // the persistent marker, then defaults: an existing wallet.sqlite | ||
| 864 | // stays on SQLite, an existing wallet.dat stays on Berkeley DB (the | ||
| 865 | // GUI offers to convert), and a fresh install starts on SQLite -- | ||
| 866 | // the new default. wallet.dat is never touched by any of this. | ||
| 867 | string strSQLitePath = GetAppDir() + "/wallet.sqlite"; | ||
| 868 | bool fSQLiteExists = FileExists(strSQLitePath.c_str()); | ||
| 869 | bool fWalletDatExists = FileExists((GetAppDir() + "/wallet.dat").c_str()); | ||
| 870 | string strMarker = ReadWalletBackendMarker(); | ||
| 871 | |||
| 872 | bool fUseSQLite = false; | ||
| 873 | bool fCreateSQLite = false; | ||
| 874 | if (strMarker == "sqlite") | ||
| 875 | { | ||
| 876 | if (fSQLiteExists) fUseSQLite = true; | ||
| 877 | else if (fWalletDatExists) fUseSQLite = false; // marker stale; real wallet is BDB | ||
| 878 | else { fUseSQLite = true; fCreateSQLite = true; } | ||
| 879 | } | ||
| 880 | else if (strMarker == "bdb") | ||
| 881 | { | ||
| 882 | fUseSQLite = false; | ||
| 883 | } | ||
| 884 | else // no marker recorded yet | ||
| 885 | { | ||
| 886 | if (fSQLiteExists && !fWalletDatExists) fUseSQLite = true; | ||
| 887 | else if (fWalletDatExists) fUseSQLite = false; | ||
| 888 | else { fUseSQLite = true; fCreateSQLite = true; } | ||
| 889 | } | ||
| 890 | |||
| 891 | // A headless node whose datadir holds no wallet of either kind is | ||
| 892 | // far more often an operations fault -- datadir not mounted, or | ||
| 893 | // wallet.dat caught mid-rename by a backup -- than a first run. | ||
| 894 | // Creating one here is not the harmless default it looks like: | ||
| 895 | // success also writes the backend marker, and from then on | ||
| 896 | // restoring the real wallet.dat no longer takes effect, because the | ||
| 897 | // marker keeps the node on the empty wallet it just made. Under | ||
| 898 | // 1.2.19 the same fault created a wallet.dat that a restore | ||
| 899 | // overwrote, so operators could recover by putting the file back. | ||
| 900 | // Refuse instead, and name the flag that makes it deliberate. | ||
| 901 | if (fCreateSQLite && fHeadlessStartup && | ||
| 902 | !arg(argc, argv, "/createwallet") && !arg(argc, argv, "-createwallet")) | ||
| 903 | { | ||
| 904 | AttachTerminal(); | ||
| 905 | fprintf(stderr, | ||
| 906 | "No wallet found in %s\n" | ||
| 907 | "Refusing to create one. On a headless node an absent wallet is\n" | ||
| 908 | "usually a mount or backup fault, and creating one would record a\n" | ||
| 909 | "backend marker that makes restoring the real wallet a no-op.\n" | ||
| 910 | "Pass -createwallet to start a new one deliberately, or\n" | ||
| 911 | "-walletbackend=bdb to run on a Berkeley DB wallet.dat.\n", | ||
| 912 | GetAppDir().c_str()); | ||
| 913 | fflush(stderr); | ||
| 914 | return 1; | ||
| 915 | } | ||
| 916 | |||
| 917 | if (fUseSQLite) | ||
| 918 | { | ||
| 919 | AttachTerminal(); | ||
| 920 | bool fOk = fCreateSQLite | ||
| 921 | ? CreateNewSQLiteWallet(strSQLitePath) | ||
| 922 | : LoadWalletFromSQLiteRuntime(strSQLitePath); | ||
| 923 | if (!fOk) | ||
| 924 | { | ||
| 925 | FatalStartupError(fHeadlessStartup, | ||
| 926 | fCreateSQLite ? "Cannot create the SQLite wallet." | ||
| 927 | : "Cannot open the SQLite wallet.", | ||
| 928 | strWalletLoadError); | ||
| 929 | return 1; | ||
| 930 | } | ||
| 931 | // Record the choice so it is stable from here on. | ||
| 932 | if (ReadWalletBackendMarker() != "sqlite") | ||
| 933 | WriteWalletBackendMarker("sqlite"); | ||
| 934 | fprintf(stderr, "Wallet backend: SQLite\n %s\n%s", | ||
| 935 | strSQLitePath.c_str(), | ||
| 936 | fCreateSQLite ? "A new wallet was created here.\n" : ""); | ||
| 937 | fflush(stderr); | ||
| 938 | // Fall through and run the node; CWalletDB routes to this file. | ||
| 939 | } | ||
| 940 | else if (!LoadWallet()) | ||
| 941 | { | ||
| 942 | // LoadWallet() explains itself into strWalletLoadError when it | ||
| 943 | // knows why -- an unsupported wallet format, for one, which is | ||
| 944 | // the case this whole path exists to make visible. | ||
| 945 | FatalStartupError(fHeadlessStartup, "Cannot open wallet.dat.", | ||
| 946 | strWalletLoadError); | ||
| 947 | return 1; | ||
| 948 | } | ||
| 949 | } | ||
| 950 | |||
| 641 | // After the block index, so there is a chain to compare the wallet | 951 | // After the block index, so there is a chain to compare the wallet |
| 642 | // against, and before anything reports a balance. | 952 | // against, and before anything reports a balance. Works on either |
| 953 | // backend: RescanSpentFlags writes corrected flags through CWalletDB, | ||
| 954 | // which routes to SQLite when that backend is active. | ||
| 643 | RescanSpentFlags(); | 955 | RescanSpentFlags(); |
| 644 | } | 956 | } |
| 645 | catch (const std::exception& e) | 957 | catch (const std::exception& e) |
| @@ -908,6 +1220,10 @@ int main(int argc, char* argv[]) | |||
| 908 | // called here, which is why a wallet.dat copied elsewhere would not | 1220 | // called here, which is why a wallet.dat copied elsewhere would not |
| 909 | // open -- issue #40. Not optional. | 1221 | // open -- issue #40. Not optional. |
| 910 | DBFlush(true); | 1222 | DBFlush(true); |
| 1223 | // Checkpoint and close the SQLite wallet backend if one is active. A | ||
| 1224 | // no-op on the Berkeley DB path. Safe to kill before this runs: WAL + | ||
| 1225 | // synchronous=FULL already made every committed write durable. | ||
| 1226 | WalletSQLiteRuntimeClose(); | ||
| 911 | #ifdef _WIN32 | 1227 | #ifdef _WIN32 |
| 912 | // wallet.dat is safely flushed and closed now; let a pending console | 1228 | // wallet.dat is safely flushed and closed now; let a pending console |
| 913 | // control handler (CLOSE/LOGOFF/SHUTDOWN) return so the OS can finish. | 1229 | // control handler (CLOSE/LOGOFF/SHUTDOWN) return so the OS can finish. |
| @@ -924,6 +1240,7 @@ int main(int argc, char* argv[]) | |||
| 924 | StopNode(); | 1240 | StopNode(); |
| 925 | BtfStopManagedTor(); | 1241 | BtfStopManagedTor(); |
| 926 | DBFlush(true); | 1242 | DBFlush(true); |
| 1243 | WalletSQLiteRuntimeClose(); | ||
| 927 | return ret; | 1244 | return ret; |
| 928 | #endif | 1245 | #endif |
| 929 | } | 1246 | } |