diff options
| author | Bitflash <admin@bitflash.network> | 2026-08-14 08:56:40 -0300 |
|---|---|---|
| committer | Bitflash <admin@bitflash.network> | 2026-08-14 08:56:40 -0300 |
| commit | 5306542f6121e0c0b4ed1210e24d55fa4fbb7127 (patch) | |
| tree | 5faf35daa569d987b87dbb161bb18ec170f944b0 /src/selftest.cpp | |
| parent | 9e39a50d1f110020b0841d31e4b931aa877cc448 (diff) | |
| parent | 805c5757b801d80ea575c6a8b58e2855254f9046 (diff) | |
Merge pull request 'wallet: audit Berkeley DB wallet storage' (#38) from wallet-storage-audit-bdb into main
Diffstat (limited to 'src/selftest.cpp')
| -rw-r--r-- | src/selftest.cpp | 336 |
1 files changed, 332 insertions, 4 deletions
diff --git a/src/selftest.cpp b/src/selftest.cpp index 3c93927..73c2935 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,90 @@ 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 | |||
| 969 | static bool DirectoryHasFileWithPrefix(const string& strDir, const string& strPrefix) | ||
| 970 | { | ||
| 971 | #ifdef _WIN32 | ||
| 972 | WIN32_FIND_DATAA findData; | ||
| 973 | string pattern = strDir + "\\*"; | ||
| 974 | HANDLE hFind = FindFirstFileA(pattern.c_str(), &findData); | ||
| 975 | if (hFind == INVALID_HANDLE_VALUE) | ||
| 976 | return false; | ||
| 977 | bool fFound = false; | ||
| 978 | do | ||
| 979 | { | ||
| 980 | if (!(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) | ||
| 981 | { | ||
| 982 | string name = findData.cFileName; | ||
| 983 | if (name.compare(0, strPrefix.size(), strPrefix) == 0) | ||
| 984 | { | ||
| 985 | fFound = true; | ||
| 986 | break; | ||
| 987 | } | ||
| 988 | } | ||
| 989 | } | ||
| 990 | while (FindNextFileA(hFind, &findData)); | ||
| 991 | FindClose(hFind); | ||
| 992 | return fFound; | ||
| 993 | #else | ||
| 994 | DIR* dir = opendir(strDir.c_str()); | ||
| 995 | if (!dir) | ||
| 996 | return false; | ||
| 997 | bool fFound = false; | ||
| 998 | struct dirent* ent; | ||
| 999 | while ((ent = readdir(dir)) != NULL) | ||
| 1000 | { | ||
| 1001 | string name = ent->d_name; | ||
| 1002 | if (name.compare(0, strPrefix.size(), strPrefix) == 0) | ||
| 1003 | { | ||
| 1004 | fFound = true; | ||
| 1005 | break; | ||
| 1006 | } | ||
| 1007 | } | ||
| 1008 | closedir(dir); | ||
| 1009 | return fFound; | ||
| 1010 | #endif | ||
| 1011 | } | ||
| 1012 | |||
| 928 | static string QuoteCommandArg(const string& str) | 1013 | static string QuoteCommandArg(const string& str) |
| 929 | { | 1014 | { |
| 930 | string out = "\""; | 1015 | string out = "\""; |
| @@ -941,7 +1026,8 @@ static string QuoteCommandArg(const string& str) | |||
| 941 | 1026 | ||
| 942 | static int RunBitflashChild(const string& strExe, | 1027 | static int RunBitflashChild(const string& strExe, |
| 943 | const vector<string>& vArgs, | 1028 | const vector<string>& vArgs, |
| 944 | const string* pStdinFile = NULL) | 1029 | const string* pStdinFile = NULL, |
| 1030 | const string* pOutputFile = NULL) | ||
| 945 | { | 1031 | { |
| 946 | #ifdef _WIN32 | 1032 | #ifdef _WIN32 |
| 947 | vector<char*> argv; | 1033 | vector<char*> argv; |
| @@ -954,8 +1040,16 @@ static int RunBitflashChild(const string& strExe, | |||
| 954 | int nOldErr = _dup(2); | 1040 | int nOldErr = _dup(2); |
| 955 | int nOldIn = _dup(0); | 1041 | int nOldIn = _dup(0); |
| 956 | int nNull = _open("NUL", _O_WRONLY); | 1042 | int nNull = _open("NUL", _O_WRONLY); |
| 1043 | int nOut = -1; | ||
| 957 | int nIn = -1; | 1044 | int nIn = -1; |
| 958 | if (nNull >= 0) | 1045 | if (pOutputFile) |
| 1046 | nOut = _open(pOutputFile->c_str(), _O_WRONLY|_O_CREAT|_O_TRUNC|_O_BINARY, _S_IREAD|_S_IWRITE); | ||
| 1047 | if (nOut >= 0) | ||
| 1048 | { | ||
| 1049 | _dup2(nOut, 1); | ||
| 1050 | _dup2(nOut, 2); | ||
| 1051 | } | ||
| 1052 | else if (nNull >= 0) | ||
| 959 | { | 1053 | { |
| 960 | _dup2(nNull, 1); | 1054 | _dup2(nNull, 1); |
| 961 | _dup2(nNull, 2); | 1055 | _dup2(nNull, 2); |
| @@ -969,6 +1063,8 @@ static int RunBitflashChild(const string& strExe, | |||
| 969 | int nRet = _spawnv(_P_WAIT, strExe.c_str(), &argv[0]); | 1063 | int nRet = _spawnv(_P_WAIT, strExe.c_str(), &argv[0]); |
| 970 | if (nIn >= 0) | 1064 | if (nIn >= 0) |
| 971 | _close(nIn); | 1065 | _close(nIn); |
| 1066 | if (nOut >= 0) | ||
| 1067 | _close(nOut); | ||
| 972 | if (nNull >= 0) | 1068 | if (nNull >= 0) |
| 973 | _close(nNull); | 1069 | _close(nNull); |
| 974 | if (nOldIn >= 0) | 1070 | if (nOldIn >= 0) |
| @@ -993,7 +1089,10 @@ static int RunBitflashChild(const string& strExe, | |||
| 993 | strCmd += " " + QuoteCommandArg(vArgs[i]); | 1089 | strCmd += " " + QuoteCommandArg(vArgs[i]); |
| 994 | if (pStdinFile) | 1090 | if (pStdinFile) |
| 995 | strCmd += " < " + QuoteCommandArg(*pStdinFile); | 1091 | strCmd += " < " + QuoteCommandArg(*pStdinFile); |
| 996 | strCmd += " > /dev/null 2>&1"; | 1092 | if (pOutputFile) |
| 1093 | strCmd += " > " + QuoteCommandArg(*pOutputFile) + " 2>&1"; | ||
| 1094 | else | ||
| 1095 | strCmd += " > /dev/null 2>&1"; | ||
| 997 | return system(strCmd.c_str()); | 1096 | return system(strCmd.c_str()); |
| 998 | #endif | 1097 | #endif |
| 999 | } | 1098 | } |
| @@ -1066,6 +1165,8 @@ static int RunWalletEncryptSelfTest() | |||
| 1066 | string strRightDump = tmp + "/right-pass-dump.txt"; | 1165 | string strRightDump = tmp + "/right-pass-dump.txt"; |
| 1067 | string strLiteralDump = tmp + "/literal-pass-dump.txt"; | 1166 | string strLiteralDump = tmp + "/literal-pass-dump.txt"; |
| 1068 | string strStdinDump = tmp + "/stdin-pass-dump.txt"; | 1167 | string strStdinDump = tmp + "/stdin-pass-dump.txt"; |
| 1168 | string strLockedAudit = tmp + "/locked-recovery-audit.txt"; | ||
| 1169 | string strUnlockedAudit = tmp + "/unlocked-recovery-audit.txt"; | ||
| 1069 | string strWrongPassFile = tmp + "/wrong-pass.txt"; | 1170 | string strWrongPassFile = tmp + "/wrong-pass.txt"; |
| 1070 | string strRightPassFile = tmp + "/right-pass.txt"; | 1171 | string strRightPassFile = tmp + "/right-pass.txt"; |
| 1071 | nFail += Check(WriteTextFile(strWrongPassFile, "wrong-passphrase\n") && | 1172 | nFail += Check(WriteTextFile(strWrongPassFile, "wrong-passphrase\n") && |
| @@ -1081,6 +1182,17 @@ static int RunWalletEncryptSelfTest() | |||
| 1081 | nFail += Check(nWrongRet != 0 && !FileExists(strWrongDump.c_str()), | 1182 | nFail += Check(nWrongRet != 0 && !FileExists(strWrongDump.c_str()), |
| 1082 | "a restarted wallet rejects the wrong-passphrase") ? 0 : 1; | 1183 | "a restarted wallet rejects the wrong-passphrase") ? 0 : 1; |
| 1083 | 1184 | ||
| 1185 | vector<string> vLockedAuditArgs; | ||
| 1186 | vLockedAuditArgs.push_back("-datadir=" + tmp); | ||
| 1187 | vLockedAuditArgs.push_back("-recoveryaudit"); | ||
| 1188 | vLockedAuditArgs.push_back("-nogui"); | ||
| 1189 | int nLockedAuditRet = RunBitflashChild(strExe, vLockedAuditArgs, NULL, &strLockedAudit); | ||
| 1190 | nFail += Check(nLockedAuditRet == 2 && | ||
| 1191 | FileContainsText(strLockedAudit, "recovery phrase: encrypted, unlock wallet to audit") && | ||
| 1192 | FileContainsText(strLockedAudit, "recovery coverage: unavailable while wallet is locked") && | ||
| 1193 | FileContainsText(strLockedAudit, "Unlock the wallet with /walletpassphrase"), | ||
| 1194 | "a locked encrypted wallet reports that phrase coverage needs unlock") ? 0 : 1; | ||
| 1195 | |||
| 1084 | vector<string> vLiteralArgs; | 1196 | vector<string> vLiteralArgs; |
| 1085 | vLiteralArgs.push_back("-datadir=" + tmp); | 1197 | vLiteralArgs.push_back("-datadir=" + tmp); |
| 1086 | vLiteralArgs.push_back("-walletpassphrase=btf-test-passphrase"); | 1198 | vLiteralArgs.push_back("-walletpassphrase=btf-test-passphrase"); |
| @@ -1101,6 +1213,17 @@ static int RunWalletEncryptSelfTest() | |||
| 1101 | nFail += Check(FileContainsText(strRightDump, HexStrLocal(vchDefaultPrivBytes)), | 1213 | nFail += Check(FileContainsText(strRightDump, HexStrLocal(vchDefaultPrivBytes)), |
| 1102 | "the restarted wallet can decrypt and dump the original key") ? 0 : 1; | 1214 | "the restarted wallet can decrypt and dump the original key") ? 0 : 1; |
| 1103 | 1215 | ||
| 1216 | vector<string> vUnlockedAuditArgs; | ||
| 1217 | vUnlockedAuditArgs.push_back("-datadir=" + tmp); | ||
| 1218 | vUnlockedAuditArgs.push_back("-walletpassphrase=@" + strRightPassFile); | ||
| 1219 | vUnlockedAuditArgs.push_back("-recoveryaudit"); | ||
| 1220 | vUnlockedAuditArgs.push_back("-nogui"); | ||
| 1221 | int nUnlockedAuditRet = RunBitflashChild(strExe, vUnlockedAuditArgs, NULL, &strUnlockedAudit); | ||
| 1222 | nFail += Check(nUnlockedAuditRet == 0 && | ||
| 1223 | FileContainsText(strUnlockedAudit, "recovery phrase: present") && | ||
| 1224 | !FileContainsText(strUnlockedAudit, "recovery phrase: not installed"), | ||
| 1225 | "an unlocked encrypted wallet audits the installed recovery phrase") ? 0 : 1; | ||
| 1226 | |||
| 1104 | vector<string> vStdinArgs; | 1227 | vector<string> vStdinArgs; |
| 1105 | vStdinArgs.push_back("-datadir=" + tmp); | 1228 | vStdinArgs.push_back("-datadir=" + tmp); |
| 1106 | vStdinArgs.push_back("-walletpassphrase"); | 1229 | vStdinArgs.push_back("-walletpassphrase"); |
| @@ -1131,6 +1254,209 @@ static int RunWalletEncryptSelfTest() | |||
| 1131 | return nFail == 0 ? 0 : 1; | 1254 | return nFail == 0 ? 0 : 1; |
| 1132 | } | 1255 | } |
| 1133 | 1256 | ||
| 1257 | static int RunWalletPortabilitySelfTest() | ||
| 1258 | { | ||
| 1259 | fflush(stdout); | ||
| 1260 | printf("wallet-portability self-test\n"); | ||
| 1261 | |||
| 1262 | std::string tmp; | ||
| 1263 | std::string cwd; | ||
| 1264 | if (!MakeTempDir(tmp)) | ||
| 1265 | { | ||
| 1266 | printf(" FAIL could not create a temporary data directory\n"); | ||
| 1267 | return 1; | ||
| 1268 | } | ||
| 1269 | if (!GetCurrentDir(cwd)) | ||
| 1270 | { | ||
| 1271 | printf(" FAIL could not read current directory\n"); | ||
| 1272 | RemoveTree(tmp); | ||
| 1273 | return 1; | ||
| 1274 | } | ||
| 1275 | |||
| 1276 | int nFail = 0; | ||
| 1277 | printf(" temp root: %s\n", tmp.c_str()); | ||
| 1278 | |||
| 1279 | try | ||
| 1280 | { | ||
| 1281 | #ifdef _WIN32 | ||
| 1282 | string strExe = cwd + "\\bitflash.exe"; | ||
| 1283 | #else | ||
| 1284 | string strExe = cwd + "/bitflash-node"; | ||
| 1285 | #endif | ||
| 1286 | string strOriginal = tmp + "/original"; | ||
| 1287 | string strRawCopy = tmp + "/raw-copy"; | ||
| 1288 | string strBackupCopy = tmp + "/backup-copy"; | ||
| 1289 | nFail += Check(MakeDirLocal(strOriginal) && | ||
| 1290 | MakeDirLocal(strRawCopy) && | ||
| 1291 | MakeDirLocal(strBackupCopy), | ||
| 1292 | "temporary wallet directories can be created") ? 0 : 1; | ||
| 1293 | |||
| 1294 | string strCreateOut = tmp + "/create.txt"; | ||
| 1295 | vector<string> vCreateArgs; | ||
| 1296 | vCreateArgs.push_back("-datadir=" + strOriginal); | ||
| 1297 | vCreateArgs.push_back("-nomanagedtor"); | ||
| 1298 | vCreateArgs.push_back("-nogui"); | ||
| 1299 | vCreateArgs.push_back("-newphrase"); | ||
| 1300 | int nCreateRet = RunBitflashChild(strExe, vCreateArgs, NULL, &strCreateOut); | ||
| 1301 | nFail += Check(nCreateRet == 0 && | ||
| 1302 | FileContainsText(strCreateOut, "Write these twelve words down"), | ||
| 1303 | "a phrase wallet can be created in a fresh datadir") ? 0 : 1; | ||
| 1304 | |||
| 1305 | string strOriginalAudit = tmp + "/original-audit.txt"; | ||
| 1306 | vector<string> vOriginalAuditArgs; | ||
| 1307 | vOriginalAuditArgs.push_back("-datadir=" + strOriginal); | ||
| 1308 | vOriginalAuditArgs.push_back("-nomanagedtor"); | ||
| 1309 | vOriginalAuditArgs.push_back("-nogui"); | ||
| 1310 | vOriginalAuditArgs.push_back("-recoveryaudit"); | ||
| 1311 | int nOriginalAuditRet = RunBitflashChild(strExe, vOriginalAuditArgs, NULL, &strOriginalAudit); | ||
| 1312 | nFail += Check(nOriginalAuditRet == 0 && | ||
| 1313 | FileContainsText(strOriginalAudit, "recovery phrase: present") && | ||
| 1314 | FileContainsText(strOriginalAudit, "SLIP-0044 BITFLASH"), | ||
| 1315 | "the original wallet reports its recovery phrase") ? 0 : 1; | ||
| 1316 | |||
| 1317 | string strOriginalStorageAudit = tmp + "/original-storage-audit.txt"; | ||
| 1318 | vector<string> vOriginalStorageAuditArgs; | ||
| 1319 | vOriginalStorageAuditArgs.push_back("-datadir=" + strOriginal); | ||
| 1320 | vOriginalStorageAuditArgs.push_back("-nomanagedtor"); | ||
| 1321 | vOriginalStorageAuditArgs.push_back("-nogui"); | ||
| 1322 | vOriginalStorageAuditArgs.push_back("-walletstorageaudit"); | ||
| 1323 | int nOriginalStorageAuditRet = | ||
| 1324 | RunBitflashChild(strExe, vOriginalStorageAuditArgs, NULL, &strOriginalStorageAudit); | ||
| 1325 | nFail += Check(nOriginalStorageAuditRet == 0 && | ||
| 1326 | FileContainsText(strOriginalStorageAudit, "Wallet storage audit") && | ||
| 1327 | FileContainsText(strOriginalStorageAudit, "plain HD seed: complete") && | ||
| 1328 | FileContainsText(strOriginalStorageAudit, "encrypted HD seed: none") && | ||
| 1329 | FileContainsText(strOriginalStorageAudit, "malformed records: 0"), | ||
| 1330 | "the storage audit recognizes a plaintext phrase wallet") ? 0 : 1; | ||
| 1331 | |||
| 1332 | string strOriginalStorageAuditJson = tmp + "/original-storage-audit.json"; | ||
| 1333 | vector<string> vOriginalStorageAuditJsonArgs; | ||
| 1334 | vOriginalStorageAuditJsonArgs.push_back("-datadir=" + strOriginal); | ||
| 1335 | vOriginalStorageAuditJsonArgs.push_back("-nomanagedtor"); | ||
| 1336 | vOriginalStorageAuditJsonArgs.push_back("-nogui"); | ||
| 1337 | vOriginalStorageAuditJsonArgs.push_back("-walletstorageauditjson=" + | ||
| 1338 | strOriginalStorageAuditJson); | ||
| 1339 | int nOriginalStorageAuditJsonRet = | ||
| 1340 | RunBitflashChild(strExe, vOriginalStorageAuditJsonArgs); | ||
| 1341 | nFail += Check(nOriginalStorageAuditJsonRet == 0 && | ||
| 1342 | FileContainsText(strOriginalStorageAuditJson, | ||
| 1343 | "\"format\": \"bitflash-wallet-storage-audit-v1\"") && | ||
| 1344 | FileContainsText(strOriginalStorageAuditJson, | ||
| 1345 | "\"plain_hd_seed\": \"complete\"") && | ||
| 1346 | FileContainsText(strOriginalStorageAuditJson, | ||
| 1347 | "\"encrypted_hd_seed\": \"none\""), | ||
| 1348 | "the storage audit can write plaintext-wallet JSON") ? 0 : 1; | ||
| 1349 | |||
| 1350 | string strPortableWallet = tmp + "/portable-wallet.dat"; | ||
| 1351 | string strBackupOut = tmp + "/backupwallet.txt"; | ||
| 1352 | vector<string> vBackupArgs; | ||
| 1353 | vBackupArgs.push_back("-datadir=" + strOriginal); | ||
| 1354 | vBackupArgs.push_back("-nomanagedtor"); | ||
| 1355 | vBackupArgs.push_back("-nogui"); | ||
| 1356 | vBackupArgs.push_back("-backupwallet=" + strPortableWallet); | ||
| 1357 | int nBackupRet = RunBitflashChild(strExe, vBackupArgs, NULL, &strBackupOut); | ||
| 1358 | nFail += Check(nBackupRet == 0 && FileExists(strPortableWallet.c_str()), | ||
| 1359 | "/backupwallet writes a portable wallet.dat") ? 0 : 1; | ||
| 1360 | |||
| 1361 | nFail += Check(CopyFileLocal(strOriginal + "/wallet.dat", | ||
| 1362 | strRawCopy + "/wallet.dat"), | ||
| 1363 | "a raw wallet.dat can be copied without database logs") ? 0 : 1; | ||
| 1364 | string strRawAudit = tmp + "/raw-copy-audit.txt"; | ||
| 1365 | vector<string> vRawAuditArgs; | ||
| 1366 | vRawAuditArgs.push_back("-datadir=" + strRawCopy); | ||
| 1367 | vRawAuditArgs.push_back("-nomanagedtor"); | ||
| 1368 | vRawAuditArgs.push_back("-nogui"); | ||
| 1369 | vRawAuditArgs.push_back("-recoveryaudit"); | ||
| 1370 | int nRawAuditRet = RunBitflashChild(strExe, vRawAuditArgs, NULL, &strRawAudit); | ||
| 1371 | nFail += Check(nRawAuditRet == 0 && | ||
| 1372 | FileContainsText(strRawAudit, "recovery phrase: present") && | ||
| 1373 | !FileContainsText(strRawAudit, "Cannot open wallet.dat"), | ||
| 1374 | "a raw wallet.dat copy opens in a new datadir") ? 0 : 1; | ||
| 1375 | |||
| 1376 | nFail += Check(CopyFileLocal(strPortableWallet, | ||
| 1377 | strBackupCopy + "/wallet.dat"), | ||
| 1378 | "the portable backup can be installed as wallet.dat") ? 0 : 1; | ||
| 1379 | string strBackupAudit = tmp + "/backup-copy-audit.txt"; | ||
| 1380 | vector<string> vBackupAuditArgs; | ||
| 1381 | vBackupAuditArgs.push_back("-datadir=" + strBackupCopy); | ||
| 1382 | vBackupAuditArgs.push_back("-nomanagedtor"); | ||
| 1383 | vBackupAuditArgs.push_back("-nogui"); | ||
| 1384 | vBackupAuditArgs.push_back("-recoveryaudit"); | ||
| 1385 | int nBackupAuditRet = RunBitflashChild(strExe, vBackupAuditArgs, NULL, &strBackupAudit); | ||
| 1386 | nFail += Check(nBackupAuditRet == 0 && | ||
| 1387 | FileContainsText(strBackupAudit, "recovery phrase: present") && | ||
| 1388 | FileContainsText(strBackupAudit, "SLIP-0044 BITFLASH"), | ||
| 1389 | "a /backupwallet copy opens in a new datadir") ? 0 : 1; | ||
| 1390 | |||
| 1391 | string strPassFile = tmp + "/encrypt-pass.txt"; | ||
| 1392 | string strEncryptOut = tmp + "/encryptwallet.txt"; | ||
| 1393 | nFail += Check(WriteTextFile(strPassFile, "portable-test-passphrase\n"), | ||
| 1394 | "an encryption passphrase file can be written") ? 0 : 1; | ||
| 1395 | vector<string> vEncryptArgs; | ||
| 1396 | vEncryptArgs.push_back("-datadir=" + strOriginal); | ||
| 1397 | vEncryptArgs.push_back("-nomanagedtor"); | ||
| 1398 | vEncryptArgs.push_back("-nogui"); | ||
| 1399 | vEncryptArgs.push_back("-encryptwallet=@" + strPassFile); | ||
| 1400 | int nEncryptRet = RunBitflashChild(strExe, vEncryptArgs, NULL, &strEncryptOut); | ||
| 1401 | nFail += Check(nEncryptRet == 0 && | ||
| 1402 | !DirectoryHasFileWithPrefix(strOriginal + "/database", "log."), | ||
| 1403 | "the encryptwallet command purges Berkeley DB environment logs") ? 0 : 1; | ||
| 1404 | |||
| 1405 | string strEncryptedStorageAudit = tmp + "/encrypted-storage-audit.txt"; | ||
| 1406 | vector<string> vEncryptedStorageAuditArgs; | ||
| 1407 | vEncryptedStorageAuditArgs.push_back("-datadir=" + strOriginal); | ||
| 1408 | vEncryptedStorageAuditArgs.push_back("-nomanagedtor"); | ||
| 1409 | vEncryptedStorageAuditArgs.push_back("-nogui"); | ||
| 1410 | vEncryptedStorageAuditArgs.push_back("-walletstorageaudit"); | ||
| 1411 | int nEncryptedStorageAuditRet = | ||
| 1412 | RunBitflashChild(strExe, vEncryptedStorageAuditArgs, NULL, &strEncryptedStorageAudit); | ||
| 1413 | nFail += Check(nEncryptedStorageAuditRet == 0 && | ||
| 1414 | FileContainsText(strEncryptedStorageAudit, "plain private keys: 0") && | ||
| 1415 | FileContainsText(strEncryptedStorageAudit, "encrypted private keys:") && | ||
| 1416 | FileContainsText(strEncryptedStorageAudit, "plain HD seed: none") && | ||
| 1417 | FileContainsText(strEncryptedStorageAudit, "encrypted HD seed: complete") && | ||
| 1418 | FileContainsText(strEncryptedStorageAudit, "wallet minimum version: present") && | ||
| 1419 | FileContainsText(strEncryptedStorageAudit, "malformed records: 0"), | ||
| 1420 | "the storage audit recognizes an encrypted wallet") ? 0 : 1; | ||
| 1421 | |||
| 1422 | string strEncryptedStorageAuditJson = tmp + "/encrypted-storage-audit.json"; | ||
| 1423 | vector<string> vEncryptedStorageAuditJsonArgs; | ||
| 1424 | vEncryptedStorageAuditJsonArgs.push_back("-datadir=" + strOriginal); | ||
| 1425 | vEncryptedStorageAuditJsonArgs.push_back("-nomanagedtor"); | ||
| 1426 | vEncryptedStorageAuditJsonArgs.push_back("-nogui"); | ||
| 1427 | vEncryptedStorageAuditJsonArgs.push_back("-walletstorageauditjson=" + | ||
| 1428 | strEncryptedStorageAuditJson); | ||
| 1429 | int nEncryptedStorageAuditJsonRet = | ||
| 1430 | RunBitflashChild(strExe, vEncryptedStorageAuditJsonArgs); | ||
| 1431 | nFail += Check(nEncryptedStorageAuditJsonRet == 0 && | ||
| 1432 | FileContainsText(strEncryptedStorageAuditJson, | ||
| 1433 | "\"plain_private_keys\": 0") && | ||
| 1434 | FileContainsText(strEncryptedStorageAuditJson, | ||
| 1435 | "\"plain_hd_seed\": \"none\"") && | ||
| 1436 | FileContainsText(strEncryptedStorageAuditJson, | ||
| 1437 | "\"encrypted_hd_seed\": \"complete\"") && | ||
| 1438 | FileContainsText(strEncryptedStorageAuditJson, | ||
| 1439 | "\"wallet_minimum_version\": \"present\""), | ||
| 1440 | "the storage audit can write encrypted-wallet JSON") ? 0 : 1; | ||
| 1441 | } | ||
| 1442 | catch (const std::exception& e) | ||
| 1443 | { | ||
| 1444 | printf(" FAIL exception: %s\n", e.what()); | ||
| 1445 | nFail++; | ||
| 1446 | } | ||
| 1447 | catch (...) | ||
| 1448 | { | ||
| 1449 | printf(" FAIL unknown exception\n"); | ||
| 1450 | nFail++; | ||
| 1451 | } | ||
| 1452 | |||
| 1453 | RemoveTree(tmp); | ||
| 1454 | printf("%s (%d failure%s)\n", nFail == 0 ? "ALL TESTS PASSED" : "TESTS FAILED", | ||
| 1455 | nFail, nFail == 1 ? "" : "s"); | ||
| 1456 | fflush(stdout); | ||
| 1457 | return nFail == 0 ? 0 : 1; | ||
| 1458 | } | ||
| 1459 | |||
| 1134 | static int RunNetMessageSelfTest() | 1460 | static int RunNetMessageSelfTest() |
| 1135 | { | 1461 | { |
| 1136 | fflush(stdout); | 1462 | fflush(stdout); |
| @@ -1615,6 +1941,8 @@ int RunSelfTest(const std::string& name) | |||
| 1615 | return RunWalletCryptoSelfTest(); | 1941 | return RunWalletCryptoSelfTest(); |
| 1616 | if (name == "wallet-encrypt") | 1942 | if (name == "wallet-encrypt") |
| 1617 | return RunWalletEncryptSelfTest(); | 1943 | return RunWalletEncryptSelfTest(); |
| 1944 | if (name == "wallet-portability") | ||
| 1945 | return RunWalletPortabilitySelfTest(); | ||
| 1618 | if (name == "net-message") | 1946 | if (name == "net-message") |
| 1619 | return RunNetMessageSelfTest(); | 1947 | return RunNetMessageSelfTest(); |
| 1620 | if (name == "consensus-limits") | 1948 | if (name == "consensus-limits") |
| @@ -1629,6 +1957,6 @@ int RunSelfTest(const std::string& name) | |||
| 1629 | return RunManagedTorSelfTest(); | 1957 | return RunManagedTorSelfTest(); |
| 1630 | 1958 | ||
| 1631 | printf("Unknown self-test '%s'\n", name.c_str()); | 1959 | printf("Unknown self-test '%s'\n", name.c_str()); |
| 1632 | 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"); | 1960 | 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"); |
| 1633 | return 1; | 1961 | return 1; |
| 1634 | } | 1962 | } |