aboutsummaryrefslogtreecommitdiff
path: root/src/walletdb.cpp
diff options
context:
space:
mode:
authorLuke Dashjr <luke-jr+git@utopios.org>2012-05-27 23:06:09 +0000
committerLuke Dashjr <luke-jr+git@utopios.org>2012-08-23 18:18:20 +0000
commit9c7722b7c5ce49130bd978b932f73b629ce5cebe (patch)
treed1020863fbc36871042171d73433f0f055f27f3f /src/walletdb.cpp
parentcf78183fadac6e9fccb51c7355cfa34641fc06d5 (diff)
downloadbitcoin-9c7722b7c5ce49130bd978b932f73b629ce5cebe.tar.xz
Store a fixed order of transactions (and accounting) in the wallet
For backward compatibility, new accounting data is stored after a \0 in the comment string. This way, old versions and third-party software should load and store them, but all actual use (listtransactions, for example) ignores it.
Diffstat (limited to 'src/walletdb.cpp')
-rw-r--r--src/walletdb.cpp97
1 files changed, 96 insertions, 1 deletions
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;
}