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 13 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)
throw JSONRPCError(-8, "Negative from"); throw JSONRPCError(-8, "Negative from");
Array ret; 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 CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(strAccount);
// 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)));
}
// iterate backwards until we have nCount items to return: // 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; CWalletTx *const pwtx = (*it).second.first;
if (pwtx != 0) if (pwtx != 0)

73
src/wallet.cpp

@ -291,6 +291,31 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
return true; 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) void CWallet::WalletUpdateSpent(const CTransaction &tx)
{ {
// Anytime a signature is successfully verified, it's proof the outpoint is spent. // 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.nTimeReceived = GetAdjustedTime();
wtx.nOrderPos = nOrderPosNext++; 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; bool fUpdated = false;
@ -488,7 +558,8 @@ bool CWallet::IsChange(const CTxOut& txout) const
int64 CWalletTx::GetTxTime() const int64 CWalletTx::GetTxTime() const
{ {
return nTimeReceived; int64 n = nTimeSmart;
return n ? n : nTimeReceived;
} }
int CWalletTx::GetRequestCount() const int CWalletTx::GetRequestCount() const

16
src/wallet.h

@ -17,6 +17,7 @@
#include "ui_interface.h" #include "ui_interface.h"
#include "util.h" #include "util.h"
class CAccountingEntry;
class CWalletTx; class CWalletTx;
class CReserveKey; class CReserveKey;
class CWalletDB; class CWalletDB;
@ -143,6 +144,10 @@ public:
bool ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase); bool ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase);
bool EncryptWallet(const SecureString& strWalletPassphrase); bool EncryptWallet(const SecureString& strWalletPassphrase);
typedef std::pair<CWalletTx*, CAccountingEntry*> TxPair;
typedef std::multimap<int64, TxPair > TxItems;
TxItems OrderedTxItems(std::string strAccount = "");
void MarkDirty(); void MarkDirty();
bool AddToWallet(const CWalletTx& wtxIn); bool AddToWallet(const CWalletTx& wtxIn);
bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate = false, bool fFindBlock = false); 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; std::vector<std::pair<std::string, std::string> > vOrderForm;
unsigned int fTimeReceivedIsTxTime; unsigned int fTimeReceivedIsTxTime;
unsigned int nTimeReceived; // time received by this node unsigned int nTimeReceived; // time received by this node
unsigned int nTimeSmart;
char fFromMe; char fFromMe;
std::string strFromAccount; std::string strFromAccount;
std::vector<char> vfSpent; // which outputs are already spent std::vector<char> vfSpent; // which outputs are already spent
@ -394,6 +400,7 @@ public:
vOrderForm.clear(); vOrderForm.clear();
fTimeReceivedIsTxTime = false; fTimeReceivedIsTxTime = false;
nTimeReceived = 0; nTimeReceived = 0;
nTimeSmart = 0;
fFromMe = false; fFromMe = false;
strFromAccount.clear(); strFromAccount.clear();
vfSpent.clear(); vfSpent.clear();
@ -429,6 +436,9 @@ public:
pthis->mapValue["spent"] = str; pthis->mapValue["spent"] = str;
WriteOrderPos(pthis->nOrderPos, pthis->mapValue); WriteOrderPos(pthis->nOrderPos, pthis->mapValue);
if (nTimeSmart)
pthis->mapValue["timesmart"] = strprintf("%u", nTimeSmart);
} }
nSerSize += SerReadWrite(s, *(CMerkleTx*)this, nType, nVersion,ser_action); nSerSize += SerReadWrite(s, *(CMerkleTx*)this, nType, nVersion,ser_action);
@ -449,15 +459,17 @@ public:
pthis->vfSpent.push_back(c != '0'); pthis->vfSpent.push_back(c != '0');
else else
pthis->vfSpent.assign(vout.size(), fSpent); pthis->vfSpent.assign(vout.size(), fSpent);
}
if (fRead)
ReadOrderPos(pthis->nOrderPos, pthis->mapValue); ReadOrderPos(pthis->nOrderPos, pthis->mapValue);
pthis->nTimeSmart = mapValue.count("timesmart") ? (unsigned int)atoi64(pthis->mapValue["timesmart"]) : 0;
}
pthis->mapValue.erase("fromaccount"); pthis->mapValue.erase("fromaccount");
pthis->mapValue.erase("version"); pthis->mapValue.erase("version");
pthis->mapValue.erase("spent"); pthis->mapValue.erase("spent");
pthis->mapValue.erase("n"); pthis->mapValue.erase("n");
pthis->mapValue.erase("timesmart");
) )
// marks certain txout's as spent // marks certain txout's as spent

Loading…
Cancel
Save