CWalletTx wtx(this,tx);
// Get merkle branch if transaction was found in a block
if (pblock)
- wtx.SetMerkleBranch(*pblock);
+ wtx.SetMerkleBranch(pblock);
return AddToWallet(wtx);
}
else
return MINE_NO;
}
+// marks certain txout's as spent
+// returns true if any update took place
+bool CWalletTx::UpdateSpent(const std::vector<char>& vfNewSpent)
+{
+ bool fReturn = false;
+ for (unsigned int i = 0; i < vfNewSpent.size(); i++)
+ {
+ if (i == vfSpent.size())
+ break;
+
+ if (vfNewSpent[i] && !vfSpent[i])
+ {
+ vfSpent[i] = true;
+ fReturn = true;
+ fAvailableCreditCached = fAvailableWatchCreditCached = false;
+ }
+ }
+ return fReturn;
+}
+
+// make sure balances are recalculated
+void CWalletTx::MarkDirty()
+{
+ fCreditCached = false;
+ fAvailableCreditCached = fAvailableWatchCreditCached = false;
+ fDebitCached = fWatchDebitCached = false;
+ fChangeCached = false;
+}
+
+void CWalletTx::BindWallet(CWallet *pwalletIn)
+{
+ pwallet = pwalletIn;
+ MarkDirty();
+}
+
+void CWalletTx::MarkSpent(unsigned int nOut)
+{
+ if (nOut >= vout.size())
+ throw std::runtime_error("CWalletTx::MarkSpent() : nOut out of range");
+ vfSpent.resize(vout.size());
+ if (!vfSpent[nOut])
+ {
+ vfSpent[nOut] = true;
+ fAvailableCreditCached = fAvailableWatchCreditCached = false;
+ }
+}
+
+void CWalletTx::MarkUnspent(unsigned int nOut)
+{
+ if (nOut >= vout.size())
+ throw std::runtime_error("CWalletTx::MarkUnspent() : nOut out of range");
+ vfSpent.resize(vout.size());
+ if (vfSpent[nOut])
+ {
+ vfSpent[nOut] = false;
+ fAvailableCreditCached = fAvailableWatchCreditCached = false;
+ }
+}
+
+bool CWalletTx::IsSpent(unsigned int nOut) const
+{
+ if (nOut >= vout.size())
+ throw std::runtime_error("CWalletTx::IsSpent() : nOut out of range");
+ if (nOut >= vfSpent.size())
+ return false;
+ return (!!vfSpent[nOut]);
+}
+
int64_t CWallet::GetDebit(const CTxIn &txin, const isminefilter& filter) const
{
{
}
}
-void CWalletTx::RelayWalletTransaction(CTxDB& txdb)
+bool CWalletTx::RelayWalletTransaction(CTxDB& txdb)
{
- BOOST_FOREACH(const CMerkleTx& tx, vtxPrev)
- {
- if (!(tx.IsCoinBase() || tx.IsCoinStake()))
- {
- uint256 hash = tx.GetHash();
- if (!txdb.ContainsTx(hash))
- RelayTransaction((CTransaction)tx, hash);
- }
- }
- if (!(IsCoinBase() || IsCoinStake()))
+ uint256 hash = GetHash();
+ if (IsCoinBase() || IsCoinStake() || txdb.ContainsTx(hash) || !InMempool())
+ return false;
+
+ for(std::vector<CMerkleTx>::const_iterator it = vtxPrev.begin(); it != vtxPrev.end(); it++)
{
- uint256 hash = GetHash();
+ const CMerkleTx& tx = *it;
+ uint256 hash = tx.GetHash();
+
+ if (tx.IsCoinBase() || tx.IsCoinStake())
+ continue;
+
if (!txdb.ContainsTx(hash))
- {
- printf("Relaying wtx %s\n", hash.ToString().substr(0,10).c_str());
- RelayTransaction((CTransaction)*this, hash);
- }
+ RelayTransaction((CTransaction)tx, hash);
}
+
+ printf("Relaying wtx %s\n", hash.ToString().substr(0,10).c_str());
+ RelayTransaction((CTransaction)*this, hash);
+ return true;
}
-void CWalletTx::RelayWalletTransaction()
+bool CWalletTx::RelayWalletTransaction()
{
CTxDB txdb("r");
- RelayWalletTransaction(txdb);
+ return RelayWalletTransaction(txdb);
}
-void CWallet::ResendWalletTransactions(bool fForceResend)
+std::vector<uint256> CWallet::ResendWalletTransactionsBefore(int64_t nTime)
{
- if (!fForceResend) {
- // Do this infrequently and randomly to avoid giving away
- // that these are our transactions.
- static int64_t nNextTime = GetRand(GetTime() + 30 * 60);
- if (GetTime() < nNextTime)
- return;
- bool fFirst = (nNextTime == 0);
- nNextTime = GetTime() + GetRand(30 * 60);
- if (fFirst)
- return;
+ std::vector<uint256> result;
- // Only do it if there's been a new block since last time
- static int64_t nLastTime = 0;
- if (nTimeBestReceived < nLastTime)
- return;
- nLastTime = GetTime();
+ LOCK(cs_wallet);
+ // Sort them in chronological order
+ map<unsigned int, CWalletTx*> mapSorted;
+ BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
+ {
+ CWalletTx& wtx = item.second;
+ // Don't rebroadcast if newer than nTime:
+ if (wtx.nTimeReceived > nTime)
+ continue;
+ mapSorted.insert(make_pair(wtx.nTimeReceived, &wtx));
}
-
- // Rebroadcast any of our txes that aren't in a block yet
- printf("ResendWalletTransactions()\n");
- CTxDB txdb("r");
+ BOOST_FOREACH(PAIRTYPE(const unsigned int, CWalletTx*)& item, mapSorted)
{
- LOCK(cs_wallet);
- // Sort them in chronological order
- multimap<unsigned int, CWalletTx*> mapSorted;
- BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
- {
- CWalletTx& wtx = item.second;
- // Don't rebroadcast until it's had plenty of time that
- // it should have gotten in already by now.
- if (fForceResend || nTimeBestReceived - (int64_t)wtx.nTimeReceived > 5 * 60)
- mapSorted.insert(make_pair(wtx.nTimeReceived, &wtx));
- }
- BOOST_FOREACH(PAIRTYPE(const unsigned int, CWalletTx*)& item, mapSorted)
- {
- CWalletTx& wtx = *item.second;
- if (wtx.CheckTransaction())
- wtx.RelayWalletTransaction(txdb);
- else
- printf("ResendWalletTransactions() : CheckTransaction failed for transaction %s\n", wtx.GetHash().ToString().c_str());
- }
+ CWalletTx& wtx = *item.second;
+ if (wtx.RelayWalletTransaction())
+ result.push_back(wtx.GetHash());
}
+ return result;
}
+void CWallet::ResendWalletTransactions(int64_t nBestBlockTime)
+{
+ int64_t nNow = GetTime();
+ // Do this infrequently and randomly to avoid giving away
+ // that these are our transactions.
+ if (nNow < nNextResend)
+ return;
+ bool fFirst = (nNextResend == 0);
+ nNextResend = PoissonNextSend(nNow, 5*60);
+ if (fFirst)
+ return;
+ // Only do it if there's been a new block since last time
+ if (nBestBlockTime < nLastResend)
+ return;
+ nLastResend = nNow;
+ // Rebroadcast unconfirmed txes older than 5 minutes before the last
+ // block was found:
+ std::vector<uint256> relayed = ResendWalletTransactionsBefore(nBestBlockTime - 5*60);
+ if (!relayed.empty())
+ printf("CWallet::ResendWalletTransactions: rebroadcast %" PRIszu " unconfirmed transactions\n", relayed.size());
+}
//////////////////////////////////////////////////////////////////////////////
}
// Solve subset sum by stochastic approximation
- sort(vValue.rbegin(), vValue.rend(), CompareValueOnly());
+ std::sort(vValue.begin(), vValue.end(), CompareValueOnly());
+ std::reverse(vValue.begin(), vValue.end());
vector<char> vfBest;
int64_t nBest;
{
CWalletTx *pcoin = &walletEntry.second;
- if (pcoin->vin.size() > 0 && IsMine(pcoin->vin[0]))
+ if (pcoin->vin.size() > 0)
{
+ bool any_mine = false;
// group all input addresses with each other
BOOST_FOREACH(CTxIn txin, pcoin->vin)
{
CBitcoinAddress address;
+ if(!IsMine(txin)) // If this input isn't mine, ignore it
+ continue;
if(!ExtractAddress(*this, mapWallet[txin.prevout.hash].vout[txin.prevout.n].scriptPubKey, address))
continue;
grouping.insert(address);
+ any_mine = true;
}
// group change with input addresses
- BOOST_FOREACH(CTxOut txout, pcoin->vout)
+ if (any_mine)
+ {
+ BOOST_FOREACH(CTxOut txout, pcoin->vout)
if (IsChange(txout))
{
- CWalletTx tx = mapWallet[pcoin->vin[0].prevout.hash];
CBitcoinAddress txoutAddr;
if(!ExtractAddress(*this, txout.scriptPubKey, txoutAddr))
continue;
grouping.insert(txoutAddr);
}
- groupings.insert(grouping);
- grouping.clear();
+ }
+ if (!grouping.empty())
+ {
+ groupings.insert(grouping);
+ grouping.clear();
+ }
}
// group lone addrs by themselves