aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Maxwell <greg@xiph.org>2012-08-23 12:38:50 -0700
committerGregory Maxwell <greg@xiph.org>2012-08-23 12:38:50 -0700
commit47753fa369f15274718779ffea1e2f151aa8307d (patch)
tree0caa89a1b21692c7e9a1dc03404280455186773f
parentcf78183fadac6e9fccb51c7355cfa34641fc06d5 (diff)
parentc3f95ef13f48d21db53992984976eac93e7a08fc (diff)
Merge pull request #1393 from luke-jr/refactor_times
Refactor transaction/accounting time
-rw-r--r--src/rpcrawtransaction.cpp1
-rw-r--r--src/rpcwallet.cpp26
-rw-r--r--src/test/accounting_tests.cpp123
-rw-r--r--src/wallet.cpp76
-rw-r--r--src/wallet.h95
-rw-r--r--src/walletdb.cpp97
-rw-r--r--src/walletdb.h4
7 files changed, 399 insertions, 23 deletions
diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp
index 29b9d072d6..fefefc7d62 100644
--- a/src/rpcrawtransaction.cpp
+++ b/src/rpcrawtransaction.cpp
@@ -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));
diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp
index 3b68105dd7..eacb5b3b1a 100644
--- a/src/rpcwallet.cpp
+++ b/src/rpcwallet.cpp
@@ -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));
}
@@ -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;
@@ -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;
@@ -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)
diff --git a/src/test/accounting_tests.cpp b/src/test/accounting_tests.cpp
new file mode 100644
index 0000000000..c474fd65c1
--- /dev/null
+++ b/src/test/accounting_tests.cpp
@@ -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()
diff --git a/src/wallet.cpp b/src/wallet.cpp
index 821b8851a6..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.
@@ -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)
@@ -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
diff --git a/src/wallet.h b/src/wallet.h
index 5bf38699ef..9103aa675e 100644
--- a/src/wallet.h
+++ b/src/wallet.h
@@ -5,12 +5,19 @@
#ifndef BITCOIN_WALLET_H
#define BITCOIN_WALLET_H
+#include <string>
+#include <vector>
+
+#include <stdlib.h>
+
#include "main.h"
#include "key.h"
#include "keystore.h"
#include "script.h"
#include "ui_interface.h"
+#include "util.h"
+class CAccountingEntry;
class CWalletTx;
class CReserveKey;
class CWalletDB;
@@ -103,6 +110,7 @@ public:
}
std::map<uint256, CWalletTx> mapWallet;
+ int64 nOrderPosNext;
std::map<uint256, int> mapRequestCount;
std::map<CTxDestination, std::string> mapAddressBook;
@@ -136,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);
@@ -304,6 +316,32 @@ public:
};
+typedef std::map<std::string, std::string> mapValue_t;
+
+
+static
+void
+ReadOrderPos(int64& nOrderPos, mapValue_t& mapValue)
+{
+ if (!mapValue.count("n"))
+ {
+ nOrderPos = -1; // TODO: calculate elsewhere
+ return;
+ }
+ nOrderPos = atoi64(mapValue["n"].c_str());
+}
+
+
+static
+void
+WriteOrderPos(const int64& nOrderPos, mapValue_t& mapValue)
+{
+ if (nOrderPos == -1)
+ return;
+ mapValue["n"] = i64tostr(nOrderPos);
+}
+
+
/** A transaction with a bunch of additional info that only the owner cares about.
* It includes any unrecorded transactions needed to link it back to the block chain.
*/
@@ -314,13 +352,15 @@ private:
public:
std::vector<CMerkleTx> vtxPrev;
- std::map<std::string, std::string> mapValue;
+ mapValue_t mapValue;
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
+ int64 nOrderPos; // position in ordered transaction list
// memory only
mutable bool fDebitCached;
@@ -360,6 +400,7 @@ public:
vOrderForm.clear();
fTimeReceivedIsTxTime = false;
nTimeReceived = 0;
+ nTimeSmart = 0;
fFromMe = false;
strFromAccount.clear();
vfSpent.clear();
@@ -371,6 +412,7 @@ public:
nCreditCached = 0;
nAvailableCreditCached = 0;
nChangeCached = 0;
+ nOrderPos = -1;
}
IMPLEMENT_SERIALIZE
@@ -392,6 +434,11 @@ public:
fSpent = true;
}
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);
@@ -412,11 +459,17 @@ public:
pthis->vfSpent.push_back(c != '0');
else
pthis->vfSpent.assign(vout.size(), fSpent);
+
+ 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
@@ -705,6 +758,9 @@ public:
int64 nTime;
std::string strOtherAccount;
std::string strComment;
+ mapValue_t mapValue;
+ int64 nOrderPos; // position in ordered transaction list
+ uint64 nEntryNo;
CAccountingEntry()
{
@@ -718,18 +774,55 @@ public:
strAccount.clear();
strOtherAccount.clear();
strComment.clear();
+ nOrderPos = -1;
}
IMPLEMENT_SERIALIZE
(
+ CAccountingEntry& me = *const_cast<CAccountingEntry*>(this);
if (!(nType & SER_GETHASH))
READWRITE(nVersion);
// Note: strAccount is serialized as part of the key, not here.
READWRITE(nCreditDebit);
READWRITE(nTime);
READWRITE(strOtherAccount);
+
+ if (!fRead)
+ {
+ WriteOrderPos(nOrderPos, me.mapValue);
+
+ if (!(mapValue.empty() && _ssExtra.empty()))
+ {
+ CDataStream ss(nType, nVersion);
+ ss.insert(ss.begin(), '\0');
+ ss << mapValue;
+ ss.insert(ss.end(), _ssExtra.begin(), _ssExtra.end());
+ me.strComment.append(ss.str());
+ }
+ }
+
READWRITE(strComment);
+
+ size_t nSepPos = strComment.find("\0", 0, 1);
+ if (fRead)
+ {
+ me.mapValue.clear();
+ if (std::string::npos != nSepPos)
+ {
+ CDataStream ss(std::vector<char>(strComment.begin() + nSepPos + 1, strComment.end()), nType, nVersion);
+ ss >> me.mapValue;
+ me._ssExtra = std::vector<char>(ss.begin(), ss.end());
+ }
+ ReadOrderPos(me.nOrderPos, me.mapValue);
+ }
+ if (std::string::npos != nSepPos)
+ me.strComment.erase(nSepPos);
+
+ me.mapValue.erase("n");
)
+
+private:
+ std::vector<char> _ssExtra;
};
bool GetWalletFile(CWallet* pwallet, std::string &strWalletFileOut);
diff --git a/src/walletdb.cpp b/src/walletdb.cpp
index 72c548e602..164b68e11f 100644
--- a/src/walletdb.cpp
+++ b/src/walletdb.cpp
@@ -42,9 +42,14 @@ bool CWalletDB::WriteAccount(const string& strAccount, const CAccount& account)
return Write(make_pair(string("acc"), strAccount), account);
}
+bool CWalletDB::WriteAccountingEntry(const uint64 nAccEntryNum, const CAccountingEntry& acentry)
+{
+ return Write(boost::make_tuple(string("acentry"), acentry.strAccount, nAccEntryNum), acentry);
+}
+
bool CWalletDB::WriteAccountingEntry(const CAccountingEntry& acentry)
{
- return Write(boost::make_tuple(string("acentry"), acentry.strAccount, ++nAccountingEntryNumber), acentry);
+ return WriteAccountingEntry(++nAccountingEntryNumber, acentry);
}
int64 CWalletDB::GetAccountCreditDebit(const string& strAccount)
@@ -95,6 +100,7 @@ void CWalletDB::ListAccountCreditDebit(const string& strAccount, list<CAccountin
break;
ssValue >> acentry;
+ ssKey >> acentry.nEntryNo;
entries.push_back(acentry);
}
@@ -102,12 +108,86 @@ void CWalletDB::ListAccountCreditDebit(const string& strAccount, list<CAccountin
}
+int
+CWalletDB::ReorderTransactions(CWallet* pwallet)
+{
+ LOCK(pwallet->cs_wallet);
+ // Old wallets didn't have any defined order for transactions
+ // Probably a bad idea to change the output of this
+
+ // First: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap.
+ typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
+ typedef multimap<int64, TxPair > TxItems;
+ TxItems txByTime;
+
+ for (map<uint256, CWalletTx>::iterator it = pwallet->mapWallet.begin(); it != pwallet->mapWallet.end(); ++it)
+ {
+ CWalletTx* wtx = &((*it).second);
+ txByTime.insert(make_pair(wtx->nTimeReceived, TxPair(wtx, (CAccountingEntry*)0)));
+ }
+ list<CAccountingEntry> acentries;
+ ListAccountCreditDebit("", acentries);
+ BOOST_FOREACH(CAccountingEntry& entry, acentries)
+ {
+ txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
+ }
+
+ int64& nOrderPosNext = pwallet->nOrderPosNext;
+ nOrderPosNext = 0;
+ std::vector<int64> nOrderPosOffsets;
+ for (TxItems::iterator it = txByTime.begin(); it != txByTime.end(); ++it)
+ {
+ CWalletTx *const pwtx = (*it).second.first;
+ CAccountingEntry *const pacentry = (*it).second.second;
+ int64& nOrderPos = (pwtx != 0) ? pwtx->nOrderPos : pacentry->nOrderPos;
+
+ if (nOrderPos == -1)
+ {
+ nOrderPos = nOrderPosNext++;
+ nOrderPosOffsets.push_back(nOrderPos);
+
+ if (pacentry)
+ // Have to write accounting regardless, since we don't keep it in memory
+ if (!WriteAccountingEntry(pacentry->nEntryNo, *pacentry))
+ return DB_LOAD_FAIL;
+ }
+ else
+ {
+ int64 nOrderPosOff = 0;
+ BOOST_FOREACH(const int64& nOffsetStart, nOrderPosOffsets)
+ {
+ if (nOrderPos >= nOffsetStart)
+ ++nOrderPosOff;
+ }
+ nOrderPos += nOrderPosOff;
+ nOrderPosNext = std::max(nOrderPosNext, nOrderPos + 1);
+
+ if (!nOrderPosOff)
+ continue;
+
+ // Since we're changing the order, write it back
+ if (pwtx)
+ {
+ if (!WriteTx(pwtx->GetHash(), *pwtx))
+ return DB_LOAD_FAIL;
+ }
+ else
+ if (!WriteAccountingEntry(pacentry->nEntryNo, *pacentry))
+ return DB_LOAD_FAIL;
+ }
+ }
+
+ return DB_LOAD_OK;
+}
+
+
int CWalletDB::LoadWallet(CWallet* pwallet)
{
pwallet->vchDefaultKey = CPubKey();
int nFileVersion = 0;
vector<uint256> vWalletUpgrade;
bool fIsEncrypted = false;
+ bool fAnyUnordered = false;
//// todo: shouldn't we catch exceptions and try to recover and continue?
{
@@ -183,6 +263,9 @@ int CWalletDB::LoadWallet(CWallet* pwallet)
vWalletUpgrade.push_back(hash);
}
+ if (wtx.nOrderPos == -1)
+ fAnyUnordered = true;
+
//// debug print
//printf("LoadWallet %s\n", wtx.GetHash().ToString().c_str());
//printf(" %12"PRI64d" %s %s %s\n",
@@ -199,6 +282,14 @@ int CWalletDB::LoadWallet(CWallet* pwallet)
ssKey >> nNumber;
if (nNumber > nAccountingEntryNumber)
nAccountingEntryNumber = nNumber;
+
+ if (!fAnyUnordered)
+ {
+ CAccountingEntry acentry;
+ ssValue >> acentry;
+ if (acentry.nOrderPos == -1)
+ fAnyUnordered = true;
+ }
}
else if (strType == "key" || strType == "wkey")
{
@@ -318,6 +409,10 @@ int CWalletDB::LoadWallet(CWallet* pwallet)
if (nFileVersion < CLIENT_VERSION) // Update
WriteVersion(CLIENT_VERSION);
+ if (fAnyUnordered)
+ return ReorderTransactions(pwallet);
+
+ // If you add anything else here... be sure to do it if ReorderTransactions returns DB_LOAD_OK too!
return DB_LOAD_OK;
}
diff --git a/src/walletdb.h b/src/walletdb.h
index 39182279d5..187be65a97 100644
--- a/src/walletdb.h
+++ b/src/walletdb.h
@@ -170,10 +170,14 @@ public:
bool ReadAccount(const std::string& strAccount, CAccount& account);
bool WriteAccount(const std::string& strAccount, const CAccount& account);
+private:
+ bool WriteAccountingEntry(const uint64 nAccEntryNum, const CAccountingEntry& acentry);
+public:
bool WriteAccountingEntry(const CAccountingEntry& acentry);
int64 GetAccountCreditDebit(const std::string& strAccount);
void ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& acentries);
+ int ReorderTransactions(CWallet*);
int LoadWallet(CWallet* pwallet);
};