diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp index d75e43d4f9..eacb5b3b1a 100644 --- a/src/rpcwallet.cpp +++ b/src/rpcwallet.cpp @@ -986,29 +986,11 @@ Value listtransactions(const Array& params, bool fHelp) throw JSONRPCError(-8, "Negative from"); Array ret; - CWalletDB walletdb(pwalletMain->strWalletFile); - // First: get all CWalletTx and CAccountingEntry into a sorted-by-order multimap. - typedef pair TxPair; - typedef multimap TxItems; - TxItems txOrdered; - - // Note: maintaining indices in the database of (account,time) --> txid and (account, time) --> acentry - // would make this much faster for applications that do this a lot. - for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) - { - CWalletTx* wtx = &((*it).second); - txOrdered.insert(make_pair(wtx->nOrderPos, TxPair(wtx, (CAccountingEntry*)0))); - } - list acentries; - walletdb.ListAccountCreditDebit(strAccount, acentries); - BOOST_FOREACH(CAccountingEntry& entry, acentries) - { - txOrdered.insert(make_pair(entry.nOrderPos, TxPair((CWalletTx*)0, &entry))); - } + CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(strAccount); // iterate backwards until we have nCount items to return: - for (TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) + for (CWallet::TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) { CWalletTx *const pwtx = (*it).second.first; if (pwtx != 0) diff --git a/src/wallet.cpp b/src/wallet.cpp index 3d380c827f..07a5047cef 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -291,6 +291,31 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase) return true; } +CWallet::TxItems +CWallet::OrderedTxItems(std::string strAccount) +{ + CWalletDB walletdb(strWalletFile); + + // First: get all CWalletTx and CAccountingEntry into a sorted-by-order multimap. + TxItems txOrdered; + + // Note: maintaining indices in the database of (account,time) --> txid and (account, time) --> acentry + // would make this much faster for applications that do this a lot. + for (map::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + { + CWalletTx* wtx = &((*it).second); + txOrdered.insert(make_pair(wtx->nOrderPos, TxPair(wtx, (CAccountingEntry*)0))); + } + list acentries; + walletdb.ListAccountCreditDebit(strAccount, acentries); + BOOST_FOREACH(CAccountingEntry& entry, acentries) + { + txOrdered.insert(make_pair(entry.nOrderPos, TxPair((CWalletTx*)0, &entry))); + } + + return txOrdered; +} + void CWallet::WalletUpdateSpent(const CTransaction &tx) { // Anytime a signature is successfully verified, it's proof the outpoint is spent. @@ -339,6 +364,51 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn) { wtx.nTimeReceived = GetAdjustedTime(); wtx.nOrderPos = nOrderPosNext++; + + wtx.nTimeSmart = wtx.nTimeReceived; + if (wtxIn.hashBlock != 0) + { + if (mapBlockIndex.count(wtxIn.hashBlock)) + { + unsigned int latestNow = wtx.nTimeReceived; + unsigned int latestEntry = 0; + { + // Tolerate times up to the last timestamp in the wallet not more than 5 minutes into the future + int64 latestTolerated = latestNow + 300; + TxItems txOrdered = OrderedTxItems(); + for (TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) + { + CWalletTx *const pwtx = (*it).second.first; + if (pwtx == &wtx) + continue; + CAccountingEntry *const pacentry = (*it).second.second; + int64 nSmartTime; + if (pwtx) + { + nSmartTime = pwtx->nTimeSmart; + if (!nSmartTime) + nSmartTime = pwtx->nTimeReceived; + } + else + nSmartTime = pacentry->nTime; + if (nSmartTime <= latestTolerated) + { + latestEntry = nSmartTime; + if (nSmartTime > latestNow) + latestNow = nSmartTime; + break; + } + } + } + + unsigned int& blocktime = mapBlockIndex[wtxIn.hashBlock]->nTime; + wtx.nTimeSmart = std::max(latestEntry, std::min(blocktime, latestNow)); + } + else + printf("AddToWallet() : found %s in block %s not in index\n", + wtxIn.GetHash().ToString().substr(0,10).c_str(), + wtxIn.hashBlock.ToString().c_str()); + } } bool fUpdated = false; @@ -488,7 +558,8 @@ bool CWallet::IsChange(const CTxOut& txout) const int64 CWalletTx::GetTxTime() const { - return nTimeReceived; + int64 n = nTimeSmart; + return n ? n : nTimeReceived; } int CWalletTx::GetRequestCount() const diff --git a/src/wallet.h b/src/wallet.h index b32face5bf..9103aa675e 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -17,6 +17,7 @@ #include "ui_interface.h" #include "util.h" +class CAccountingEntry; class CWalletTx; class CReserveKey; class CWalletDB; @@ -143,6 +144,10 @@ public: bool ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase); bool EncryptWallet(const SecureString& strWalletPassphrase); + typedef std::pair TxPair; + typedef std::multimap TxItems; + TxItems OrderedTxItems(std::string strAccount = ""); + void MarkDirty(); bool AddToWallet(const CWalletTx& wtxIn); bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate = false, bool fFindBlock = false); @@ -351,6 +356,7 @@ public: std::vector > vOrderForm; unsigned int fTimeReceivedIsTxTime; unsigned int nTimeReceived; // time received by this node + unsigned int nTimeSmart; char fFromMe; std::string strFromAccount; std::vector vfSpent; // which outputs are already spent @@ -394,6 +400,7 @@ public: vOrderForm.clear(); fTimeReceivedIsTxTime = false; nTimeReceived = 0; + nTimeSmart = 0; fFromMe = false; strFromAccount.clear(); vfSpent.clear(); @@ -429,6 +436,9 @@ public: pthis->mapValue["spent"] = str; WriteOrderPos(pthis->nOrderPos, pthis->mapValue); + + if (nTimeSmart) + pthis->mapValue["timesmart"] = strprintf("%u", nTimeSmart); } nSerSize += SerReadWrite(s, *(CMerkleTx*)this, nType, nVersion,ser_action); @@ -449,15 +459,17 @@ public: pthis->vfSpent.push_back(c != '0'); else pthis->vfSpent.assign(vout.size(), fSpent); - } - if (fRead) ReadOrderPos(pthis->nOrderPos, pthis->mapValue); + pthis->nTimeSmart = mapValue.count("timesmart") ? (unsigned int)atoi64(pthis->mapValue["timesmart"]) : 0; + } + pthis->mapValue.erase("fromaccount"); pthis->mapValue.erase("version"); pthis->mapValue.erase("spent"); pthis->mapValue.erase("n"); + pthis->mapValue.erase("timesmart"); ) // marks certain txout's as spent