diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp --- a/src/wallet/scriptpubkeyman.cpp +++ b/src/wallet/scriptpubkeyman.cpp @@ -2015,7 +2015,18 @@ bool DescriptorScriptPubKeyMan::SignTransaction( CMutableTransaction &tx, const std::map &coins, SigHashType sighash, std::map &input_errors) const { - return false; + std::unique_ptr keys = + std::make_unique(); + for (const auto &coin_pair : coins) { + std::unique_ptr coin_keys = + GetSigningProvider(coin_pair.second.GetTxOut().scriptPubKey, true); + if (!coin_keys) { + continue; + } + *keys = Merge(*keys, *coin_keys); + } + + return ::SignTransaction(tx, keys.get(), coins, sighash, input_errors); } SigningResult diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -2740,13 +2740,17 @@ const std::map &coins, SigHashType 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 (size_t i = 0; i < tx.vin.size(); i++) { // Get the prevout CTxIn &txin = tx.vin[i]; @@ -2759,35 +2763,10 @@ // Check if this input is complete SignatureData sigdata = DataFromTransaction(tx, i, coin->second.GetTxOut()); - if (sigdata.complete) { - continue; - } - - // Input needs to be signed, find the right ScriptPubKeyMan - std::set spk_mans = - GetScriptPubKeyMans(coin->second.GetTxOut().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()); - } } // When there are no available providers for the remaining inputs, use the