aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main.cpp33
-rw-r--r--src/net.cpp1
-rw-r--r--src/net.h1
-rw-r--r--src/qt/clientmodel.cpp12
-rw-r--r--src/qt/clientmodel.h6
-rw-r--r--src/qt/forms/debugwindow.ui148
-rw-r--r--src/qt/rpcconsole.cpp12
-rw-r--r--src/qt/rpcconsole.h2
-rw-r--r--src/rpcblockchain.cpp6
-rw-r--r--src/rpcnet.cpp2
-rw-r--r--src/test/accounting_tests.cpp8
-rw-r--r--src/wallet/rpcwallet.cpp12
-rw-r--r--src/wallet/wallet.cpp47
-rw-r--r--src/wallet/wallet.h17
-rw-r--r--src/wallet/walletdb.cpp8
-rw-r--r--src/wallet/walletdb.h4
16 files changed, 216 insertions, 103 deletions
diff --git a/src/main.cpp b/src/main.cpp
index 8fb121c00d..2579b642b8 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -670,10 +670,11 @@ bool CheckFinalTx(const CTransaction &tx, int flags)
// IsFinalTx() with one more than chainActive.Height().
const int nBlockHeight = chainActive.Height() + 1;
- // Timestamps on the other hand don't get any special treatment,
- // because we can't know what timestamp the next block will have,
- // and there aren't timestamp applications where it matters.
- // However this changes once median past time-locks are enforced:
+ // BIP113 will require that time-locked transactions have nLockTime set to
+ // less than the median time of the previous block they're contained in.
+ // When the next block is created its previous block will be the current
+ // chain tip, so we use that to calculate the median time passed to
+ // IsFinalTx() if LOCKTIME_MEDIAN_TIME_PAST is set.
const int64_t nBlockTime = (flags & LOCKTIME_MEDIAN_TIME_PAST)
? chainActive.Tip()->GetMedianTimePast()
: GetAdjustedTime();
@@ -4210,6 +4211,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
return error("message inv size() = %u", vInv.size());
}
+ bool fBlocksOnly = GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY);
+
+ // Allow whitelisted peers to send data other than blocks in blocks only mode if whitelistalwaysrelay is true
+ if (pfrom->fWhitelisted && GetBoolArg("-whitelistalwaysrelay", DEFAULT_WHITELISTALWAYSRELAY))
+ fBlocksOnly = false;
+
LOCK(cs_main);
std::vector<CInv> vToFetch;
@@ -4224,9 +4231,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
bool fAlreadyHave = AlreadyHave(inv);
LogPrint("net", "got inv: %s %s peer=%d\n", inv.ToString(), fAlreadyHave ? "have" : "new", pfrom->id);
- if (!fAlreadyHave && !fImporting && !fReindex && inv.type != MSG_BLOCK && !GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY))
- pfrom->AskFor(inv);
-
if (inv.type == MSG_BLOCK) {
UpdateBlockAvailability(pfrom->GetId(), inv.hash);
if (!fAlreadyHave && !fImporting && !fReindex && !mapBlocksInFlight.count(inv.hash)) {
@@ -4250,6 +4254,13 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
LogPrint("net", "getheaders (%d) %s to peer=%d\n", pindexBestHeader->nHeight, inv.hash.ToString(), pfrom->id);
}
}
+ else
+ {
+ if (fBlocksOnly)
+ LogPrint("net", "transaction (%s) inv sent in violation of protocol peer=%d\n", inv.hash.ToString(), pfrom->id);
+ else if (!fAlreadyHave && !fImporting && !fReindex)
+ pfrom->AskFor(inv);
+ }
// Track requests for our stuff
GetMainSignals().Inventory(inv.hash);
@@ -4374,6 +4385,14 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
else if (strCommand == "tx")
{
+ // Stop processing the transaction early if
+ // We are in blocks only mode and peer is either not whitelisted or whitelistalwaysrelay is off
+ if (GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY) && (!pfrom->fWhitelisted || !GetBoolArg("-whitelistalwaysrelay", DEFAULT_WHITELISTALWAYSRELAY)))
+ {
+ LogPrint("net", "transaction sent in violation of protocol peer=%d\n", pfrom->id);
+ return true;
+ }
+
vector<uint256> vWorkQueue;
vector<uint256> vEraseQueue;
CTransaction tx;
diff --git a/src/net.cpp b/src/net.cpp
index 000eefc858..cff4c54505 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -617,6 +617,7 @@ void CNode::copyStats(CNodeStats &stats)
{
stats.nodeid = this->GetId();
X(nServices);
+ X(fRelayTxes);
X(nLastSend);
X(nLastRecv);
X(nTimeConnected);
diff --git a/src/net.h b/src/net.h
index ebdbe77565..559cdf0878 100644
--- a/src/net.h
+++ b/src/net.h
@@ -180,6 +180,7 @@ class CNodeStats
public:
NodeId nodeid;
uint64_t nServices;
+ bool fRelayTxes;
int64_t nLastSend;
int64_t nLastRecv;
int64_t nTimeConnected;
diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp
index 0900a35cc4..566e8fa62d 100644
--- a/src/qt/clientmodel.cpp
+++ b/src/qt/clientmodel.cpp
@@ -13,6 +13,7 @@
#include "checkpoints.h"
#include "clientversion.h"
#include "net.h"
+#include "txmempool.h"
#include "ui_interface.h"
#include "util.h"
@@ -88,6 +89,16 @@ QDateTime ClientModel::getLastBlockDate() const
return QDateTime::fromTime_t(Params().GenesisBlock().GetBlockTime()); // Genesis block's time of current network
}
+long ClientModel::getMempoolSize() const
+{
+ return mempool.size();
+}
+
+size_t ClientModel::getMempoolDynamicUsage() const
+{
+ return mempool.DynamicMemoryUsage();
+}
+
double ClientModel::getVerificationProgress() const
{
LOCK(cs_main);
@@ -122,6 +133,7 @@ void ClientModel::updateTimer()
Q_EMIT numBlocksChanged(newNumBlocks, newBlockDate);
}
+ Q_EMIT mempoolSizeChanged(getMempoolSize(), getMempoolDynamicUsage());
Q_EMIT bytesChanged(getTotalBytesRecv(), getTotalBytesSent());
}
diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h
index 627bdf862d..493a759331 100644
--- a/src/qt/clientmodel.h
+++ b/src/qt/clientmodel.h
@@ -51,6 +51,11 @@ public:
int getNumConnections(unsigned int flags = CONNECTIONS_ALL) const;
int getNumBlocks() const;
+ //! Return number of transactions in the mempool
+ long getMempoolSize() const;
+ //! Return the dynamic memory usage of the mempool
+ size_t getMempoolDynamicUsage() const;
+
quint64 getTotalBytesRecv() const;
quint64 getTotalBytesSent() const;
@@ -89,6 +94,7 @@ private:
Q_SIGNALS:
void numConnectionsChanged(int count);
void numBlocksChanged(int count, const QDateTime& blockDate);
+ void mempoolSizeChanged(long count, size_t mempoolSizeInBytes);
void alertsChanged(const QString &warnings);
void bytesChanged(quint64 totalBytesIn, quint64 totalBytesOut);
diff --git a/src/qt/forms/debugwindow.ui b/src/qt/forms/debugwindow.ui
index eb02dd80ff..2471470363 100644
--- a/src/qt/forms/debugwindow.ui
+++ b/src/qt/forms/debugwindow.ui
@@ -23,7 +23,7 @@
<attribute name="title">
<string>&amp;Information</string>
</attribute>
- <layout class="QGridLayout" name="gridLayout" columnstretch="0,1">
+ <layout class="QGridLayout" name="gridLayout" columnstretch="0,1,0">
<property name="horizontalSpacing">
<number>12</number>
</property>
@@ -47,7 +47,7 @@
</property>
</widget>
</item>
- <item row="1" column="1">
+ <item row="1" column="1" colspan="2">
<widget class="QLabel" name="clientName">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -70,7 +70,7 @@
</property>
</widget>
</item>
- <item row="2" column="1">
+ <item row="2" column="1" colspan="2">
<widget class="QLabel" name="clientVersion">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -96,7 +96,7 @@
</property>
</widget>
</item>
- <item row="3" column="1">
+ <item row="3" column="1" colspan="2">
<widget class="QLabel" name="clientUserAgent">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -122,7 +122,7 @@
</property>
</widget>
</item>
- <item row="4" column="1">
+ <item row="4" column="1" colspan="2">
<widget class="QLabel" name="openSSLVersion">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -148,7 +148,7 @@
</property>
</widget>
</item>
- <item row="5" column="1">
+ <item row="5" column="1" colspan="2">
<widget class="QLabel" name="berkeleyDBVersion">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -171,7 +171,7 @@
</property>
</widget>
</item>
- <item row="6" column="1">
+ <item row="6" column="1" colspan="2">
<widget class="QLabel" name="buildDate">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -194,7 +194,7 @@
</property>
</widget>
</item>
- <item row="7" column="1">
+ <item row="7" column="1" colspan="2">
<widget class="QLabel" name="startupTime">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -210,19 +210,6 @@
</property>
</widget>
</item>
- <item row="8" column="0">
- <widget class="QLabel" name="label_11">
- <property name="font">
- <font>
- <weight>75</weight>
- <bold>true</bold>
- </font>
- </property>
- <property name="text">
- <string>Network</string>
- </property>
- </widget>
- </item>
<item row="9" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
@@ -230,7 +217,7 @@
</property>
</widget>
</item>
- <item row="9" column="1">
+ <item row="9" column="1" colspan="2">
<widget class="QLabel" name="networkName">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -253,7 +240,7 @@
</property>
</widget>
</item>
- <item row="10" column="1">
+ <item row="10" column="1" colspan="2">
<widget class="QLabel" name="numberOfConnections">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -289,7 +276,7 @@
</property>
</widget>
</item>
- <item row="12" column="1">
+ <item row="12" column="1" colspan="2">
<widget class="QLabel" name="numberOfBlocks">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -306,13 +293,13 @@
</widget>
</item>
<item row="13" column="0">
- <widget class="QLabel" name="label_2">
+ <widget class="QLabel" name="labelLastBlockTime">
<property name="text">
<string>Last block time</string>
</property>
</widget>
</item>
- <item row="13" column="1">
+ <item row="13" column="1" colspan="2">
<widget class="QLabel" name="lastBlockTime">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -329,20 +316,43 @@
</widget>
</item>
<item row="14" column="0">
- <spacer name="verticalSpacer_2">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
+ <widget class="QLabel" name="labelMempoolTitle">
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
</property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>20</height>
- </size>
+ <property name="text">
+ <string>Memory Pool</string>
</property>
- </spacer>
+ </widget>
</item>
<item row="15" column="0">
- <widget class="QLabel" name="labelDebugLogfile">
+ <widget class="QLabel" name="labelNumberOfTransactions">
+ <property name="text">
+ <string>Current number of transactions</string>
+ </property>
+ </widget>
+ </item>
+ <item row="15" column="1">
+ <widget class="QLabel" name="mempoolNumberTxs">
+ <property name="cursor">
+ <cursorShape>IBeamCursor</cursorShape>
+ </property>
+ <property name="text">
+ <string>N/A</string>
+ </property>
+ <property name="textFormat">
+ <enum>Qt::PlainText</enum>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="8" column="0">
+ <widget class="QLabel" name="labelNetwork">
<property name="font">
<font>
<weight>75</weight>
@@ -350,24 +360,74 @@
</font>
</property>
<property name="text">
- <string>Debug log file</string>
+ <string>Network</string>
</property>
</widget>
</item>
<item row="16" column="0">
- <widget class="QPushButton" name="openDebugLogfileButton">
- <property name="toolTip">
- <string>Open the Bitcoin Core debug log file from the current data directory. This can take a few seconds for large log files.</string>
+ <widget class="QLabel" name="labelMemoryUsage">
+ <property name="text">
+ <string>Memory usage</string>
+ </property>
+ </widget>
+ </item>
+ <item row="16" column="1">
+ <widget class="QLabel" name="mempoolSize">
+ <property name="cursor">
+ <cursorShape>IBeamCursor</cursorShape>
</property>
<property name="text">
- <string>&amp;Open</string>
+ <string>N/A</string>
</property>
- <property name="autoDefault">
- <bool>false</bool>
+ <property name="textFormat">
+ <enum>Qt::PlainText</enum>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
- <item row="17" column="0">
+ <item row="14" column="2" rowspan="3">
+ <layout class="QVBoxLayout" name="verticalLayoutDebugButton">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <item>
+ <spacer name="verticalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>10</width>
+ <height>5</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QLabel" name="labelDebugLogfile">
+ <property name="text">
+ <string>Debug log file</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="openDebugLogfileButton">
+ <property name="toolTip">
+ <string>Open the Bitcoin Core debug log file from the current data directory. This can take a few seconds for large log files.</string>
+ </property>
+ <property name="text">
+ <string>&amp;Open</string>
+ </property>
+ <property name="autoDefault">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="18" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index 4554281e0f..619c8631ae 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -343,6 +343,8 @@ void RPCConsole::setClientModel(ClientModel *model)
updateTrafficStats(model->getTotalBytesRecv(), model->getTotalBytesSent());
connect(model, SIGNAL(bytesChanged(quint64,quint64)), this, SLOT(updateTrafficStats(quint64, quint64)));
+ connect(model, SIGNAL(mempoolSizeChanged(long,size_t)), this, SLOT(setMempoolSize(long,size_t)));
+
// set up peer table
ui->peerWidget->setModel(model->getPeerTableModel());
ui->peerWidget->verticalHeader()->hide();
@@ -523,6 +525,16 @@ void RPCConsole::setNumBlocks(int count, const QDateTime& blockDate)
ui->lastBlockTime->setText(blockDate.toString());
}
+void RPCConsole::setMempoolSize(long numberOfTxs, size_t dynUsage)
+{
+ ui->mempoolNumberTxs->setText(QString::number(numberOfTxs));
+
+ if (dynUsage < 1000000)
+ ui->mempoolSize->setText(QString::number(dynUsage/1000.0, 'f', 2) + " KB");
+ else
+ ui->mempoolSize->setText(QString::number(dynUsage/1000000.0, 'f', 2) + " MB");
+}
+
void RPCConsole::on_lineEdit_returnPressed()
{
QString cmd = ui->lineEdit->text();
diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h
index 0914612c3e..4b242affcd 100644
--- a/src/qt/rpcconsole.h
+++ b/src/qt/rpcconsole.h
@@ -84,6 +84,8 @@ public Q_SLOTS:
void setNumConnections(int count);
/** Set number of blocks and last block date shown in the UI */
void setNumBlocks(int count, const QDateTime& blockDate);
+ /** Set size (number of transactions and memory usage) of the mempool in the UI */
+ void setMempoolSize(long numberOfTxs, size_t dynUsage);
/** Go forward or back in history */
void browseHistory(int offset);
/** Scroll console view to end */
diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp
index 9c0e78f772..012370ed10 100644
--- a/src/rpcblockchain.cpp
+++ b/src/rpcblockchain.cpp
@@ -71,6 +71,7 @@ UniValue blockheaderToJSON(const CBlockIndex* blockindex)
result.push_back(Pair("version", blockindex->nVersion));
result.push_back(Pair("merkleroot", blockindex->hashMerkleRoot.GetHex()));
result.push_back(Pair("time", (int64_t)blockindex->nTime));
+ result.push_back(Pair("mediantime", (int64_t)blockindex->GetMedianTimePast()));
result.push_back(Pair("nonce", (uint64_t)blockindex->nNonce));
result.push_back(Pair("bits", strprintf("%08x", blockindex->nBits)));
result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
@@ -111,6 +112,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx
}
result.push_back(Pair("tx", txs));
result.push_back(Pair("time", block.GetBlockTime()));
+ result.push_back(Pair("mediantime", (int64_t)blockindex->GetMedianTimePast()));
result.push_back(Pair("nonce", (uint64_t)block.nNonce));
result.push_back(Pair("bits", strprintf("%08x", block.nBits)));
result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
@@ -313,6 +315,7 @@ UniValue getblockheader(const UniValue& params, bool fHelp)
" \"version\" : n, (numeric) The block version\n"
" \"merkleroot\" : \"xxxx\", (string) The merkle root\n"
" \"time\" : ttt, (numeric) The block time in seconds since epoch (Jan 1 1970 GMT)\n"
+ " \"mediantime\" : ttt, (numeric) The median block time in seconds since epoch (Jan 1 1970 GMT)\n"
" \"nonce\" : n, (numeric) The nonce\n"
" \"bits\" : \"1d00ffff\", (string) The bits\n"
" \"difficulty\" : x.xxx, (numeric) The difficulty\n"
@@ -374,6 +377,7 @@ UniValue getblock(const UniValue& params, bool fHelp)
" ,...\n"
" ],\n"
" \"time\" : ttt, (numeric) The block time in seconds since epoch (Jan 1 1970 GMT)\n"
+ " \"mediantime\" : ttt, (numeric) The median block time in seconds since epoch (Jan 1 1970 GMT)\n"
" \"nonce\" : n, (numeric) The nonce\n"
" \"bits\" : \"1d00ffff\", (string) The bits\n"
" \"difficulty\" : x.xxx, (numeric) The difficulty\n"
@@ -608,6 +612,7 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp)
" \"headers\": xxxxxx, (numeric) the current number of headers we have validated\n"
" \"bestblockhash\": \"...\", (string) the hash of the currently best block\n"
" \"difficulty\": xxxxxx, (numeric) the current difficulty\n"
+ " \"mediantime\": xxxxxx, (numeric) median time for the current best block\n"
" \"verificationprogress\": xxxx, (numeric) estimate of verification progress [0..1]\n"
" \"chainwork\": \"xxxx\" (string) total amount of work in active chain, in hexadecimal\n"
" \"pruned\": xx, (boolean) if the blocks are subject to pruning\n"
@@ -639,6 +644,7 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp)
obj.push_back(Pair("headers", pindexBestHeader ? pindexBestHeader->nHeight : -1));
obj.push_back(Pair("bestblockhash", chainActive.Tip()->GetBlockHash().GetHex()));
obj.push_back(Pair("difficulty", (double)GetDifficulty()));
+ obj.push_back(Pair("mediantime", (int64_t)chainActive.Tip()->GetMedianTimePast()));
obj.push_back(Pair("verificationprogress", Checkpoints::GuessVerificationProgress(Params().Checkpoints(), chainActive.Tip())));
obj.push_back(Pair("chainwork", chainActive.Tip()->nChainWork.GetHex()));
obj.push_back(Pair("pruned", fPruneMode));
diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp
index 8915010649..2578848891 100644
--- a/src/rpcnet.cpp
+++ b/src/rpcnet.cpp
@@ -90,6 +90,7 @@ UniValue getpeerinfo(const UniValue& params, bool fHelp)
" \"addr\":\"host:port\", (string) The ip address and port of the peer\n"
" \"addrlocal\":\"ip:port\", (string) local address\n"
" \"services\":\"xxxxxxxxxxxxxxxx\", (string) The services offered\n"
+ " \"relaytxes\":true|false, (boolean) Whether peer has asked us to relay transactions to it\n"
" \"lastsend\": ttt, (numeric) The time in seconds since epoch (Jan 1 1970 GMT) of the last send\n"
" \"lastrecv\": ttt, (numeric) The time in seconds since epoch (Jan 1 1970 GMT) of the last receive\n"
" \"bytessent\": n, (numeric) The total bytes sent\n"
@@ -134,6 +135,7 @@ UniValue getpeerinfo(const UniValue& params, bool fHelp)
if (!(stats.addrLocal.empty()))
obj.push_back(Pair("addrlocal", stats.addrLocal));
obj.push_back(Pair("services", strprintf("%016x", stats.nServices)));
+ obj.push_back(Pair("relaytxes", stats.fRelayTxes));
obj.push_back(Pair("lastsend", stats.nLastSend));
obj.push_back(Pair("lastrecv", stats.nLastRecv));
obj.push_back(Pair("bytessent", stats.nSendBytes));
diff --git a/src/test/accounting_tests.cpp b/src/test/accounting_tests.cpp
index 0c2ade48d6..4a294c6712 100644
--- a/src/test/accounting_tests.cpp
+++ b/src/test/accounting_tests.cpp
@@ -45,7 +45,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade)
ae.nTime = 1333333333;
ae.strOtherAccount = "b";
ae.strComment = "";
- walletdb.WriteAccountingEntry(ae);
+ pwalletMain->AddAccountingEntry(ae, walletdb);
wtx.mapValue["comment"] = "z";
pwalletMain->AddToWallet(wtx, false, &walletdb);
@@ -55,7 +55,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade)
ae.nTime = 1333333336;
ae.strOtherAccount = "c";
- walletdb.WriteAccountingEntry(ae);
+ pwalletMain->AddAccountingEntry(ae, walletdb);
GetResults(walletdb, results);
@@ -71,7 +71,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade)
ae.nTime = 1333333330;
ae.strOtherAccount = "d";
ae.nOrderPos = pwalletMain->IncOrderPosNext();
- walletdb.WriteAccountingEntry(ae);
+ pwalletMain->AddAccountingEntry(ae, walletdb);
GetResults(walletdb, results);
@@ -121,7 +121,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade)
ae.nTime = 1333333334;
ae.strOtherAccount = "e";
ae.nOrderPos = -1;
- walletdb.WriteAccountingEntry(ae);
+ pwalletMain->AddAccountingEntry(ae, walletdb);
GetResults(walletdb, results);
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index bc00c62e9c..84881226c4 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -835,7 +835,7 @@ UniValue movecmd(const UniValue& params, bool fHelp)
debit.nTime = nNow;
debit.strOtherAccount = strTo;
debit.strComment = strComment;
- walletdb.WriteAccountingEntry(debit);
+ pwalletMain->AddAccountingEntry(debit, walletdb);
// Credit
CAccountingEntry credit;
@@ -845,7 +845,7 @@ UniValue movecmd(const UniValue& params, bool fHelp)
credit.nTime = nNow;
credit.strOtherAccount = strFrom;
credit.strComment = strComment;
- walletdb.WriteAccountingEntry(credit);
+ pwalletMain->AddAccountingEntry(credit, walletdb);
if (!walletdb.TxnCommit())
throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
@@ -1470,11 +1470,10 @@ UniValue listtransactions(const UniValue& params, bool fHelp)
UniValue ret(UniValue::VARR);
- std::list<CAccountingEntry> acentries;
- CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount);
+ const CWallet::TxItems & txOrdered = pwalletMain->wtxOrdered;
// iterate backwards until we have nCount items to return:
- for (CWallet::TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
+ for (CWallet::TxItems::const_reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
{
CWalletTx *const pwtx = (*it).second.first;
if (pwtx != 0)
@@ -1579,8 +1578,7 @@ UniValue listaccounts(const UniValue& params, bool fHelp)
}
}
- list<CAccountingEntry> acentries;
- CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
+ const list<CAccountingEntry> & acentries = pwalletMain->laccentries;
BOOST_FOREACH(const CAccountingEntry& entry, acentries)
mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index d51b8ddaef..1b152f4192 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -588,31 +588,6 @@ int64_t CWallet::IncOrderPosNext(CWalletDB *pwalletdb)
return nRet;
}
-CWallet::TxItems CWallet::OrderedTxItems(std::list<CAccountingEntry>& acentries, std::string strAccount)
-{
- AssertLockHeld(cs_wallet); // mapWallet
- 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)));
- }
- acentries.clear();
- walletdb.ListAccountCreditDebit(strAccount, acentries);
- BOOST_FOREACH(CAccountingEntry& entry, acentries)
- {
- txOrdered.insert(make_pair(entry.nOrderPos, TxPair((CWalletTx*)0, &entry)));
- }
-
- return txOrdered;
-}
-
void CWallet::MarkDirty()
{
{
@@ -629,7 +604,9 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletD
if (fFromLoadWallet)
{
mapWallet[hash] = wtxIn;
- mapWallet[hash].BindWallet(this);
+ CWalletTx& wtx = mapWallet[hash];
+ wtx.BindWallet(this);
+ wtxOrdered.insert(make_pair(wtx.nOrderPos, TxPair(&wtx, (CAccountingEntry*)0)));
AddToSpends(hash);
}
else
@@ -644,6 +621,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletD
{
wtx.nTimeReceived = GetAdjustedTime();
wtx.nOrderPos = IncOrderPosNext(pwalletdb);
+ wtxOrdered.insert(make_pair(wtx.nOrderPos, TxPair(&wtx, (CAccountingEntry*)0)));
wtx.nTimeSmart = wtx.nTimeReceived;
if (!wtxIn.hashBlock.IsNull())
@@ -655,9 +633,8 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletD
{
// Tolerate times up to the last timestamp in the wallet not more than 5 minutes into the future
int64_t latestTolerated = latestNow + 300;
- std::list<CAccountingEntry> acentries;
- TxItems txOrdered = OrderedTxItems(acentries);
- for (TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
+ const TxItems & txOrdered = wtxOrdered;
+ for (TxItems::const_reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
{
CWalletTx *const pwtx = (*it).second.first;
if (pwtx == &wtx)
@@ -2118,6 +2095,18 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
return true;
}
+bool CWallet::AddAccountingEntry(const CAccountingEntry& acentry, CWalletDB & pwalletdb)
+{
+ if (!pwalletdb.WriteAccountingEntry_Backend(acentry))
+ return false;
+
+ laccentries.push_back(acentry);
+ CAccountingEntry & entry = laccentries.back();
+ wtxOrdered.insert(make_pair(entry.nOrderPos, TxPair((CWalletTx*)0, &entry)));
+
+ return true;
+}
+
CAmount CWallet::GetRequiredFee(unsigned int nTxBytes)
{
return std::max(minTxFee.GetFee(nTxBytes), ::minRelayTxFee.GetFee(nTxBytes));
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 719f11f206..7e846569ff 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -531,6 +531,11 @@ public:
}
std::map<uint256, CWalletTx> mapWallet;
+ std::list<CAccountingEntry> laccentries;
+
+ typedef std::pair<CWalletTx*, CAccountingEntry*> TxPair;
+ typedef std::multimap<int64_t, TxPair > TxItems;
+ TxItems wtxOrdered;
int64_t nOrderPosNext;
std::map<uint256, int> mapRequestCount;
@@ -617,16 +622,6 @@ public:
*/
int64_t IncOrderPosNext(CWalletDB *pwalletdb = NULL);
- typedef std::pair<CWalletTx*, CAccountingEntry*> TxPair;
- typedef std::multimap<int64_t, TxPair > TxItems;
-
- /**
- * Get the wallet's activity log
- * @return multimap of ordered transactions and accounting entries
- * @warning Returned pointers are *only* valid within the scope of passed acentries
- */
- TxItems OrderedTxItems(std::list<CAccountingEntry>& acentries, std::string strAccount = "");
-
void MarkDirty();
bool AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletDB* pwalletdb);
void SyncTransaction(const CTransaction& tx, const CBlock* pblock);
@@ -656,6 +651,8 @@ public:
std::string& strFailReason, const CCoinControl *coinControl = NULL, bool sign = true);
bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey);
+ bool AddAccountingEntry(const CAccountingEntry&, CWalletDB & pwalletdb);
+
static CFeeRate minTxFee;
/**
* Estimate the minimum fee considering user set parameters
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index ea8a4eb043..9ce9f53bd9 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -191,7 +191,7 @@ bool CWalletDB::WriteAccountingEntry(const uint64_t nAccEntryNum, const CAccount
return Write(std::make_pair(std::string("acentry"), std::make_pair(acentry.strAccount, nAccEntryNum)), acentry);
}
-bool CWalletDB::WriteAccountingEntry(const CAccountingEntry& acentry)
+bool CWalletDB::WriteAccountingEntry_Backend(const CAccountingEntry& acentry)
{
return WriteAccountingEntry(++nAccountingEntryNumber, acentry);
}
@@ -709,6 +709,12 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
if (wss.fAnyUnordered)
result = ReorderTransactions(pwallet);
+ pwallet->laccentries.clear();
+ ListAccountCreditDebit("*", pwallet->laccentries);
+ BOOST_FOREACH(CAccountingEntry& entry, pwallet->laccentries) {
+ pwallet->wtxOrdered.insert(make_pair(entry.nOrderPos, CWallet::TxPair((CWalletTx*)0, &entry)));
+ }
+
return result;
}
diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h
index 270f826aed..3ebc05afd1 100644
--- a/src/wallet/walletdb.h
+++ b/src/wallet/walletdb.h
@@ -110,6 +110,9 @@ public:
bool WriteMinVersion(int nVersion);
+ /// This writes directly to the database, and will not update the CWallet's cached accounting entries!
+ /// Use wallet.AddAccountingEntry instead, to write *and* update its caches.
+ bool WriteAccountingEntry_Backend(const CAccountingEntry& acentry);
bool ReadAccount(const std::string& strAccount, CAccount& account);
bool WriteAccount(const std::string& strAccount, const CAccount& account);
@@ -118,7 +121,6 @@ public:
/// Erase destination data tuple from wallet database
bool EraseDestData(const std::string &address, const std::string &key);
- bool WriteAccountingEntry(const CAccountingEntry& acentry);
CAmount GetAccountCreditDebit(const std::string& strAccount);
void ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& acentries);