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