upleb.uk

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

summaryrefslogtreecommitdiff
path: root/src/db.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/db.cpp')
-rw-r--r--src/db.cpp361
1 files changed, 344 insertions, 17 deletions
diff --git a/src/db.cpp b/src/db.cpp
index 8b82fe5..581e5a7 100644
--- a/src/db.cpp
+++ b/src/db.cpp
@@ -3,6 +3,7 @@
3// file license.txt or http://www.opensource.org/licenses/mit-license.php. 3// file license.txt or http://www.opensource.org/licenses/mit-license.php.
4 4
5#include "headers.h" 5#include "headers.h"
6#include "wallet_sqlite.h"
6 7
7 8
8 9
@@ -650,6 +651,289 @@ bool CReviewDB::WriteReviews(uint256 hash, const vector<CReview>& vReviews)
650// CWalletDB 651// CWalletDB
651// 652//
652 653
654class CSQLiteWalletRuntimeLoadVisitor : public CWalletRecordVisitor
655{
656public:
657 bool fHaveStoredMineMode;
658 bool fHaveStoredHDCoinType;
659 string strLastType;
660
661 CSQLiteWalletRuntimeLoadVisitor() :
662 fHaveStoredMineMode(false),
663 fHaveStoredHDCoinType(false)
664 {
665 }
666
667 bool VisitWalletRecord(const CDataStream& ssKeyIn,
668 const CDataStream& ssValueIn,
669 string& strErrorRet)
670 {
671 CDataStream ssKey = ssKeyIn;
672 CDataStream ssValue = ssValueIn;
673 string strType;
674 ssKey >> strType;
675 strLastType = strType;
676
677 if (strType == "name")
678 {
679 string strAddress;
680 ssKey >> strAddress;
681 ssValue >> mapAddressBook[strAddress];
682 }
683 else if (strType == "tx")
684 {
685 uint256 hash;
686 ssKey >> hash;
687 CWalletTx& wtx = mapWallet[hash];
688 ssValue >> wtx;
689
690 if (wtx.GetHash() != hash)
691 printf("Error in SQLite wallet export, hash mismatch\n");
692 }
693 else if (strType == "key")
694 {
695 vector<unsigned char> vchPubKey;
696 ssKey >> vchPubKey;
697 CPrivKey vchPrivKey;
698 ssValue >> vchPrivKey;
699
700 mapKeys[vchPubKey] = vchPrivKey;
701 mapPubKeys[Hash160(vchPubKey)] = vchPubKey;
702 }
703 else if (strType == "mkey")
704 {
705 unsigned int nID = 0;
706 ssKey >> nID;
707 CWalletMasterKey kMasterKey;
708 ssValue >> kMasterKey;
709 mapMasterKeys[nID] = kMasterKey;
710 nWalletMasterKeyMaxID = max(nWalletMasterKeyMaxID, nID);
711 fWalletEncrypted = true;
712 fWalletLocked = true;
713 }
714 else if (strType == "ckey")
715 {
716 vector<unsigned char> vchPubKey;
717 ssKey >> vchPubKey;
718 vector<unsigned char> vchCryptedSecret;
719 ssValue >> vchCryptedSecret;
720 if (!AddCryptedKey(vchPubKey, vchCryptedSecret))
721 {
722 strErrorRet = "SQLite wallet export has an unreadable encrypted key record";
723 return false;
724 }
725 }
726 else if (strType == "defaultkey")
727 {
728 ssValue >> vchDefaultKey;
729 }
730 else if (strType == "hdmaster")
731 {
732 ssValue >> vchHDMaster;
733 }
734 else if (strType == "hdchaincode")
735 {
736 ssValue >> vchHDChainCode;
737 }
738 else if (strType == "hdnext")
739 {
740 ssValue >> nHDNext;
741 }
742 else if (strType == "hdschema")
743 {
744 ssValue >> nHDKeySchema;
745 }
746 else if (strType == "hdcointype")
747 {
748 ssValue >> nHDCoinType;
749 fHaveStoredHDCoinType = true;
750 }
751 else if (strType == "hdreceivenext")
752 {
753 ssValue >> nHDReceiveNext;
754 }
755 else if (strType == "hdchangenext")
756 {
757 ssValue >> nHDChangeNext;
758 }
759 else if (strType == "cryptedhdmaster")
760 {
761 ssValue >> vchCryptedHDMaster;
762 fWalletEncrypted = true;
763 fWalletLocked = true;
764 }
765 else if (strType == "cryptedhdchaincode")
766 {
767 ssValue >> vchCryptedHDChainCode;
768 fWalletEncrypted = true;
769 fWalletLocked = true;
770 }
771 else if (strType == "walletminversion")
772 {
773 int nMinVersion = 0;
774 ssValue >> nMinVersion;
775 if (nMinVersion > WALLET_FORMAT_SUPPORTED)
776 {
777 strWalletLoadError = strprintf(
778 "This SQLite wallet export was written by a newer version of "
779 "Bitflash (wallet format %d; this build understands %d). "
780 "Upgrade Bitflash before opening it.",
781 nMinVersion, WALLET_FORMAT_SUPPORTED);
782 strErrorRet = strWalletLoadError;
783 return false;
784 }
785 }
786 else if (strType == "pool")
787 {
788 int64 nIndex;
789 ssKey >> nIndex;
790 vector<unsigned char> vchPubKey;
791 ssValue >> vchPubKey;
792 mapKeyPool[nIndex] = vchPubKey;
793 }
794 else if (strType == "setting")
795 {
796 string strKey;
797 ssKey >> strKey;
798 if (strKey == "nTransactionFee") ssValue >> nTransactionFee;
799 if (strKey == "addrIncoming") ssValue >> addrIncoming;
800
801 if (!fMineModeFromCommandLine)
802 {
803 if (strKey == "nMineMode") { ssValue >> nMineMode; fHaveStoredMineMode = true; }
804 if (strKey == "fGenerateBitcoins") ssValue >> fGenerateBitcoins;
805 if (strKey == "strParticipantPool") ssValue >> strParticipantPool;
806 }
807 }
808
809 if (ssKey.fail())
810 {
811 strErrorRet = strprintf("malformed SQLite wallet record key while handling '%s'",
812 strLastType.c_str());
813 return false;
814 }
815 if (ssValue.fail())
816 {
817 strErrorRet = strprintf("malformed SQLite wallet record value while handling '%s'",
818 strLastType.c_str());
819 return false;
820 }
821 return true;
822 }
823
824 vector<unsigned char> vchDefaultKey;
825};
826
827static bool FinishLoadedWallet(const vector<unsigned char>& vchDefaultKey,
828 bool fMayCreateDefaultKey)
829{
830 if (!vchDefaultKey.empty() && mapPubKeys.count(Hash160(vchDefaultKey)))
831 {
832 keyUser.SetPubKey(vchDefaultKey);
833 if (mapKeys.count(vchDefaultKey))
834 keyUser.SetPrivKey(mapKeys[vchDefaultKey]);
835 }
836 else if (IsWalletEncrypted())
837 {
838 printf("LoadWallet: encrypted wallet has no usable default public key. "
839 "The file was left untouched.\n");
840 return false;
841 }
842 else
843 {
844 if (!fMayCreateDefaultKey)
845 {
846 strWalletLoadError =
847 "SQLite wallet export has no usable default public key";
848 printf("LoadWallet: %s\n", strWalletLoadError.c_str());
849 return false;
850 }
851
852 keyUser.MakeNewKey();
853 if (!AddKey(keyUser))
854 return false;
855 if (!SetAddressBookName(PubKeyToAddress(keyUser.GetPubKey()), "Your Address"))
856 return false;
857 CWalletDB().WriteDefaultKey(keyUser.GetPubKey());
858 }
859
860 return true;
861}
862
863static bool ReconcileLoadedWalletMetadata(bool fHaveStoredMineMode,
864 bool fHaveStoredHDCoinType)
865{
866 // An encrypted wallet has a seed; it just has not been decrypted yet.
867 //
868 // The reset in the else branch was written when "no seed in memory after
869 // loading" could only mean "this wallet has no seed". With encryption that
870 // is no longer true, and taking the else branch here wiped the schema and
871 // the derivation counters that had just been read correctly out of the
872 // file. Unlocking later restores the seed but nothing restores those, so a
873 // BIP44 wallet came back deriving legacy addresses -- different addresses
874 // from the ones its own recovery phrase produces, while the audit reported
875 // the phrase as covering nothing.
876 if (HaveHDSeed() || !vchCryptedHDMaster.empty())
877 {
878 if (nHDKeySchema == HD_SCHEMA_NONE)
879 {
880 nHDKeySchema = HD_SCHEMA_LEGACY;
881 printf("LoadWallet: deterministic seed has no schema metadata; "
882 "treating it as legacy m/index'\n");
883 }
884 else if (nHDKeySchema != HD_SCHEMA_LEGACY &&
885 nHDKeySchema != HD_SCHEMA_BIP44)
886 {
887 printf("LoadWallet: deterministic wallet schema %d (%s) is not "
888 "supported by this build\n",
889 nHDKeySchema, HDKeySchemaName(nHDKeySchema).c_str());
890 return false;
891 }
892 if (!fHaveStoredHDCoinType)
893 {
894 nHDCoinType = HD_BIP44_COIN_TYPE_BITFLASH;
895 printf("LoadWallet: deterministic seed has no BIP44 coin type metadata; "
896 "using Bitflash coin type %u\n", nHDCoinType);
897 }
898 }
899 else
900 {
901 nHDKeySchema = HD_SCHEMA_NONE;
902 nHDNext = 0;
903 nHDReceiveNext = 0;
904 nHDChangeNext = 0;
905 nHDCoinType = HD_BIP44_COIN_TYPE_BITFLASH;
906 }
907
908 // fGenerateBitcoins and nMineMode only mean anything together, and a
909 // wallet.dat can easily hold one without the other: Bitcoin 0.1.0 already
910 // wrote fGenerateBitcoins when mining was toggled, years before this fork
911 // had a mode at all. Restoring that lone flag put a node into the one state
912 // the miner cannot act on -- generate on, mode relay -- so every miner
913 // thread started and returned at the relay guard, and the machine sat there
914 // looking like it was mining while hashing nothing. That happened to a
915 // 32-core node on the first 1.2.11 start.
916 //
917 // So the flag is only believed when the mode it belongs to was stored with
918 // it, and the pair is made coherent either way.
919 if (!fMineModeFromCommandLine)
920 {
921 if (!fHaveStoredMineMode)
922 {
923 if (fGenerateBitcoins)
924 printf("LoadWallet: ignoring a stored fGenerateBitcoins with no mining mode "
925 "beside it -- it predates this setting and cannot be read on its own\n");
926 fGenerateBitcoins = 0;
927 }
928 else
929 {
930 fGenerateBitcoins = (nMineMode != MINE_RELAY) ? 1 : 0;
931 }
932 }
933
934 return true;
935}
936
653bool CWalletDB::LoadWallet(vector<unsigned char>& vchDefaultKeyRet) 937bool CWalletDB::LoadWallet(vector<unsigned char>& vchDefaultKeyRet)
654{ 938{
655 // Whether wallet.dat actually carried a mining mode, as opposed to just the 939 // Whether wallet.dat actually carried a mining mode, as opposed to just the
@@ -1005,31 +1289,74 @@ bool LoadWallet()
1005 if (!CWalletDB("cr").LoadWallet(vchDefaultKey)) 1289 if (!CWalletDB("cr").LoadWallet(vchDefaultKey))
1006 return false; 1290 return false;
1007 1291
1008 if (!vchDefaultKey.empty() && mapPubKeys.count(Hash160(vchDefaultKey))) 1292 return FinishLoadedWallet(vchDefaultKey, true);
1293}
1294
1295bool LoadWalletFromSQLite(const string& strPath)
1296{
1297 strWalletLoadError.clear();
1298
1299 if (!FileExists(strPath.c_str()))
1009 { 1300 {
1010 // Set keyUser 1301 strWalletLoadError = strprintf("SQLite wallet export does not exist: %s",
1011 keyUser.SetPubKey(vchDefaultKey); 1302 strPath.c_str());
1012 if (mapKeys.count(vchDefaultKey)) 1303 printf("LoadWallet: %s\n", strWalletLoadError.c_str());
1013 keyUser.SetPrivKey(mapKeys[vchDefaultKey]); 1304 return false;
1014 } 1305 }
1015 else if (IsWalletEncrypted()) 1306
1307 CWalletDBSQLite sqlite;
1308 string strError;
1309 if (!sqlite.OpenReadOnly(strPath, strError))
1016 { 1310 {
1017 printf("LoadWallet: encrypted wallet has no usable default public key. " 1311 strWalletLoadError = strError;
1018 "The file was left untouched.\n"); 1312 printf("LoadWallet: cannot open SQLite wallet export: %s\n",
1313 strError.c_str());
1019 return false; 1314 return false;
1020 } 1315 }
1021 else 1316
1317 CSQLiteWalletRuntimeLoadVisitor visitor;
1318 try
1022 { 1319 {
1023 // Create new keyUser and set as default key 1320 CRITICAL_BLOCK(cs_mapKeys)
1024 keyUser.MakeNewKey(); 1321 CRITICAL_BLOCK(cs_mapWallet)
1025 if (!AddKey(keyUser)) 1322 {
1026 return false; 1323 if (!sqlite.ScanRecords(visitor, strError))
1027 if (!SetAddressBookName(PubKeyToAddress(keyUser.GetPubKey()), "Your Address")) 1324 {
1028 return false; 1325 if (strWalletLoadError.empty())
1029 CWalletDB().WriteDefaultKey(keyUser.GetPubKey()); 1326 strWalletLoadError = strError;
1327 printf("LoadWallet: SQLite wallet export could not be read. "
1328 "Failed while handling a '%s' record: %s\n",
1329 visitor.strLastType.c_str(), strError.c_str());
1330 return false;
1331 }
1332 }
1333 }
1334 catch (const std::exception& e)
1335 {
1336 strWalletLoadError = strprintf(
1337 "SQLite wallet export could not be read while handling a '%s' record: %s",
1338 visitor.strLastType.c_str(), e.what());
1339 printf("LoadWallet: %s\n", strWalletLoadError.c_str());
1340 return false;
1341 }
1342 catch (...)
1343 {
1344 strWalletLoadError = strprintf(
1345 "SQLite wallet export could not be read while handling a '%s' record",
1346 visitor.strLastType.c_str());
1347 printf("LoadWallet: %s\n", strWalletLoadError.c_str());
1348 return false;
1030 } 1349 }
1031 1350
1032 return true; 1351 if (!ReconcileLoadedWalletMetadata(visitor.fHaveStoredMineMode,
1352 visitor.fHaveStoredHDCoinType))
1353 {
1354 if (strWalletLoadError.empty())
1355 strWalletLoadError = "SQLite wallet metadata is not supported by this build";
1356 return false;
1357 }
1358
1359 return FinishLoadedWallet(visitor.vchDefaultKey, false);
1033} 1360}
1034 1361
1035 1362