aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Dashjr <luke-jr+git@utopios.org>2012-05-28 18:45:12 +0000
committerLuke Dashjr <luke-jr+git@utopios.org>2012-08-23 18:38:22 +0000
commitc3f95ef13f48d21db53992984976eac93e7a08fc (patch)
tree0caa89a1b21692c7e9a1dc03404280455186773f
parentbdbfd2329a92ab3fa7ad51e50a9fb0411ec64dae (diff)
Choose reasonable "smart" times to display for transactions
Logic: - If sending a transaction, assign its timestamp to the current time. - If receiving a transaction outside a block, assign its timestamp to the current time. - If receiving a block with a future timestamp, assign all its (not already known) transactions' timestamps to the current time. - If receiving a block with a past timestamp, before the most recent known transaction (that we care about), assign all its (not already known) transactions' timestamps to the same timestamp as that most-recent-known transaction. - If receiving a block with a past timestamp, but after the most recent known transaction, assign all its (not already known) transactions' timestamps to the block time.
-rw-r--r--src/rpcwallet.cpp22
-rw-r--r--src/wallet.cpp73
-rw-r--r--src/wallet.h16
3 files changed, 88 insertions, 23 deletions
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<CWalletTx*, CAccountingEntry*> TxPair;
- typedef multimap<int64, TxPair > 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<uint256, CWalletTx>::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<CAccountingEntry> 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<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ {
+ CWalletTx* wtx = &((*it).second);
+ txOrdered.insert(make_pair(wtx->nOrderPos, TxPair(wtx, (CAccountingEntry*)0)));
+ }
+ list<CAccountingEntry> 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<CWalletTx*, CAccountingEntry*> TxPair;
+ typedef std::multimap<int64, TxPair > 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<std::pair<std::string, std::string> > vOrderForm;
unsigned int fTimeReceivedIsTxTime;
unsigned int nTimeReceived; // time received by this node
+ unsigned int nTimeSmart;
char fFromMe;
std::string strFromAccount;
std::vector<char> 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