diff options
| author | Nsable-sh <nsable-sh@noreply.git.bitflash.network> | 2026-08-13 17:19:37 -0300 |
|---|---|---|
| committer | Nsable-sh <nsable-sh@noreply.git.bitflash.network> | 2026-08-13 17:59:24 -0300 |
| commit | 6f9e07186d06f772c93832f0dcbd4f9432b44579 (patch) | |
| tree | 1ee2e5a351e704dd7ac0d3789a85d5a77f2981fb | |
| parent | f57d58155cdf65ec2ddb1a01c9d9466bf60df9ab (diff) | |
tests: cover portable wallet copies
| -rw-r--r-- | src/main_gui.cpp | 3 | ||||
| -rw-r--r-- | src/selftest.cpp | 164 |
2 files changed, 165 insertions, 2 deletions
diff --git a/src/main_gui.cpp b/src/main_gui.cpp index 3f52e91..50c4f34 100644 --- a/src/main_gui.cpp +++ b/src/main_gui.cpp | |||
| @@ -114,7 +114,8 @@ static void PrintUsage() | |||
| 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-crypto, wallet-encrypt,\n"); |
| 117 | printf(" net-message, consensus-limits, pool-stratum, parse-money, socks5-proxy, or managed-tor\n"); | 117 | printf(" wallet-portability, net-message, consensus-limits, pool-stratum,\n"); |
| 118 | printf(" parse-money, socks5-proxy, or managed-tor\n"); | ||
| 118 | printf("\n"); | 119 | printf("\n"); |
| 119 | printf("Mining mode:\n"); | 120 | printf("Mining mode:\n"); |
| 120 | printf(" /operator\n"); | 121 | printf(" /operator\n"); |
diff --git a/src/selftest.cpp b/src/selftest.cpp index 79feddf..3f3cb16 100644 --- a/src/selftest.cpp +++ b/src/selftest.cpp | |||
| @@ -34,6 +34,7 @@ extern int RunPoolStratumSelfTest(); | |||
| 34 | #undef printf | 34 | #undef printf |
| 35 | 35 | ||
| 36 | #include <mutex> | 36 | #include <mutex> |
| 37 | #include <cerrno> | ||
| 37 | #include <stdexcept> | 38 | #include <stdexcept> |
| 38 | #include <thread> | 39 | #include <thread> |
| 39 | 40 | ||
| @@ -925,6 +926,46 @@ static bool WriteTextFile(const string& strPath, const string& strText) | |||
| 925 | return fOk; | 926 | return fOk; |
| 926 | } | 927 | } |
| 927 | 928 | ||
| 929 | static bool MakeDirLocal(const string& strPath) | ||
| 930 | { | ||
| 931 | #ifdef _WIN32 | ||
| 932 | return CreateDirectoryA(strPath.c_str(), NULL) || GetLastError() == ERROR_ALREADY_EXISTS; | ||
| 933 | #else | ||
| 934 | return mkdir(strPath.c_str(), 0700) == 0 || errno == EEXIST; | ||
| 935 | #endif | ||
| 936 | } | ||
| 937 | |||
| 938 | static bool CopyFileLocal(const string& strSrc, const string& strDst) | ||
| 939 | { | ||
| 940 | FILE* in = fopen(strSrc.c_str(), "rb"); | ||
| 941 | if (!in) | ||
| 942 | return false; | ||
| 943 | FILE* out = fopen(strDst.c_str(), "wb"); | ||
| 944 | if (!out) | ||
| 945 | { | ||
| 946 | fclose(in); | ||
| 947 | return false; | ||
| 948 | } | ||
| 949 | |||
| 950 | bool fOk = true; | ||
| 951 | char buf[65536]; | ||
| 952 | size_t n = 0; | ||
| 953 | while ((n = fread(buf, 1, sizeof(buf), in)) > 0) | ||
| 954 | { | ||
| 955 | if (fwrite(buf, 1, n, out) != n) | ||
| 956 | { | ||
| 957 | fOk = false; | ||
| 958 | break; | ||
| 959 | } | ||
| 960 | } | ||
| 961 | if (ferror(in)) | ||
| 962 | fOk = false; | ||
| 963 | if (fclose(out) != 0) | ||
| 964 | fOk = false; | ||
| 965 | fclose(in); | ||
| 966 | return fOk; | ||
| 967 | } | ||
| 968 | |||
| 928 | static string QuoteCommandArg(const string& str) | 969 | static string QuoteCommandArg(const string& str) |
| 929 | { | 970 | { |
| 930 | string out = "\""; | 971 | string out = "\""; |
| @@ -1169,6 +1210,125 @@ static int RunWalletEncryptSelfTest() | |||
| 1169 | return nFail == 0 ? 0 : 1; | 1210 | return nFail == 0 ? 0 : 1; |
| 1170 | } | 1211 | } |
| 1171 | 1212 | ||
| 1213 | static int RunWalletPortabilitySelfTest() | ||
| 1214 | { | ||
| 1215 | fflush(stdout); | ||
| 1216 | printf("wallet-portability self-test\n"); | ||
| 1217 | |||
| 1218 | std::string tmp; | ||
| 1219 | std::string cwd; | ||
| 1220 | if (!MakeTempDir(tmp)) | ||
| 1221 | { | ||
| 1222 | printf(" FAIL could not create a temporary data directory\n"); | ||
| 1223 | return 1; | ||
| 1224 | } | ||
| 1225 | if (!GetCurrentDir(cwd)) | ||
| 1226 | { | ||
| 1227 | printf(" FAIL could not read current directory\n"); | ||
| 1228 | RemoveTree(tmp); | ||
| 1229 | return 1; | ||
| 1230 | } | ||
| 1231 | |||
| 1232 | int nFail = 0; | ||
| 1233 | printf(" temp root: %s\n", tmp.c_str()); | ||
| 1234 | |||
| 1235 | try | ||
| 1236 | { | ||
| 1237 | #ifdef _WIN32 | ||
| 1238 | string strExe = cwd + "\\bitflash.exe"; | ||
| 1239 | #else | ||
| 1240 | string strExe = cwd + "/bitflash-node"; | ||
| 1241 | #endif | ||
| 1242 | string strOriginal = tmp + "/original"; | ||
| 1243 | string strRawCopy = tmp + "/raw-copy"; | ||
| 1244 | string strBackupCopy = tmp + "/backup-copy"; | ||
| 1245 | nFail += Check(MakeDirLocal(strOriginal) && | ||
| 1246 | MakeDirLocal(strRawCopy) && | ||
| 1247 | MakeDirLocal(strBackupCopy), | ||
| 1248 | "temporary wallet directories can be created") ? 0 : 1; | ||
| 1249 | |||
| 1250 | string strCreateOut = tmp + "/create.txt"; | ||
| 1251 | vector<string> vCreateArgs; | ||
| 1252 | vCreateArgs.push_back("-datadir=" + strOriginal); | ||
| 1253 | vCreateArgs.push_back("-nomanagedtor"); | ||
| 1254 | vCreateArgs.push_back("-nogui"); | ||
| 1255 | vCreateArgs.push_back("-newphrase"); | ||
| 1256 | int nCreateRet = RunBitflashChild(strExe, vCreateArgs, NULL, &strCreateOut); | ||
| 1257 | nFail += Check(nCreateRet == 0 && | ||
| 1258 | FileContainsText(strCreateOut, "Write these twelve words down"), | ||
| 1259 | "a phrase wallet can be created in a fresh datadir") ? 0 : 1; | ||
| 1260 | |||
| 1261 | string strOriginalAudit = tmp + "/original-audit.txt"; | ||
| 1262 | vector<string> vOriginalAuditArgs; | ||
| 1263 | vOriginalAuditArgs.push_back("-datadir=" + strOriginal); | ||
| 1264 | vOriginalAuditArgs.push_back("-nomanagedtor"); | ||
| 1265 | vOriginalAuditArgs.push_back("-nogui"); | ||
| 1266 | vOriginalAuditArgs.push_back("-recoveryaudit"); | ||
| 1267 | int nOriginalAuditRet = RunBitflashChild(strExe, vOriginalAuditArgs, NULL, &strOriginalAudit); | ||
| 1268 | nFail += Check(nOriginalAuditRet == 0 && | ||
| 1269 | FileContainsText(strOriginalAudit, "recovery phrase: present") && | ||
| 1270 | FileContainsText(strOriginalAudit, "SLIP-0044 BITFLASH"), | ||
| 1271 | "the original wallet reports its recovery phrase") ? 0 : 1; | ||
| 1272 | |||
| 1273 | string strPortableWallet = tmp + "/portable-wallet.dat"; | ||
| 1274 | string strBackupOut = tmp + "/backupwallet.txt"; | ||
| 1275 | vector<string> vBackupArgs; | ||
| 1276 | vBackupArgs.push_back("-datadir=" + strOriginal); | ||
| 1277 | vBackupArgs.push_back("-nomanagedtor"); | ||
| 1278 | vBackupArgs.push_back("-nogui"); | ||
| 1279 | vBackupArgs.push_back("-backupwallet=" + strPortableWallet); | ||
| 1280 | int nBackupRet = RunBitflashChild(strExe, vBackupArgs, NULL, &strBackupOut); | ||
| 1281 | nFail += Check(nBackupRet == 0 && FileExists(strPortableWallet.c_str()), | ||
| 1282 | "/backupwallet writes a portable wallet.dat") ? 0 : 1; | ||
| 1283 | |||
| 1284 | nFail += Check(CopyFileLocal(strOriginal + "/wallet.dat", | ||
| 1285 | strRawCopy + "/wallet.dat"), | ||
| 1286 | "a raw wallet.dat can be copied without database logs") ? 0 : 1; | ||
| 1287 | string strRawAudit = tmp + "/raw-copy-audit.txt"; | ||
| 1288 | vector<string> vRawAuditArgs; | ||
| 1289 | vRawAuditArgs.push_back("-datadir=" + strRawCopy); | ||
| 1290 | vRawAuditArgs.push_back("-nomanagedtor"); | ||
| 1291 | vRawAuditArgs.push_back("-nogui"); | ||
| 1292 | vRawAuditArgs.push_back("-recoveryaudit"); | ||
| 1293 | int nRawAuditRet = RunBitflashChild(strExe, vRawAuditArgs, NULL, &strRawAudit); | ||
| 1294 | nFail += Check(nRawAuditRet == 0 && | ||
| 1295 | FileContainsText(strRawAudit, "recovery phrase: present") && | ||
| 1296 | !FileContainsText(strRawAudit, "Cannot open wallet.dat"), | ||
| 1297 | "a raw wallet.dat copy opens in a new datadir") ? 0 : 1; | ||
| 1298 | |||
| 1299 | nFail += Check(CopyFileLocal(strPortableWallet, | ||
| 1300 | strBackupCopy + "/wallet.dat"), | ||
| 1301 | "the portable backup can be installed as wallet.dat") ? 0 : 1; | ||
| 1302 | string strBackupAudit = tmp + "/backup-copy-audit.txt"; | ||
| 1303 | vector<string> vBackupAuditArgs; | ||
| 1304 | vBackupAuditArgs.push_back("-datadir=" + strBackupCopy); | ||
| 1305 | vBackupAuditArgs.push_back("-nomanagedtor"); | ||
| 1306 | vBackupAuditArgs.push_back("-nogui"); | ||
| 1307 | vBackupAuditArgs.push_back("-recoveryaudit"); | ||
| 1308 | int nBackupAuditRet = RunBitflashChild(strExe, vBackupAuditArgs, NULL, &strBackupAudit); | ||
| 1309 | nFail += Check(nBackupAuditRet == 0 && | ||
| 1310 | FileContainsText(strBackupAudit, "recovery phrase: present") && | ||
| 1311 | FileContainsText(strBackupAudit, "SLIP-0044 BITFLASH"), | ||
| 1312 | "a /backupwallet copy opens in a new datadir") ? 0 : 1; | ||
| 1313 | } | ||
| 1314 | catch (const std::exception& e) | ||
| 1315 | { | ||
| 1316 | printf(" FAIL exception: %s\n", e.what()); | ||
| 1317 | nFail++; | ||
| 1318 | } | ||
| 1319 | catch (...) | ||
| 1320 | { | ||
| 1321 | printf(" FAIL unknown exception\n"); | ||
| 1322 | nFail++; | ||
| 1323 | } | ||
| 1324 | |||
| 1325 | RemoveTree(tmp); | ||
| 1326 | printf("%s (%d failure%s)\n", nFail == 0 ? "ALL TESTS PASSED" : "TESTS FAILED", | ||
| 1327 | nFail, nFail == 1 ? "" : "s"); | ||
| 1328 | fflush(stdout); | ||
| 1329 | return nFail == 0 ? 0 : 1; | ||
| 1330 | } | ||
| 1331 | |||
| 1172 | static int RunNetMessageSelfTest() | 1332 | static int RunNetMessageSelfTest() |
| 1173 | { | 1333 | { |
| 1174 | fflush(stdout); | 1334 | fflush(stdout); |
| @@ -1653,6 +1813,8 @@ int RunSelfTest(const std::string& name) | |||
| 1653 | return RunWalletCryptoSelfTest(); | 1813 | return RunWalletCryptoSelfTest(); |
| 1654 | if (name == "wallet-encrypt") | 1814 | if (name == "wallet-encrypt") |
| 1655 | return RunWalletEncryptSelfTest(); | 1815 | return RunWalletEncryptSelfTest(); |
| 1816 | if (name == "wallet-portability") | ||
| 1817 | return RunWalletPortabilitySelfTest(); | ||
| 1656 | if (name == "net-message") | 1818 | if (name == "net-message") |
| 1657 | return RunNetMessageSelfTest(); | 1819 | return RunNetMessageSelfTest(); |
| 1658 | if (name == "consensus-limits") | 1820 | if (name == "consensus-limits") |
| @@ -1667,6 +1829,6 @@ int RunSelfTest(const std::string& name) | |||
| 1667 | return RunManagedTorSelfTest(); | 1829 | return RunManagedTorSelfTest(); |
| 1668 | 1830 | ||
| 1669 | printf("Unknown self-test '%s'\n", name.c_str()); | 1831 | printf("Unknown self-test '%s'\n", name.c_str()); |
| 1670 | printf("Known self-tests: wallet-keypool, wallet-hd, wallet-format, wallet-crypto, wallet-encrypt, net-message, consensus-limits, pool-stratum, parse-money, socks5-proxy, managed-tor\n"); | 1832 | printf("Known self-tests: wallet-keypool, wallet-hd, wallet-format, wallet-crypto, wallet-encrypt, wallet-portability, net-message, consensus-limits, pool-stratum, parse-money, socks5-proxy, managed-tor\n"); |
| 1671 | return 1; | 1833 | return 1; |
| 1672 | } | 1834 | } |