upleb.uk

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

summaryrefslogtreecommitdiff
path: root/src/selftest.cpp
diff options
context:
space:
mode:
authorBitflash <btf01@proton.me>2026-08-04 10:01:36 -0300
committerGitHub <noreply@github.com>2026-08-04 10:01:36 -0300
commit1db5f372c36eb701602a70a358de2344726ed734 (patch)
tree9d028ed3097ac51368ca312ff439664c76f439b7 /src/selftest.cpp
parent9176d5b3f32b907e4bafde5152828b2ae04ae8a1 (diff)
wallet encryption: the stack from #130–#133, with the two blockers fixed (#134)
* wallet: refuse future encrypted wallet formats * wallet: add encrypted key unlock core * wallet: add encryptwallet rewrite command * wallet: read passphrases from stdin or files * wallet: keep the derivation across encryption, and take the logs with it Two things stopped the encryption stack from being safe to merge. Both were found against a wallet holding real coin, not in the self-tests. 1. Encrypting turned a BIP44 wallet into a legacy one. LoadWallet() ends by resetting the schema and the derivation counters when no seed is in memory. That was written when "no seed after loading" could only mean the wallet had none. An encrypted wallet has a seed -- it just has not been decrypted yet -- so the reset threw away metadata that had been read correctly a moment earlier. Unlocking later restores the seed and nothing restores the rest. Measured on the wallet from the #124 proof: after encrypting, index 1 moved off BAtgSgra2X8Dqo5PJzPCLJhPwrrC2thYVJ, the address actually holding 1.00 BTF, and the audit went from "1.00 covered by the phrase" to "0.00 covered, 1.00 wallet.dat-only". Encrypt your wallet and the program told you your recovery phrase no longer covered your money. Now the condition also accepts a wallet whose seed is present but encrypted. Same wallet, before and after: schema bip44, same four derived addresses, 1.00 BTF still reported as covered. 2. The plaintext keys stayed behind in the Berkeley DB logs. wallet.dat comes out clean -- verified by scanning the raw file for the 118 bytes of a known private key. database/log.0000000002 did not: it held the whole key, and still did after a full node restart, because every record this wallet ever wrote passed through the log. That defeats the feature for the case it exists for, since our own backup advice is to copy the whole directory rather than wallet.dat alone. log_archive() cannot fix it: it only drops logs Berkeley DB considers obsolete and never the one it is writing to, and with one 10 MB log per directory that is precisely where the keys are. They also did not get there at encryption time -- they accumulated over the wallet's whole life -- so nothing done during the rewrite can archive them out. So the encrypt command now closes the environment and deletes the logs on its way out, after the flush that makes every .dat self-contained. This is not secure erasure; the blocks are unlinked, not overwritten. It closes the case of someone reading a copied data directory. Getting there uncovered a third bug, older than both. DBFlush(true) is not safe to call twice. The first call closes the environment, and txn_checkpoint() on a closed environment segfaults instead of returning an error, so the try/catch around it never sees anything. EncryptWallet() already flushes before renaming the wallet, and the command flushes again on the way out -- that pair crashed every single time. Guarded now. The same function has been calling log_archive() with the address of an uninitialised pointer since 0.1.0, on every clean shutdown, in a path whose catch(...) cannot catch a structured fault on Windows. DB_ARCH_REMOVE requires that argument to be NULL. Fixed while here, because the encryption cleanup depends on that call not being a coin flip. --------- Co-authored-by: Gilcimar Duarte <ti@gpm.infra>
Diffstat (limited to 'src/selftest.cpp')
-rw-r--r--src/selftest.cpp504
1 files changed, 503 insertions, 1 deletions
diff --git a/src/selftest.cpp b/src/selftest.cpp
index aee2951..ff0289b 100644
--- a/src/selftest.cpp
+++ b/src/selftest.cpp
@@ -33,6 +33,8 @@
33 33
34#ifdef _WIN32 34#ifdef _WIN32
35#include <direct.h> 35#include <direct.h>
36#include <fcntl.h>
37#include <io.h>
36#else 38#else
37#include <dirent.h> 39#include <dirent.h>
38#include <sys/stat.h> 40#include <sys/stat.h>
@@ -601,6 +603,500 @@ static int RunWalletHDSelfTest()
601 return nFail == 0 ? 0 : 1; 603 return nFail == 0 ? 0 : 1;
602} 604}
603 605
606static int RunWalletFormatSelfTest()
607{
608 fflush(stdout);
609 printf("wallet-format self-test\n");
610
611 std::string tmp;
612 std::string cwd;
613 if (!MakeTempDir(tmp))
614 {
615 printf(" FAIL could not create a temporary data directory\n");
616 return 1;
617 }
618 if (!GetCurrentDir(cwd) || !SetCurrentDir(tmp))
619 {
620 printf(" FAIL could not move into the temporary data directory\n");
621 RemoveTree(tmp);
622 return 1;
623 }
624
625 int nFail = 0;
626 strSetDataDir = tmp;
627 printf(" temp datadir: %s\n", tmp.c_str());
628
629 try
630 {
631 class CWalletDBRaw : public CWalletDB
632 {
633 public:
634 CWalletDBRaw(const char* pszMode="r+") : CWalletDB(pszMode) { }
635 bool WriteStringRecord(const string& strType, int nValue)
636 {
637 return Write(strType, nValue);
638 }
639 bool EraseStringRecord(const string& strType)
640 {
641 return Erase(strType);
642 }
643 };
644
645 if (!LoadWallet())
646 throw std::runtime_error("LoadWallet failed");
647
648 {
649 CWalletDB walletdb;
650 nFail += Check(walletdb.WriteWalletMinVersion(WALLET_FORMAT_SUPPORTED),
651 "the current wallet format marker can be written") ? 0 : 1;
652 }
653
654 std::vector<unsigned char> vchDefaultKey;
655 nFail += Check(CWalletDB("r").LoadWallet(vchDefaultKey),
656 "the current wallet format marker loads") ? 0 : 1;
657
658 {
659 CWalletDBRaw walletdb;
660 nFail += Check(walletdb.WriteStringRecord("mkey", 1),
661 "a malformed encrypted master-key record can be written") ? 0 : 1;
662 }
663
664 vchDefaultKey.clear();
665 nFail += Check(!CWalletDB("r").LoadWallet(vchDefaultKey),
666 "a malformed encrypted master-key record is refused") ? 0 : 1;
667
668 {
669 CWalletDBRaw walletdb;
670 nFail += Check(walletdb.EraseStringRecord("mkey"),
671 "the malformed encrypted master-key record can be removed") ? 0 : 1;
672 }
673
674 {
675 CWalletDB walletdb;
676 nFail += Check(walletdb.WriteWalletMinVersion(WALLET_FORMAT_SUPPORTED + 1),
677 "a future wallet format marker can be written") ? 0 : 1;
678 }
679
680 vchDefaultKey.clear();
681 nFail += Check(!CWalletDB("r").LoadWallet(vchDefaultKey),
682 "a future wallet format marker is refused") ? 0 : 1;
683 }
684 catch (const std::exception& e)
685 {
686 printf(" FAIL exception: %s\n", e.what());
687 nFail++;
688 }
689 catch (...)
690 {
691 printf(" FAIL unknown exception\n");
692 nFail++;
693 }
694
695 DBFlush(true);
696 SetCurrentDir(cwd);
697 RemoveTree(tmp);
698 printf("%s (%d failure%s)\n", nFail == 0 ? "ALL TESTS PASSED" : "TESTS FAILED",
699 nFail, nFail == 1 ? "" : "s");
700 fflush(stdout);
701 return nFail == 0 ? 0 : 1;
702}
703
704static void ClearWalletRuntimeForTest()
705{
706 CRITICAL_BLOCK(cs_mapKeys)
707 {
708 mapKeys.clear();
709 mapCryptedKeys.clear();
710 mapPubKeys.clear();
711 mapMasterKeys.clear();
712 vWalletMasterKey.clear();
713 vchCryptedHDMaster.clear();
714 vchCryptedHDChainCode.clear();
715 fWalletEncrypted = false;
716 fWalletLocked = true;
717 }
718 CRITICAL_BLOCK(cs_keyPool)
719 mapKeyPool.clear();
720 vchHDMaster.clear();
721 vchHDChainCode.clear();
722 nHDNext = 0;
723}
724
725static int RunWalletCryptoSelfTest()
726{
727 fflush(stdout);
728 printf("wallet-crypto self-test\n");
729
730 std::string tmp;
731 std::string cwd;
732 if (!MakeTempDir(tmp))
733 {
734 printf(" FAIL could not create a temporary data directory\n");
735 return 1;
736 }
737 if (!GetCurrentDir(cwd) || !SetCurrentDir(tmp))
738 {
739 printf(" FAIL could not move into the temporary data directory\n");
740 RemoveTree(tmp);
741 return 1;
742 }
743
744 int nFail = 0;
745 strSetDataDir = tmp;
746 printf(" temp datadir: %s\n", tmp.c_str());
747
748 try
749 {
750 const string strPassphrase = "btf-test-passphrase";
751 const string strWrongPassphrase = "btf-test-passphraser";
752
753 CKey key;
754 key.MakeNewKey();
755 vector<unsigned char> vchPubKey = key.GetPubKey();
756 CPrivKey vchPrivKey = key.GetPrivKey();
757
758 CKeyingMaterial vchMasterKey;
759 for (int i = 0; i < 32; i++)
760 vchMasterKey.push_back((unsigned char)(i + 1));
761
762 CWalletMasterKey kMasterKey;
763 kMasterKey.vchSalt.clear();
764 for (int i = 0; i < 8; i++)
765 kMasterKey.vchSalt.push_back((unsigned char)(0xa0 + i));
766 kMasterKey.nDeriveIterations = 2500;
767
768 CKeyingMaterial vchPassKey;
769 vector<unsigned char> vchPassIV;
770 nFail += Check(DeriveWalletPassphraseKey(strPassphrase, kMasterKey.vchSalt,
771 kMasterKey.nDeriveIterations,
772 vchPassKey, vchPassIV),
773 "a passphrase key can be derived") ? 0 : 1;
774 nFail += Check(EncryptSecret(vchPassKey,
775 vector<unsigned char>(vchMasterKey.begin(), vchMasterKey.end()),
776 vchPassIV, kMasterKey.vchCryptedKey),
777 "the wallet master key can be encrypted") ? 0 : 1;
778
779 vector<unsigned char> vchCryptedKey;
780 nFail += Check(EncryptSecret(vchMasterKey,
781 vector<unsigned char>(vchPrivKey.begin(), vchPrivKey.end()),
782 WalletKeyIV(vchPubKey), vchCryptedKey),
783 "a private key can be encrypted under the wallet master key") ? 0 : 1;
784
785 {
786 CWalletDB walletdb("cr");
787 nFail += Check(walletdb.WriteWalletMinVersion(WALLET_FORMAT_ENCRYPTED),
788 "an encrypted wallet format marker can be written") ? 0 : 1;
789 nFail += Check(walletdb.WriteMasterKey(0, kMasterKey),
790 "the encrypted master key can be written") ? 0 : 1;
791 nFail += Check(walletdb.WriteCryptedKey(vchPubKey, vchCryptedKey),
792 "the encrypted private key can be written") ? 0 : 1;
793 nFail += Check(walletdb.WriteDefaultKey(vchPubKey),
794 "the encrypted wallet default key can be written") ? 0 : 1;
795 }
796
797 ClearWalletRuntimeForTest();
798
799 vector<unsigned char> vchDefaultKey;
800 nFail += Check(CWalletDB("r").LoadWallet(vchDefaultKey),
801 "an encrypted wallet can be loaded") ? 0 : 1;
802 nFail += Check(vchDefaultKey == vchPubKey,
803 "the encrypted wallet default public key loads") ? 0 : 1;
804 nFail += Check(IsWalletEncrypted() && IsWalletLocked(),
805 "an encrypted wallet loads locked") ? 0 : 1;
806 nFail += Check(WalletCanSpendKey(vchPubKey),
807 "an encrypted key is recognized as wallet-owned while locked") ? 0 : 1;
808
809 CPrivKey vchDecrypted;
810 string strError;
811 nFail += Check(!GetWalletPrivKey(vchPubKey, vchDecrypted, strError),
812 "a locked encrypted key cannot be read") ? 0 : 1;
813 nFail += Check(!UnlockWallet(strWrongPassphrase, strError),
814 "the wrong-passphrase does not unlock") ? 0 : 1;
815 nFail += Check(UnlockWallet(strPassphrase, strError),
816 "the right passphrase unlocks") ? 0 : 1;
817 nFail += Check(!IsWalletLocked(),
818 "the wallet reports unlocked") ? 0 : 1;
819 nFail += Check(GetWalletPrivKey(vchPubKey, vchDecrypted, strError) &&
820 vchDecrypted == vchPrivKey,
821 "an unlocked encrypted key decrypts to the original private key") ? 0 : 1;
822 LockWallet();
823 nFail += Check(IsWalletLocked(),
824 "locking clears the unlocked state") ? 0 : 1;
825 }
826 catch (const std::exception& e)
827 {
828 printf(" FAIL exception: %s\n", e.what());
829 nFail++;
830 }
831 catch (...)
832 {
833 printf(" FAIL unknown exception\n");
834 nFail++;
835 }
836
837 DBFlush(true);
838 SetCurrentDir(cwd);
839 RemoveTree(tmp);
840 printf("%s (%d failure%s)\n", nFail == 0 ? "ALL TESTS PASSED" : "TESTS FAILED",
841 nFail, nFail == 1 ? "" : "s");
842 fflush(stdout);
843 return nFail == 0 ? 0 : 1;
844}
845
846static bool FileContainsBytes(const string& strPath, const vector<unsigned char>& vchNeedle)
847{
848 if (vchNeedle.empty())
849 return false;
850 FILE* pf = fopen(strPath.c_str(), "rb");
851 if (!pf)
852 return false;
853
854 vector<unsigned char> vchHaystack;
855 unsigned char buf[4096];
856 size_t n = 0;
857 while ((n = fread(buf, 1, sizeof(buf), pf)) > 0)
858 vchHaystack.insert(vchHaystack.end(), buf, buf + n);
859 fclose(pf);
860
861 if (vchHaystack.size() < vchNeedle.size())
862 return false;
863 return search(vchHaystack.begin(), vchHaystack.end(),
864 vchNeedle.begin(), vchNeedle.end()) != vchHaystack.end();
865}
866
867static bool FileContainsText(const string& strPath, const string& strNeedle)
868{
869 FILE* pf = fopen(strPath.c_str(), "rb");
870 if (!pf)
871 return false;
872
873 string strHaystack;
874 char buf[4096];
875 size_t n = 0;
876 while ((n = fread(buf, 1, sizeof(buf), pf)) > 0)
877 strHaystack.append(buf, buf + n);
878 fclose(pf);
879
880 return strHaystack.find(strNeedle) != string::npos;
881}
882
883static bool WriteTextFile(const string& strPath, const string& strText)
884{
885 FILE* pf = fopen(strPath.c_str(), "wb");
886 if (!pf)
887 return false;
888 bool fOk = fwrite(strText.data(), 1, strText.size(), pf) == strText.size();
889 if (fclose(pf) != 0)
890 fOk = false;
891 return fOk;
892}
893
894static string QuoteCommandArg(const string& str)
895{
896 string out = "\"";
897 for (size_t i = 0; i < str.size(); i++)
898 {
899 if (str[i] == '"')
900 out += "\\\"";
901 else
902 out += str[i];
903 }
904 out += "\"";
905 return out;
906}
907
908static int RunBitflashChild(const string& strExe,
909 const vector<string>& vArgs,
910 const string* pStdinFile = NULL)
911{
912#ifdef _WIN32
913 vector<char*> argv;
914 argv.push_back((char*)strExe.c_str());
915 for (size_t i = 0; i < vArgs.size(); i++)
916 argv.push_back((char*)vArgs[i].c_str());
917 argv.push_back(NULL);
918
919 int nOldOut = _dup(1);
920 int nOldErr = _dup(2);
921 int nOldIn = _dup(0);
922 int nNull = _open("NUL", _O_WRONLY);
923 int nIn = -1;
924 if (nNull >= 0)
925 {
926 _dup2(nNull, 1);
927 _dup2(nNull, 2);
928 }
929 if (pStdinFile)
930 {
931 nIn = _open(pStdinFile->c_str(), _O_RDONLY);
932 if (nIn >= 0)
933 _dup2(nIn, 0);
934 }
935 int nRet = _spawnv(_P_WAIT, strExe.c_str(), &argv[0]);
936 if (nIn >= 0)
937 _close(nIn);
938 if (nNull >= 0)
939 _close(nNull);
940 if (nOldIn >= 0)
941 {
942 _dup2(nOldIn, 0);
943 _close(nOldIn);
944 }
945 if (nOldOut >= 0)
946 {
947 _dup2(nOldOut, 1);
948 _close(nOldOut);
949 }
950 if (nOldErr >= 0)
951 {
952 _dup2(nOldErr, 2);
953 _close(nOldErr);
954 }
955 return nRet;
956#else
957 string strCmd = QuoteCommandArg(strExe);
958 for (size_t i = 0; i < vArgs.size(); i++)
959 strCmd += " " + QuoteCommandArg(vArgs[i]);
960 if (pStdinFile)
961 strCmd += " < " + QuoteCommandArg(*pStdinFile);
962 strCmd += " > /dev/null 2>&1";
963 return system(strCmd.c_str());
964#endif
965}
966
967static int RunWalletEncryptSelfTest()
968{
969 fflush(stdout);
970 printf("wallet-encrypt self-test\n");
971
972 std::string tmp;
973 std::string cwd;
974 if (!MakeTempDir(tmp))
975 {
976 printf(" FAIL could not create a temporary data directory\n");
977 return 1;
978 }
979 if (!GetCurrentDir(cwd) || !SetCurrentDir(tmp))
980 {
981 printf(" FAIL could not move into the temporary data directory\n");
982 RemoveTree(tmp);
983 return 1;
984 }
985
986 int nFail = 0;
987 bool fWalletEnvClosed = false;
988 strSetDataDir = tmp;
989 printf(" temp datadir: %s\n", tmp.c_str());
990
991 try
992 {
993 if (!LoadWallet())
994 throw std::runtime_error("LoadWallet failed");
995
996 string strError;
997 const string strMnemonic =
998 "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";
999 nFail += Check(SetHDSeedFromMnemonic(strMnemonic, strError),
1000 "a phrase can be installed before encryption") ? 0 : 1;
1001 TopUpKeyPool();
1002
1003 vector<unsigned char> vchDefaultPubKey = keyUser.GetPubKey();
1004 CPrivKey vchDefaultPrivKey;
1005 nFail += Check(GetWalletPrivKey(vchDefaultPubKey, vchDefaultPrivKey, strError),
1006 "the default private key is readable before encryption") ? 0 : 1;
1007 vector<unsigned char> vchDefaultPrivBytes(vchDefaultPrivKey.begin(), vchDefaultPrivKey.end());
1008 vector<unsigned char> vchPlainHDMaster = vchHDMaster;
1009 vector<unsigned char> vchPlainHDChainCode = vchHDChainCode;
1010
1011 string strBackup;
1012 nFail += Check(EncryptWallet("btf-test-passphrase", strBackup, strError),
1013 "wallet.dat can be rewritten encrypted") ? 0 : 1;
1014 fWalletEnvClosed = true;
1015 nFail += Check(FileExists(strBackup.c_str()),
1016 "the original wallet is preserved as an explicit backup") ? 0 : 1;
1017
1018 string strWalletPath = GetAppDir() + "/wallet.dat";
1019 nFail += Check(!FileContainsBytes(strWalletPath, vchDefaultPrivBytes),
1020 "the active wallet no longer contains the default private key bytes") ? 0 : 1;
1021 nFail += Check(!FileContainsBytes(strWalletPath, vchPlainHDMaster),
1022 "the active wallet no longer contains the HD master key bytes") ? 0 : 1;
1023 nFail += Check(!FileContainsBytes(strWalletPath, vchPlainHDChainCode),
1024 "the active wallet no longer contains the HD chain-code bytes") ? 0 : 1;
1025
1026#ifdef _WIN32
1027 string strExe = cwd + "\\bitflash.exe";
1028#else
1029 string strExe = cwd + "/bitflash-node";
1030#endif
1031 string strWrongDump = tmp + "/wrong-pass-dump.txt";
1032 string strRightDump = tmp + "/right-pass-dump.txt";
1033 string strLiteralDump = tmp + "/literal-pass-dump.txt";
1034 string strStdinDump = tmp + "/stdin-pass-dump.txt";
1035 string strWrongPassFile = tmp + "/wrong-pass.txt";
1036 string strRightPassFile = tmp + "/right-pass.txt";
1037 nFail += Check(WriteTextFile(strWrongPassFile, "wrong-passphrase\n") &&
1038 WriteTextFile(strRightPassFile, "btf-test-passphrase\n"),
1039 "passphrase files can be written for restarted commands") ? 0 : 1;
1040
1041 vector<string> vWrongArgs;
1042 vWrongArgs.push_back("-datadir=" + tmp);
1043 vWrongArgs.push_back("-walletpassphrase=@" + strWrongPassFile);
1044 vWrongArgs.push_back("-dumpwallet=" + strWrongDump);
1045 vWrongArgs.push_back("-nogui");
1046 int nWrongRet = RunBitflashChild(strExe, vWrongArgs);
1047 nFail += Check(nWrongRet != 0 && !FileExists(strWrongDump.c_str()),
1048 "a restarted wallet rejects the wrong-passphrase") ? 0 : 1;
1049
1050 vector<string> vLiteralArgs;
1051 vLiteralArgs.push_back("-datadir=" + tmp);
1052 vLiteralArgs.push_back("-walletpassphrase=btf-test-passphrase");
1053 vLiteralArgs.push_back("-dumpwallet=" + strLiteralDump);
1054 vLiteralArgs.push_back("-nogui");
1055 int nLiteralRet = RunBitflashChild(strExe, vLiteralArgs);
1056 nFail += Check(nLiteralRet != 0 && !FileExists(strLiteralDump.c_str()),
1057 "literal passphrases on the command line are refused") ? 0 : 1;
1058
1059 vector<string> vRightArgs;
1060 vRightArgs.push_back("-datadir=" + tmp);
1061 vRightArgs.push_back("-walletpassphrase=@" + strRightPassFile);
1062 vRightArgs.push_back("-dumpwallet=" + strRightDump);
1063 vRightArgs.push_back("-nogui");
1064 int nRightRet = RunBitflashChild(strExe, vRightArgs);
1065 nFail += Check(nRightRet == 0 && FileExists(strRightDump.c_str()),
1066 "a restarted wallet unlocks with the right passphrase") ? 0 : 1;
1067 nFail += Check(FileContainsText(strRightDump, HexStrLocal(vchDefaultPrivBytes)),
1068 "the restarted wallet can decrypt and dump the original key") ? 0 : 1;
1069
1070 vector<string> vStdinArgs;
1071 vStdinArgs.push_back("-datadir=" + tmp);
1072 vStdinArgs.push_back("-walletpassphrase");
1073 vStdinArgs.push_back("-dumpwallet=" + strStdinDump);
1074 vStdinArgs.push_back("-nogui");
1075 int nStdinRet = RunBitflashChild(strExe, vStdinArgs, &strRightPassFile);
1076 nFail += Check(nStdinRet == 0 && FileExists(strStdinDump.c_str()),
1077 "a restarted wallet can read the passphrase from stdin") ? 0 : 1;
1078 }
1079 catch (const std::exception& e)
1080 {
1081 printf(" FAIL exception: %s\n", e.what());
1082 nFail++;
1083 }
1084 catch (...)
1085 {
1086 printf(" FAIL unknown exception\n");
1087 nFail++;
1088 }
1089
1090 if (!fWalletEnvClosed)
1091 DBFlush(true);
1092 SetCurrentDir(cwd);
1093 RemoveTree(tmp);
1094 printf("%s (%d failure%s)\n", nFail == 0 ? "ALL TESTS PASSED" : "TESTS FAILED",
1095 nFail, nFail == 1 ? "" : "s");
1096 fflush(stdout);
1097 return nFail == 0 ? 0 : 1;
1098}
1099
604static int RunNetMessageSelfTest() 1100static int RunNetMessageSelfTest()
605{ 1101{
606 fflush(stdout); 1102 fflush(stdout);
@@ -728,12 +1224,18 @@ int RunSelfTest(const std::string& name)
728 return RunWalletKeyPoolSelfTest(); 1224 return RunWalletKeyPoolSelfTest();
729 if (name == "wallet-hd") 1225 if (name == "wallet-hd")
730 return RunWalletHDSelfTest(); 1226 return RunWalletHDSelfTest();
1227 if (name == "wallet-format")
1228 return RunWalletFormatSelfTest();
1229 if (name == "wallet-crypto")
1230 return RunWalletCryptoSelfTest();
1231 if (name == "wallet-encrypt")
1232 return RunWalletEncryptSelfTest();
731 if (name == "net-message") 1233 if (name == "net-message")
732 return RunNetMessageSelfTest(); 1234 return RunNetMessageSelfTest();
733 if (name == "consensus-limits") 1235 if (name == "consensus-limits")
734 return RunConsensusLimitsSelfTest(); 1236 return RunConsensusLimitsSelfTest();
735 1237
736 printf("Unknown self-test '%s'\n", name.c_str()); 1238 printf("Unknown self-test '%s'\n", name.c_str());
737 printf("Known self-tests: wallet-keypool, wallet-hd, net-message, consensus-limits\n"); 1239 printf("Known self-tests: wallet-keypool, wallet-hd, wallet-format, wallet-crypto, wallet-encrypt, net-message, consensus-limits\n");
738 return 1; 1240 return 1;
739} 1241}