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.
3501// Search the cache for relevant SPKMs instead of iterating m_spk_managers3502const auto& it = m_cached_spks.find(script);3503if (it != m_cached_spks.end()) {3504spk_mans.insert(it->second.begin(), it->second.end());3505}3506SignatureData sigdata;3507Assume(std::all_of(spk_mans.begin(), spk_mans.end(), [&script, &sigdata](ScriptPubKeyMan* spkm) { return spkm->CanProvide(script, sigdata); }));3509return spk_mans;3510}3512ScriptPubKeyMan* CWallet::GetScriptPubKeyMan(const uint256& id) const3513{3514if (m_spk_managers.contains(id)) {3515return m_spk_managers.at(id).get();3516}3517return nullptr;3518}3520std::unique_ptr<SigningProvider> CWallet::GetSolvingProvider(const CScript& script) const3521{3522SignatureData sigdata;3523return GetSolvingProvider(script, sigdata);3524}3526std::unique_ptr<SigningProvider> CWallet::GetSolvingProvider(const CScript& script, SignatureData& sigdata) const3527{3528// Search the cache for relevant SPKMs instead of iterating m_spk_managers3529const auto& it = m_cached_spks.find(script);3530if (it != m_cached_spks.end()) {3531// All spkms for a given script must already be able to make a SigningProvider for the script, so just return the first one.3532Assume(it->second.at(0)->CanProvide(script, sigdata));3533return it->second.at(0)->GetSolvingProvider(script);3534}3536return nullptr;3537}3539std::vector<WalletDescriptor> CWallet::GetWalletDescriptors(const CScript& script) const3540{3541std::vector<WalletDescriptor> descs;3542for (const auto spk_man: GetScriptPubKeyMans(script)) {3543if (const auto desc_spk_man = dynamic_cast<DescriptorScriptPubKeyMan*>(spk_man)) {3544LOCK(desc_spk_man->cs_desc_man);3545descs.push_back(desc_spk_man->GetWalletDescriptor());3546}3547}3548return descs;3549}3551LegacyDataSPKM* CWallet::GetLegacyDataSPKM() const3552{3553if (IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {3554return nullptr;3555}3556auto it = m_internal_spk_managers.find(OutputType::LEGACY);3557if (it == m_internal_spk_managers.end()) return nullptr;3558return dynamic_cast<LegacyDataSPKM*>(it->second);3559}3561void CWallet::AddScriptPubKeyMan(const uint256& id, std::unique_ptr<ScriptPubKeyMan> spkm_man)3562{3563// Add spkm_man to m_spk_managers before calling any method3564// that might access it.3565const auto& spkm = m_spk_managers[id] = std::move(spkm_man);3567// Update birth time if needed3568MaybeUpdateBirthTime(spkm->GetTimeFirstKey());3569}3571LegacyDataSPKM* CWallet::GetOrCreateLegacyDataSPKM()3572{3573SetupLegacyDataSPKM();3574return GetLegacyDataSPKM();3575}3577void CWallet::SetupLegacyDataSPKM()3578{3579if (!m_internal_spk_managers.empty() || !m_external_spk_managers.empty() || !m_spk_managers.empty() || IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {3580return;3581}3583Assert(m_database->Format() == "bdb_ro" || m_database->Format() == "sqlite-mock");3584std::unique_ptr<ScriptPubKeyMan> spk_manager = std::make_unique<LegacyDataSPKM>(*this);3586for (const auto& type : LEGACY_OUTPUT_TYPES) {3587m_internal_spk_managers[type] = spk_manager.get();3588m_external_spk_managers[type] = spk_manager.get();3589}3590uint256 id = spk_manager->GetID();3591AddScriptPubKeyMan(id, std::move(spk_manager));3592}3594bool CWallet::WithEncryptionKey(std::function<bool (const CKeyingMaterial&)> cb) const3595{3596LOCK(cs_wallet);3597return cb(vMasterKey);3598}3600bool CWallet::HasEncryptionKeys() const3601{3602return !mapMasterKeys.empty();3603}3605bool CWallet::HaveCryptedKeys() const3606{3607for (const auto& spkm : GetAllScriptPubKeyMans()) {3608if (spkm->HaveCryptedKeys()) return true;3609}3610return false;3611}3613void CWallet::ConnectScriptPubKeyManNotifiers()3614{3615for (const auto& spk_man : GetActiveScriptPubKeyMans()) {3616spk_man->NotifyCanGetAddressesChanged.connect([this] {3617NotifyCanGetAddressesChanged();3618});3619spk_man->NotifyFirstKeyTimeChanged.connect([this](const ScriptPubKeyMan*, int64_t time) {3620MaybeUpdateBirthTime(time);3621});3622}3623}3625void CWallet::LoadDescriptorScriptPubKeyMan(uint256 id, WalletDescriptor& desc, const KeyMap& keys, const CryptedKeyMap& ckeys)3626{3627std::unique_ptr<DescriptorScriptPubKeyMan> spk_manager;3628if (IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER)) {3629spk_manager = ExternalSignerScriptPubKeyMan::LoadFromStorage(*this, id, desc, m_keypool_size, keys, ckeys);3630} else {3631spk_manager = DescriptorScriptPubKeyMan::LoadFromStorage(*this, id, desc, m_keypool_size, keys, ckeys);3632}3633AddScriptPubKeyMan(id, std::move(spk_manager));3634}3636DescriptorScriptPubKeyMan& CWallet::SetupDescriptorScriptPubKeyMan(WalletBatch& batch, const CExtKey& master_key, const OutputType& output_type, bool internal)3637{3638AssertLockHeld(cs_wallet);3639if (IsLocked()) {3640throw std::runtime_error(std::string(__func__) + ": Wallet is locked, cannot setup new descriptors");3641}3642auto spk_manager = DescriptorScriptPubKeyMan::GenerateNewSingleSig(*this, batch, m_keypool_size, master_key, output_type, internal);3643DescriptorScriptPubKeyMan* out = spk_manager.get();3644uint256 id = spk_manager->GetID();3645AddScriptPubKeyMan(id, std::move(spk_manager));3646AddActiveScriptPubKeyManWithDb(batch, id, output_type, internal);3647return *out;3648}3650void CWallet::SetupDescriptorScriptPubKeyMans(WalletBatch& batch, const CExtKey& master_key)3651{3652AssertLockHeld(cs_wallet);3653for (bool internal : {false, true}) {3654for (OutputType t : OUTPUT_TYPES) {3655SetupDescriptorScriptPubKeyMan(batch, master_key, t, internal);3656}3657}3658}3660void CWallet::SetupOwnDescriptorScriptPubKeyMans(WalletBatch& batch)3661{3662AssertLockHeld(cs_wallet);3663assert(!IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER));3664// Make a seed3665CKey seed_key = GenerateRandomKey();3666CPubKey seed = seed_key.GetPubKey();3667assert(seed_key.VerifyPubKey(seed));3669// Get the extended key3670CExtKey master_key;3671master_key.SetSeed(seed_key);3673SetupDescriptorScriptPubKeyMans(batch, master_key);3674}3676void CWallet::SetupDescriptorScriptPubKeyMans()3677{3678AssertLockHeld(cs_wallet);3680if (!IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER)) {3681if (!RunWithinTxn(GetDatabase(), /*process_desc=*/"setup descriptors", [&](WalletBatch& batch) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet){3682SetupOwnDescriptorScriptPubKeyMans(batch);3683return true;3684})) throw std::runtime_error("Error: cannot process db transaction for descriptors setup");3685} else {3686auto signer = ExternalSignerScriptPubKeyMan::GetExternalSigner();3687if (!signer) throw std::runtime_error(util::ErrorString(signer).original);3689// TODO: add account parameter3690int account = 0;3691UniValue signer_res = signer->GetDescriptors(account);3693if (!signer_res.isObject()) throw std::runtime_error(std::string(__func__) + ": Unexpected result");3695WalletBatch batch(GetDatabase());3696if (!batch.TxnBegin()) throw std::runtime_error("Error: cannot create db transaction for descriptors import");3698for (bool internal : {false, true}) {3699const UniValue& descriptor_vals = signer_res.find_value(internal ? "internal" : "receive");3700if (!descriptor_vals.isArray()) throw std::runtime_error(std::string(__func__) + ": Unexpected result");3701for (const UniValue& desc_val : descriptor_vals.get_array().getValues()) {3702const std::string& desc_str = desc_val.getValStr();3703FlatSigningProvider keys;3704std::string desc_error;3705auto descs = Parse(desc_str, keys, desc_error, false);3706if (descs.empty()) {3707throw std::runtime_error(std::string(__func__) + ": Invalid descriptor \"" + desc_str + "\" (" + desc_error + ")");3708}3709auto& desc = descs.at(0);3710if (!desc->GetOutputType()) {3711continue;3712}3713OutputType t = *desc->GetOutputType();3714auto spk_manager = ExternalSignerScriptPubKeyMan::CreateNew(*this, batch, m_keypool_size, std::move(desc));3715uint256 id = spk_manager->GetID();3716AddScriptPubKeyMan(id, std::move(spk_manager));3717AddActiveScriptPubKeyManWithDb(batch, id, t, internal);3718}3719}3721// Ensure imported descriptors are committed to disk3722if (!batch.TxnCommit()) throw std::runtime_error("Error: cannot commit db transaction for descriptors import");3723}3724}3726void CWallet::SetupWalletGeneration()3727{3728AssertLockHeld(cs_wallet);3729// Skip setup for non-external-signer wallets that are either blank3730// or have private keys disabled (not having private keys implies blank).3731if (!IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER) &&3732(IsWalletFlagSet(WALLET_FLAG_BLANK_WALLET) || IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS))) {3733return;3734}3735SetupDescriptorScriptPubKeyMans();3736}3738void CWallet::AddActiveScriptPubKeyMan(uint256 id, OutputType type, bool internal)3739{3740WalletBatch batch(GetDatabase());3741return AddActiveScriptPubKeyManWithDb(batch, id, type, internal);3742}3744void CWallet::AddActiveScriptPubKeyManWithDb(WalletBatch& batch, uint256 id, OutputType type, bool internal)3745{3746if (!batch.WriteActiveScriptPubKeyMan(static_cast<uint8_t>(type), id, internal)) {3747throw std::runtime_error(std::string(__func__) + ": writing active ScriptPubKeyMan id failed");3748}3749LoadActiveScriptPubKeyMan(id, type, internal);3750}