Changeset View
Changeset View
Standalone View
Standalone View
src/wallet/wallet.cpp
Show First 20 Lines • Show All 2,701 Lines • ▼ Show 20 Lines | bool CWallet::SelectCoins(const std::vector<COutput> &vAvailableCoins, | ||||
util::insert(setCoinsRet, setPresetCoins); | util::insert(setCoinsRet, setPresetCoins); | ||||
// Add preset inputs to the total value selected. | // Add preset inputs to the total value selected. | ||||
nValueRet += nValueFromPresetInputs; | nValueRet += nValueFromPresetInputs; | ||||
return res; | return res; | ||||
} | } | ||||
bool CWallet::SignTransaction(CMutableTransaction &tx) { | bool CWallet::SignTransaction(CMutableTransaction &tx) const { | ||||
AssertLockHeld(cs_wallet); | AssertLockHeld(cs_wallet); | ||||
// sign the new tx | |||||
int nIn = 0; | // Build coins map | ||||
for (CTxIn &input : tx.vin) { | std::map<COutPoint, Coin> coins; | ||||
for (auto &input : tx.vin) { | |||||
auto mi = mapWallet.find(input.prevout.GetTxId()); | auto mi = mapWallet.find(input.prevout.GetTxId()); | ||||
if (mi == mapWallet.end() || | if (mi == mapWallet.end() || | ||||
input.prevout.GetN() >= mi->second.tx->vout.size()) { | input.prevout.GetN() >= mi->second.tx->vout.size()) { | ||||
return false; | return false; | ||||
} | } | ||||
const CScript &scriptPubKey = | const CWalletTx &wtx = mi->second; | ||||
mi->second.tx->vout[input.prevout.GetN()].scriptPubKey; | coins[input.prevout] = | ||||
const Amount amount = mi->second.tx->vout[input.prevout.GetN()].nValue; | Coin(wtx.tx->vout[input.prevout.GetN()], wtx.m_confirm.block_height, | ||||
SignatureData sigdata; | wtx.IsCoinBase()); | ||||
SigHashType sigHashType = SigHashType().withForkId(); | } | ||||
std::map<int, std::string> input_errors; | |||||
return SignTransaction(tx, coins, SigHashType().withForkId(), input_errors); | |||||
} | |||||
bool CWallet::SignTransaction(CMutableTransaction &tx, | |||||
const std::map<COutPoint, Coin> &coins, | |||||
SigHashType sighash, | |||||
std::map<int, std::string> &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<uint256> visited_spk_mans; | |||||
for (size_t i = 0; i < tx.vin.size(); i++) { | |||||
// Get the prevout | |||||
CTxIn &txin = tx.vin[i]; | |||||
auto coin = coins.find(txin.prevout); | |||||
if (coin == coins.end() || coin->second.IsSpent()) { | |||||
input_errors[i] = "Input not found or already spent"; | |||||
continue; | |||||
} | |||||
std::unique_ptr<SigningProvider> provider = | // Check if this input is complete | ||||
GetSigningProvider(scriptPubKey); | SignatureData sigdata = | ||||
if (!provider) { | DataFromTransaction(tx, i, coin->second.GetTxOut()); | ||||
// We don't know about this scriptpbuKey; | if (sigdata.complete) { | ||||
return false; | continue; | ||||
} | } | ||||
if (!ProduceSignature(*provider, | // Input needs to be signed, find the right ScriptPubKeyMan | ||||
MutableTransactionSignatureCreator( | std::set<ScriptPubKeyMan *> spk_mans = | ||||
&tx, nIn, amount, sigHashType), | GetScriptPubKeyMans(coin->second.GetTxOut().scriptPubKey, sigdata); | ||||
scriptPubKey, sigdata)) { | if (spk_mans.size() == 0) { | ||||
return false; | input_errors[i] = "Unable to sign input, missing keys"; | ||||
continue; | |||||
} | } | ||||
UpdateInput(input, sigdata); | |||||
nIn++; | 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; | 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; | |||||
} | |||||
bool CWallet::FundTransaction(CMutableTransaction &tx, Amount &nFeeRet, | bool CWallet::FundTransaction(CMutableTransaction &tx, Amount &nFeeRet, | ||||
int &nChangePosInOut, bilingual_str &error, | int &nChangePosInOut, bilingual_str &error, | ||||
bool lockUnspents, | bool lockUnspents, | ||||
const std::set<int> &setSubtractFeeFromOutputs, | const std::set<int> &setSubtractFeeFromOutputs, | ||||
CCoinControl coinControl) { | CCoinControl coinControl) { | ||||
std::vector<CRecipient> vecSend; | std::vector<CRecipient> vecSend; | ||||
// Turn the txout set into a CRecipient vector. | // Turn the txout set into a CRecipient vector. | ||||
▲ Show 20 Lines • Show All 1,918 Lines • ▼ Show 20 Lines | if (it == spk_managers.end()) { | ||||
WalletLogPrintf( | WalletLogPrintf( | ||||
"%s scriptPubKey Manager for output type %d does not exist\n", | "%s scriptPubKey Manager for output type %d does not exist\n", | ||||
internal ? "Internal" : "External", static_cast<int>(type)); | internal ? "Internal" : "External", static_cast<int>(type)); | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
return it->second; | return it->second; | ||||
} | } | ||||
std::set<ScriptPubKeyMan *> | |||||
CWallet::GetScriptPubKeyMans(const CScript &script, | |||||
SignatureData &sigdata) const { | |||||
std::set<ScriptPubKeyMan *> spk_mans; | |||||
for (const auto &spk_man_pair : m_spk_managers) { | |||||
if (spk_man_pair.second->CanProvide(script, sigdata)) { | |||||
spk_mans.insert(spk_man_pair.second.get()); | |||||
} | |||||
} | |||||
return spk_mans; | |||||
} | |||||
ScriptPubKeyMan *CWallet::GetScriptPubKeyMan(const CScript &script) const { | ScriptPubKeyMan *CWallet::GetScriptPubKeyMan(const CScript &script) const { | ||||
SignatureData sigdata; | SignatureData sigdata; | ||||
for (const auto &spk_man_pair : m_spk_managers) { | for (const auto &spk_man_pair : m_spk_managers) { | ||||
if (spk_man_pair.second->CanProvide(script, sigdata)) { | if (spk_man_pair.second->CanProvide(script, sigdata)) { | ||||
return spk_man_pair.second.get(); | return spk_man_pair.second.get(); | ||||
} | } | ||||
} | } | ||||
return nullptr; | return nullptr; | ||||
▲ Show 20 Lines • Show All 72 Lines • Show Last 20 Lines |