|
|
@ -136,11 +136,7 @@ bool AddToWallet(const CWalletTx& wtxIn) |
|
|
|
wtx.fFromMe = wtxIn.fFromMe; |
|
|
|
wtx.fFromMe = wtxIn.fFromMe; |
|
|
|
fUpdated = true; |
|
|
|
fUpdated = true; |
|
|
|
} |
|
|
|
} |
|
|
|
if (wtxIn.fSpent && wtxIn.fSpent != wtx.fSpent) |
|
|
|
fUpdated |= wtx.UpdateSpent(wtxIn.vfSpent); |
|
|
|
{ |
|
|
|
|
|
|
|
wtx.fSpent = wtxIn.fSpent; |
|
|
|
|
|
|
|
fUpdated = true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//// debug print
|
|
|
|
//// debug print
|
|
|
@ -221,10 +217,10 @@ void WalletUpdateSpent(const COutPoint& prevout) |
|
|
|
if (mi != mapWallet.end()) |
|
|
|
if (mi != mapWallet.end()) |
|
|
|
{ |
|
|
|
{ |
|
|
|
CWalletTx& wtx = (*mi).second; |
|
|
|
CWalletTx& wtx = (*mi).second; |
|
|
|
if (!wtx.fSpent && wtx.vout[prevout.n].IsMine()) |
|
|
|
if (!wtx.IsSpent(prevout.n) && wtx.vout[prevout.n].IsMine()) |
|
|
|
{ |
|
|
|
{ |
|
|
|
printf("WalletUpdateSpent found spent coin %sbc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str()); |
|
|
|
printf("WalletUpdateSpent found spent coin %sbc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str()); |
|
|
|
wtx.fSpent = true; |
|
|
|
wtx.MarkSpent(prevout.n); |
|
|
|
wtx.WriteToDisk(); |
|
|
|
wtx.WriteToDisk(); |
|
|
|
vWalletUpdated.push_back(prevout.hash); |
|
|
|
vWalletUpdated.push_back(prevout.hash); |
|
|
|
} |
|
|
|
} |
|
|
@ -939,34 +935,34 @@ void ReacceptWalletTransactions() |
|
|
|
foreach(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet) |
|
|
|
foreach(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet) |
|
|
|
{ |
|
|
|
{ |
|
|
|
CWalletTx& wtx = item.second; |
|
|
|
CWalletTx& wtx = item.second; |
|
|
|
if (wtx.fSpent && wtx.IsCoinBase()) |
|
|
|
if (wtx.IsCoinBase() && wtx.IsSpent(0)) |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
|
|
CTxIndex txindex; |
|
|
|
CTxIndex txindex; |
|
|
|
|
|
|
|
bool fUpdated = false; |
|
|
|
if (txdb.ReadTxIndex(wtx.GetHash(), txindex)) |
|
|
|
if (txdb.ReadTxIndex(wtx.GetHash(), txindex)) |
|
|
|
{ |
|
|
|
{ |
|
|
|
// Update fSpent if a tx got spent somewhere else by a copy of wallet.dat
|
|
|
|
// Update fSpent if a tx got spent somewhere else by a copy of wallet.dat
|
|
|
|
if (!wtx.fSpent) |
|
|
|
if (txindex.vSpent.size() != wtx.vout.size()) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (txindex.vSpent.size() != wtx.vout.size()) |
|
|
|
printf("ERROR: ReacceptWalletTransactions() : txindex.vSpent.size() %d != wtx.vout.size() %d\n", txindex.vSpent.size(), wtx.vout.size()); |
|
|
|
{ |
|
|
|
continue; |
|
|
|
printf("ERROR: ReacceptWalletTransactions() : txindex.vSpent.size() %d != wtx.vout.size() %d\n", txindex.vSpent.size(), wtx.vout.size()); |
|
|
|
} |
|
|
|
continue; |
|
|
|
for (int i = 0; i < txindex.vSpent.size(); i++) |
|
|
|
} |
|
|
|
{ |
|
|
|
for (int i = 0; i < txindex.vSpent.size(); i++) |
|
|
|
if (!txindex.vSpent[i].IsNull() && wtx.vout[i].IsMine()) |
|
|
|
{ |
|
|
|
|
|
|
|
if (!txindex.vSpent[i].IsNull() && wtx.vout[i].IsMine()) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
wtx.fSpent = true; |
|
|
|
|
|
|
|
vMissingTx.push_back(txindex.vSpent[i]); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (wtx.fSpent) |
|
|
|
|
|
|
|
{ |
|
|
|
{ |
|
|
|
printf("ReacceptWalletTransactions found spent coin %sbc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str()); |
|
|
|
wtx.MarkSpent(i); |
|
|
|
wtx.WriteToDisk(); |
|
|
|
fUpdated = true; |
|
|
|
|
|
|
|
vMissingTx.push_back(txindex.vSpent[i]); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (fUpdated) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
printf("ReacceptWalletTransactions found spent coin %sbc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str()); |
|
|
|
|
|
|
|
wtx.MarkDirty(); |
|
|
|
|
|
|
|
wtx.WriteToDisk(); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
else |
|
|
|
{ |
|
|
|
{ |
|
|
@ -3732,9 +3728,9 @@ int64 GetBalance() |
|
|
|
for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) |
|
|
|
for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) |
|
|
|
{ |
|
|
|
{ |
|
|
|
CWalletTx* pcoin = &(*it).second; |
|
|
|
CWalletTx* pcoin = &(*it).second; |
|
|
|
if (!pcoin->IsFinal() || pcoin->fSpent || !pcoin->IsConfirmed()) |
|
|
|
if (!pcoin->IsFinal() || !pcoin->IsConfirmed()) |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
nTotal += pcoin->GetCredit(); |
|
|
|
nTotal += pcoin->GetAvailableCredit(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -3743,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) |
|
|
@ -3763,30 +3761,43 @@ bool SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, set< |
|
|
|
|
|
|
|
|
|
|
|
foreach(CWalletTx* pcoin, vCoins) |
|
|
|
foreach(CWalletTx* pcoin, vCoins) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (!pcoin->IsFinal() || pcoin->fSpent || !pcoin->IsConfirmed()) |
|
|
|
if (!pcoin->IsFinal() || !pcoin->IsConfirmed()) |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0) |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
|
|
int nDepth = pcoin->GetDepthInMainChain(); |
|
|
|
int nDepth = pcoin->GetDepthInMainChain(); |
|
|
|
if (nDepth < (pcoin->IsFromMe() ? nConfMine : nConfTheirs)) |
|
|
|
if (nDepth < (pcoin->IsFromMe() ? nConfMine : nConfTheirs)) |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
|
|
int64 n = pcoin->GetCredit(); |
|
|
|
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)); |
|
|
|
|
|
|
|
nTotalLower += n; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else if (n < nLowestLarger) |
|
|
|
|
|
|
|
{ |
|
|
|
{ |
|
|
|
nLowestLarger = n; |
|
|
|
if (pcoin->IsSpent(i) || !pcoin->vout[i].IsMine()) |
|
|
|
pcoinLowestLarger = pcoin; |
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int64 n = pcoin->vout[i].nValue; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (n <= 0) |
|
|
|
|
|
|
|
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; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -3794,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; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -3845,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: "); |
|
|
@ -3864,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)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -3906,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
|
|
|
@ -3947,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); |
|
|
@ -4017,12 +4032,11 @@ bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey) |
|
|
|
// Mark old coins as spent
|
|
|
|
// Mark old coins as spent
|
|
|
|
set<CWalletTx*> setCoins; |
|
|
|
set<CWalletTx*> setCoins; |
|
|
|
foreach(const CTxIn& txin, wtxNew.vin) |
|
|
|
foreach(const CTxIn& txin, wtxNew.vin) |
|
|
|
setCoins.insert(&mapWallet[txin.prevout.hash]); |
|
|
|
|
|
|
|
foreach(CWalletTx* pcoin, setCoins) |
|
|
|
|
|
|
|
{ |
|
|
|
{ |
|
|
|
pcoin->fSpent = true; |
|
|
|
CWalletTx &pcoin = mapWallet[txin.prevout.hash]; |
|
|
|
pcoin->WriteToDisk(); |
|
|
|
pcoin.MarkSpent(txin.prevout.n); |
|
|
|
vWalletUpdated.push_back(pcoin->GetHash()); |
|
|
|
pcoin.WriteToDisk(); |
|
|
|
|
|
|
|
vWalletUpdated.push_back(pcoin.GetHash()); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|