Browse Source

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.
0.8
Luke Dashjr 12 years ago
parent
commit
c3f95ef13f
  1. 22
      src/rpcwallet.cpp
  2. 73
      src/wallet.cpp
  3. 16
      src/wallet.h

22
src/rpcwallet.cpp

@ -986,29 +986,11 @@ Value listtransactions(const Array& params, bool fHelp) @@ -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)

73
src/wallet.cpp

@ -291,6 +291,31 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase) @@ -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) @@ -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 @@ -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

16
src/wallet.h

@ -17,6 +17,7 @@ @@ -17,6 +17,7 @@
#include "ui_interface.h"
#include "util.h"
class CAccountingEntry;
class CWalletTx;
class CReserveKey;
class CWalletDB;
@ -143,6 +144,10 @@ public: @@ -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: @@ -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: @@ -394,6 +400,7 @@ public:
vOrderForm.clear();
fTimeReceivedIsTxTime = false;
nTimeReceived = 0;
nTimeSmart = 0;
fFromMe = false;
strFromAccount.clear();
vfSpent.clear();
@ -429,6 +436,9 @@ public: @@ -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: @@ -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

Loading…
Cancel
Save