Browse Source

select transaction outputs separately

Update to SelectCoins and CreateTransaction to select source transaction outputs separately instead of per whole transaction.
miguelfreitas
Pieter Wuille 14 years ago
parent
commit
aca3f961db
  1. 108
      main.cpp

108
main.cpp

@ -3739,14 +3739,16 @@ int64 GetBalance()
} }
bool SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, set<CWalletTx*>& setCoinsRet) bool SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, set<pair<CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet)
{ {
setCoinsRet.clear(); setCoinsRet.clear();
nValueRet = 0;
// List of values less than target // List of values less than target
int64 nLowestLarger = INT64_MAX; pair<int64, pair<CWalletTx*,unsigned int> > coinLowestLarger;
CWalletTx* pcoinLowestLarger = NULL; coinLowestLarger.first = INT64_MAX;
vector<pair<int64, CWalletTx*> > vValue; coinLowestLarger.second.first = NULL;
vector<pair<int64, pair<CWalletTx*,unsigned int> > > vValue;
int64 nTotalLower = 0; int64 nTotalLower = 0;
CRITICAL_BLOCK(cs_mapWallet) CRITICAL_BLOCK(cs_mapWallet)
@ -3769,23 +3771,33 @@ bool SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, set<
if (nDepth < (pcoin->IsFromMe() ? nConfMine : nConfTheirs)) if (nDepth < (pcoin->IsFromMe() ? nConfMine : nConfTheirs))
continue; continue;
int64 n = pcoin->GetAvailableCredit(); for (int i = 0; i < pcoin->vout.size(); i++)
if (n <= 0)
continue;
if (n == nTargetValue)
{
setCoinsRet.insert(pcoin);
return true;
}
else if (n < nTargetValue + CENT)
{ {
vValue.push_back(make_pair(n, pcoin)); if (pcoin->IsSpent(i) || !pcoin->vout[i].IsMine())
nTotalLower += n; continue;
}
else if (n < nLowestLarger) int64 n = pcoin->vout[i].nValue;
{
nLowestLarger = n; if (n <= 0)
pcoinLowestLarger = pcoin; continue;
pair<int64,pair<CWalletTx*,unsigned int> > coin = make_pair(n,make_pair(pcoin,i));
if (n == nTargetValue)
{
setCoinsRet.insert(coin.second);
nValueRet += coin.first;
return true;
}
else if (n < nTargetValue + CENT)
{
vValue.push_back(coin);
nTotalLower += n;
}
else if (n < coinLowestLarger.first)
{
coinLowestLarger = coin;
}
} }
} }
} }
@ -3793,15 +3805,19 @@ bool SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, set<
if (nTotalLower == nTargetValue || nTotalLower == nTargetValue + CENT) if (nTotalLower == nTargetValue || nTotalLower == nTargetValue + CENT)
{ {
for (int i = 0; i < vValue.size(); ++i) for (int i = 0; i < vValue.size(); ++i)
{
setCoinsRet.insert(vValue[i].second); setCoinsRet.insert(vValue[i].second);
nValueRet += vValue[i].first;
}
return true; return true;
} }
if (nTotalLower < nTargetValue + (pcoinLowestLarger ? CENT : 0)) if (nTotalLower < nTargetValue + (coinLowestLarger.second.first ? CENT : 0))
{ {
if (pcoinLowestLarger == NULL) if (coinLowestLarger.second.first == NULL)
return false; return false;
setCoinsRet.insert(pcoinLowestLarger); setCoinsRet.insert(coinLowestLarger.second);
nValueRet += coinLowestLarger.first;
return true; return true;
} }
@ -3844,13 +3860,18 @@ bool SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, set<
} }
// If the next larger is still closer, return it // If the next larger is still closer, return it
if (pcoinLowestLarger && nLowestLarger - nTargetValue <= nBest - nTargetValue) if (coinLowestLarger.second.first && coinLowestLarger.first - nTargetValue <= nBest - nTargetValue)
setCoinsRet.insert(pcoinLowestLarger);
else
{ {
setCoinsRet.insert(coinLowestLarger.second);
nValueRet += coinLowestLarger.first;
}
else {
for (int i = 0; i < vValue.size(); i++) for (int i = 0; i < vValue.size(); i++)
if (vfBest[i]) if (vfBest[i])
{
setCoinsRet.insert(vValue[i].second); setCoinsRet.insert(vValue[i].second);
nValueRet += vValue[i].first;
}
//// debug print //// debug print
printf("SelectCoins() best subset: "); printf("SelectCoins() best subset: ");
@ -3863,11 +3884,11 @@ bool SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, set<
return true; return true;
} }
bool SelectCoins(int64 nTargetValue, set<CWalletTx*>& setCoinsRet) bool SelectCoins(int64 nTargetValue, set<pair<CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet)
{ {
return (SelectCoinsMinConf(nTargetValue, 1, 6, setCoinsRet) || return (SelectCoinsMinConf(nTargetValue, 1, 6, setCoinsRet, nValueRet) ||
SelectCoinsMinConf(nTargetValue, 1, 1, setCoinsRet) || SelectCoinsMinConf(nTargetValue, 1, 1, setCoinsRet, nValueRet) ||
SelectCoinsMinConf(nTargetValue, 0, 1, setCoinsRet)); SelectCoinsMinConf(nTargetValue, 0, 1, setCoinsRet, nValueRet));
} }
@ -3905,15 +3926,14 @@ bool CreateTransaction(const vector<pair<CScript, int64> >& vecSend, CWalletTx&
wtxNew.vout.push_back(CTxOut(s.second, s.first)); wtxNew.vout.push_back(CTxOut(s.second, s.first));
// Choose coins to use // Choose coins to use
set<CWalletTx*> setCoins; set<pair<CWalletTx*,unsigned int> > setCoins;
if (!SelectCoins(nTotalValue, setCoins))
return false;
int64 nValueIn = 0; int64 nValueIn = 0;
foreach(CWalletTx* pcoin, setCoins) if (!SelectCoins(nTotalValue, setCoins, nValueIn))
return false;
foreach(PAIRTYPE(CWalletTx*, unsigned int) pcoin, setCoins)
{ {
int64 nCredit = pcoin->GetCredit(); int64 nCredit = pcoin.first->vout[pcoin.second].nValue;
nValueIn += nCredit; dPriority += (double)nCredit * pcoin.first->GetDepthInMainChain();
dPriority += (double)nCredit * pcoin->GetDepthInMainChain();
} }
// Fill a vout back to self with any change // Fill a vout back to self with any change
@ -3946,18 +3966,14 @@ bool CreateTransaction(const vector<pair<CScript, int64> >& vecSend, CWalletTx&
reservekey.ReturnKey(); reservekey.ReturnKey();
// Fill vin // Fill vin
foreach(CWalletTx* pcoin, setCoins) foreach(const PAIRTYPE(CWalletTx*,unsigned int)& coin, setCoins)
for (int nOut = 0; nOut < pcoin->vout.size(); nOut++) wtxNew.vin.push_back(CTxIn(coin.first->GetHash(),coin.second));
if (pcoin->vout[nOut].IsMine())
wtxNew.vin.push_back(CTxIn(pcoin->GetHash(), nOut));
// Sign // Sign
int nIn = 0; int nIn = 0;
foreach(CWalletTx* pcoin, setCoins) foreach(const PAIRTYPE(CWalletTx*,unsigned int)& coin, setCoins)
for (int nOut = 0; nOut < pcoin->vout.size(); nOut++) if (!SignSignature(*coin.first, wtxNew, nIn++))
if (pcoin->vout[nOut].IsMine()) return false;
if (!SignSignature(*pcoin, wtxNew, nIn++))
return false;
// Limit size // Limit size
unsigned int nBytes = ::GetSerializeSize(*(CTransaction*)&wtxNew, SER_NETWORK); unsigned int nBytes = ::GetSerializeSize(*(CTransaction*)&wtxNew, SER_NETWORK);

Loading…
Cancel
Save