|
|
|
@ -1509,7 +1509,7 @@ void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const
@@ -1509,7 +1509,7 @@ void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const
|
|
|
|
|
isminetype mine = IsMine(pcoin->vout[i]); |
|
|
|
|
if (!(IsSpent(wtxid, i)) && mine != ISMINE_NO && |
|
|
|
|
!IsLockedCoin((*it).first, i) && (pcoin->vout[i].nValue > 0 || fIncludeZeroValue) && |
|
|
|
|
(!coinControl || !coinControl->HasSelected() || coinControl->IsSelected((*it).first, i))) |
|
|
|
|
(!coinControl || !coinControl->HasSelected() || coinControl->fAllowOtherInputs || coinControl->IsSelected((*it).first, i))) |
|
|
|
|
vCoins.push_back(COutput(pcoin, i, nDepth, (mine & ISMINE_SPENDABLE) != ISMINE_NO)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -1669,25 +1669,108 @@ bool CWallet::SelectCoins(const CAmount& nTargetValue, set<pair<const CWalletTx*
@@ -1669,25 +1669,108 @@ bool CWallet::SelectCoins(const CAmount& nTargetValue, set<pair<const CWalletTx*
|
|
|
|
|
AvailableCoins(vCoins, true, coinControl); |
|
|
|
|
|
|
|
|
|
// coin control -> return all selected outputs (we want all selected to go into the transaction for sure)
|
|
|
|
|
if (coinControl && coinControl->HasSelected()) |
|
|
|
|
if (coinControl && coinControl->HasSelected() && !coinControl->fAllowOtherInputs) |
|
|
|
|
{ |
|
|
|
|
BOOST_FOREACH(const COutput& out, vCoins) |
|
|
|
|
{ |
|
|
|
|
if(!out.fSpendable) |
|
|
|
|
continue; |
|
|
|
|
if (!out.fSpendable) |
|
|
|
|
continue; |
|
|
|
|
nValueRet += out.tx->vout[out.i].nValue; |
|
|
|
|
setCoinsRet.insert(make_pair(out.tx, out.i)); |
|
|
|
|
} |
|
|
|
|
return (nValueRet >= nTargetValue); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return (SelectCoinsMinConf(nTargetValue, 1, 6, vCoins, setCoinsRet, nValueRet) || |
|
|
|
|
SelectCoinsMinConf(nTargetValue, 1, 1, vCoins, setCoinsRet, nValueRet) || |
|
|
|
|
(bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue, 0, 1, vCoins, setCoinsRet, nValueRet))); |
|
|
|
|
// calculate value from preset inputs and store them
|
|
|
|
|
set<pair<const CWalletTx*, uint32_t> > setPresetCoins; |
|
|
|
|
CAmount nValueFromPresetInputs = 0; |
|
|
|
|
|
|
|
|
|
std::vector<COutPoint> vPresetInputs; |
|
|
|
|
if (coinControl) |
|
|
|
|
coinControl->ListSelected(vPresetInputs); |
|
|
|
|
BOOST_FOREACH(const COutPoint& outpoint, vPresetInputs) |
|
|
|
|
{ |
|
|
|
|
map<uint256, CWalletTx>::const_iterator it = mapWallet.find(outpoint.hash); |
|
|
|
|
if (it != mapWallet.end()) |
|
|
|
|
{ |
|
|
|
|
const CWalletTx* pcoin = &it->second; |
|
|
|
|
// Clearly invalid input, fail
|
|
|
|
|
if (pcoin->vout.size() <= outpoint.n) |
|
|
|
|
return false; |
|
|
|
|
nValueFromPresetInputs += pcoin->vout[outpoint.n].nValue; |
|
|
|
|
setPresetCoins.insert(make_pair(pcoin, outpoint.n)); |
|
|
|
|
} else |
|
|
|
|
return false; // TODO: Allow non-wallet inputs
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// remove preset inputs from vCoins
|
|
|
|
|
for (vector<COutput>::iterator it = vCoins.begin(); it != vCoins.end() && coinControl && coinControl->HasSelected();) |
|
|
|
|
{ |
|
|
|
|
if (setPresetCoins.count(make_pair(it->tx, it->i))) |
|
|
|
|
it = vCoins.erase(it); |
|
|
|
|
else |
|
|
|
|
++it; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool res = nTargetValue <= nValueFromPresetInputs || |
|
|
|
|
SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 1, 6, vCoins, setCoinsRet, nValueRet) || |
|
|
|
|
SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 1, 1, vCoins, setCoinsRet, nValueRet) || |
|
|
|
|
(bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, vCoins, setCoinsRet, nValueRet)); |
|
|
|
|
|
|
|
|
|
// because SelectCoinsMinConf clears the setCoinsRet, we now add the possible inputs to the coinset
|
|
|
|
|
setCoinsRet.insert(setPresetCoins.begin(), setPresetCoins.end()); |
|
|
|
|
|
|
|
|
|
// add preset inputs to the total value selected
|
|
|
|
|
nValueRet += nValueFromPresetInputs; |
|
|
|
|
|
|
|
|
|
return res; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, |
|
|
|
|
CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, int& nChangePosRet, std::string& strFailReason, const CCoinControl* coinControl) |
|
|
|
|
bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount &nFeeRet, int& nChangePosRet, std::string& strFailReason) |
|
|
|
|
{ |
|
|
|
|
vector<CRecipient> vecSend; |
|
|
|
|
|
|
|
|
|
// Turn the txout set into a CRecipient vector
|
|
|
|
|
BOOST_FOREACH(const CTxOut& txOut, tx.vout) |
|
|
|
|
{ |
|
|
|
|
CRecipient recipient = {txOut.scriptPubKey, txOut.nValue, false}; |
|
|
|
|
vecSend.push_back(recipient); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
CCoinControl coinControl; |
|
|
|
|
coinControl.fAllowOtherInputs = true; |
|
|
|
|
BOOST_FOREACH(const CTxIn& txin, tx.vin) |
|
|
|
|
coinControl.Select(txin.prevout); |
|
|
|
|
|
|
|
|
|
CReserveKey reservekey(this); |
|
|
|
|
CWalletTx wtx; |
|
|
|
|
if (!CreateTransaction(vecSend, wtx, reservekey, nFeeRet, nChangePosRet, strFailReason, &coinControl, false)) |
|
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
if (nChangePosRet != -1) |
|
|
|
|
tx.vout.insert(tx.vout.begin() + nChangePosRet, wtx.vout[nChangePosRet]); |
|
|
|
|
|
|
|
|
|
// Add new txins (keeping original txin scriptSig/order)
|
|
|
|
|
BOOST_FOREACH(const CTxIn& txin, wtx.vin) |
|
|
|
|
{ |
|
|
|
|
bool found = false; |
|
|
|
|
BOOST_FOREACH(const CTxIn& origTxIn, tx.vin) |
|
|
|
|
{ |
|
|
|
|
if (txin.prevout.hash == origTxIn.prevout.hash && txin.prevout.n == origTxIn.prevout.n) |
|
|
|
|
{ |
|
|
|
|
found = true; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (!found) |
|
|
|
|
tx.vin.push_back(txin); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, |
|
|
|
|
int& nChangePosRet, std::string& strFailReason, const CCoinControl* coinControl, bool sign) |
|
|
|
|
{ |
|
|
|
|
CAmount nValue = 0; |
|
|
|
|
unsigned int nSubtractFeeFromAmount = 0; |
|
|
|
@ -1890,23 +1973,43 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend,
@@ -1890,23 +1973,43 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend,
|
|
|
|
|
|
|
|
|
|
// Sign
|
|
|
|
|
int nIn = 0; |
|
|
|
|
CTransaction txNewConst(txNew); |
|
|
|
|
BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins) |
|
|
|
|
if (!SignSignature(*this, *coin.first, txNew, nIn++)) |
|
|
|
|
{ |
|
|
|
|
bool signSuccess; |
|
|
|
|
const CScript& scriptPubKey = coin.first->vout[coin.second].scriptPubKey; |
|
|
|
|
CScript& scriptSigRes = txNew.vin[nIn].scriptSig; |
|
|
|
|
if (sign) |
|
|
|
|
signSuccess = ProduceSignature(TransactionSignatureCreator(this, &txNewConst, nIn, SIGHASH_ALL), scriptPubKey, scriptSigRes); |
|
|
|
|
else |
|
|
|
|
signSuccess = ProduceSignature(DummySignatureCreator(this), scriptPubKey, scriptSigRes); |
|
|
|
|
|
|
|
|
|
if (!signSuccess) |
|
|
|
|
{ |
|
|
|
|
strFailReason = _("Signing transaction failed"); |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
nIn++; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
unsigned int nBytes = ::GetSerializeSize(txNew, SER_NETWORK, PROTOCOL_VERSION); |
|
|
|
|
|
|
|
|
|
// Remove scriptSigs if we used dummy signatures for fee calculation
|
|
|
|
|
if (!sign) { |
|
|
|
|
BOOST_FOREACH (CTxIn& vin, txNew.vin) |
|
|
|
|
vin.scriptSig = CScript(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Embed the constructed transaction data in wtxNew.
|
|
|
|
|
*static_cast<CTransaction*>(&wtxNew) = CTransaction(txNew); |
|
|
|
|
|
|
|
|
|
// Limit size
|
|
|
|
|
unsigned int nBytes = ::GetSerializeSize(*(CTransaction*)&wtxNew, SER_NETWORK, PROTOCOL_VERSION); |
|
|
|
|
if (nBytes >= MAX_STANDARD_TX_SIZE) |
|
|
|
|
{ |
|
|
|
|
strFailReason = _("Transaction too large"); |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
dPriority = wtxNew.ComputePriority(dPriority, nBytes); |
|
|
|
|
|
|
|
|
|
// Can we complete this as a free transaction?
|
|
|
|
|