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.
251}252return true;253}255std::unique_ptr<SigningProvider> LegacyDataSPKM::GetSolvingProvider(const CScript& script) const256{257return std::make_unique<LegacySigningProvider>(*this);258}260bool LegacyDataSPKM::CanProvide(const CScript& script, SignatureData& sigdata)261{262IsMineResult ismine = LegacyWalletIsMineInnerDONOTUSE(*this, script, IsMineSigVersion::TOP, /* recurse_scripthash= */ false);263if (ismine == IsMineResult::SPENDABLE || ismine == IsMineResult::WATCH_ONLY) {264// If ismine, it means we recognize keys or script ids in the script, or265// are watching the script itself, and we can at least provide metadata266// or solving information, even if not able to sign fully.267return true;268} else {269// If, given the stuff in sigdata, we could make a valid signature, then we can provide for this script270ProduceSignature(*this, DUMMY_SIGNATURE_CREATOR, script, sigdata);271if (!sigdata.signatures.empty()) {272// If we could make signatures, make sure we have a private key to actually make a signature273bool has_privkeys = false;274for (const auto& key_sig_pair : sigdata.signatures) {275has_privkeys |= HaveKey(key_sig_pair.first);276}277return has_privkeys;278}279return false;280}281}283bool LegacyDataSPKM::LoadKey(const CKey& key, const CPubKey &pubkey)284{285return AddKeyPubKeyInner(key, pubkey);286}288bool LegacyDataSPKM::LoadCScript(const CScript& redeemScript)289{290/* A sanity check was added in pull #3843 to avoid adding redeemScripts291* that never can be redeemed. However, old wallets may still contain292* these. Do not add them to the wallet and warn. */293if (redeemScript.size() > MAX_SCRIPT_ELEMENT_SIZE)294{295std::string strAddr = EncodeDestination(ScriptHash(redeemScript));296WalletLogPrintf("%s: Warning: This wallet contains a redeemScript of size %i which exceeds maximum size %i thus can never be redeemed. Do not use address %s.\n", __func__, redeemScript.size(), MAX_SCRIPT_ELEMENT_SIZE, strAddr);297return true;298}300return FillableSigningProvider::AddCScript(redeemScript);301}303void LegacyDataSPKM::LoadKeyMetadata(const CKeyID& keyID, const CKeyMetadata& meta)304{305LOCK(cs_KeyStore);306mapKeyMetadata[keyID] = meta;307}309void LegacyDataSPKM::LoadScriptMetadata(const CScriptID& script_id, const CKeyMetadata& meta)310{311LOCK(cs_KeyStore);312m_script_metadata[script_id] = meta;313}315bool LegacyDataSPKM::AddKeyPubKeyInner(const CKey& key, const CPubKey& pubkey)316{317LOCK(cs_KeyStore);318return FillableSigningProvider::AddKeyPubKey(key, pubkey);319}321bool LegacyDataSPKM::LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret, bool checksum_valid)322{323// Set fDecryptionThoroughlyChecked to false when the checksum is invalid324if (!checksum_valid) {325fDecryptionThoroughlyChecked = false;326}328return AddCryptedKeyInner(vchPubKey, vchCryptedSecret);329}331bool LegacyDataSPKM::AddCryptedKeyInner(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)332{333LOCK(cs_KeyStore);334assert(mapKeys.empty());336mapCryptedKeys[vchPubKey.GetID()] = make_pair(vchPubKey, vchCryptedSecret);337ImplicitlyLearnRelatedKeyScripts(vchPubKey);338return true;339}341bool LegacyDataSPKM::HaveWatchOnly(const CScript &dest) const342{343LOCK(cs_KeyStore);344return setWatchOnly.contains(dest);345}347bool LegacyDataSPKM::LoadWatchOnly(const CScript &dest)348{349return AddWatchOnlyInMem(dest);350}352static bool ExtractPubKey(const CScript &dest, CPubKey& pubKeyOut)353{354std::vector<std::vector<unsigned char>> solutions;355return Solver(dest, solutions) == TxoutType::PUBKEY &&356(pubKeyOut = CPubKey(solutions[0])).IsFullyValid();357}359bool LegacyDataSPKM::AddWatchOnlyInMem(const CScript &dest)360{361LOCK(cs_KeyStore);362setWatchOnly.insert(dest);363CPubKey pubKey;364if (ExtractPubKey(dest, pubKey)) {365mapWatchKeys[pubKey.GetID()] = pubKey;366ImplicitlyLearnRelatedKeyScripts(pubKey);367}368return true;369}371void LegacyDataSPKM::LoadHDChain(const CHDChain& chain)372{373LOCK(cs_KeyStore);374m_hd_chain = chain;375}377void LegacyDataSPKM::AddInactiveHDChain(const CHDChain& chain)378{379LOCK(cs_KeyStore);380assert(!chain.seed_id.IsNull());381m_inactive_hd_chains[chain.seed_id] = chain;382}384bool LegacyDataSPKM::HaveKey(const CKeyID &address) const385{386LOCK(cs_KeyStore);387if (!m_storage.HasEncryptionKeys()) {388return FillableSigningProvider::HaveKey(address);389}390return mapCryptedKeys.contains(address);391}393bool LegacyDataSPKM::GetKey(const CKeyID &address, CKey& keyOut) const394{395LOCK(cs_KeyStore);396if (!m_storage.HasEncryptionKeys()) {397return FillableSigningProvider::GetKey(address, keyOut);398}400CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);401if (mi != mapCryptedKeys.end())402{403const CPubKey &vchPubKey = (*mi).second.first;404const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;405return m_storage.WithEncryptionKey([&](const CKeyingMaterial& encryption_key) {406return DecryptKey(encryption_key, vchCryptedSecret, vchPubKey, keyOut);407});408}409return false;410}412bool LegacyDataSPKM::GetKeyOrigin(const CKeyID& keyID, KeyOriginInfo& info) const413{414CKeyMetadata meta;415{416LOCK(cs_KeyStore);417auto it = mapKeyMetadata.find(keyID);418if (it == mapKeyMetadata.end()) {419return false;420}421meta = it->second;422}423if (meta.has_key_origin) {424info.fingerprint = meta.key_origin.fingerprint;425info.path = meta.key_origin.path;426} else { // Single pubkeys get the master fingerprint of themselves427info.fingerprint = keyID.fingerprint();428}429return true;430}432bool LegacyDataSPKM::GetWatchPubKey(const CKeyID &address, CPubKey &pubkey_out) const433{434LOCK(cs_KeyStore);435WatchKeyMap::const_iterator it = mapWatchKeys.find(address);436if (it != mapWatchKeys.end()) {437pubkey_out = it->second;438return true;439}440return false;441}443bool LegacyDataSPKM::GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const444{445LOCK(cs_KeyStore);446if (!m_storage.HasEncryptionKeys()) {447if (!FillableSigningProvider::GetPubKey(address, vchPubKeyOut)) {448return GetWatchPubKey(address, vchPubKeyOut);449}450return true;451}453CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);454if (mi != mapCryptedKeys.end())455{456vchPubKeyOut = (*mi).second.first;457return true;458}459// Check for watch-only pubkeys460return GetWatchPubKey(address, vchPubKeyOut);461}463std::unordered_set<CScript, SaltedSipHasher> LegacyDataSPKM::GetCandidateScriptPubKeys() const464{465LOCK(cs_KeyStore);466std::unordered_set<CScript, SaltedSipHasher> candidate_spks;468// For every private key in the wallet, there should be a P2PK, P2PKH, P2WPKH, and P2SH-P2WPKH469const auto& add_pubkey = [&candidate_spks](const CPubKey& pub) -> void {470candidate_spks.insert(GetScriptForRawPubKey(pub));471candidate_spks.insert(GetScriptForDestination(PKHash(pub)));473CScript wpkh = GetScriptForDestination(WitnessV0KeyHash(pub));474candidate_spks.insert(wpkh);475candidate_spks.insert(GetScriptForDestination(ScriptHash(wpkh)));476};477for (const auto& [_, key] : mapKeys) {478add_pubkey(key.GetPubKey());479}480for (const auto& [_, ckeypair] : mapCryptedKeys) {481add_pubkey(ckeypair.first);482}484// mapScripts contains all redeemScripts and witnessScripts. Therefore each script in it has485// itself, P2SH, P2WSH, and P2SH-P2WSH as a candidate.486// Invalid scripts such as P2SH-P2SH and P2WSH-P2SH, among others, will be added as candidates.487// Callers of this function will need to remove such scripts.488const auto& add_script = [&candidate_spks](const CScript& script) -> void {489candidate_spks.insert(script);490candidate_spks.insert(GetScriptForDestination(ScriptHash(script)));492CScript wsh = GetScriptForDestination(WitnessV0ScriptHash(script));493candidate_spks.insert(wsh);494candidate_spks.insert(GetScriptForDestination(ScriptHash(wsh)));495};496for (const auto& [_, script] : mapScripts) {497add_script(script);498}500// Although setWatchOnly should only contain output scripts, we will also include each script's