diff options
| author | Nsable-sh <nsable-sh@noreply.git.bitflash.network> | 2026-08-14 17:02:35 -0300 |
|---|---|---|
| committer | Nsable-sh <nsable-sh@noreply.git.bitflash.network> | 2026-08-14 17:02:35 -0300 |
| commit | df129cc672b9b894ff2558d3e9361ddab082433d (patch) | |
| tree | a72cd83e2981deb95a2f17d0e02a7dfd64ab2eca /src/walletcmd.cpp | |
| parent | 35f6c752f9f879ca94478985978e4a9c862ede3e (diff) | |
wallet: restore BDB wallets from SQLite exports
Diffstat (limited to 'src/walletcmd.cpp')
| -rw-r--r-- | src/walletcmd.cpp | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/src/walletcmd.cpp b/src/walletcmd.cpp index 36f6783..d1bad98 100644 --- a/src/walletcmd.cpp +++ b/src/walletcmd.cpp | |||
| @@ -844,6 +844,52 @@ public: | |||
| 844 | } | 844 | } |
| 845 | }; | 845 | }; |
| 846 | 846 | ||
| 847 | class CWalletRawRestoreDB : public CWalletDB | ||
| 848 | { | ||
| 849 | public: | ||
| 850 | CWalletRawRestoreDB(const char* pszMode="cr+", bool fTxn=true) | ||
| 851 | : CWalletDB(pszMode, fTxn) { } | ||
| 852 | |||
| 853 | bool WriteRaw(CDataStream ssKey, CDataStream ssValue) | ||
| 854 | { | ||
| 855 | if (!pdb || ssKey.empty()) | ||
| 856 | return false; | ||
| 857 | |||
| 858 | Dbt datKey((void*)&ssKey[0], ssKey.size()); | ||
| 859 | Dbt datValue(ssValue.empty() ? NULL : (void*)&ssValue[0], | ||
| 860 | ssValue.size()); | ||
| 861 | int ret = pdb->put(GetTxn(), &datKey, &datValue, 0); | ||
| 862 | |||
| 863 | memset(datKey.get_data(), 0, datKey.get_size()); | ||
| 864 | if (datValue.get_data()) | ||
| 865 | memset(datValue.get_data(), 0, datValue.get_size()); | ||
| 866 | return ret == 0; | ||
| 867 | } | ||
| 868 | }; | ||
| 869 | |||
| 870 | class CWalletSQLiteRestoreVisitor : public CWalletRecordVisitor | ||
| 871 | { | ||
| 872 | public: | ||
| 873 | CWalletRawRestoreDB& db; | ||
| 874 | int& nCopied; | ||
| 875 | |||
| 876 | CWalletSQLiteRestoreVisitor(CWalletRawRestoreDB& dbIn, int& nCopiedIn) | ||
| 877 | : db(dbIn), nCopied(nCopiedIn) { } | ||
| 878 | |||
| 879 | bool VisitWalletRecord(const CDataStream& ssKey, | ||
| 880 | const CDataStream& ssValue, | ||
| 881 | string& strErrorRet) | ||
| 882 | { | ||
| 883 | if (!db.WriteRaw(ssKey, ssValue)) | ||
| 884 | { | ||
| 885 | strErrorRet = "could not write raw wallet record"; | ||
| 886 | return false; | ||
| 887 | } | ||
| 888 | nCopied++; | ||
| 889 | return true; | ||
| 890 | } | ||
| 891 | }; | ||
| 892 | |||
| 847 | } // namespace | 893 | } // namespace |
| 848 | 894 | ||
| 849 | int CmdWalletSQLiteExport(const std::string& strDest) | 895 | int CmdWalletSQLiteExport(const std::string& strDest) |
| @@ -994,6 +1040,86 @@ int CmdWalletSQLiteVerify(const std::string& strPath) | |||
| 994 | return 2; | 1040 | return 2; |
| 995 | } | 1041 | } |
| 996 | 1042 | ||
| 1043 | int CmdWalletSQLiteRestore(const std::string& strPath) | ||
| 1044 | { | ||
| 1045 | AttachTerminal(); | ||
| 1046 | |||
| 1047 | if (strPath.empty()) | ||
| 1048 | { | ||
| 1049 | fprintf(stderr, "Missing SQLite wallet export path.\n"); | ||
| 1050 | return 1; | ||
| 1051 | } | ||
| 1052 | if (!FileExists(strPath.c_str())) | ||
| 1053 | { | ||
| 1054 | fprintf(stderr, "SQLite wallet export does not exist: %s\n", | ||
| 1055 | strPath.c_str()); | ||
| 1056 | return 1; | ||
| 1057 | } | ||
| 1058 | |||
| 1059 | string strWalletPath = GetAppDir() + "/wallet.dat"; | ||
| 1060 | if (FileExists(strWalletPath.c_str())) | ||
| 1061 | { | ||
| 1062 | fprintf(stderr, "Refusing to overwrite existing wallet.dat: %s\n", | ||
| 1063 | strWalletPath.c_str()); | ||
| 1064 | return 1; | ||
| 1065 | } | ||
| 1066 | |||
| 1067 | string strError; | ||
| 1068 | CWalletDBSQLite sqlite; | ||
| 1069 | if (!sqlite.Open(strPath, strError)) | ||
| 1070 | { | ||
| 1071 | fprintf(stderr, "Cannot open SQLite wallet export: %s\n", strError.c_str()); | ||
| 1072 | return 1; | ||
| 1073 | } | ||
| 1074 | |||
| 1075 | int nSQLiteRecords = 0; | ||
| 1076 | if (!sqlite.CountRecords(nSQLiteRecords, strError)) | ||
| 1077 | { | ||
| 1078 | fprintf(stderr, "Cannot count SQLite wallet export records: %s\n", | ||
| 1079 | strError.c_str()); | ||
| 1080 | return 1; | ||
| 1081 | } | ||
| 1082 | if (nSQLiteRecords <= 0) | ||
| 1083 | { | ||
| 1084 | fprintf(stderr, "SQLite wallet export contains no records.\n"); | ||
| 1085 | return 2; | ||
| 1086 | } | ||
| 1087 | |||
| 1088 | CWalletRawRestoreDB bdb("cr+", true); | ||
| 1089 | if (!bdb.TxnBegin()) | ||
| 1090 | { | ||
| 1091 | fprintf(stderr, "Cannot begin Berkeley DB restore transaction.\n"); | ||
| 1092 | return 1; | ||
| 1093 | } | ||
| 1094 | |||
| 1095 | int nCopied = 0; | ||
| 1096 | CWalletSQLiteRestoreVisitor visitor(bdb, nCopied); | ||
| 1097 | if (!sqlite.ScanRecords(visitor, strError)) | ||
| 1098 | { | ||
| 1099 | bdb.TxnAbort(); | ||
| 1100 | fprintf(stderr, "Cannot restore SQLite wallet export: %s\n", | ||
| 1101 | strError.c_str()); | ||
| 1102 | return 1; | ||
| 1103 | } | ||
| 1104 | if (nCopied != nSQLiteRecords) | ||
| 1105 | { | ||
| 1106 | bdb.TxnAbort(); | ||
| 1107 | fprintf(stderr, "SQLite wallet restore copied %d records, expected %d.\n", | ||
| 1108 | nCopied, nSQLiteRecords); | ||
| 1109 | return 2; | ||
| 1110 | } | ||
| 1111 | if (!bdb.TxnCommit()) | ||
| 1112 | { | ||
| 1113 | fprintf(stderr, "Cannot commit Berkeley DB restore transaction.\n"); | ||
| 1114 | return 1; | ||
| 1115 | } | ||
| 1116 | |||
| 1117 | printf("SQLite wallet export restored to wallet.dat\n"); | ||
| 1118 | printf(" records restored: %d\n", nCopied); | ||
| 1119 | fflush(stdout); | ||
| 1120 | return 0; | ||
| 1121 | } | ||
| 1122 | |||
| 997 | int CmdEncryptWallet(const std::string& strPassphrase) | 1123 | int CmdEncryptWallet(const std::string& strPassphrase) |
| 998 | { | 1124 | { |
| 999 | AttachTerminal(); | 1125 | AttachTerminal(); |