Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/rpcrawtransaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry)
{
entry.push_back(Pair("confirmations", 1 + nBestHeight - pindex->nHeight));
entry.push_back(Pair("time", (boost::int64_t)pindex->nTime));
entry.push_back(Pair("blocktime", (boost::int64_t)pindex->nTime));
}
else
entry.push_back(Pair("confirmations", 0));
Expand Down
26 changes: 6 additions & 20 deletions src/rpcwallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,11 @@ void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
{
entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex()));
entry.push_back(Pair("blockindex", wtx.nIndex));
entry.push_back(Pair("blocktime", (boost::int64_t)(mapBlockIndex[wtx.hashBlock]->nTime)));
}
entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime()));
entry.push_back(Pair("timereceived", (boost::int64_t)wtx.nTimeReceived));
BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
entry.push_back(Pair(item.first, item.second));
}
Expand Down Expand Up @@ -542,6 +544,7 @@ Value movecmd(const Array& params, bool fHelp)

// Debit
CAccountingEntry debit;
debit.nOrderPos = pwalletMain->nOrderPosNext++;
debit.strAccount = strFrom;
debit.nCreditDebit = -nAmount;
debit.nTime = nNow;
Expand All @@ -551,6 +554,7 @@ Value movecmd(const Array& params, bool fHelp)

// Credit
CAccountingEntry credit;
credit.nOrderPos = pwalletMain->nOrderPosNext++;
credit.strAccount = strTo;
credit.nCreditDebit = nAmount;
credit.nTime = nNow;
Expand Down Expand Up @@ -982,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-time multimap.
typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
typedef multimap<int64, TxPair > TxItems;
TxItems txByTime;

// 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);
txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
}
list<CAccountingEntry> acentries;
walletdb.ListAccountCreditDebit(strAccount, acentries);
BOOST_FOREACH(CAccountingEntry& entry, acentries)
{
txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
}
CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(strAccount);

// iterate backwards until we have nCount items to return:
for (TxItems::reverse_iterator it = txByTime.rbegin(); it != txByTime.rend(); ++it)
for (CWallet::TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
{
CWalletTx *const pwtx = (*it).second.first;
if (pwtx != 0)
Expand Down
123 changes: 123 additions & 0 deletions src/test/accounting_tests.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
#include <boost/test/unit_test.hpp>

#include <boost/foreach.hpp>

#include "init.h"
#include "wallet.h"
#include "walletdb.h"

BOOST_AUTO_TEST_SUITE(accounting_tests)

static void
GetResults(CWalletDB& walletdb, std::map<int64, CAccountingEntry>& results)
{
std::list<CAccountingEntry> aes;

results.clear();
BOOST_CHECK(walletdb.ReorderTransactions(pwalletMain) == DB_LOAD_OK);
walletdb.ListAccountCreditDebit("", aes);
BOOST_FOREACH(CAccountingEntry& ae, aes)
{
results[ae.nOrderPos] = ae;
}
}

BOOST_AUTO_TEST_CASE(acc_orderupgrade)
{
CWalletDB walletdb(pwalletMain->strWalletFile);
std::vector<CWalletTx*> vpwtx;
CWalletTx wtx;
CAccountingEntry ae;
std::map<int64, CAccountingEntry> results;

ae.strAccount = "";
ae.nCreditDebit = 1;
ae.nTime = 1333333333;
ae.strOtherAccount = "b";
ae.strComment = "";
walletdb.WriteAccountingEntry(ae);

wtx.mapValue["comment"] = "z";
pwalletMain->AddToWallet(wtx);
vpwtx.push_back(&pwalletMain->mapWallet[wtx.GetHash()]);
vpwtx[0]->nTimeReceived = (unsigned int)1333333335;
vpwtx[0]->nOrderPos = -1;

ae.nTime = 1333333336;
ae.strOtherAccount = "c";
walletdb.WriteAccountingEntry(ae);

GetResults(walletdb, results);

BOOST_CHECK(pwalletMain->nOrderPosNext == 3);
BOOST_CHECK(2 == results.size());
BOOST_CHECK(results[0].nTime == 1333333333);
BOOST_CHECK(results[0].strComment.empty());
BOOST_CHECK(1 == vpwtx[0]->nOrderPos);
BOOST_CHECK(results[2].nTime == 1333333336);
BOOST_CHECK(results[2].strOtherAccount == "c");


ae.nTime = 1333333330;
ae.strOtherAccount = "d";
ae.nOrderPos = pwalletMain->nOrderPosNext++;
walletdb.WriteAccountingEntry(ae);

GetResults(walletdb, results);

BOOST_CHECK(results.size() == 3);
BOOST_CHECK(pwalletMain->nOrderPosNext == 4);
BOOST_CHECK(results[0].nTime == 1333333333);
BOOST_CHECK(1 == vpwtx[0]->nOrderPos);
BOOST_CHECK(results[2].nTime == 1333333336);
BOOST_CHECK(results[3].nTime == 1333333330);
BOOST_CHECK(results[3].strComment.empty());


wtx.mapValue["comment"] = "y";
--wtx.nLockTime; // Just to change the hash :)
pwalletMain->AddToWallet(wtx);
vpwtx.push_back(&pwalletMain->mapWallet[wtx.GetHash()]);
vpwtx[1]->nTimeReceived = (unsigned int)1333333336;

wtx.mapValue["comment"] = "x";
--wtx.nLockTime; // Just to change the hash :)
pwalletMain->AddToWallet(wtx);
vpwtx.push_back(&pwalletMain->mapWallet[wtx.GetHash()]);
vpwtx[2]->nTimeReceived = (unsigned int)1333333329;
vpwtx[2]->nOrderPos = -1;

GetResults(walletdb, results);

BOOST_CHECK(results.size() == 3);
BOOST_CHECK(pwalletMain->nOrderPosNext == 6);
BOOST_CHECK(0 == vpwtx[2]->nOrderPos);
BOOST_CHECK(results[1].nTime == 1333333333);
BOOST_CHECK(2 == vpwtx[0]->nOrderPos);
BOOST_CHECK(results[3].nTime == 1333333336);
BOOST_CHECK(results[4].nTime == 1333333330);
BOOST_CHECK(results[4].strComment.empty());
BOOST_CHECK(5 == vpwtx[1]->nOrderPos);


ae.nTime = 1333333334;
ae.strOtherAccount = "e";
ae.nOrderPos = -1;
walletdb.WriteAccountingEntry(ae);

GetResults(walletdb, results);

BOOST_CHECK(results.size() == 4);
BOOST_CHECK(pwalletMain->nOrderPosNext == 7);
BOOST_CHECK(0 == vpwtx[2]->nOrderPos);
BOOST_CHECK(results[1].nTime == 1333333333);
BOOST_CHECK(2 == vpwtx[0]->nOrderPos);
BOOST_CHECK(results[3].nTime == 1333333336);
BOOST_CHECK(results[3].strComment.empty());
BOOST_CHECK(results[4].nTime == 1333333330);
BOOST_CHECK(results[4].strComment.empty());
BOOST_CHECK(results[5].nTime == 1333333334);
BOOST_CHECK(6 == vpwtx[1]->nOrderPos);
}

BOOST_AUTO_TEST_SUITE_END()
76 changes: 75 additions & 1 deletion src/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -336,7 +361,55 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn)
wtx.BindWallet(this);
bool fInsertedNew = ret.second;
if (fInsertedNew)
{
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;
if (!fInsertedNew)
Expand Down Expand Up @@ -485,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
Expand Down
Loading