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:
Diffstat (limited to 'src')
-rw-r--r--src/main_gui.cpp10
-rw-r--r--src/selftest.cpp38
-rw-r--r--src/walletcmd.cpp71
-rw-r--r--src/walletcmd.h2
4 files changed, 117 insertions, 4 deletions
diff --git a/src/main_gui.cpp b/src/main_gui.cpp
index 532bc3b..395cc0f 100644
--- a/src/main_gui.cpp
+++ b/src/main_gui.cpp
@@ -174,6 +174,8 @@ static void PrintUsage()
174 printf(" exits 2 when wallet.dat is still needed)\n"); 174 printf(" exits 2 when wallet.dat is still needed)\n");
175 printf(" /walletstorageaudit (count wallet.dat record types without\n"); 175 printf(" /walletstorageaudit (count wallet.dat record types without\n");
176 printf(" printing wallet values, then exit)\n"); 176 printf(" printing wallet values, then exit)\n");
177 printf(" /walletstorageauditjson=FILE\n");
178 printf(" (write the same audit as deterministic JSON)\n");
177 printf(" /rescan (walk the chain for coins this wallet owns\n"); 179 printf(" /rescan (walk the chain for coins this wallet owns\n");
178 printf(" but never recorded, then exit)\n"); 180 printf(" but never recorded, then exit)\n");
179 printf("\n"); 181 printf("\n");
@@ -706,9 +708,13 @@ int main(int argc, char* argv[])
706 return nRet; 708 return nRet;
707 } 709 }
708 710
709 if (arg(argc,argv,"/walletstorageaudit") || arg(argc,argv,"-walletstorageaudit")) 711 string strWalletStorageAuditJson =
712 argval2(argc, argv, "/walletstorageauditjson", "-walletstorageauditjson");
713 if (arg(argc,argv,"/walletstorageaudit") ||
714 arg(argc,argv,"-walletstorageaudit") ||
715 !strWalletStorageAuditJson.empty())
710 { 716 {
711 int nRet = CmdWalletStorageAudit(); 717 int nRet = CmdWalletStorageAudit(strWalletStorageAuditJson);
712 DBFlush(true); 718 DBFlush(true);
713 return nRet; 719 return nRet;
714 } 720 }
diff --git a/src/selftest.cpp b/src/selftest.cpp
index b112238..73c2935 100644
--- a/src/selftest.cpp
+++ b/src/selftest.cpp
@@ -1329,6 +1329,24 @@ static int RunWalletPortabilitySelfTest()
1329 FileContainsText(strOriginalStorageAudit, "malformed records: 0"), 1329 FileContainsText(strOriginalStorageAudit, "malformed records: 0"),
1330 "the storage audit recognizes a plaintext phrase wallet") ? 0 : 1; 1330 "the storage audit recognizes a plaintext phrase wallet") ? 0 : 1;
1331 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
1332 string strPortableWallet = tmp + "/portable-wallet.dat"; 1350 string strPortableWallet = tmp + "/portable-wallet.dat";
1333 string strBackupOut = tmp + "/backupwallet.txt"; 1351 string strBackupOut = tmp + "/backupwallet.txt";
1334 vector<string> vBackupArgs; 1352 vector<string> vBackupArgs;
@@ -1400,6 +1418,26 @@ static int RunWalletPortabilitySelfTest()
1400 FileContainsText(strEncryptedStorageAudit, "wallet minimum version: present") && 1418 FileContainsText(strEncryptedStorageAudit, "wallet minimum version: present") &&
1401 FileContainsText(strEncryptedStorageAudit, "malformed records: 0"), 1419 FileContainsText(strEncryptedStorageAudit, "malformed records: 0"),
1402 "the storage audit recognizes an encrypted wallet") ? 0 : 1; 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;
1403 } 1441 }
1404 catch (const std::exception& e) 1442 catch (const std::exception& e)
1405 { 1443 {
diff --git a/src/walletcmd.cpp b/src/walletcmd.cpp
index 896d593..6f8258d 100644
--- a/src/walletcmd.cpp
+++ b/src/walletcmd.cpp
@@ -605,7 +605,60 @@ static bool ReadWalletStorageCounts(WalletStorageAuditCounts& counts,
605 return true; 605 return true;
606} 606}
607 607
608int CmdWalletStorageAudit() 608static std::string WalletStorageAuditJson(const WalletStorageAuditCounts& counts)
609{
610 std::string strJson;
611 strJson += "{\n";
612 strJson += " \"format\": \"bitflash-wallet-storage-audit-v1\",\n";
613 strJson += strprintf(" \"records_total\": %u,\n", counts.nTotal);
614 strJson += strprintf(" \"malformed_records\": %u,\n", counts.nMalformed);
615 strJson += strprintf(" \"unknown_records\": %u,\n", counts.nUnknown);
616 strJson += strprintf(" \"plain_private_keys\": %u,\n", counts.nPlainKeys);
617 strJson += strprintf(" \"encrypted_private_keys\": %u,\n", counts.nEncryptedKeys);
618 strJson += strprintf(" \"encryption_master_keys\": %u,\n", counts.nMasterKeys);
619 strJson += strprintf(" \"default_public_key\": \"%s\",\n",
620 counts.nDefaultKey ? "present" : "none");
621 strJson += strprintf(" \"plain_hd_seed\": \"%s\",\n",
622 HDSeedStorageState(counts.nPlainHDMaster,
623 counts.nPlainHDChainCode).c_str());
624 strJson += strprintf(" \"encrypted_hd_seed\": \"%s\",\n",
625 HDSeedStorageState(counts.nCryptedHDMaster,
626 counts.nCryptedHDChainCode).c_str());
627 strJson += strprintf(" \"wallet_minimum_version\": \"%s\",\n",
628 counts.nWalletMinVersion ? "present" : "none");
629 strJson += strprintf(" \"keypool_entries\": %u,\n", counts.nPool);
630 strJson += strprintf(" \"wallet_transactions\": %u,\n", counts.nTransactions);
631 strJson += strprintf(" \"address_book_labels\": %u,\n", counts.nNames);
632 strJson += strprintf(" \"settings\": %u,\n", counts.nSettings);
633 strJson += strprintf(" \"hd_metadata_records\": %u,\n",
634 counts.nHDNext + counts.nHDSchema + counts.nHDCoinType +
635 counts.nHDReceiveNext + counts.nHDChangeNext);
636 strJson += strprintf(" \"database_version_records\": %u\n", counts.nVersion);
637 strJson += "}\n";
638 return strJson;
639}
640
641static bool WriteAuditTextFile(const std::string& strPath,
642 const std::string& strText,
643 std::string& strError)
644{
645 FILE* pf = fopen(strPath.c_str(), "wb");
646 if (!pf)
647 {
648 strError = "cannot open output file";
649 return false;
650 }
651 size_t nWritten = fwrite(strText.data(), 1, strText.size(), pf);
652 bool fCloseOk = fclose(pf) == 0;
653 if (nWritten != strText.size() || !fCloseOk)
654 {
655 strError = "could not write the complete output file";
656 return false;
657 }
658 return true;
659}
660
661int CmdWalletStorageAudit(const std::string& strJsonOut)
609{ 662{
610 AttachTerminal(); 663 AttachTerminal();
611 664
@@ -617,6 +670,22 @@ int CmdWalletStorageAudit()
617 return 1; 670 return 1;
618 } 671 }
619 672
673 if (!strJsonOut.empty())
674 {
675 std::string strWriteError;
676 if (!WriteAuditTextFile(strJsonOut,
677 WalletStorageAuditJson(counts),
678 strWriteError))
679 {
680 fprintf(stderr, "Cannot write wallet storage audit JSON: %s\n",
681 strWriteError.c_str());
682 return 1;
683 }
684 printf("Wallet storage audit written to %s\n", strJsonOut.c_str());
685 fflush(stdout);
686 return counts.nMalformed > 0 ? 2 : 0;
687 }
688
620 printf("Wallet storage audit\n"); 689 printf("Wallet storage audit\n");
621 printf(" records total: %u\n", counts.nTotal); 690 printf(" records total: %u\n", counts.nTotal);
622 printf(" malformed records: %u\n", counts.nMalformed); 691 printf(" malformed records: %u\n", counts.nMalformed);
diff --git a/src/walletcmd.h b/src/walletcmd.h
index 4a703db..c6342a6 100644
--- a/src/walletcmd.h
+++ b/src/walletcmd.h
@@ -64,7 +64,7 @@ int CmdRecoveryAudit();
64 64
65// Diagnostic: count wallet.dat record types without printing keys, 65// Diagnostic: count wallet.dat record types without printing keys,
66// addresses, transaction ids, labels, or other wallet values. 66// addresses, transaction ids, labels, or other wallet values.
67int CmdWalletStorageAudit(); 67int CmdWalletStorageAudit(const std::string& strJsonOut = "");
68 68
69// Rewrite wallet.dat so private keys and the HD seed are encrypted with the 69// Rewrite wallet.dat so private keys and the HD seed are encrypted with the
70// given passphrase. Returns 0 on success and exits without starting the node. 70// given passphrase. Returns 0 on success and exits without starting the node.