/
githubmirror
/
bitcoin
Обзор
Документация
Войти
/
githubmirror
/
bitcoin
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/wallet/external_signer_scriptpubkeyman.cpp
116 строк
5 KB
merge-script
Merge bitcoin/bitcoin#28333: wallet: Construct ScriptPubKeyMans with all data rather than loaded progressively
28 май 2026, 22:49
Не верифицирован
28 май 2026, 22:49
c6f225c
Код
Авторство
О чём код?
// Copyright (c) 2020-present The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <chainparams.h> #include <common/args.h> #include <common/system.h> #include <external_signer.h> #include <node/types.h> #include <wallet/external_signer_scriptpubkeyman.h> #include <iostream> #include <key_io.h> #include <memory> #include <stdexcept> #include <string> #include <univalue.h> #include <utility> #include <vector> using common::PSBTError; namespace wallet { std::unique_ptr<ExternalSignerScriptPubKeyMan> ExternalSignerScriptPubKeyMan::LoadFromStorage(WalletStorage& storage, WalletDescriptor& descriptor, int64_t keypool_size, const KeyMap& keys, const CryptedKeyMap& ckeys) { return std::unique_ptr<ExternalSignerScriptPubKeyMan>(new ExternalSignerScriptPubKeyMan(storage, descriptor, keypool_size, keys, ckeys)); } std::unique_ptr<ExternalSignerScriptPubKeyMan> ExternalSignerScriptPubKeyMan::CreateNew(WalletStorage& storage, WalletBatch& batch, int64_t keypool_size, std::unique_ptr<Descriptor> desc) { auto spkm = std::unique_ptr<ExternalSignerScriptPubKeyMan>(new ExternalSignerScriptPubKeyMan(storage, keypool_size)); LOCK(spkm->cs_desc_man); assert(storage.IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)); assert(storage.IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER)); int64_t creation_time = GetTime(); // Make the descriptor WalletDescriptor w_desc(std::move(desc), creation_time, 0, 0, 0); spkm->m_wallet_descriptor = w_desc; // Store the descriptor if (!batch.WriteDescriptor(spkm->GetID(), spkm->m_wallet_descriptor)) { throw std::runtime_error(std::string(__func__) + ": writing descriptor failed"); } // TopUp spkm->TopUpWithDB(batch); storage.UnsetBlankWalletFlag(batch); return spkm; } util::Result<ExternalSigner> ExternalSignerScriptPubKeyMan::GetExternalSigner() { const std::string command = gArgs.GetArg("-signer", ""); if (command == "") return util::Error{Untranslated("restart bitcoind with -signer=<cmd>")}; std::vector<ExternalSigner> signers; ExternalSigner::Enumerate(command, signers, Params().GetChainTypeString()); if (signers.empty()) return util::Error{Untranslated("No external signers found")}; // TODO: add fingerprint argument instead of failing in case of multiple signers. if (signers.size() > 1) return util::Error{Untranslated("More than one external signer found. Please connect only one at a time.")}; return signers[0]; } util::Result<void> ExternalSignerScriptPubKeyMan::DisplayAddress(const CTxDestination& dest, const ExternalSigner &signer) const { // TODO: avoid the need to infer a descriptor from inside a descriptor wallet const CScript& scriptPubKey = GetScriptForDestination(dest); auto provider = GetSolvingProvider(scriptPubKey); auto descriptor = InferDescriptor(scriptPubKey, *provider); const UniValue& result = signer.DisplayAddress(descriptor->ToString()); const UniValue& error = result.find_value("error"); if (error.isStr()) return util::Error{strprintf(_("Signer returned error: %s"), error.getValStr())}; const UniValue& ret_address = result.find_value("address"); if (!ret_address.isStr()) return util::Error{_("Signer did not echo address")}; if (ret_address.getValStr() != EncodeDestination(dest)) { return util::Error{strprintf(_("Signer echoed unexpected address %s"), ret_address.getValStr())}; } return util::Result<void>(); } // If sign is true, transaction must previously have been filled std::optional<PSBTError> ExternalSignerScriptPubKeyMan::FillPSBT(PartiallySignedTransaction& psbt, const PrecomputedTransactionData& txdata, const common::PSBTFillOptions& options, int* n_signed) const { if (!options.sign) { return DescriptorScriptPubKeyMan::FillPSBT(psbt, txdata, options, n_signed); } // Already complete if every input is now signed bool complete = true; for (const auto& input : psbt.inputs) { complete &= PSBTInputSigned(input); } if (complete) return {}; auto signer{GetExternalSigner()}; if (!signer) { LogWarning("%s", util::ErrorString(signer).original); return PSBTError::EXTERNAL_SIGNER_NOT_FOUND; } std::string failure_reason; if(!signer->SignTransaction(psbt, failure_reason)) { LogWarning("Failed to sign: %s\n", failure_reason); return PSBTError::EXTERNAL_SIGNER_FAILED; } if (options.finalize) FinalizePSBT(psbt); // This won't work in a multisig setup return {}; } } // namespace wallet