Changeset View
Changeset View
Standalone View
Standalone View
src/wallet/wallet.cpp
Show First 20 Lines • Show All 1,613 Lines • ▼ Show 20 Lines | if (IsCoinBase()) { | ||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } | ||||
return nRequests; | return nRequests; | ||||
} | } | ||||
// Helper for producing a max-sized low-S signature (eg 72 bytes) | |||||
bool CWallet::DummySignInput(CTxIn &tx_in, const CTxOut &txout) const { | |||||
// Fill in dummy signatures for fee calculation. | |||||
const CScript &scriptPubKey = txout.scriptPubKey; | |||||
SignatureData sigdata; | |||||
if (!ProduceSignature(DummySignatureCreator(this), scriptPubKey, sigdata)) { | |||||
return false; | |||||
} | |||||
UpdateInput(tx_in, sigdata); | |||||
return true; | |||||
} | |||||
// Helper for producing a bunch of max-sized low-S signatures (eg 72 bytes) | |||||
bool CWallet::DummySignTx(CMutableTransaction &txNew, | |||||
const std::vector<CTxOut> &txouts) const { | |||||
// Fill in dummy signatures for fee calculation. | |||||
int nIn = 0; | |||||
for (const auto &txout : txouts) { | |||||
if (!DummySignInput(txNew.vin[nIn], txout)) { | |||||
return false; | |||||
} | |||||
nIn++; | |||||
} | |||||
return true; | |||||
} | |||||
int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, | |||||
const CWallet *wallet) { | |||||
std::vector<CTxOut> txouts; | |||||
// Look up the inputs. We should have already checked that this transaction | |||||
// IsAllFromMe(ISMINE_SPENDABLE), so every input should already be in our | |||||
// wallet, with a valid index into the vout array, and the ability to sign. | |||||
for (auto &input : tx.vin) { | |||||
const auto mi = wallet->mapWallet.find(input.prevout.GetTxId()); | |||||
if (mi == wallet->mapWallet.end()) { | |||||
return -1; | |||||
} | |||||
assert(input.prevout.GetN() < mi->second.tx->vout.size()); | |||||
txouts.emplace_back(mi->second.tx->vout[input.prevout.GetN()]); | |||||
} | |||||
return CalculateMaximumSignedTxSize(tx, wallet, txouts); | |||||
} | |||||
// txouts needs to be in the order of tx.vin | |||||
int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, | |||||
const CWallet *wallet, | |||||
const std::vector<CTxOut> &txouts) { | |||||
CMutableTransaction txNew(tx); | |||||
if (!wallet->DummySignTx(txNew, txouts)) { | |||||
// This should never happen, because IsAllFromMe(ISMINE_SPENDABLE) | |||||
// implies that we can sign for every input. | |||||
return -1; | |||||
} | |||||
return GetVirtualTransactionSize(CTransaction(txNew)); | |||||
} | |||||
int CalculateMaximumSignedInputSize(const CTxOut &txout, | |||||
const CWallet *wallet) { | |||||
CMutableTransaction txn; | |||||
txn.vin.push_back(CTxIn(COutPoint())); | |||||
if (!wallet->DummySignInput(txn.vin[0], txout)) { | |||||
// This should never happen, because IsAllFromMe(ISMINE_SPENDABLE) | |||||
// implies that we can sign for every input. | |||||
return -1; | |||||
} | |||||
return GetVirtualTransactionInputSize(txn.vin[0]); | |||||
} | |||||
void CWalletTx::GetAmounts(std::list<COutputEntry> &listReceived, | void CWalletTx::GetAmounts(std::list<COutputEntry> &listReceived, | ||||
std::list<COutputEntry> &listSent, Amount &nFee, | std::list<COutputEntry> &listSent, Amount &nFee, | ||||
std::string &strSentAccount, | std::string &strSentAccount, | ||||
const isminefilter &filter) const { | const isminefilter &filter) const { | ||||
nFee = Amount::zero(); | nFee = Amount::zero(); | ||||
listReceived.clear(); | listReceived.clear(); | ||||
listSent.clear(); | listSent.clear(); | ||||
strSentAccount = strFromAccount; | strSentAccount = strFromAccount; | ||||
▲ Show 20 Lines • Show All 1,447 Lines • ▼ Show 20 Lines | assert(txNew.nLockTime < LOCKTIME_THRESHOLD); | ||||
// Note how the sequence number is set to non-maxint so that the | // Note how the sequence number is set to non-maxint so that the | ||||
// nLockTime set above actually works. | // nLockTime set above actually works. | ||||
for (const auto &coin : setCoins) { | for (const auto &coin : setCoins) { | ||||
txNew.vin.push_back( | txNew.vin.push_back( | ||||
CTxIn(coin.outpoint, CScript(), | CTxIn(coin.outpoint, CScript(), | ||||
std::numeric_limits<uint32_t>::max() - 1)); | std::numeric_limits<uint32_t>::max() - 1)); | ||||
} | } | ||||
// Fill in dummy signatures for fee calculation. | CTransaction txNewConst(txNew); | ||||
if (!DummySignTx(txNew, setCoins)) { | int nBytes = CalculateMaximumSignedTxSize(txNewConst, this); | ||||
if (nBytes < 0) { | |||||
strFailReason = _("Signing transaction failed"); | strFailReason = _("Signing transaction failed"); | ||||
return false; | return false; | ||||
} | } | ||||
CTransaction txNewConst(txNew); | |||||
unsigned int nBytes = txNewConst.GetTotalSize(); | |||||
// Remove scriptSigs to eliminate the fee calculation dummy | |||||
// signatures. | |||||
for (auto &vin : txNew.vin) { | |||||
vin.scriptSig = CScript(); | |||||
} | |||||
Amount nFeeNeeded = GetMinimumFee(nBytes, coinControl, g_mempool); | Amount nFeeNeeded = GetMinimumFee(nBytes, coinControl, g_mempool); | ||||
// If we made it here and we aren't even able to meet the relay fee | // If we made it here and we aren't even able to meet the relay fee | ||||
// on the next pass, give up because we must be at the maximum | // on the next pass, give up because we must be at the maximum | ||||
// allowed fee. | // allowed fee. | ||||
Amount minFee = GetConfig().GetMinFeePerKB().GetFeeCeiling(nBytes); | Amount minFee = GetConfig().GetMinFeePerKB().GetFeeCeiling(nBytes); | ||||
if (nFeeNeeded < minFee) { | if (nFeeNeeded < minFee) { | ||||
strFailReason = _("Transaction too large for fee policy"); | strFailReason = _("Transaction too large for fee policy"); | ||||
▲ Show 20 Lines • Show All 1,444 Lines • Show Last 20 Lines |