Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
751template<typename... Args>752static DataStream PrefixStream(const Args&... args)753{754DataStream prefix;755SerializeMany(prefix, args...);756return prefix;757}759static DBErrors LoadDescriptorWalletRecords(CWallet* pwallet, DatabaseBatch& batch, int last_client) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)760{761AssertLockHeld(pwallet->cs_wallet);763// Load descriptor record764int num_keys = 0;765int num_ckeys= 0;766LoadResult desc_res = LoadRecords(pwallet, batch, DBKeys::WALLETDESCRIPTOR,767[&batch, &num_keys, &num_ckeys, &last_client] (CWallet* pwallet, DataStream& key, DataStream& value, std::string& strErr) {768DBErrors result = DBErrors::LOAD_OK;770uint256 id;771key >> id;772std::optional<WalletDescriptor> desc;773try {774desc.emplace(WalletDescriptor::FromStream(deserialize, value));775} catch (const std::ios_base::failure& e) {776strErr = strprintf("Error: Unrecognized descriptor found in wallet %s. ", pwallet->GetName());777strErr += (last_client > CLIENT_VERSION) ? "The wallet might have been created on a newer version. " :778"The database might be corrupted or the software version is not compatible with one of your wallet descriptors. ";779strErr += "Please try running the latest software version";780// Also include error details781strErr = strprintf("%s\nDetails: %s", strErr, e.what());782return DBErrors::UNKNOWN_DESCRIPTOR;783}785DescriptorCache cache;787// Get key cache for this descriptor788DataStream prefix = PrefixStream(DBKeys::WALLETDESCRIPTORCACHE, id);789LoadResult key_cache_res = LoadRecords(pwallet, batch, DBKeys::WALLETDESCRIPTORCACHE, prefix,790[&id, &cache] (CWallet* pwallet, DataStream& key, DataStream& value, std::string& err) {791bool parent = true;792uint256 desc_id;793uint32_t key_exp_index;794uint32_t der_index;795key >> desc_id;796assert(desc_id == id);797key >> key_exp_index;799// if the der_index exists, it's a derived xpub800try801{802key >> der_index;803parent = false;804}805catch (...) {}807std::vector<unsigned char> ser_xpub(BIP32_EXTKEY_SIZE);808value >> ser_xpub;809CExtPubKey xpub;810xpub.Decode(ser_xpub.data());811if (parent) {812cache.CacheParentExtPubKey(key_exp_index, xpub);813} else {814cache.CacheDerivedExtPubKey(key_exp_index, der_index, xpub);815}816return DBErrors::LOAD_OK;817});818result = std::max(result, key_cache_res.m_result);820// Get last hardened cache for this descriptor821prefix = PrefixStream(DBKeys::WALLETDESCRIPTORLHCACHE, id);822LoadResult lh_cache_res = LoadRecords(pwallet, batch, DBKeys::WALLETDESCRIPTORLHCACHE, prefix,823[&id, &cache] (CWallet* pwallet, DataStream& key, DataStream& value, std::string& err) {824uint256 desc_id;825uint32_t key_exp_index;826key >> desc_id;827assert(desc_id == id);828key >> key_exp_index;830std::vector<unsigned char> ser_xpub(BIP32_EXTKEY_SIZE);831value >> ser_xpub;832CExtPubKey xpub;833xpub.Decode(ser_xpub.data());834cache.CacheLastHardenedExtPubKey(key_exp_index, xpub);835return DBErrors::LOAD_OK;836});837result = std::max(result, lh_cache_res.m_result);839// Set the cache to the WalletDescriptor840desc->cache = cache;842// Get unencrypted keys843KeyMap keys;844prefix = PrefixStream(DBKeys::WALLETDESCRIPTORKEY, id);845LoadResult key_res = LoadRecords(pwallet, batch, DBKeys::WALLETDESCRIPTORKEY, prefix,846[&id, &keys] (CWallet* pwallet, DataStream& key, DataStream& value, std::string& strErr) {847uint256 desc_id;848CPubKey pubkey;849key >> desc_id;850assert(desc_id == id);851key >> pubkey;852if (!pubkey.IsValid())853{854strErr = "Error reading wallet database: descriptor unencrypted key CPubKey corrupt";855return DBErrors::CORRUPT;856}857CKey privkey;858CPrivKey pkey;859uint256 hash;861value >> pkey;862value >> hash;864// hash pubkey/privkey to accelerate wallet load865const auto keypair_hash = Hash(pubkey, pkey);867if (keypair_hash != hash)868{869strErr = "Error reading wallet database: descriptor unencrypted key CPubKey/CPrivKey corrupt";870return DBErrors::CORRUPT;871}873if (!privkey.Load(pkey, pubkey, true))874{875strErr = "Error reading wallet database: descriptor unencrypted key CPrivKey corrupt";876return DBErrors::CORRUPT;877}878keys[pubkey.GetID()] = privkey;879return DBErrors::LOAD_OK;880});881result = std::max(result, key_res.m_result);882num_keys = key_res.m_records;884// Get encrypted keys885CryptedKeyMap ckeys;886prefix = PrefixStream(DBKeys::WALLETDESCRIPTORCKEY, id);887LoadResult ckey_res = LoadRecords(pwallet, batch, DBKeys::WALLETDESCRIPTORCKEY, prefix,888[&id, &ckeys] (CWallet* pwallet, DataStream& key, DataStream& value, std::string& err) {889uint256 desc_id;890CPubKey pubkey;891key >> desc_id;892assert(desc_id == id);893key >> pubkey;894if (!pubkey.IsValid())895{896err = "Error reading wallet database: descriptor encrypted key CPubKey corrupt";897return DBErrors::CORRUPT;898}899std::vector<unsigned char> privkey;900value >> privkey;902ckeys[pubkey.GetID()] = std::make_pair(pubkey, privkey);903return DBErrors::LOAD_OK;904});905result = std::max(result, ckey_res.m_result);906num_ckeys = ckey_res.m_records;908try {909pwallet->LoadDescriptorScriptPubKeyMan(id, *desc, keys, ckeys);910} catch (std::runtime_error& e) {911strErr = e.what();912return DBErrors::CORRUPT;913}915return result;916});918if (desc_res.m_result <= DBErrors::NONCRITICAL_ERROR) {919// Only log if there are no critical errors920pwallet->WalletLogPrintf("Descriptors: %u, Descriptor Keys: %u plaintext, %u encrypted, %u total.\n",921desc_res.m_records, num_keys, num_ckeys, num_keys + num_ckeys);922}924return desc_res.m_result;925}927static DBErrors LoadAddressBookRecords(CWallet* pwallet, DatabaseBatch& batch) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)928{929AssertLockHeld(pwallet->cs_wallet);930DBErrors result = DBErrors::LOAD_OK;932// Load name record933LoadResult name_res = LoadRecords(pwallet, batch, DBKeys::NAME,934[] (CWallet* pwallet, DataStream& key, DataStream& value, std::string& err) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet) {935std::string strAddress;936key >> strAddress;937std::string label;938value >> label;939pwallet->m_address_book[DecodeDestination(strAddress)].SetLabel(label);940return DBErrors::LOAD_OK;941});942result = std::max(result, name_res.m_result);944// Load purpose record945LoadResult purpose_res = LoadRecords(pwallet, batch, DBKeys::PURPOSE,946[] (CWallet* pwallet, DataStream& key, DataStream& value, std::string& err) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet) {947std::string strAddress;948key >> strAddress;949std::string purpose_str;950value >> purpose_str;951std::optional<AddressPurpose> purpose{PurposeFromString(purpose_str)};952if (!purpose) {953pwallet->WalletLogPrintf("Warning: nonstandard purpose string '%s' for address '%s'\n", purpose_str, strAddress);954}955pwallet->m_address_book[DecodeDestination(strAddress)].purpose = purpose;956return DBErrors::LOAD_OK;957});958result = std::max(result, purpose_res.m_result);960// Load destination data record961LoadResult dest_res = LoadRecords(pwallet, batch, DBKeys::DESTDATA,962[] (CWallet* pwallet, DataStream& key, DataStream& value, std::string& err) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet) {963std::string strAddress, strKey, strValue;964key >> strAddress;965key >> strKey;966value >> strValue;967const CTxDestination& dest{DecodeDestination(strAddress)};968if (strKey.compare("used") == 0) {969// Load "used" key indicating if an IsMine address has970// previously been spent from with avoid_reuse option enabled.971// The strValue is not used for anything currently, but could972// hold more information in the future. Current values are just973// "1" or "p" for present (which was written prior to974// f5ba424cd44619d9b9be88b8593d69a7ba96db26).975pwallet->LoadAddressPreviouslySpent(dest);976} else if (strKey.starts_with("rr")) {977// Load "rr##" keys where ## is a decimal number, and strValue978// is a serialized RecentRequestEntry object.979pwallet->LoadAddressReceiveRequest(dest, strKey.substr(2), strValue);980}981return DBErrors::LOAD_OK;982});983result = std::max(result, dest_res.m_result);985return result;986}988static std::map<Wtxid, CTransactionRef> ReadWtxVariants(DatabaseBatch& batch, const Txid& txid)989{990std::map<Wtxid, CTransactionRef> variants;992DataStream prefix;993prefix << DBKeys::WTX_VARIANT << txid;994std::unique_ptr<DatabaseCursor> cursor = batch.GetNewPrefixCursor(prefix);995if (!cursor) {996throw std::runtime_error(strprintf("Error getting database cursor for '%s' records", DBKeys::WTX_VARIANT));997}999DataStream key;1000DataStream value;