select transaction outputs separately

Update to SelectCoins and CreateTransaction to select source transaction outputs separately instead of per whole transaction.
This commit is contained in:
Pieter Wuille 2011-03-17 22:54:20 +01:00
parent 335e878be8
commit aca3f961db
1 changed files with 62 additions and 46 deletions

108
main.cpp
View File

@ -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); if (pcoin->IsSpent(i) || !pcoin->vout[i].IsMine())
return true; continue;
}
else if (n < nTargetValue + CENT) int64 n = pcoin->vout[i].nValue;
{
vValue.push_back(make_pair(n, pcoin)); if (n <= 0)
nTotalLower += n; continue;
}
else if (n < nLowestLarger) pair<int64,pair<CWalletTx*,unsigned int> > coin = make_pair(n,make_pair(pcoin,i));
{
nLowestLarger = n; if (n == nTargetValue)
pcoinLowestLarger = pcoin; {
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);