upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBitflash <admin@bitflash.network>2026-08-14 17:32:07 -0300
committerBitflash <admin@bitflash.network>2026-08-14 17:32:07 -0300
commit307d1a79d4f9bdecd3f834f9ab4987f46d16d177 (patch)
treee0f5626e7d70caad3f568a04d2264cfc7bd15e9e /src
parent3227564b26d0a9c5b8f1bcc5e21bb572a2968e5f (diff)
parentf7f9885e89e2c2527933b99ec713592ebf930483 (diff)
Merge pull request 'wallet: clean up failed SQLite migrations' (#52) from wallet-sqlite-cleanup-failures into main
Diffstat (limited to 'src')
-rw-r--r--src/selftest.cpp53
-rw-r--r--src/walletcmd.cpp32
2 files changed, 85 insertions, 0 deletions
diff --git a/src/selftest.cpp b/src/selftest.cpp
index 7d3a96e..343d9c5 100644
--- a/src/selftest.cpp
+++ b/src/selftest.cpp
@@ -1162,6 +1162,39 @@ public:
1162 1162
1163} // namespace 1163} // namespace
1164 1164
1165static bool CreateSQLiteWalletWithEmptyKey(const string& strPath)
1166{
1167 sqlite3* pdb = NULL;
1168 int ret = sqlite3_open_v2(strPath.c_str(), &pdb,
1169 SQLITE_OPEN_READWRITE |
1170 SQLITE_OPEN_CREATE |
1171 SQLITE_OPEN_FULLMUTEX,
1172 NULL);
1173 if (ret != SQLITE_OK || !pdb)
1174 {
1175 if (pdb)
1176 sqlite3_close(pdb);
1177 return false;
1178 }
1179
1180 char* pszErr = NULL;
1181 bool fOk =
1182 sqlite3_exec(pdb,
1183 "CREATE TABLE wallet_records ("
1184 "key BLOB PRIMARY KEY NOT NULL,"
1185 "value BLOB NOT NULL"
1186 ");",
1187 NULL, NULL, &pszErr) == SQLITE_OK &&
1188 sqlite3_exec(pdb,
1189 "INSERT INTO wallet_records(key, value) "
1190 "VALUES(x'', x'01');",
1191 NULL, NULL, &pszErr) == SQLITE_OK;
1192 if (pszErr)
1193 sqlite3_free(pszErr);
1194 sqlite3_close(pdb);
1195 return fOk;
1196}
1197
1165static int RunWalletSQLiteMigrationSelfTest() 1198static int RunWalletSQLiteMigrationSelfTest()
1166{ 1199{
1167 fflush(stdout); 1200 fflush(stdout);
@@ -1265,6 +1298,26 @@ static int RunWalletSQLiteMigrationSelfTest()
1265 "Refusing to overwrite existing wallet.dat"), 1298 "Refusing to overwrite existing wallet.dat"),
1266 "SQLite wallet restore refuses to overwrite wallet.dat") ? 0 : 1; 1299 "SQLite wallet restore refuses to overwrite wallet.dat") ? 0 : 1;
1267 1300
1301 string strBadSQLite = tmp + "/bad-empty-key.sqlite";
1302 nFail += Check(CreateSQLiteWalletWithEmptyKey(strBadSQLite),
1303 "bad SQLite export with an empty key can be created") ? 0 : 1;
1304 string strBadRestoreDir = tmp + "/bad-restore-wallet";
1305 nFail += Check(MakeDirLocal(strBadRestoreDir),
1306 "bad restore wallet directory can be created") ? 0 : 1;
1307 string strBadRestoreOut = tmp + "/sqlite-restore-bad.txt";
1308 vector<string> vBadRestoreArgs;
1309 vBadRestoreArgs.push_back("-datadir=" + strBadRestoreDir);
1310 vBadRestoreArgs.push_back("-nomanagedtor");
1311 vBadRestoreArgs.push_back("-nogui");
1312 vBadRestoreArgs.push_back("-walletsqliterestore=" + strBadSQLite);
1313 int nBadRestoreRet =
1314 RunBitflashChild(strExe, vBadRestoreArgs, NULL, &strBadRestoreOut);
1315 nFail += Check(nBadRestoreRet == 1 &&
1316 FileContainsText(strBadRestoreOut,
1317 "Cannot restore SQLite wallet export") &&
1318 !FileExists((strBadRestoreDir + "/wallet.dat").c_str()),
1319 "failed SQLite wallet restore removes incomplete wallet.dat") ? 0 : 1;
1320
1268 string strOverwriteOut = tmp + "/sqlite-export-overwrite.txt"; 1321 string strOverwriteOut = tmp + "/sqlite-export-overwrite.txt";
1269 int nOverwriteRet = 1322 int nOverwriteRet =
1270 RunBitflashChild(strExe, vExportArgs, NULL, &strOverwriteOut); 1323 RunBitflashChild(strExe, vExportArgs, NULL, &strOverwriteOut);
diff --git a/src/walletcmd.cpp b/src/walletcmd.cpp
index d1bad98..9e4a981 100644
--- a/src/walletcmd.cpp
+++ b/src/walletcmd.cpp
@@ -798,6 +798,19 @@ static vector<unsigned char> DataStreamBytesLocal(const CDataStream& ss)
798 798
799namespace { 799namespace {
800 800
801static void RemoveSQLiteExportFiles(const string& strPath)
802{
803 remove(strPath.c_str());
804 remove((strPath + "-wal").c_str());
805 remove((strPath + "-shm").c_str());
806}
807
808static void RemoveFailedRestoreWallet(const string& strWalletPath)
809{
810 DBFlush(true);
811 remove(strWalletPath.c_str());
812}
813
801class CWalletSQLiteExportVisitor : public CWalletRecordVisitor 814class CWalletSQLiteExportVisitor : public CWalletRecordVisitor
802{ 815{
803public: 816public:
@@ -912,11 +925,14 @@ int CmdWalletSQLiteExport(const std::string& strDest)
912 CWalletDBSQLite db; 925 CWalletDBSQLite db;
913 if (!db.Open(strDest, strError)) 926 if (!db.Open(strDest, strError))
914 { 927 {
928 RemoveSQLiteExportFiles(strDest);
915 fprintf(stderr, "Cannot open SQLite wallet export: %s\n", strError.c_str()); 929 fprintf(stderr, "Cannot open SQLite wallet export: %s\n", strError.c_str());
916 return 1; 930 return 1;
917 } 931 }
918 if (!db.BeginTransaction(strError)) 932 if (!db.BeginTransaction(strError))
919 { 933 {
934 db.Close();
935 RemoveSQLiteExportFiles(strDest);
920 fprintf(stderr, "Cannot begin SQLite wallet export: %s\n", strError.c_str()); 936 fprintf(stderr, "Cannot begin SQLite wallet export: %s\n", strError.c_str());
921 return 1; 937 return 1;
922 } 938 }
@@ -927,16 +943,22 @@ int CmdWalletSQLiteExport(const std::string& strDest)
927 { 943 {
928 string strRollbackError; 944 string strRollbackError;
929 db.RollbackTransaction(strRollbackError); 945 db.RollbackTransaction(strRollbackError);
946 db.Close();
947 RemoveSQLiteExportFiles(strDest);
930 fprintf(stderr, "Cannot export wallet.dat to SQLite: %s\n", strError.c_str()); 948 fprintf(stderr, "Cannot export wallet.dat to SQLite: %s\n", strError.c_str());
931 return 1; 949 return 1;
932 } 950 }
933 if (!db.CommitTransaction(strError)) 951 if (!db.CommitTransaction(strError))
934 { 952 {
953 db.Close();
954 RemoveSQLiteExportFiles(strDest);
935 fprintf(stderr, "Cannot commit SQLite wallet export: %s\n", strError.c_str()); 955 fprintf(stderr, "Cannot commit SQLite wallet export: %s\n", strError.c_str());
936 return 1; 956 return 1;
937 } 957 }
938 if (!db.Checkpoint(strError)) 958 if (!db.Checkpoint(strError))
939 { 959 {
960 db.Close();
961 RemoveSQLiteExportFiles(strDest);
940 fprintf(stderr, "Cannot checkpoint SQLite wallet export: %s\n", strError.c_str()); 962 fprintf(stderr, "Cannot checkpoint SQLite wallet export: %s\n", strError.c_str());
941 return 1; 963 return 1;
942 } 964 }
@@ -944,12 +966,16 @@ int CmdWalletSQLiteExport(const std::string& strDest)
944 int nCount = 0; 966 int nCount = 0;
945 if (!db.CountRecords(nCount, strError)) 967 if (!db.CountRecords(nCount, strError))
946 { 968 {
969 db.Close();
970 RemoveSQLiteExportFiles(strDest);
947 fprintf(stderr, "Cannot verify SQLite wallet export count: %s\n", 971 fprintf(stderr, "Cannot verify SQLite wallet export count: %s\n",
948 strError.c_str()); 972 strError.c_str());
949 return 1; 973 return 1;
950 } 974 }
951 if (nCount != nCopied) 975 if (nCount != nCopied)
952 { 976 {
977 db.Close();
978 RemoveSQLiteExportFiles(strDest);
953 fprintf(stderr, "SQLite wallet export count mismatch: copied %d, stored %d\n", 979 fprintf(stderr, "SQLite wallet export count mismatch: copied %d, stored %d\n",
954 nCopied, nCount); 980 nCopied, nCount);
955 return 1; 981 return 1;
@@ -1097,6 +1123,8 @@ int CmdWalletSQLiteRestore(const std::string& strPath)
1097 if (!sqlite.ScanRecords(visitor, strError)) 1123 if (!sqlite.ScanRecords(visitor, strError))
1098 { 1124 {
1099 bdb.TxnAbort(); 1125 bdb.TxnAbort();
1126 bdb.Close();
1127 RemoveFailedRestoreWallet(strWalletPath);
1100 fprintf(stderr, "Cannot restore SQLite wallet export: %s\n", 1128 fprintf(stderr, "Cannot restore SQLite wallet export: %s\n",
1101 strError.c_str()); 1129 strError.c_str());
1102 return 1; 1130 return 1;
@@ -1104,12 +1132,16 @@ int CmdWalletSQLiteRestore(const std::string& strPath)
1104 if (nCopied != nSQLiteRecords) 1132 if (nCopied != nSQLiteRecords)
1105 { 1133 {
1106 bdb.TxnAbort(); 1134 bdb.TxnAbort();
1135 bdb.Close();
1136 RemoveFailedRestoreWallet(strWalletPath);
1107 fprintf(stderr, "SQLite wallet restore copied %d records, expected %d.\n", 1137 fprintf(stderr, "SQLite wallet restore copied %d records, expected %d.\n",
1108 nCopied, nSQLiteRecords); 1138 nCopied, nSQLiteRecords);
1109 return 2; 1139 return 2;
1110 } 1140 }
1111 if (!bdb.TxnCommit()) 1141 if (!bdb.TxnCommit())
1112 { 1142 {
1143 bdb.Close();
1144 RemoveFailedRestoreWallet(strWalletPath);
1113 fprintf(stderr, "Cannot commit Berkeley DB restore transaction.\n"); 1145 fprintf(stderr, "Cannot commit Berkeley DB restore transaction.\n");
1114 return 1; 1146 return 1;
1115 } 1147 }