diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp index 67063ad23c3..1eb9dc4d7a2 100644 --- a/src/wallet/scriptpubkeyman.cpp +++ b/src/wallet/scriptpubkeyman.cpp @@ -1943,7 +1943,16 @@ bool DescriptorScriptPubKeyMan::CanProvide(const CScript& script, SignatureData& bool DescriptorScriptPubKeyMan::SignTransaction(CMutableTransaction& tx, const std::map& coins, int sighash, std::map& input_errors) const { - return false; + std::unique_ptr keys = MakeUnique(); + for (const auto& coin_pair : coins) { + std::unique_ptr coin_keys = GetSigningProvider(coin_pair.second.out.scriptPubKey, true); + if (!coin_keys) { + continue; + } + *keys = Merge(*keys, *coin_keys); + } + + return ::SignTransaction(tx, keys.get(), coins, sighash, input_errors); } SigningResult DescriptorScriptPubKeyMan::SignMessage(const std::string& message, const PKHash& pkhash, std::string& str_sig) const diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 8f42d1d75f5..062162bdf79 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -2428,11 +2428,17 @@ bool CWallet::SignTransaction(CMutableTransaction& tx) const bool CWallet::SignTransaction(CMutableTransaction& tx, const std::map& coins, int sighash, std::map& input_errors) const { - // Sign the tx with ScriptPubKeyMans - // Because each ScriptPubKeyMan can sign more than one input, we need to keep track of each ScriptPubKeyMan that has signed this transaction. - // Each iteration, we may sign more txins than the txin that is specified in that iteration. - // We assume that each input is signed by only one ScriptPubKeyMan. - std::set visited_spk_mans; + // Try to sign with all ScriptPubKeyMans + for (ScriptPubKeyMan* spk_man : GetAllScriptPubKeyMans()) { + // spk_man->SignTransaction will return true if the transaction is complete, + // so we can exit early and return true if that happens + if (spk_man->SignTransaction(tx, coins, sighash, input_errors)) { + return true; + } + } + + // At this point, one input was not fully signed otherwise we would have exited already + // Find that input and figure out what went wrong. for (unsigned int i = 0; i < tx.vin.size(); i++) { // Get the prevout CTxIn& txin = tx.vin[i]; @@ -2444,33 +2450,10 @@ bool CWallet::SignTransaction(CMutableTransaction& tx, const std::mapsecond.out); - if (sigdata.complete) { - continue; - } - - // Input needs to be signed, find the right ScriptPubKeyMan - std::set spk_mans = GetScriptPubKeyMans(coin->second.out.scriptPubKey, sigdata); - if (spk_mans.size() == 0) { + if (!sigdata.complete) { input_errors[i] = "Unable to sign input, missing keys"; continue; } - - for (auto& spk_man : spk_mans) { - // If we've already been signed by this spk_man, skip it - if (visited_spk_mans.count(spk_man->GetID()) > 0) { - continue; - } - - // Sign the tx. - // spk_man->SignTransaction will return true if the transaction is complete, - // so we can exit early and return true if that happens. - if (spk_man->SignTransaction(tx, coins, sighash, input_errors)) { - return true; - } - - // Add this spk_man to visited_spk_mans so we can skip it later - visited_spk_mans.insert(spk_man->GetID()); - } } return false; }