Implement SignTransaction in DescriptorScriptPubKeyMan

pull/16528/head
Andrew Chow 5 years ago
parent d50c8ddd41
commit bde7c9fa38

@ -1943,7 +1943,16 @@ bool DescriptorScriptPubKeyMan::CanProvide(const CScript& script, SignatureData&
bool DescriptorScriptPubKeyMan::SignTransaction(CMutableTransaction& tx, const std::map<COutPoint, Coin>& coins, int sighash, std::map<int, std::string>& input_errors) const bool DescriptorScriptPubKeyMan::SignTransaction(CMutableTransaction& tx, const std::map<COutPoint, Coin>& coins, int sighash, std::map<int, std::string>& input_errors) const
{ {
return false; std::unique_ptr<FlatSigningProvider> keys = MakeUnique<FlatSigningProvider>();
for (const auto& coin_pair : coins) {
std::unique_ptr<FlatSigningProvider> 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 SigningResult DescriptorScriptPubKeyMan::SignMessage(const std::string& message, const PKHash& pkhash, std::string& str_sig) const

@ -2428,11 +2428,17 @@ bool CWallet::SignTransaction(CMutableTransaction& tx) const
bool CWallet::SignTransaction(CMutableTransaction& tx, const std::map<COutPoint, Coin>& coins, int sighash, std::map<int, std::string>& input_errors) const bool CWallet::SignTransaction(CMutableTransaction& tx, const std::map<COutPoint, Coin>& coins, int sighash, std::map<int, std::string>& input_errors) const
{ {
// Sign the tx with ScriptPubKeyMans // Try to sign with all ScriptPubKeyMans
// Because each ScriptPubKeyMan can sign more than one input, we need to keep track of each ScriptPubKeyMan that has signed this transaction. for (ScriptPubKeyMan* spk_man : GetAllScriptPubKeyMans()) {
// Each iteration, we may sign more txins than the txin that is specified in that iteration. // spk_man->SignTransaction will return true if the transaction is complete,
// We assume that each input is signed by only one ScriptPubKeyMan. // so we can exit early and return true if that happens
std::set<uint256> visited_spk_mans; 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++) { for (unsigned int i = 0; i < tx.vin.size(); i++) {
// Get the prevout // Get the prevout
CTxIn& txin = tx.vin[i]; CTxIn& txin = tx.vin[i];
@ -2444,33 +2450,10 @@ bool CWallet::SignTransaction(CMutableTransaction& tx, const std::map<COutPoint,
// Check if this input is complete // Check if this input is complete
SignatureData sigdata = DataFromTransaction(tx, i, coin->second.out); SignatureData sigdata = DataFromTransaction(tx, i, coin->second.out);
if (sigdata.complete) { if (!sigdata.complete) {
continue;
}
// Input needs to be signed, find the right ScriptPubKeyMan
std::set<ScriptPubKeyMan*> spk_mans = GetScriptPubKeyMans(coin->second.out.scriptPubKey, sigdata);
if (spk_mans.size() == 0) {
input_errors[i] = "Unable to sign input, missing keys"; input_errors[i] = "Unable to sign input, missing keys";
continue; 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; return false;
} }

Loading…
Cancel
Save