Inside Bitcoin
Opening the selected file…
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.
251std::vector<unsigned char> ser_xpub(BIP32_EXTKEY_SIZE);252xpub.Encode(ser_xpub.data());253return WriteIC(std::make_pair(std::make_pair(DBKeys::WALLETDESCRIPTORCACHE, desc_id), std::make_pair(key_exp_index, der_index)), ser_xpub);254}256bool WalletBatch::WriteDescriptorParentCache(const CExtPubKey& xpub, const uint256& desc_id, uint32_t key_exp_index)257{258std::vector<unsigned char> ser_xpub(BIP32_EXTKEY_SIZE);259xpub.Encode(ser_xpub.data());260return WriteIC(std::make_pair(std::make_pair(DBKeys::WALLETDESCRIPTORCACHE, desc_id), key_exp_index), ser_xpub);261}263bool WalletBatch::WriteDescriptorLastHardenedCache(const CExtPubKey& xpub, const uint256& desc_id, uint32_t key_exp_index)264{265std::vector<unsigned char> ser_xpub(BIP32_EXTKEY_SIZE);266xpub.Encode(ser_xpub.data());267return WriteIC(std::make_pair(std::make_pair(DBKeys::WALLETDESCRIPTORLHCACHE, desc_id), key_exp_index), ser_xpub);268}270bool WalletBatch::WriteDescriptorCacheItems(const uint256& desc_id, const DescriptorCache& cache)271{272for (const auto& parent_xpub_pair : cache.GetCachedParentExtPubKeys()) {273if (!WriteDescriptorParentCache(parent_xpub_pair.second, desc_id, parent_xpub_pair.first)) {274return false;275}276}277for (const auto& derived_xpub_map_pair : cache.GetCachedDerivedExtPubKeys()) {278for (const auto& derived_xpub_pair : derived_xpub_map_pair.second) {279if (!WriteDescriptorDerivedCache(derived_xpub_pair.second, desc_id, derived_xpub_map_pair.first, derived_xpub_pair.first)) {280return false;281}282}283}284for (const auto& lh_xpub_pair : cache.GetCachedLastHardenedExtPubKeys()) {285if (!WriteDescriptorLastHardenedCache(lh_xpub_pair.second, desc_id, lh_xpub_pair.first)) {286return false;287}288}289return true;290}292bool WalletBatch::WriteLockedUTXO(const COutPoint& output)293{294return WriteIC(std::make_pair(DBKeys::LOCKED_UTXO, std::make_pair(output.hash, output.n)), uint8_t{'1'});295}297bool WalletBatch::EraseLockedUTXO(const COutPoint& output)298{299return EraseIC(std::make_pair(DBKeys::LOCKED_UTXO, std::make_pair(output.hash, output.n)));300}302bool LoadKey(CWallet* pwallet, DataStream& ssKey, DataStream& ssValue, std::string& strErr)303{304LOCK(pwallet->cs_wallet);305try {306CPubKey vchPubKey;307ssKey >> vchPubKey;308if (!vchPubKey.IsValid())309{310strErr = "Error reading wallet database: CPubKey corrupt";311return false;312}313CKey key;314CPrivKey pkey;315uint256 hash;317ssValue >> pkey;319// Old wallets store keys as DBKeys::KEY [pubkey] => [privkey]320// ... which was slow for wallets with lots of keys, because the public key is re-derived from the private key321// using EC operations as a checksum.322// Newer wallets store keys as DBKeys::KEY [pubkey] => [privkey][hash(pubkey,privkey)], which is much faster while323// remaining backwards-compatible.324try325{326ssValue >> hash;327}328catch (const std::ios_base::failure&) {}330bool fSkipCheck = false;332if (!hash.IsNull())333{334// hash pubkey/privkey to accelerate wallet load335const auto keypair_hash = Hash(vchPubKey, pkey);337if (keypair_hash != hash)338{339strErr = "Error reading wallet database: CPubKey/CPrivKey corrupt";340return false;341}343fSkipCheck = true;344}346if (!key.Load(pkey, vchPubKey, fSkipCheck))347{348strErr = "Error reading wallet database: CPrivKey corrupt";349return false;350}351if (!pwallet->GetOrCreateLegacyDataSPKM()->LoadKey(key, vchPubKey))352{353strErr = "Error reading wallet database: LegacyDataSPKM::LoadKey failed";354return false;355}356} catch (const std::exception& e) {357if (strErr.empty()) {358strErr = e.what();359}360return false;361}362return true;363}365bool LoadCryptedKey(CWallet* pwallet, DataStream& ssKey, DataStream& ssValue, std::string& strErr)366{367LOCK(pwallet->cs_wallet);368try {369CPubKey vchPubKey;370ssKey >> vchPubKey;371if (!vchPubKey.IsValid())372{373strErr = "Error reading wallet database: CPubKey corrupt";374return false;375}376std::vector<unsigned char> vchPrivKey;377ssValue >> vchPrivKey;379// Get the checksum and check it380bool checksum_valid = false;381if (!ssValue.empty()) {382uint256 checksum;383ssValue >> checksum;384if (!(checksum_valid = Hash(vchPrivKey) == checksum)) {385strErr = "Error reading wallet database: Encrypted key corrupt";386return false;387}388}390if (!pwallet->GetOrCreateLegacyDataSPKM()->LoadCryptedKey(vchPubKey, vchPrivKey, checksum_valid))391{392strErr = "Error reading wallet database: LegacyDataSPKM::LoadCryptedKey failed";393return false;394}395} catch (const std::exception& e) {396if (strErr.empty()) {397strErr = e.what();398}399return false;400}401return true;402}404bool LoadEncryptionKey(CWallet* pwallet, DataStream& ssKey, DataStream& ssValue, std::string& strErr)405{406LOCK(pwallet->cs_wallet);407try {408// Master encryption key is loaded into only the wallet and not any of the ScriptPubKeyMans.409unsigned int nID;410ssKey >> nID;411CMasterKey kMasterKey;412ssValue >> kMasterKey;413if(pwallet->mapMasterKeys.contains(nID))414{415strErr = strprintf("Error reading wallet database: duplicate CMasterKey id %u", nID);416return false;417}418pwallet->mapMasterKeys[nID] = kMasterKey;419if (pwallet->nMasterKeyMaxID < nID)420pwallet->nMasterKeyMaxID = nID;422} catch (const std::exception& e) {423if (strErr.empty()) {424strErr = e.what();425}426return false;427}428return true;429}431bool LoadHDChain(CWallet* pwallet, DataStream& ssValue, std::string& strErr)432{433LOCK(pwallet->cs_wallet);434try {435CHDChain chain;436ssValue >> chain;437pwallet->GetOrCreateLegacyDataSPKM()->LoadHDChain(chain);438} catch (const std::exception& e) {439if (strErr.empty()) {440strErr = e.what();441}442return false;443}444return true;445}447static DBErrors LoadWalletFlags(CWallet* pwallet, DatabaseBatch& batch) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)448{449AssertLockHeld(pwallet->cs_wallet);450uint64_t flags;451if (batch.Read(DBKeys::FLAGS, flags)) {452if (!pwallet->LoadWalletFlags(flags)) {453pwallet->WalletLogPrintf("Error reading wallet database: Unknown non-tolerable wallet flags found\n");454return DBErrors::TOO_NEW;455}456// All wallets must be descriptor wallets unless opened with a bdb_ro db457// bdb_ro is only used for legacy to descriptor migration.458if (pwallet->GetDatabase().Format() != "bdb_ro" && !pwallet->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {459return DBErrors::LEGACY_WALLET;460}461}462return DBErrors::LOAD_OK;463}465struct LoadResult466{467DBErrors m_result{DBErrors::LOAD_OK};468int m_records{0};469};471using LoadFunc = std::function<DBErrors(CWallet* pwallet, DataStream& key, DataStream& value, std::string& err)>;472static LoadResult LoadRecords(CWallet* pwallet, DatabaseBatch& batch, const std::string& key, DataStream& prefix, LoadFunc load_func)473{474LoadResult result;475DataStream ssKey;476DataStream ssValue{};478Assume(!prefix.empty());479std::unique_ptr<DatabaseCursor> cursor = batch.GetNewPrefixCursor(prefix);480if (!cursor) {481pwallet->WalletLogPrintf("Error getting database cursor for '%s' records\n", key);482result.m_result = DBErrors::CORRUPT;483return result;484}486while (true) {487DatabaseCursor::Status status = cursor->Next(ssKey, ssValue);488if (status == DatabaseCursor::Status::DONE) {489break;490} else if (status == DatabaseCursor::Status::FAIL) {491pwallet->WalletLogPrintf("Error reading next '%s' record for wallet database\n", key);492result.m_result = DBErrors::CORRUPT;493return result;494}495std::string type;496ssKey >> type;497assert(type == key);498std::string error;499DBErrors record_res = load_func(pwallet, ssKey, ssValue, error);500if (record_res != DBErrors::LOAD_OK) {