Branch data Line data Source code
# 1 : : // Copyright (c) 2009-2010 Satoshi Nakamoto
# 2 : : // Copyright (c) 2009-2020 The Bitcoin Core developers
# 3 : : // Distributed under the MIT software license, see the accompanying
# 4 : : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
# 5 : :
# 6 : : #include <wallet/walletdb.h>
# 7 : :
# 8 : : #include <fs.h>
# 9 : : #include <key_io.h>
# 10 : : #include <protocol.h>
# 11 : : #include <serialize.h>
# 12 : : #include <sync.h>
# 13 : : #include <util/bip32.h>
# 14 : : #include <util/system.h>
# 15 : : #include <util/time.h>
# 16 : : #include <util/translation.h>
# 17 : : #ifdef USE_BDB
# 18 : : #include <wallet/bdb.h>
# 19 : : #endif
# 20 : : #ifdef USE_SQLITE
# 21 : : #include <wallet/sqlite.h>
# 22 : : #endif
# 23 : : #include <wallet/wallet.h>
# 24 : :
# 25 : : #include <atomic>
# 26 : : #include <optional>
# 27 : : #include <string>
# 28 : :
# 29 : : namespace DBKeys {
# 30 : : const std::string ACENTRY{"acentry"};
# 31 : : const std::string ACTIVEEXTERNALSPK{"activeexternalspk"};
# 32 : : const std::string ACTIVEINTERNALSPK{"activeinternalspk"};
# 33 : : const std::string BESTBLOCK_NOMERKLE{"bestblock_nomerkle"};
# 34 : : const std::string BESTBLOCK{"bestblock"};
# 35 : : const std::string CRYPTED_KEY{"ckey"};
# 36 : : const std::string CSCRIPT{"cscript"};
# 37 : : const std::string DEFAULTKEY{"defaultkey"};
# 38 : : const std::string DESTDATA{"destdata"};
# 39 : : const std::string FLAGS{"flags"};
# 40 : : const std::string HDCHAIN{"hdchain"};
# 41 : : const std::string KEYMETA{"keymeta"};
# 42 : : const std::string KEY{"key"};
# 43 : : const std::string MASTER_KEY{"mkey"};
# 44 : : const std::string MINVERSION{"minversion"};
# 45 : : const std::string NAME{"name"};
# 46 : : const std::string OLD_KEY{"wkey"};
# 47 : : const std::string ORDERPOSNEXT{"orderposnext"};
# 48 : : const std::string POOL{"pool"};
# 49 : : const std::string PURPOSE{"purpose"};
# 50 : : const std::string SETTINGS{"settings"};
# 51 : : const std::string TX{"tx"};
# 52 : : const std::string VERSION{"version"};
# 53 : : const std::string WALLETDESCRIPTOR{"walletdescriptor"};
# 54 : : const std::string WALLETDESCRIPTORCACHE{"walletdescriptorcache"};
# 55 : : const std::string WALLETDESCRIPTORCKEY{"walletdescriptorckey"};
# 56 : : const std::string WALLETDESCRIPTORKEY{"walletdescriptorkey"};
# 57 : : const std::string WATCHMETA{"watchmeta"};
# 58 : : const std::string WATCHS{"watchs"};
# 59 : : } // namespace DBKeys
# 60 : :
# 61 : : //
# 62 : : // WalletBatch
# 63 : : //
# 64 : :
# 65 : : bool WalletBatch::WriteName(const std::string& strAddress, const std::string& strName)
# 66 : 13953 : {
# 67 : 13953 : return WriteIC(std::make_pair(DBKeys::NAME, strAddress), strName);
# 68 : 13953 : }
# 69 : :
# 70 : : bool WalletBatch::EraseName(const std::string& strAddress)
# 71 : 0 : {
# 72 : : // This should only be used for sending addresses, never for receiving addresses,
# 73 : : // receiving addresses must always have an address book entry if they're not change return.
# 74 : 0 : return EraseIC(std::make_pair(DBKeys::NAME, strAddress));
# 75 : 0 : }
# 76 : :
# 77 : : bool WalletBatch::WritePurpose(const std::string& strAddress, const std::string& strPurpose)
# 78 : 13953 : {
# 79 : 13953 : return WriteIC(std::make_pair(DBKeys::PURPOSE, strAddress), strPurpose);
# 80 : 13953 : }
# 81 : :
# 82 : : bool WalletBatch::ErasePurpose(const std::string& strAddress)
# 83 : 0 : {
# 84 : 0 : return EraseIC(std::make_pair(DBKeys::PURPOSE, strAddress));
# 85 : 0 : }
# 86 : :
# 87 : : bool WalletBatch::WriteTx(const CWalletTx& wtx)
# 88 : 143205 : {
# 89 : 143205 : return WriteIC(std::make_pair(DBKeys::TX, wtx.GetHash()), wtx);
# 90 : 143205 : }
# 91 : :
# 92 : : bool WalletBatch::EraseTx(uint256 hash)
# 93 : 5 : {
# 94 : 5 : return EraseIC(std::make_pair(DBKeys::TX, hash));
# 95 : 5 : }
# 96 : :
# 97 : : bool WalletBatch::WriteKeyMetadata(const CKeyMetadata& meta, const CPubKey& pubkey, const bool overwrite)
# 98 : 28174 : {
# 99 : 28174 : return WriteIC(std::make_pair(DBKeys::KEYMETA, pubkey), meta, overwrite);
# 100 : 28174 : }
# 101 : :
# 102 : : bool WalletBatch::WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, const CKeyMetadata& keyMeta)
# 103 : 27139 : {
# 104 [ - + ]: 27139 : if (!WriteKeyMetadata(keyMeta, vchPubKey, false)) {
# 105 : 0 : return false;
# 106 : 0 : }
# 107 : :
# 108 : : // hash pubkey/privkey to accelerate wallet load
# 109 : 27139 : std::vector<unsigned char> vchKey;
# 110 : 27139 : vchKey.reserve(vchPubKey.size() + vchPrivKey.size());
# 111 : 27139 : vchKey.insert(vchKey.end(), vchPubKey.begin(), vchPubKey.end());
# 112 : 27139 : vchKey.insert(vchKey.end(), vchPrivKey.begin(), vchPrivKey.end());
# 113 : :
# 114 : 27139 : return WriteIC(std::make_pair(DBKeys::KEY, vchPubKey), std::make_pair(vchPrivKey, Hash(vchKey)), false);
# 115 : 27139 : }
# 116 : :
# 117 : : bool WalletBatch::WriteCryptedKey(const CPubKey& vchPubKey,
# 118 : : const std::vector<unsigned char>& vchCryptedSecret,
# 119 : : const CKeyMetadata &keyMeta)
# 120 : 879 : {
# 121 [ - + ]: 879 : if (!WriteKeyMetadata(keyMeta, vchPubKey, true)) {
# 122 : 0 : return false;
# 123 : 0 : }
# 124 : :
# 125 : : // Compute a checksum of the encrypted key
# 126 : 879 : uint256 checksum = Hash(vchCryptedSecret);
# 127 : :
# 128 : 879 : const auto key = std::make_pair(DBKeys::CRYPTED_KEY, vchPubKey);
# 129 [ + + ]: 879 : if (!WriteIC(key, std::make_pair(vchCryptedSecret, checksum), false)) {
# 130 : : // It may already exist, so try writing just the checksum
# 131 : 71 : std::vector<unsigned char> val;
# 132 [ - + ]: 71 : if (!m_batch->Read(key, val)) {
# 133 : 0 : return false;
# 134 : 0 : }
# 135 [ - + ]: 71 : if (!WriteIC(key, std::make_pair(val, checksum), true)) {
# 136 : 0 : return false;
# 137 : 0 : }
# 138 : 879 : }
# 139 : 879 : EraseIC(std::make_pair(DBKeys::KEY, vchPubKey));
# 140 : 879 : return true;
# 141 : 879 : }
# 142 : :
# 143 : : bool WalletBatch::WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey)
# 144 : 29 : {
# 145 : 29 : return WriteIC(std::make_pair(DBKeys::MASTER_KEY, nID), kMasterKey, true);
# 146 : 29 : }
# 147 : :
# 148 : : bool WalletBatch::WriteCScript(const uint160& hash, const CScript& redeemScript)
# 149 : 20927 : {
# 150 : 20927 : return WriteIC(std::make_pair(DBKeys::CSCRIPT, hash), redeemScript, false);
# 151 : 20927 : }
# 152 : :
# 153 : : bool WalletBatch::WriteWatchOnly(const CScript &dest, const CKeyMetadata& keyMeta)
# 154 : 672 : {
# 155 [ - + ]: 672 : if (!WriteIC(std::make_pair(DBKeys::WATCHMETA, dest), keyMeta)) {
# 156 : 0 : return false;
# 157 : 0 : }
# 158 : 672 : return WriteIC(std::make_pair(DBKeys::WATCHS, dest), '1');
# 159 : 672 : }
# 160 : :
# 161 : : bool WalletBatch::EraseWatchOnly(const CScript &dest)
# 162 : 13 : {
# 163 [ - + ]: 13 : if (!EraseIC(std::make_pair(DBKeys::WATCHMETA, dest))) {
# 164 : 0 : return false;
# 165 : 0 : }
# 166 : 13 : return EraseIC(std::make_pair(DBKeys::WATCHS, dest));
# 167 : 13 : }
# 168 : :
# 169 : : bool WalletBatch::WriteBestBlock(const CBlockLocator& locator)
# 170 : 1347 : {
# 171 : 1347 : WriteIC(DBKeys::BESTBLOCK, CBlockLocator()); // Write empty block locator so versions that require a merkle branch automatically rescan
# 172 : 1347 : return WriteIC(DBKeys::BESTBLOCK_NOMERKLE, locator);
# 173 : 1347 : }
# 174 : :
# 175 : : bool WalletBatch::ReadBestBlock(CBlockLocator& locator)
# 176 : 728 : {
# 177 [ + + ][ - + ]: 728 : if (m_batch->Read(DBKeys::BESTBLOCK, locator) && !locator.vHave.empty()) return true;
# 178 : 728 : return m_batch->Read(DBKeys::BESTBLOCK_NOMERKLE, locator);
# 179 : 728 : }
# 180 : :
# 181 : : bool WalletBatch::WriteOrderPosNext(int64_t nOrderPosNext)
# 182 : 138063 : {
# 183 : 138063 : return WriteIC(DBKeys::ORDERPOSNEXT, nOrderPosNext);
# 184 : 138063 : }
# 185 : :
# 186 : : bool WalletBatch::ReadPool(int64_t nPool, CKeyPool& keypool)
# 187 : 13173 : {
# 188 : 13173 : return m_batch->Read(std::make_pair(DBKeys::POOL, nPool), keypool);
# 189 : 13173 : }
# 190 : :
# 191 : : bool WalletBatch::WritePool(int64_t nPool, const CKeyPool& keypool)
# 192 : 26395 : {
# 193 : 26395 : return WriteIC(std::make_pair(DBKeys::POOL, nPool), keypool);
# 194 : 26395 : }
# 195 : :
# 196 : : bool WalletBatch::ErasePool(int64_t nPool)
# 197 : 12373 : {
# 198 : 12373 : return EraseIC(std::make_pair(DBKeys::POOL, nPool));
# 199 : 12373 : }
# 200 : :
# 201 : : bool WalletBatch::WriteMinVersion(int nVersion)
# 202 : 417 : {
# 203 : 417 : return WriteIC(DBKeys::MINVERSION, nVersion);
# 204 : 417 : }
# 205 : :
# 206 : : bool WalletBatch::WriteActiveScriptPubKeyMan(uint8_t type, const uint256& id, bool internal)
# 207 : 791 : {
# 208 [ + + ]: 791 : std::string key = internal ? DBKeys::ACTIVEINTERNALSPK : DBKeys::ACTIVEEXTERNALSPK;
# 209 : 791 : return WriteIC(make_pair(key, type), id);
# 210 : 791 : }
# 211 : :
# 212 : : bool WalletBatch::WriteDescriptorKey(const uint256& desc_id, const CPubKey& pubkey, const CPrivKey& privkey)
# 213 : 812 : {
# 214 : : // hash pubkey/privkey to accelerate wallet load
# 215 : 812 : std::vector<unsigned char> key;
# 216 : 812 : key.reserve(pubkey.size() + privkey.size());
# 217 : 812 : key.insert(key.end(), pubkey.begin(), pubkey.end());
# 218 : 812 : key.insert(key.end(), privkey.begin(), privkey.end());
# 219 : :
# 220 : 812 : return WriteIC(std::make_pair(DBKeys::WALLETDESCRIPTORKEY, std::make_pair(desc_id, pubkey)), std::make_pair(privkey, Hash(key)), false);
# 221 : 812 : }
# 222 : :
# 223 : : bool WalletBatch::WriteCryptedDescriptorKey(const uint256& desc_id, const CPubKey& pubkey, const std::vector<unsigned char>& secret)
# 224 : 112 : {
# 225 [ - + ]: 112 : if (!WriteIC(std::make_pair(DBKeys::WALLETDESCRIPTORCKEY, std::make_pair(desc_id, pubkey)), secret, false)) {
# 226 : 0 : return false;
# 227 : 0 : }
# 228 : 112 : EraseIC(std::make_pair(DBKeys::WALLETDESCRIPTORKEY, std::make_pair(desc_id, pubkey)));
# 229 : 112 : return true;
# 230 : 112 : }
# 231 : :
# 232 : : bool WalletBatch::WriteDescriptor(const uint256& desc_id, const WalletDescriptor& descriptor)
# 233 : 43363 : {
# 234 : 43363 : return WriteIC(make_pair(DBKeys::WALLETDESCRIPTOR, desc_id), descriptor);
# 235 : 43363 : }
# 236 : :
# 237 : : bool WalletBatch::WriteDescriptorDerivedCache(const CExtPubKey& xpub, const uint256& desc_id, uint32_t key_exp_index, uint32_t der_index)
# 238 : 770 : {
# 239 : 770 : std::vector<unsigned char> ser_xpub(BIP32_EXTKEY_SIZE);
# 240 : 770 : xpub.Encode(ser_xpub.data());
# 241 : 770 : return WriteIC(std::make_pair(std::make_pair(DBKeys::WALLETDESCRIPTORCACHE, desc_id), std::make_pair(key_exp_index, der_index)), ser_xpub);
# 242 : 770 : }
# 243 : :
# 244 : : bool WalletBatch::WriteDescriptorParentCache(const CExtPubKey& xpub, const uint256& desc_id, uint32_t key_exp_index)
# 245 : 869 : {
# 246 : 869 : std::vector<unsigned char> ser_xpub(BIP32_EXTKEY_SIZE);
# 247 : 869 : xpub.Encode(ser_xpub.data());
# 248 : 869 : return WriteIC(std::make_pair(std::make_pair(DBKeys::WALLETDESCRIPTORCACHE, desc_id), key_exp_index), ser_xpub);
# 249 : 869 : }
# 250 : :
# 251 : : class CWalletScanState {
# 252 : : public:
# 253 : : unsigned int nKeys{0};
# 254 : : unsigned int nCKeys{0};
# 255 : : unsigned int nWatchKeys{0};
# 256 : : unsigned int nKeyMeta{0};
# 257 : : unsigned int m_unknown_records{0};
# 258 : : bool fIsEncrypted{false};
# 259 : : bool fAnyUnordered{false};
# 260 : : std::vector<uint256> vWalletUpgrade;
# 261 : : std::map<OutputType, uint256> m_active_external_spks;
# 262 : : std::map<OutputType, uint256> m_active_internal_spks;
# 263 : : std::map<uint256, DescriptorCache> m_descriptor_caches;
# 264 : : std::map<std::pair<uint256, CKeyID>, CKey> m_descriptor_keys;
# 265 : : std::map<std::pair<uint256, CKeyID>, std::pair<CPubKey, std::vector<unsigned char>>> m_descriptor_crypt_keys;
# 266 : : std::map<uint160, CHDChain> m_hd_chains;
# 267 : :
# 268 : 794 : CWalletScanState() {
# 269 : 794 : }
# 270 : : };
# 271 : :
# 272 : : static bool
# 273 : : ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
# 274 : : CWalletScanState &wss, std::string& strType, std::string& strErr, const KeyFilterFn& filter_fn = nullptr) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
# 275 : 56712 : {
# 276 : 56712 : try {
# 277 : : // Unserialize
# 278 : : // Taking advantage of the fact that pair serialization
# 279 : : // is just the two items serialized one after the other
# 280 : 56712 : ssKey >> strType;
# 281 : : // If we have a filter, check if this matches the filter
# 282 [ + + ][ + + ]: 56712 : if (filter_fn && !filter_fn(strType)) {
# 283 : 10 : return true;
# 284 : 10 : }
# 285 [ + + ]: 56702 : if (strType == DBKeys::NAME) {
# 286 : 4678 : std::string strAddress;
# 287 : 4678 : ssKey >> strAddress;
# 288 : 4678 : std::string label;
# 289 : 4678 : ssValue >> label;
# 290 : 4678 : pwallet->m_address_book[DecodeDestination(strAddress)].SetLabel(label);
# 291 [ + + ]: 52024 : } else if (strType == DBKeys::PURPOSE) {
# 292 : 4678 : std::string strAddress;
# 293 : 4678 : ssKey >> strAddress;
# 294 : 4678 : ssValue >> pwallet->m_address_book[DecodeDestination(strAddress)].purpose;
# 295 [ + + ]: 47346 : } else if (strType == DBKeys::TX) {
# 296 : 9892 : uint256 hash;
# 297 : 9892 : ssKey >> hash;
# 298 : : // LoadToWallet call below creates a new CWalletTx that fill_wtx
# 299 : : // callback fills with transaction metadata.
# 300 : 9892 : auto fill_wtx = [&](CWalletTx& wtx, bool new_tx) {
# 301 : 9892 : assert(new_tx);
# 302 : 9892 : ssValue >> wtx;
# 303 [ - + ]: 9892 : if (wtx.GetHash() != hash)
# 304 : 0 : return false;
# 305 : :
# 306 : : // Undo serialize changes in 31600
# 307 [ - + ][ # # ]: 9892 : if (31404 <= wtx.fTimeReceivedIsTxTime && wtx.fTimeReceivedIsTxTime <= 31703)
# 308 : 0 : {
# 309 [ # # ]: 0 : if (!ssValue.empty())
# 310 : 0 : {
# 311 : 0 : char fTmp;
# 312 : 0 : char fUnused;
# 313 : 0 : std::string unused_string;
# 314 : 0 : ssValue >> fTmp >> fUnused >> unused_string;
# 315 : 0 : strErr = strprintf("LoadWallet() upgrading tx ver=%d %d %s",
# 316 : 0 : wtx.fTimeReceivedIsTxTime, fTmp, hash.ToString());
# 317 : 0 : wtx.fTimeReceivedIsTxTime = fTmp;
# 318 : 0 : }
# 319 : 0 : else
# 320 : 0 : {
# 321 : 0 : strErr = strprintf("LoadWallet() repairing tx ver=%d %s", wtx.fTimeReceivedIsTxTime, hash.ToString());
# 322 : 0 : wtx.fTimeReceivedIsTxTime = 0;
# 323 : 0 : }
# 324 : 0 : wss.vWalletUpgrade.push_back(hash);
# 325 : 0 : }
# 326 : :
# 327 [ - + ]: 9892 : if (wtx.nOrderPos == -1)
# 328 : 0 : wss.fAnyUnordered = true;
# 329 : :
# 330 : 9892 : return true;
# 331 : 9892 : };
# 332 [ - + ]: 9892 : if (!pwallet->LoadToWallet(hash, fill_wtx)) {
# 333 : 0 : return false;
# 334 : 0 : }
# 335 [ + + ]: 37454 : } else if (strType == DBKeys::WATCHS) {
# 336 : 255 : wss.nWatchKeys++;
# 337 : 255 : CScript script;
# 338 : 255 : ssKey >> script;
# 339 : 255 : char fYes;
# 340 : 255 : ssValue >> fYes;
# 341 [ + - ]: 255 : if (fYes == '1') {
# 342 : 255 : pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadWatchOnly(script);
# 343 : 255 : }
# 344 [ + + ]: 37199 : } else if (strType == DBKeys::KEY) {
# 345 : 10575 : CPubKey vchPubKey;
# 346 : 10575 : ssKey >> vchPubKey;
# 347 [ - + ]: 10575 : if (!vchPubKey.IsValid())
# 348 : 0 : {
# 349 : 0 : strErr = "Error reading wallet database: CPubKey corrupt";
# 350 : 0 : return false;
# 351 : 0 : }
# 352 : 10575 : CKey key;
# 353 : 10575 : CPrivKey pkey;
# 354 : 10575 : uint256 hash;
# 355 : :
# 356 : 10575 : wss.nKeys++;
# 357 : 10575 : ssValue >> pkey;
# 358 : :
# 359 : : // Old wallets store keys as DBKeys::KEY [pubkey] => [privkey]
# 360 : : // ... which was slow for wallets with lots of keys, because the public key is re-derived from the private key
# 361 : : // using EC operations as a checksum.
# 362 : : // Newer wallets store keys as DBKeys::KEY [pubkey] => [privkey][hash(pubkey,privkey)], which is much faster while
# 363 : : // remaining backwards-compatible.
# 364 : 10575 : try
# 365 : 10575 : {
# 366 : 10575 : ssValue >> hash;
# 367 : 10575 : }
# 368 : 10575 : catch (const std::ios_base::failure&) {}
# 369 : :
# 370 : 10575 : bool fSkipCheck = false;
# 371 : :
# 372 [ + - ]: 10575 : if (!hash.IsNull())
# 373 : 10575 : {
# 374 : : // hash pubkey/privkey to accelerate wallet load
# 375 : 10575 : std::vector<unsigned char> vchKey;
# 376 : 10575 : vchKey.reserve(vchPubKey.size() + pkey.size());
# 377 : 10575 : vchKey.insert(vchKey.end(), vchPubKey.begin(), vchPubKey.end());
# 378 : 10575 : vchKey.insert(vchKey.end(), pkey.begin(), pkey.end());
# 379 : :
# 380 [ - + ]: 10575 : if (Hash(vchKey) != hash)
# 381 : 0 : {
# 382 : 0 : strErr = "Error reading wallet database: CPubKey/CPrivKey corrupt";
# 383 : 0 : return false;
# 384 : 0 : }
# 385 : :
# 386 : 10575 : fSkipCheck = true;
# 387 : 10575 : }
# 388 : :
# 389 [ - + ]: 10575 : if (!key.Load(pkey, vchPubKey, fSkipCheck))
# 390 : 0 : {
# 391 : 0 : strErr = "Error reading wallet database: CPrivKey corrupt";
# 392 : 0 : return false;
# 393 : 0 : }
# 394 [ - + ]: 10575 : if (!pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadKey(key, vchPubKey))
# 395 : 0 : {
# 396 : 0 : strErr = "Error reading wallet database: LegacyScriptPubKeyMan::LoadKey failed";
# 397 : 0 : return false;
# 398 : 0 : }
# 399 [ + + ]: 26624 : } else if (strType == DBKeys::MASTER_KEY) {
# 400 : : // Master encryption key is loaded into only the wallet and not any of the ScriptPubKeyMans.
# 401 : 15 : unsigned int nID;
# 402 : 15 : ssKey >> nID;
# 403 : 15 : CMasterKey kMasterKey;
# 404 : 15 : ssValue >> kMasterKey;
# 405 [ - + ]: 15 : if(pwallet->mapMasterKeys.count(nID) != 0)
# 406 : 0 : {
# 407 : 0 : strErr = strprintf("Error reading wallet database: duplicate CMasterKey id %u", nID);
# 408 : 0 : return false;
# 409 : 0 : }
# 410 : 15 : pwallet->mapMasterKeys[nID] = kMasterKey;
# 411 [ + - ]: 15 : if (pwallet->nMasterKeyMaxID < nID)
# 412 : 15 : pwallet->nMasterKeyMaxID = nID;
# 413 [ + + ]: 26609 : } else if (strType == DBKeys::CRYPTED_KEY) {
# 414 : 132 : CPubKey vchPubKey;
# 415 : 132 : ssKey >> vchPubKey;
# 416 [ - + ]: 132 : if (!vchPubKey.IsValid())
# 417 : 0 : {
# 418 : 0 : strErr = "Error reading wallet database: CPubKey corrupt";
# 419 : 0 : return false;
# 420 : 0 : }
# 421 : 132 : std::vector<unsigned char> vchPrivKey;
# 422 : 132 : ssValue >> vchPrivKey;
# 423 : :
# 424 : : // Get the checksum and check it
# 425 : 132 : bool checksum_valid = false;
# 426 [ + - ]: 132 : if (!ssValue.eof()) {
# 427 : 132 : uint256 checksum;
# 428 : 132 : ssValue >> checksum;
# 429 [ - + ]: 132 : if ((checksum_valid = Hash(vchPrivKey) != checksum)) {
# 430 : 0 : strErr = "Error reading wallet database: Encrypted key corrupt";
# 431 : 0 : return false;
# 432 : 0 : }
# 433 : 132 : }
# 434 : :
# 435 : 132 : wss.nCKeys++;
# 436 : :
# 437 [ - + ]: 132 : if (!pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadCryptedKey(vchPubKey, vchPrivKey, checksum_valid))
# 438 : 0 : {
# 439 : 0 : strErr = "Error reading wallet database: LegacyScriptPubKeyMan::LoadCryptedKey failed";
# 440 : 0 : return false;
# 441 : 0 : }
# 442 : 132 : wss.fIsEncrypted = true;
# 443 [ + + ]: 26477 : } else if (strType == DBKeys::KEYMETA) {
# 444 : 10809 : CPubKey vchPubKey;
# 445 : 10809 : ssKey >> vchPubKey;
# 446 : 10809 : CKeyMetadata keyMeta;
# 447 : 10809 : ssValue >> keyMeta;
# 448 : 10809 : wss.nKeyMeta++;
# 449 : 10809 : pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadKeyMetadata(vchPubKey.GetID(), keyMeta);
# 450 : :
# 451 : : // Extract some CHDChain info from this metadata if it has any
# 452 [ + - ][ + + ]: 10809 : if (keyMeta.nVersion >= CKeyMetadata::VERSION_WITH_HDDATA && !keyMeta.hd_seed_id.IsNull() && keyMeta.hdKeypath.size() > 0) {
# [ + - ]
# 453 : : // Get the path from the key origin or from the path string
# 454 : : // Not applicable when path is "s" or "m" as those indicate a seed
# 455 : : // See https://github.com/bitcoin/bitcoin/pull/12924
# 456 : 10581 : bool internal = false;
# 457 : 10581 : uint32_t index = 0;
# 458 [ + + ][ + - ]: 10581 : if (keyMeta.hdKeypath != "s" && keyMeta.hdKeypath != "m") {
# 459 : 10357 : std::vector<uint32_t> path;
# 460 [ + - ]: 10357 : if (keyMeta.has_key_origin) {
# 461 : : // We have a key origin, so pull it from its path vector
# 462 : 10357 : path = keyMeta.key_origin.path;
# 463 : 10357 : } else {
# 464 : : // No key origin, have to parse the string
# 465 [ # # ]: 0 : if (!ParseHDKeypath(keyMeta.hdKeypath, path)) {
# 466 : 0 : strErr = "Error reading wallet database: keymeta with invalid HD keypath";
# 467 : 0 : return false;
# 468 : 0 : }
# 469 : 10357 : }
# 470 : :
# 471 : : // Extract the index and internal from the path
# 472 : : // Path string is m/0'/k'/i'
# 473 : : // Path vector is [0', k', i'] (but as ints OR'd with the hardened bit
# 474 : : // k == 0 for external, 1 for internal. i is the index
# 475 [ - + ]: 10357 : if (path.size() != 3) {
# 476 : 0 : strErr = "Error reading wallet database: keymeta found with unexpected path";
# 477 : 0 : return false;
# 478 : 0 : }
# 479 [ - + ]: 10357 : if (path[0] != 0x80000000) {
# 480 : 0 : strErr = strprintf("Unexpected path index of 0x%08x (expected 0x80000000) for the element at index 0", path[0]);
# 481 : 0 : return false;
# 482 : 0 : }
# 483 [ + + ][ - + ]: 10357 : if (path[1] != 0x80000000 && path[1] != (1 | 0x80000000)) {
# 484 : 0 : strErr = strprintf("Unexpected path index of 0x%08x (expected 0x80000000 or 0x80000001) for the element at index 1", path[1]);
# 485 : 0 : return false;
# 486 : 0 : }
# 487 [ - + ]: 10357 : if ((path[2] & 0x80000000) == 0) {
# 488 : 0 : strErr = strprintf("Unexpected path index of 0x%08x (expected to be greater than or equal to 0x80000000)", path[2]);
# 489 : 0 : return false;
# 490 : 0 : }
# 491 : 10357 : internal = path[1] == (1 | 0x80000000);
# 492 : 10357 : index = path[2] & ~0x80000000;
# 493 : 10357 : }
# 494 : :
# 495 : : // Insert a new CHDChain, or get the one that already exists
# 496 : 10581 : auto ins = wss.m_hd_chains.emplace(keyMeta.hd_seed_id, CHDChain());
# 497 : 10581 : CHDChain& chain = ins.first->second;
# 498 [ + + ]: 10581 : if (ins.second) {
# 499 : : // For new chains, we want to default to VERSION_HD_BASE until we see an internal
# 500 : 224 : chain.nVersion = CHDChain::VERSION_HD_BASE;
# 501 : 224 : chain.seed_id = keyMeta.hd_seed_id;
# 502 : 224 : }
# 503 [ + + ]: 10581 : if (internal) {
# 504 : 4326 : chain.nVersion = CHDChain::VERSION_HD_CHAIN_SPLIT;
# 505 : 4326 : chain.nInternalChainCounter = std::max(chain.nInternalChainCounter, index);
# 506 : 6255 : } else {
# 507 : 6255 : chain.nExternalChainCounter = std::max(chain.nExternalChainCounter, index);
# 508 : 6255 : }
# 509 : 10581 : }
# 510 [ + + ]: 15668 : } else if (strType == DBKeys::WATCHMETA) {
# 511 : 255 : CScript script;
# 512 : 255 : ssKey >> script;
# 513 : 255 : CKeyMetadata keyMeta;
# 514 : 255 : ssValue >> keyMeta;
# 515 : 255 : wss.nKeyMeta++;
# 516 : 255 : pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadScriptMetadata(CScriptID(script), keyMeta);
# 517 [ - + ]: 15413 : } else if (strType == DBKeys::DEFAULTKEY) {
# 518 : : // We don't want or need the default key, but if there is one set,
# 519 : : // we want to make sure that it is valid so that we can detect corruption
# 520 : 0 : CPubKey vchPubKey;
# 521 : 0 : ssValue >> vchPubKey;
# 522 [ # # ]: 0 : if (!vchPubKey.IsValid()) {
# 523 : 0 : strErr = "Error reading wallet database: Default Key corrupt";
# 524 : 0 : return false;
# 525 : 0 : }
# 526 [ + + ]: 15413 : } else if (strType == DBKeys::POOL) {
# 527 : 7839 : int64_t nIndex;
# 528 : 7839 : ssKey >> nIndex;
# 529 : 7839 : CKeyPool keypool;
# 530 : 7839 : ssValue >> keypool;
# 531 : :
# 532 : 7839 : pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadKeyPool(nIndex, keypool);
# 533 [ + + ]: 7839 : } else if (strType == DBKeys::CSCRIPT) {
# 534 : 2625 : uint160 hash;
# 535 : 2625 : ssKey >> hash;
# 536 : 2625 : CScript script;
# 537 : 2625 : ssValue >> script;
# 538 [ - + ]: 2625 : if (!pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadCScript(script))
# 539 : 0 : {
# 540 : 0 : strErr = "Error reading wallet database: LegacyScriptPubKeyMan::LoadCScript failed";
# 541 : 0 : return false;
# 542 : 0 : }
# 543 [ + + ]: 4949 : } else if (strType == DBKeys::ORDERPOSNEXT) {
# 544 : 168 : ssValue >> pwallet->nOrderPosNext;
# 545 [ - + ]: 4781 : } else if (strType == DBKeys::DESTDATA) {
# 546 : 0 : std::string strAddress, strKey, strValue;
# 547 : 0 : ssKey >> strAddress;
# 548 : 0 : ssKey >> strKey;
# 549 : 0 : ssValue >> strValue;
# 550 : 0 : pwallet->LoadDestData(DecodeDestination(strAddress), strKey, strValue);
# 551 [ + + ]: 4781 : } else if (strType == DBKeys::HDCHAIN) {
# 552 : 213 : CHDChain chain;
# 553 : 213 : ssValue >> chain;
# 554 : 213 : pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadHDChain(chain);
# 555 [ - + ]: 4568 : } else if (strType == DBKeys::OLD_KEY) {
# 556 : 0 : strErr = "Found unsupported 'wkey' record, try loading with version 0.18";
# 557 : 0 : return false;
# 558 [ + + ][ + + ]: 4568 : } else if (strType == DBKeys::ACTIVEEXTERNALSPK || strType == DBKeys::ACTIVEINTERNALSPK) {
# 559 : 603 : uint8_t type;
# 560 : 603 : ssKey >> type;
# 561 : 603 : uint256 id;
# 562 : 603 : ssValue >> id;
# 563 : :
# 564 : 603 : bool internal = strType == DBKeys::ACTIVEINTERNALSPK;
# 565 [ + + ]: 603 : auto& spk_mans = internal ? wss.m_active_internal_spks : wss.m_active_external_spks;
# 566 [ - + ]: 603 : if (spk_mans.count(static_cast<OutputType>(type)) > 0) {
# 567 : 0 : strErr = "Multiple ScriptPubKeyMans specified for a single type";
# 568 : 0 : return false;
# 569 : 0 : }
# 570 : 603 : spk_mans[static_cast<OutputType>(type)] = id;
# 571 [ + + ]: 3965 : } else if (strType == DBKeys::WALLETDESCRIPTOR) {
# 572 : 763 : uint256 id;
# 573 : 763 : ssKey >> id;
# 574 : 763 : WalletDescriptor desc;
# 575 : 763 : ssValue >> desc;
# 576 [ + + ]: 763 : if (wss.m_descriptor_caches.count(id) == 0) {
# 577 : 130 : wss.m_descriptor_caches[id] = DescriptorCache();
# 578 : 130 : }
# 579 : 763 : pwallet->LoadDescriptorScriptPubKeyMan(id, desc);
# 580 [ + + ]: 3202 : } else if (strType == DBKeys::WALLETDESCRIPTORCACHE) {
# 581 : 643 : bool parent = true;
# 582 : 643 : uint256 desc_id;
# 583 : 643 : uint32_t key_exp_index;
# 584 : 643 : uint32_t der_index;
# 585 : 643 : ssKey >> desc_id;
# 586 : 643 : ssKey >> key_exp_index;
# 587 : :
# 588 : : // if the der_index exists, it's a derived xpub
# 589 : 643 : try
# 590 : 643 : {
# 591 : 643 : ssKey >> der_index;
# 592 : 643 : parent = false;
# 593 : 643 : }
# 594 : 643 : catch (...) {}
# 595 : :
# 596 : 643 : std::vector<unsigned char> ser_xpub(BIP32_EXTKEY_SIZE);
# 597 : 643 : ssValue >> ser_xpub;
# 598 : 643 : CExtPubKey xpub;
# 599 : 643 : xpub.Decode(ser_xpub.data());
# 600 [ + - ]: 643 : if (parent) {
# 601 : 643 : wss.m_descriptor_caches[desc_id].CacheParentExtPubKey(key_exp_index, xpub);
# 602 : 643 : } else {
# 603 : 0 : wss.m_descriptor_caches[desc_id].CacheDerivedExtPubKey(key_exp_index, der_index, xpub);
# 604 : 0 : }
# 605 [ + + ]: 2559 : } else if (strType == DBKeys::WALLETDESCRIPTORKEY) {
# 606 : 613 : uint256 desc_id;
# 607 : 613 : CPubKey pubkey;
# 608 : 613 : ssKey >> desc_id;
# 609 : 613 : ssKey >> pubkey;
# 610 [ - + ]: 613 : if (!pubkey.IsValid())
# 611 : 0 : {
# 612 : 0 : strErr = "Error reading wallet database: CPubKey corrupt";
# 613 : 0 : return false;
# 614 : 0 : }
# 615 : 613 : CKey key;
# 616 : 613 : CPrivKey pkey;
# 617 : 613 : uint256 hash;
# 618 : :
# 619 : 613 : wss.nKeys++;
# 620 : 613 : ssValue >> pkey;
# 621 : 613 : ssValue >> hash;
# 622 : :
# 623 : : // hash pubkey/privkey to accelerate wallet load
# 624 : 613 : std::vector<unsigned char> to_hash;
# 625 : 613 : to_hash.reserve(pubkey.size() + pkey.size());
# 626 : 613 : to_hash.insert(to_hash.end(), pubkey.begin(), pubkey.end());
# 627 : 613 : to_hash.insert(to_hash.end(), pkey.begin(), pkey.end());
# 628 : :
# 629 [ - + ]: 613 : if (Hash(to_hash) != hash)
# 630 : 0 : {
# 631 : 0 : strErr = "Error reading wallet database: CPubKey/CPrivKey corrupt";
# 632 : 0 : return false;
# 633 : 0 : }
# 634 : :
# 635 [ - + ]: 613 : if (!key.Load(pkey, pubkey, true))
# 636 : 0 : {
# 637 : 0 : strErr = "Error reading wallet database: CPrivKey corrupt";
# 638 : 0 : return false;
# 639 : 0 : }
# 640 : 613 : wss.m_descriptor_keys.insert(std::make_pair(std::make_pair(desc_id, pubkey.GetID()), key));
# 641 [ + + ]: 1946 : } else if (strType == DBKeys::WALLETDESCRIPTORCKEY) {
# 642 : 76 : uint256 desc_id;
# 643 : 76 : CPubKey pubkey;
# 644 : 76 : ssKey >> desc_id;
# 645 : 76 : ssKey >> pubkey;
# 646 [ - + ]: 76 : if (!pubkey.IsValid())
# 647 : 0 : {
# 648 : 0 : strErr = "Error reading wallet database: CPubKey corrupt";
# 649 : 0 : return false;
# 650 : 0 : }
# 651 : 76 : std::vector<unsigned char> privkey;
# 652 : 76 : ssValue >> privkey;
# 653 : 76 : wss.nCKeys++;
# 654 : :
# 655 : 76 : wss.m_descriptor_crypt_keys.insert(std::make_pair(std::make_pair(desc_id, pubkey.GetID()), std::make_pair(pubkey, privkey)));
# 656 : 76 : wss.fIsEncrypted = true;
# 657 [ + + ][ + + ]: 1870 : } else if (strType != DBKeys::BESTBLOCK && strType != DBKeys::BESTBLOCK_NOMERKLE &&
# 658 [ + + ][ + - ]: 1870 : strType != DBKeys::MINVERSION && strType != DBKeys::ACENTRY &&
# 659 [ + + ][ + - ]: 1870 : strType != DBKeys::VERSION && strType != DBKeys::SETTINGS &&
# 660 [ - + ]: 1870 : strType != DBKeys::FLAGS) {
# 661 : 0 : wss.m_unknown_records++;
# 662 : 0 : }
# 663 : 56702 : } catch (const std::exception& e) {
# 664 [ # # ]: 0 : if (strErr.empty()) {
# 665 : 0 : strErr = e.what();
# 666 : 0 : }
# 667 : 0 : return false;
# 668 : 0 : } catch (...) {
# 669 [ # # ]: 0 : if (strErr.empty()) {
# 670 : 0 : strErr = "Caught unknown exception in ReadKeyValue";
# 671 : 0 : }
# 672 : 0 : return false;
# 673 : 0 : }
# 674 : 56702 : return true;
# 675 : 56702 : }
# 676 : :
# 677 : : bool ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, std::string& strType, std::string& strErr, const KeyFilterFn& filter_fn)
# 678 : 14 : {
# 679 : 14 : CWalletScanState dummy_wss;
# 680 : 14 : LOCK(pwallet->cs_wallet);
# 681 : 14 : return ReadKeyValue(pwallet, ssKey, ssValue, dummy_wss, strType, strErr, filter_fn);
# 682 : 14 : }
# 683 : :
# 684 : : bool WalletBatch::IsKeyType(const std::string& strType)
# 685 : 28 : {
# 686 [ + + ]: 28 : return (strType == DBKeys::KEY ||
# 687 [ - + ][ - + ]: 28 : strType == DBKeys::MASTER_KEY || strType == DBKeys::CRYPTED_KEY);
# 688 : 28 : }
# 689 : :
# 690 : : DBErrors WalletBatch::LoadWallet(CWallet* pwallet)
# 691 : 780 : {
# 692 : 780 : CWalletScanState wss;
# 693 : 780 : bool fNoncriticalErrors = false;
# 694 : 780 : DBErrors result = DBErrors::LOAD_OK;
# 695 : :
# 696 : 780 : LOCK(pwallet->cs_wallet);
# 697 : 780 : try {
# 698 : 780 : int nMinVersion = 0;
# 699 [ + + ]: 780 : if (m_batch->Read(DBKeys::MINVERSION, nMinVersion)) {
# 700 [ - + ]: 341 : if (nMinVersion > FEATURE_LATEST)
# 701 : 0 : return DBErrors::TOO_NEW;
# 702 : 341 : pwallet->LoadMinVersion(nMinVersion);
# 703 : 341 : }
# 704 : :
# 705 : : // Load wallet flags, so they are known when processing other records.
# 706 : : // The FLAGS key is absent during wallet creation.
# 707 : 780 : uint64_t flags;
# 708 [ + + ]: 780 : if (m_batch->Read(DBKeys::FLAGS, flags)) {
# 709 [ - + ]: 341 : if (!pwallet->LoadWalletFlags(flags)) {
# 710 : 0 : pwallet->WalletLogPrintf("Error reading wallet database: Unknown non-tolerable wallet flags found\n");
# 711 : 0 : return DBErrors::CORRUPT;
# 712 : 0 : }
# 713 : 780 : }
# 714 : :
# 715 : : // Get cursor
# 716 [ - + ]: 780 : if (!m_batch->StartCursor())
# 717 : 0 : {
# 718 : 0 : pwallet->WalletLogPrintf("Error getting wallet database cursor\n");
# 719 : 0 : return DBErrors::CORRUPT;
# 720 : 0 : }
# 721 : :
# 722 : 57478 : while (true)
# 723 : 57478 : {
# 724 : : // Read next record
# 725 : 57478 : CDataStream ssKey(SER_DISK, CLIENT_VERSION);
# 726 : 57478 : CDataStream ssValue(SER_DISK, CLIENT_VERSION);
# 727 : 57478 : bool complete;
# 728 : 57478 : bool ret = m_batch->ReadAtCursor(ssKey, ssValue, complete);
# 729 [ + + ]: 57478 : if (complete) {
# 730 : 780 : break;
# 731 : 780 : }
# 732 [ - + ]: 56698 : else if (!ret)
# 733 : 0 : {
# 734 : 0 : m_batch->CloseCursor();
# 735 : 0 : pwallet->WalletLogPrintf("Error reading next record from wallet database\n");
# 736 : 0 : return DBErrors::CORRUPT;
# 737 : 0 : }
# 738 : :
# 739 : : // Try to be tolerant of single corrupt records:
# 740 : 56698 : std::string strType, strErr;
# 741 [ - + ]: 56698 : if (!ReadKeyValue(pwallet, ssKey, ssValue, wss, strType, strErr))
# 742 : 0 : {
# 743 : : // losing keys is considered a catastrophic error, anything else
# 744 : : // we assume the user can live with:
# 745 [ # # ][ # # ]: 0 : if (IsKeyType(strType) || strType == DBKeys::DEFAULTKEY) {
# 746 : 0 : result = DBErrors::CORRUPT;
# 747 [ # # ]: 0 : } else if (strType == DBKeys::FLAGS) {
# 748 : : // reading the wallet flags can only fail if unknown flags are present
# 749 : 0 : result = DBErrors::TOO_NEW;
# 750 : 0 : } else {
# 751 : : // Leave other errors alone, if we try to fix them we might make things worse.
# 752 : 0 : fNoncriticalErrors = true; // ... but do warn the user there is something wrong.
# 753 [ # # ]: 0 : if (strType == DBKeys::TX)
# 754 : : // Rescan if there is a bad transaction record:
# 755 : 0 : gArgs.SoftSetBoolArg("-rescan", true);
# 756 : 0 : }
# 757 : 0 : }
# 758 [ - + ]: 56698 : if (!strErr.empty())
# 759 : 0 : pwallet->WalletLogPrintf("%s\n", strErr);
# 760 : 56698 : }
# 761 : 780 : } catch (...) {
# 762 : 0 : result = DBErrors::CORRUPT;
# 763 : 0 : }
# 764 : 780 : m_batch->CloseCursor();
# 765 : :
# 766 : : // Set the active ScriptPubKeyMans
# 767 [ + + ]: 780 : for (auto spk_man_pair : wss.m_active_external_spks) {
# 768 : 301 : pwallet->LoadActiveScriptPubKeyMan(spk_man_pair.second, spk_man_pair.first, /* internal */ false);
# 769 : 301 : }
# 770 [ + + ]: 780 : for (auto spk_man_pair : wss.m_active_internal_spks) {
# 771 : 302 : pwallet->LoadActiveScriptPubKeyMan(spk_man_pair.second, spk_man_pair.first, /* internal */ true);
# 772 : 302 : }
# 773 : :
# 774 : : // Set the descriptor caches
# 775 [ + + ]: 780 : for (auto desc_cache_pair : wss.m_descriptor_caches) {
# 776 : 763 : auto spk_man = pwallet->GetScriptPubKeyMan(desc_cache_pair.first);
# 777 : 763 : assert(spk_man);
# 778 : 763 : ((DescriptorScriptPubKeyMan*)spk_man)->SetCache(desc_cache_pair.second);
# 779 : 763 : }
# 780 : :
# 781 : : // Set the descriptor keys
# 782 [ + + ]: 780 : for (auto desc_key_pair : wss.m_descriptor_keys) {
# 783 : 613 : auto spk_man = pwallet->GetScriptPubKeyMan(desc_key_pair.first.first);
# 784 : 613 : ((DescriptorScriptPubKeyMan*)spk_man)->AddKey(desc_key_pair.first.second, desc_key_pair.second);
# 785 : 613 : }
# 786 [ + + ]: 780 : for (auto desc_key_pair : wss.m_descriptor_crypt_keys) {
# 787 : 76 : auto spk_man = pwallet->GetScriptPubKeyMan(desc_key_pair.first.first);
# 788 : 76 : ((DescriptorScriptPubKeyMan*)spk_man)->AddCryptedKey(desc_key_pair.first.second, desc_key_pair.second.first, desc_key_pair.second.second);
# 789 : 76 : }
# 790 : :
# 791 [ - + ][ # # ]: 780 : if (fNoncriticalErrors && result == DBErrors::LOAD_OK)
# 792 : 0 : result = DBErrors::NONCRITICAL_ERROR;
# 793 : :
# 794 : : // Any wallet corruption at all: skip any rewriting or
# 795 : : // upgrading, we don't want to make it worse.
# 796 [ - + ]: 780 : if (result != DBErrors::LOAD_OK)
# 797 : 0 : return result;
# 798 : :
# 799 : : // Last client version to open this wallet, was previously the file version number
# 800 : 780 : int last_client = CLIENT_VERSION;
# 801 : 780 : m_batch->Read(DBKeys::VERSION, last_client);
# 802 : :
# 803 : 780 : int wallet_version = pwallet->GetVersion();
# 804 [ + - ]: 780 : pwallet->WalletLogPrintf("Wallet File Version = %d\n", wallet_version > 0 ? wallet_version : last_client);
# 805 : :
# 806 : 780 : pwallet->WalletLogPrintf("Keys: %u plaintext, %u encrypted, %u w/ metadata, %u total. Unknown wallet records: %u\n",
# 807 : 780 : wss.nKeys, wss.nCKeys, wss.nKeyMeta, wss.nKeys + wss.nCKeys, wss.m_unknown_records);
# 808 : :
# 809 : : // nTimeFirstKey is only reliable if all keys have metadata
# 810 [ + + ][ + + ]: 780 : if (pwallet->IsLegacy() && (wss.nKeys + wss.nCKeys + wss.nWatchKeys) != wss.nKeyMeta) {
# 811 : 3 : auto spk_man = pwallet->GetOrCreateLegacyScriptPubKeyMan();
# 812 [ + - ]: 3 : if (spk_man) {
# 813 : 3 : LOCK(spk_man->cs_KeyStore);
# 814 : 3 : spk_man->UpdateTimeFirstKey(1);
# 815 : 3 : }
# 816 : 3 : }
# 817 : :
# 818 [ - + ]: 780 : for (const uint256& hash : wss.vWalletUpgrade)
# 819 : 0 : WriteTx(pwallet->mapWallet.at(hash));
# 820 : :
# 821 : : // Rewrite encrypted wallets of versions 0.4.0 and 0.5.0rc:
# 822 [ + + ][ - + ]: 780 : if (wss.fIsEncrypted && (last_client == 40000 || last_client == 50000))
# [ - + ]
# 823 : 0 : return DBErrors::NEED_REWRITE;
# 824 : :
# 825 [ - + ]: 780 : if (last_client < CLIENT_VERSION) // Update
# 826 : 0 : m_batch->Write(DBKeys::VERSION, CLIENT_VERSION);
# 827 : :
# 828 [ - + ]: 780 : if (wss.fAnyUnordered)
# 829 : 0 : result = pwallet->ReorderTransactions();
# 830 : :
# 831 : : // Upgrade all of the wallet keymetadata to have the hd master key id
# 832 : : // This operation is not atomic, but if it fails, updated entries are still backwards compatible with older software
# 833 : 780 : try {
# 834 : 780 : pwallet->UpgradeKeyMetadata();
# 835 : 780 : } catch (...) {
# 836 : 0 : result = DBErrors::CORRUPT;
# 837 : 0 : }
# 838 : :
# 839 : : // Set the inactive chain
# 840 [ + + ]: 780 : if (wss.m_hd_chains.size() > 0) {
# 841 : 212 : LegacyScriptPubKeyMan* legacy_spkm = pwallet->GetLegacyScriptPubKeyMan();
# 842 [ - + ]: 212 : if (!legacy_spkm) {
# 843 : 0 : pwallet->WalletLogPrintf("Inactive HD Chains found but no Legacy ScriptPubKeyMan\n");
# 844 : 0 : return DBErrors::CORRUPT;
# 845 : 0 : }
# 846 [ + + ]: 224 : for (const auto& chain_pair : wss.m_hd_chains) {
# 847 [ + + ]: 224 : if (chain_pair.first != pwallet->GetLegacyScriptPubKeyMan()->GetHDChain().seed_id) {
# 848 : 12 : pwallet->GetLegacyScriptPubKeyMan()->AddInactiveHDChain(chain_pair.second);
# 849 : 12 : }
# 850 : 224 : }
# 851 : 212 : }
# 852 : :
# 853 : 780 : return result;
# 854 : 780 : }
# 855 : :
# 856 : : DBErrors WalletBatch::FindWalletTx(std::vector<uint256>& vTxHash, std::list<CWalletTx>& vWtx)
# 857 : 7 : {
# 858 : 7 : DBErrors result = DBErrors::LOAD_OK;
# 859 : :
# 860 : 7 : try {
# 861 : 7 : int nMinVersion = 0;
# 862 [ + - ]: 7 : if (m_batch->Read(DBKeys::MINVERSION, nMinVersion)) {
# 863 [ - + ]: 7 : if (nMinVersion > FEATURE_LATEST)
# 864 : 0 : return DBErrors::TOO_NEW;
# 865 : 7 : }
# 866 : :
# 867 : : // Get cursor
# 868 [ - + ]: 7 : if (!m_batch->StartCursor())
# 869 : 0 : {
# 870 : 0 : LogPrintf("Error getting wallet database cursor\n");
# 871 : 0 : return DBErrors::CORRUPT;
# 872 : 0 : }
# 873 : :
# 874 : 6179 : while (true)
# 875 : 6179 : {
# 876 : : // Read next record
# 877 : 6179 : CDataStream ssKey(SER_DISK, CLIENT_VERSION);
# 878 : 6179 : CDataStream ssValue(SER_DISK, CLIENT_VERSION);
# 879 : 6179 : bool complete;
# 880 : 6179 : bool ret = m_batch->ReadAtCursor(ssKey, ssValue, complete);
# 881 [ + + ]: 6179 : if (complete) {
# 882 : 7 : break;
# 883 [ - + ]: 6172 : } else if (!ret) {
# 884 : 0 : m_batch->CloseCursor();
# 885 : 0 : LogPrintf("Error reading next record from wallet database\n");
# 886 : 0 : return DBErrors::CORRUPT;
# 887 : 0 : }
# 888 : :
# 889 : 6172 : std::string strType;
# 890 : 6172 : ssKey >> strType;
# 891 [ + + ]: 6172 : if (strType == DBKeys::TX) {
# 892 : 7 : uint256 hash;
# 893 : 7 : ssKey >> hash;
# 894 : 7 : vTxHash.push_back(hash);
# 895 : 7 : vWtx.emplace_back(nullptr /* wallet */, nullptr /* tx */);
# 896 : 7 : ssValue >> vWtx.back();
# 897 : 7 : }
# 898 : 6172 : }
# 899 : 7 : } catch (...) {
# 900 : 0 : result = DBErrors::CORRUPT;
# 901 : 0 : }
# 902 : 7 : m_batch->CloseCursor();
# 903 : :
# 904 : 7 : return result;
# 905 : 7 : }
# 906 : :
# 907 : : DBErrors WalletBatch::ZapSelectTx(std::vector<uint256>& vTxHashIn, std::vector<uint256>& vTxHashOut)
# 908 : 7 : {
# 909 : : // build list of wallet TXs and hashes
# 910 : 7 : std::vector<uint256> vTxHash;
# 911 : 7 : std::list<CWalletTx> vWtx;
# 912 : 7 : DBErrors err = FindWalletTx(vTxHash, vWtx);
# 913 [ - + ]: 7 : if (err != DBErrors::LOAD_OK) {
# 914 : 0 : return err;
# 915 : 0 : }
# 916 : :
# 917 : 7 : std::sort(vTxHash.begin(), vTxHash.end());
# 918 : 7 : std::sort(vTxHashIn.begin(), vTxHashIn.end());
# 919 : :
# 920 : : // erase each matching wallet TX
# 921 : 7 : bool delerror = false;
# 922 : 7 : std::vector<uint256>::iterator it = vTxHashIn.begin();
# 923 [ + + ]: 7 : for (const uint256& hash : vTxHash) {
# 924 [ + + ][ + + ]: 9 : while (it < vTxHashIn.end() && (*it) < hash) {
# [ + + ]
# 925 : 2 : it++;
# 926 : 2 : }
# 927 [ + + ]: 7 : if (it == vTxHashIn.end()) {
# 928 : 2 : break;
# 929 : 2 : }
# 930 [ + - ]: 5 : else if ((*it) == hash) {
# 931 [ - + ]: 5 : if(!EraseTx(hash)) {
# 932 [ # # ]: 0 : LogPrint(BCLog::WALLETDB, "Transaction was found for deletion but returned database error: %s\n", hash.GetHex());
# 933 : 0 : delerror = true;
# 934 : 0 : }
# 935 : 5 : vTxHashOut.push_back(hash);
# 936 : 5 : }
# 937 : 7 : }
# 938 : :
# 939 [ - + ]: 7 : if (delerror) {
# 940 : 0 : return DBErrors::CORRUPT;
# 941 : 0 : }
# 942 : 7 : return DBErrors::LOAD_OK;
# 943 : 7 : }
# 944 : :
# 945 : : void MaybeCompactWalletDB()
# 946 : 25766 : {
# 947 : 25766 : static std::atomic<bool> fOneThread(false);
# 948 [ - + ]: 25766 : if (fOneThread.exchange(true)) {
# 949 : 0 : return;
# 950 : 0 : }
# 951 : :
# 952 [ + + ]: 25766 : for (const std::shared_ptr<CWallet>& pwallet : GetWallets()) {
# 953 : 14139 : WalletDatabase& dbh = pwallet->GetDatabase();
# 954 : :
# 955 : 14139 : unsigned int nUpdateCounter = dbh.nUpdateCounter;
# 956 : :
# 957 [ + + ]: 14139 : if (dbh.nLastSeen != nUpdateCounter) {
# 958 : 4210 : dbh.nLastSeen = nUpdateCounter;
# 959 : 4210 : dbh.nLastWalletUpdate = GetTime();
# 960 : 4210 : }
# 961 : :
# 962 [ + + ][ + + ]: 14139 : if (dbh.nLastFlushed != nUpdateCounter && GetTime() - dbh.nLastWalletUpdate >= 2) {
# 963 [ + + ]: 2632 : if (dbh.PeriodicFlush()) {
# 964 : 284 : dbh.nLastFlushed = nUpdateCounter;
# 965 : 284 : }
# 966 : 2632 : }
# 967 : 14139 : }
# 968 : :
# 969 : 25766 : fOneThread = false;
# 970 : 25766 : }
# 971 : :
# 972 : : bool WalletBatch::WriteDestData(const std::string &address, const std::string &key, const std::string &value)
# 973 : 46 : {
# 974 : 46 : return WriteIC(std::make_pair(DBKeys::DESTDATA, std::make_pair(address, key)), value);
# 975 : 46 : }
# 976 : :
# 977 : : bool WalletBatch::EraseDestData(const std::string &address, const std::string &key)
# 978 : 0 : {
# 979 : 0 : return EraseIC(std::make_pair(DBKeys::DESTDATA, std::make_pair(address, key)));
# 980 : 0 : }
# 981 : :
# 982 : :
# 983 : : bool WalletBatch::WriteHDChain(const CHDChain& chain)
# 984 : 24512 : {
# 985 : 24512 : return WriteIC(DBKeys::HDCHAIN, chain);
# 986 : 24512 : }
# 987 : :
# 988 : : bool WalletBatch::WriteWalletFlags(const uint64_t flags)
# 989 : 14840 : {
# 990 : 14840 : return WriteIC(DBKeys::FLAGS, flags);
# 991 : 14840 : }
# 992 : :
# 993 : : bool WalletBatch::TxnBegin()
# 994 : 27 : {
# 995 : 27 : return m_batch->TxnBegin();
# 996 : 27 : }
# 997 : :
# 998 : : bool WalletBatch::TxnCommit()
# 999 : 27 : {
# 1000 : 27 : return m_batch->TxnCommit();
# 1001 : 27 : }
# 1002 : :
# 1003 : : bool WalletBatch::TxnAbort()
# 1004 : 0 : {
# 1005 : 0 : return m_batch->TxnAbort();
# 1006 : 0 : }
# 1007 : :
# 1008 : : std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error)
# 1009 : 1424 : {
# 1010 : 1424 : bool exists;
# 1011 : 1424 : try {
# 1012 : 1424 : exists = fs::symlink_status(path).type() != fs::file_not_found;
# 1013 : 1424 : } catch (const fs::filesystem_error& e) {
# 1014 : 0 : error = Untranslated(strprintf("Failed to access database path '%s': %s", path.string(), fsbridge::get_filesystem_error_message(e)));
# 1015 : 0 : status = DatabaseStatus::FAILED_BAD_PATH;
# 1016 : 0 : return nullptr;
# 1017 : 0 : }
# 1018 : :
# 1019 : 1424 : std::optional<DatabaseFormat> format;
# 1020 [ + + ]: 1424 : if (exists) {
# 1021 [ + + ]: 1151 : if (IsBDBFile(BDBDataFile(path))) {
# 1022 : 343 : format = DatabaseFormat::BERKELEY;
# 1023 : 343 : }
# 1024 [ + + ]: 1151 : if (IsSQLiteFile(SQLiteDataFile(path))) {
# 1025 [ - + ]: 166 : if (format) {
# 1026 : 0 : error = Untranslated(strprintf("Failed to load database path '%s'. Data is in ambiguous format.", path.string()));
# 1027 : 0 : status = DatabaseStatus::FAILED_BAD_FORMAT;
# 1028 : 0 : return nullptr;
# 1029 : 0 : }
# 1030 : 166 : format = DatabaseFormat::SQLITE;
# 1031 : 166 : }
# 1032 [ + + ]: 1151 : } else if (options.require_existing) {
# 1033 : 7 : error = Untranslated(strprintf("Failed to load database path '%s'. Path does not exist.", path.string()));
# 1034 : 7 : status = DatabaseStatus::FAILED_NOT_FOUND;
# 1035 : 7 : return nullptr;
# 1036 : 7 : }
# 1037 : :
# 1038 [ + + ][ + + ]: 1417 : if (!format && options.require_existing) {
# 1039 : 474 : error = Untranslated(strprintf("Failed to load database path '%s'. Data is not in recognized format.", path.string()));
# 1040 : 474 : status = DatabaseStatus::FAILED_BAD_FORMAT;
# 1041 : 474 : return nullptr;
# 1042 : 474 : }
# 1043 : :
# 1044 [ + + ][ + + ]: 943 : if (format && options.require_create) {
# 1045 : 5 : error = Untranslated(strprintf("Failed to create database path '%s'. Database already exists.", path.string()));
# 1046 : 5 : status = DatabaseStatus::FAILED_ALREADY_EXISTS;
# 1047 : 5 : return nullptr;
# 1048 : 5 : }
# 1049 : :
# 1050 : : // A db already exists so format is set, but options also specifies the format, so make sure they agree
# 1051 [ + + ][ + + ]: 938 : if (format && options.require_format && format != options.require_format) {
# [ - + ]
# 1052 : 0 : error = Untranslated(strprintf("Failed to load database path '%s'. Data is not in required format.", path.string()));
# 1053 : 0 : status = DatabaseStatus::FAILED_BAD_FORMAT;
# 1054 : 0 : return nullptr;
# 1055 : 0 : }
# 1056 : :
# 1057 : : // Format is not set when a db doesn't already exist, so use the format specified by the options if it is set.
# 1058 [ + + ][ + + ]: 938 : if (!format && options.require_format) format = options.require_format;
# 1059 : :
# 1060 : : // If the format is not specified or detected, choose the default format based on what is available. We prefer BDB over SQLite for now.
# 1061 [ + + ]: 938 : if (!format) {
# 1062 : 270 : #ifdef USE_SQLITE
# 1063 : 270 : format = DatabaseFormat::SQLITE;
# 1064 : 270 : #endif
# 1065 : 270 : #ifdef USE_BDB
# 1066 : 270 : format = DatabaseFormat::BERKELEY;
# 1067 : 270 : #endif
# 1068 : 270 : }
# 1069 : :
# 1070 [ + + ]: 938 : if (format == DatabaseFormat::SQLITE) {
# 1071 : 322 : #ifdef USE_SQLITE
# 1072 : 322 : return MakeSQLiteDatabase(path, options, status, error);
# 1073 : 322 : #endif
# 1074 : 322 : error = Untranslated(strprintf("Failed to open database path '%s'. Build does not support SQLite database format.", path.string()));
# 1075 : 0 : status = DatabaseStatus::FAILED_BAD_FORMAT;
# 1076 : 0 : return nullptr;
# 1077 : 616 : }
# 1078 : :
# 1079 : 616 : #ifdef USE_BDB
# 1080 : 616 : return MakeBerkeleyDatabase(path, options, status, error);
# 1081 : 616 : #endif
# 1082 : 616 : error = Untranslated(strprintf("Failed to open database path '%s'. Build does not support Berkeley DB database format.", path.string()));
# 1083 : 0 : status = DatabaseStatus::FAILED_BAD_FORMAT;
# 1084 : 0 : return nullptr;
# 1085 : 616 : }
# 1086 : :
# 1087 : : /** Return object for accessing dummy database with no read/write capabilities. */
# 1088 : : std::unique_ptr<WalletDatabase> CreateDummyWalletDatabase()
# 1089 : 33 : {
# 1090 : 33 : return std::make_unique<DummyDatabase>();
# 1091 : 33 : }
# 1092 : :
# 1093 : : /** Return object for accessing temporary in-memory database. */
# 1094 : : std::unique_ptr<WalletDatabase> CreateMockWalletDatabase()
# 1095 : 11 : {
# 1096 : 11 : #ifdef USE_BDB
# 1097 : 11 : return std::make_unique<BerkeleyDatabase>(std::make_shared<BerkeleyEnvironment>(), "");
# 1098 : : #elif USE_SQLITE
# 1099 : : return std::make_unique<SQLiteDatabase>("", "", true);
# 1100 : : #endif
# 1101 : 11 : }
|