Changeset View
Changeset View
Standalone View
Standalone View
src/wallet/wallet.cpp
Show First 20 Lines • Show All 2,734 Lines • ▼ Show 20 Lines | bool CWallet::SignTransaction(CMutableTransaction &tx) const { | ||||
std::map<int, std::string> input_errors; | std::map<int, std::string> input_errors; | ||||
return SignTransaction(tx, coins, SigHashType().withForkId(), input_errors); | return SignTransaction(tx, coins, SigHashType().withForkId(), input_errors); | ||||
} | } | ||||
bool CWallet::SignTransaction(CMutableTransaction &tx, | bool CWallet::SignTransaction(CMutableTransaction &tx, | ||||
const std::map<COutPoint, Coin> &coins, | const std::map<COutPoint, Coin> &coins, | ||||
SigHashType sighash, | SigHashType sighash, | ||||
std::map<int, std::string> &input_errors) const { | 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 | for (ScriptPubKeyMan *spk_man : GetAllScriptPubKeyMans()) { | ||||
// keep track of each ScriptPubKeyMan that has signed this transaction. Each | // spk_man->SignTransaction will return true if the transaction is | ||||
// iteration, we may sign more txins than the txin that is specified in that | // complete, so we can exit early and return true if that happens | ||||
// iteration. We assume that each input is signed by only one | if (spk_man->SignTransaction(tx, coins, sighash, input_errors)) { | ||||
// ScriptPubKeyMan. | return true; | ||||
std::set<uint256> visited_spk_mans; | } | ||||
} | |||||
// 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++) { | for (size_t i = 0; i < tx.vin.size(); i++) { | ||||
// Get the prevout | // Get the prevout | ||||
CTxIn &txin = tx.vin[i]; | CTxIn &txin = tx.vin[i]; | ||||
auto coin = coins.find(txin.prevout); | auto coin = coins.find(txin.prevout); | ||||
if (coin == coins.end() || coin->second.IsSpent()) { | if (coin == coins.end() || coin->second.IsSpent()) { | ||||
input_errors[i] = "Input not found or already spent"; | input_errors[i] = "Input not found or already spent"; | ||||
continue; | continue; | ||||
} | } | ||||
// Check if this input is complete | // Check if this input is complete | ||||
SignatureData sigdata = | SignatureData sigdata = | ||||
DataFromTransaction(tx, i, coin->second.GetTxOut()); | DataFromTransaction(tx, i, coin->second.GetTxOut()); | ||||
if (sigdata.complete) { | if (!sigdata.complete) { | ||||
continue; | |||||
} | |||||
// Input needs to be signed, find the right ScriptPubKeyMan | |||||
std::set<ScriptPubKeyMan *> spk_mans = | |||||
GetScriptPubKeyMans(coin->second.GetTxOut().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()); | |||||
} | |||||
} | } | ||||
// When there are no available providers for the remaining inputs, use the | // When there are no available providers for the remaining inputs, use the | ||||
// legacy provider so we can get proper error messages. | // legacy provider so we can get proper error messages. | ||||
auto legacy_spk_man = GetLegacyScriptPubKeyMan(); | auto legacy_spk_man = GetLegacyScriptPubKeyMan(); | ||||
if (legacy_spk_man->SignTransaction(tx, coins, sighash, input_errors)) { | if (legacy_spk_man->SignTransaction(tx, coins, sighash, input_errors)) { | ||||
return true; | return true; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 2,143 Lines • Show Last 20 Lines |