Changeset View
Changeset View
Standalone View
Standalone View
src/wallet/wallet.cpp
Show First 20 Lines • Show All 2,781 Lines • ▼ Show 20 Lines | bool CWallet::SignTransaction(CMutableTransaction &tx, | ||||
return false; | return false; | ||||
} | } | ||||
TransactionError CWallet::FillPSBT(PartiallySignedTransaction &psbtx, | TransactionError CWallet::FillPSBT(PartiallySignedTransaction &psbtx, | ||||
bool &complete, SigHashType sighash_type, | bool &complete, SigHashType sighash_type, | ||||
bool sign, bool bip32derivs) const { | bool sign, bool bip32derivs) const { | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
// Get all of the previous transactions | // Get all of the previous transactions | ||||
complete = true; | |||||
for (size_t i = 0; i < psbtx.tx->vin.size(); ++i) { | for (size_t i = 0; i < psbtx.tx->vin.size(); ++i) { | ||||
const CTxIn &txin = psbtx.tx->vin[i]; | const CTxIn &txin = psbtx.tx->vin[i]; | ||||
PSBTInput &input = psbtx.inputs.at(i); | PSBTInput &input = psbtx.inputs.at(i); | ||||
if (PSBTInputSigned(input)) { | if (PSBTInputSigned(input)) { | ||||
continue; | continue; | ||||
} | } | ||||
// Verify input looks sane. | // Verify input looks sane. | ||||
if (!input.IsSane()) { | if (!input.IsSane()) { | ||||
return TransactionError::INVALID_PSBT; | return TransactionError::INVALID_PSBT; | ||||
} | } | ||||
// If we have no utxo, grab it from the wallet. | // If we have no utxo, grab it from the wallet. | ||||
if (input.utxo.IsNull()) { | if (input.utxo.IsNull()) { | ||||
const TxId &txid = txin.prevout.GetTxId(); | const TxId &txid = txin.prevout.GetTxId(); | ||||
const auto it = mapWallet.find(txid); | const auto it = mapWallet.find(txid); | ||||
if (it != mapWallet.end()) { | if (it != mapWallet.end()) { | ||||
const CWalletTx &wtx = it->second; | const CWalletTx &wtx = it->second; | ||||
CTxOut utxo = wtx.tx->vout[txin.prevout.GetN()]; | CTxOut utxo = wtx.tx->vout[txin.prevout.GetN()]; | ||||
// Update UTXOs from the wallet. | // Update UTXOs from the wallet. | ||||
input.utxo = utxo; | input.utxo = utxo; | ||||
} | } | ||||
} | } | ||||
} | |||||
// Get the Sighash type | // Fill in information from ScriptPubKeyMans | ||||
if (sign && input.sighash_type.getRawSigHashType() > 0 && | // Because each ScriptPubKeyMan may be able to fill more than one input, we | ||||
input.sighash_type != sighash_type) { | // need to keep track of each ScriptPubKeyMan that has filled this psbt. | ||||
return TransactionError::SIGHASH_MISMATCH; | // Each iteration, we may fill more inputs than the input that is specified | ||||
// in that iteration. We assume that each input is filled by only one | |||||
// ScriptPubKeyMan | |||||
std::set<uint256> visited_spk_mans; | |||||
for (size_t i = 0; i < psbtx.tx->vin.size(); ++i) { | |||||
PSBTInput &input = psbtx.inputs.at(i); | |||||
if (PSBTInputSigned(input)) { | |||||
continue; | |||||
} | } | ||||
// Get the scriptPubKey to know which SigningProvider to use | // Get the scriptPubKey to know which ScriptPubKeyMan to use | ||||
CScript script; | CScript script; | ||||
if (!input.utxo.IsNull()) { | if (!input.utxo.IsNull()) { | ||||
script = input.utxo.scriptPubKey; | script = input.utxo.scriptPubKey; | ||||
} else { | } else { | ||||
// There's no UTXO so we can just skip this now | // There's no UTXO so we can just skip this now | ||||
complete = false; | |||||
continue; | continue; | ||||
} | } | ||||
SignatureData sigdata; | SignatureData sigdata; | ||||
input.FillSignatureData(sigdata); | input.FillSignatureData(sigdata); | ||||
std::unique_ptr<SigningProvider> provider = | std::set<ScriptPubKeyMan *> spk_mans = | ||||
GetSigningProvider(script, sigdata); | GetScriptPubKeyMans(script, sigdata); | ||||
if (!provider) { | if (spk_mans.size() == 0) { | ||||
complete = false; | |||||
continue; | continue; | ||||
} | } | ||||
complete &= SignPSBTInput( | for (auto &spk_man : spk_mans) { | ||||
HidingSigningProvider(provider.get(), !sign, !bip32derivs), psbtx, | // If we've already been signed by this spk_man, skip it | ||||
i, sighash_type); | if (visited_spk_mans.count(spk_man->GetID()) > 0) { | ||||
continue; | |||||
} | } | ||||
// Fill in the bip32 keypaths and redeemscripts for the outputs so that | // Fill in the information from the spk_man | ||||
// hardware wallets can identify change | TransactionError res = | ||||
for (size_t i = 0; i < psbtx.tx->vout.size(); ++i) { | spk_man->FillPSBT(psbtx, sighash_type, sign, bip32derivs); | ||||
const CTxOut &out = psbtx.tx->vout.at(i); | if (res != TransactionError::OK) { | ||||
std::unique_ptr<SigningProvider> provider = | return res; | ||||
GetSigningProvider(out.scriptPubKey); | } | ||||
if (provider) { | |||||
UpdatePSBTOutput( | // Add this spk_man to visited_spk_mans so we can skip it later | ||||
HidingSigningProvider(provider.get(), true, !bip32derivs), | visited_spk_mans.insert(spk_man->GetID()); | ||||
psbtx, i); | |||||
} | } | ||||
} | } | ||||
// Complete if every input is now signed | |||||
complete = true; | |||||
for (const auto &input : psbtx.inputs) { | |||||
complete &= PSBTInputSigned(input); | |||||
} | |||||
return TransactionError::OK; | return TransactionError::OK; | ||||
} | } | ||||
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) { | ||||
▲ Show 20 Lines • Show All 2,021 Lines • Show Last 20 Lines |