aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/net_processing.cpp26
-rw-r--r--src/qt/rpcconsole.cpp117
-rw-r--r--src/qt/rpcconsole.h6
-rw-r--r--src/qt/test/rpcnestedtests.cpp28
-rw-r--r--src/wallet/wallet.cpp87
-rw-r--r--src/wallet/wallet.h4
-rw-r--r--src/wallet/walletdb.cpp3
-rw-r--r--src/wallet/walletdb.h2
8 files changed, 218 insertions, 55 deletions
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 6282849ed1..380decbcb7 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -1782,11 +1782,24 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
}
+ // When we succeed in decoding a block's txids from a cmpctblock
+ // message we typically jump to the BLOCKTXN handling code, with a
+ // dummy (empty) BLOCKTXN message, to re-use the logic there in
+ // completing processing of the putative block (without cs_main).
+ bool fProcessBLOCKTXN = false;
+ CDataStream blockTxnMsg(SER_NETWORK, PROTOCOL_VERSION);
+
+ // If we end up treating this as a plain headers message, call that as well
+ // without cs_main.
+ bool fRevertToHeaderProcessing = false;
+ CDataStream vHeadersMsg(SER_NETWORK, PROTOCOL_VERSION);
+
// Keep a CBlock for "optimistic" compactblock reconstructions (see
// below)
std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
bool fBlockReconstructed = false;
+ {
LOCK(cs_main);
// If AcceptBlockHeader returned true, it set pindex
assert(pindex);
@@ -1868,9 +1881,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// Dirty hack to jump to BLOCKTXN code (TODO: move message handling into their own functions)
BlockTransactions txn;
txn.blockhash = cmpctblock.header.GetHash();
- CDataStream blockTxnMsg(SER_NETWORK, PROTOCOL_VERSION);
blockTxnMsg << txn;
- return ProcessMessage(pfrom, NetMsgType::BLOCKTXN, blockTxnMsg, nTimeReceived, chainparams, connman);
+ fProcessBLOCKTXN = true;
} else {
req.blockhash = pindex->GetBlockHash();
connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETBLOCKTXN, req));
@@ -1906,11 +1918,17 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// Dirty hack to process as if it were just a headers message (TODO: move message handling into their own functions)
std::vector<CBlock> headers;
headers.push_back(cmpctblock.header);
- CDataStream vHeadersMsg(SER_NETWORK, PROTOCOL_VERSION);
vHeadersMsg << headers;
- return ProcessMessage(pfrom, NetMsgType::HEADERS, vHeadersMsg, nTimeReceived, chainparams, connman);
+ fRevertToHeaderProcessing = true;
}
}
+ } // cs_main
+
+ if (fProcessBLOCKTXN)
+ return ProcessMessage(pfrom, NetMsgType::BLOCKTXN, blockTxnMsg, nTimeReceived, chainparams, connman);
+
+ if (fRevertToHeaderProcessing)
+ return ProcessMessage(pfrom, NetMsgType::HEADERS, vHeadersMsg, nTimeReceived, chainparams, connman);
if (fBlockReconstructed) {
// If we got here, we were able to optimistically reconstruct a
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index cfe197de2a..38fe659c33 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -31,6 +31,7 @@
#include <QKeyEvent>
#include <QMenu>
+#include <QMessageBox>
#include <QScrollBar>
#include <QSettings>
#include <QSignalMapper>
@@ -63,6 +64,20 @@ const struct {
{NULL, NULL}
};
+namespace {
+
+// don't add private key handling cmd's to the history
+const QStringList historyFilter = QStringList()
+ << "importprivkey"
+ << "importmulti"
+ << "signmessagewithprivkey"
+ << "signrawtransaction"
+ << "walletpassphrase"
+ << "walletpassphrasechange"
+ << "encryptwallet";
+
+}
+
/* Object for executing console RPC commands in a separate thread.
*/
class RPCExecutor : public QObject
@@ -113,10 +128,10 @@ public:
#include "rpcconsole.moc"
/**
- * Split shell command line into a list of arguments and execute the command(s).
+ * Split shell command line into a list of arguments and optionally execute the command(s).
* Aims to emulate \c bash and friends.
*
- * - Command nesting is possible with brackets [example: validateaddress(getnewaddress())]
+ * - Command nesting is possible with parenthesis; for example: validateaddress(getnewaddress())
* - Arguments are delimited with whitespace or comma
* - Extra whitespace at the beginning and end and between arguments will be ignored
* - Text can be "double" or 'single' quoted
@@ -127,9 +142,11 @@ public:
*
* @param[out] result stringified Result from the executed command(chain)
* @param[in] strCommand Command line to split
+ * @param[in] fExecute set true if you want the command to be executed
+ * @param[out] pstrFilteredOut Command line, filtered to remove any sensitive data
*/
-bool RPCConsole::RPCExecuteCommandLine(std::string &strResult, const std::string &strCommand)
+bool RPCConsole::RPCParseCommandLine(std::string &strResult, const std::string &strCommand, const bool fExecute, std::string * const pstrFilteredOut)
{
std::vector< std::vector<std::string> > stack;
stack.push_back(std::vector<std::string>());
@@ -149,12 +166,35 @@ bool RPCConsole::RPCExecuteCommandLine(std::string &strResult, const std::string
} state = STATE_EATING_SPACES;
std::string curarg;
UniValue lastResult;
+ unsigned nDepthInsideSensitive = 0;
+ size_t filter_begin_pos = 0, chpos;
+ std::vector<std::pair<size_t, size_t>> filter_ranges;
+
+ auto add_to_current_stack = [&](const std::string& curarg) {
+ if (stack.back().empty() && (!nDepthInsideSensitive) && historyFilter.contains(QString::fromStdString(curarg), Qt::CaseInsensitive)) {
+ nDepthInsideSensitive = 1;
+ filter_begin_pos = chpos;
+ }
+ stack.back().push_back(curarg);
+ };
+
+ auto close_out_params = [&]() {
+ if (nDepthInsideSensitive) {
+ if (!--nDepthInsideSensitive) {
+ assert(filter_begin_pos);
+ filter_ranges.push_back(std::make_pair(filter_begin_pos, chpos));
+ filter_begin_pos = 0;
+ }
+ }
+ stack.pop_back();
+ };
std::string strCommandTerminated = strCommand;
if (strCommandTerminated.back() != '\n')
strCommandTerminated += "\n";
- for(char ch: strCommandTerminated)
+ for (chpos = 0; chpos < strCommandTerminated.size(); ++chpos)
{
+ char ch = strCommandTerminated[chpos];
switch(state)
{
case STATE_COMMAND_EXECUTED_INNER:
@@ -173,7 +213,7 @@ bool RPCConsole::RPCExecuteCommandLine(std::string &strResult, const std::string
curarg += ch;
break;
}
- if (curarg.size())
+ if (curarg.size() && fExecute)
{
// if we have a value query, query arrays with index and objects with a string key
UniValue subelement;
@@ -198,7 +238,7 @@ bool RPCConsole::RPCExecuteCommandLine(std::string &strResult, const std::string
breakParsing = false;
// pop the stack and return the result to the current command arguments
- stack.pop_back();
+ close_out_params();
// don't stringify the json in case of a string to avoid doublequotes
if (lastResult.isStr())
@@ -210,7 +250,7 @@ bool RPCConsole::RPCExecuteCommandLine(std::string &strResult, const std::string
if (curarg.size())
{
if (stack.size())
- stack.back().push_back(curarg);
+ add_to_current_stack(curarg);
else
strResult = curarg;
}
@@ -236,25 +276,31 @@ bool RPCConsole::RPCExecuteCommandLine(std::string &strResult, const std::string
if (state == STATE_ARGUMENT)
{
if (ch == '(' && stack.size() && stack.back().size() > 0)
+ {
+ if (nDepthInsideSensitive) {
+ ++nDepthInsideSensitive;
+ }
stack.push_back(std::vector<std::string>());
+ }
// don't allow commands after executed commands on baselevel
if (!stack.size())
throw std::runtime_error("Invalid Syntax");
- stack.back().push_back(curarg);
+ add_to_current_stack(curarg);
curarg.clear();
state = STATE_EATING_SPACES_IN_BRACKETS;
}
if ((ch == ')' || ch == '\n') && stack.size() > 0)
{
- std::string strPrint;
- // Convert argument list to JSON objects in method-dependent way,
- // and pass it along with the method name to the dispatcher.
- JSONRPCRequest req;
- req.params = RPCConvertValues(stack.back()[0], std::vector<std::string>(stack.back().begin() + 1, stack.back().end()));
- req.strMethod = stack.back()[0];
- lastResult = tableRPC.execute(req);
+ if (fExecute) {
+ // Convert argument list to JSON objects in method-dependent way,
+ // and pass it along with the method name to the dispatcher.
+ JSONRPCRequest req;
+ req.params = RPCConvertValues(stack.back()[0], std::vector<std::string>(stack.back().begin() + 1, stack.back().end()));
+ req.strMethod = stack.back()[0];
+ lastResult = tableRPC.execute(req);
+ }
state = STATE_COMMAND_EXECUTED;
curarg.clear();
@@ -266,7 +312,7 @@ bool RPCConsole::RPCExecuteCommandLine(std::string &strResult, const std::string
else if(state == STATE_ARGUMENT) // Space ends argument
{
- stack.back().push_back(curarg);
+ add_to_current_stack(curarg);
curarg.clear();
}
if ((state == STATE_EATING_SPACES_IN_BRACKETS || state == STATE_ARGUMENT) && ch == ',')
@@ -303,6 +349,16 @@ bool RPCConsole::RPCExecuteCommandLine(std::string &strResult, const std::string
break;
}
}
+ if (pstrFilteredOut) {
+ if (STATE_COMMAND_EXECUTED == state) {
+ assert(!stack.empty());
+ close_out_params();
+ }
+ *pstrFilteredOut = strCommand;
+ for (auto i = filter_ranges.rbegin(); i != filter_ranges.rend(); ++i) {
+ pstrFilteredOut->replace(i->first, i->second - i->first, "(…)");
+ }
+ }
switch(state) // final state
{
case STATE_COMMAND_EXECUTED:
@@ -747,12 +803,30 @@ void RPCConsole::setMempoolSize(long numberOfTxs, size_t dynUsage)
void RPCConsole::on_lineEdit_returnPressed()
{
QString cmd = ui->lineEdit->text();
- ui->lineEdit->clear();
if(!cmd.isEmpty())
{
+ std::string strFilteredCmd;
+ try {
+ std::string dummy;
+ if (!RPCParseCommandLine(dummy, cmd.toStdString(), false, &strFilteredCmd)) {
+ // Failed to parse command, so we cannot even filter it for the history
+ throw std::runtime_error("Invalid command line");
+ }
+ } catch (const std::exception& e) {
+ QMessageBox::critical(this, "Error", QString("Error: ") + QString::fromStdString(e.what()));
+ return;
+ }
+
+ ui->lineEdit->clear();
+
+ cmdBeforeBrowsing = QString();
+
message(CMD_REQUEST, cmd);
Q_EMIT cmdRequest(cmd);
+
+ cmd = QString::fromStdString(strFilteredCmd);
+
// Remove command, if already in history
history.removeOne(cmd);
// Append command to history
@@ -762,6 +836,7 @@ void RPCConsole::on_lineEdit_returnPressed()
history.removeFirst();
// Set pointer to end of history
historyPtr = history.size();
+
// Scroll console view to end
scrollToEnd();
}
@@ -769,6 +844,11 @@ void RPCConsole::on_lineEdit_returnPressed()
void RPCConsole::browseHistory(int offset)
{
+ // store current text when start browsing through the history
+ if (historyPtr == history.size()) {
+ cmdBeforeBrowsing = ui->lineEdit->text();
+ }
+
historyPtr += offset;
if(historyPtr < 0)
historyPtr = 0;
@@ -777,6 +857,9 @@ void RPCConsole::browseHistory(int offset)
QString cmd;
if(historyPtr < history.size())
cmd = history.at(historyPtr);
+ else if (!cmdBeforeBrowsing.isNull()) {
+ cmd = cmdBeforeBrowsing;
+ }
ui->lineEdit->setText(cmd);
}
diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h
index ab8c3dc914..dfc1cc26d6 100644
--- a/src/qt/rpcconsole.h
+++ b/src/qt/rpcconsole.h
@@ -36,7 +36,10 @@ public:
explicit RPCConsole(const PlatformStyle *platformStyle, QWidget *parent);
~RPCConsole();
- static bool RPCExecuteCommandLine(std::string &strResult, const std::string &strCommand);
+ static bool RPCParseCommandLine(std::string &strResult, const std::string &strCommand, bool fExecute, std::string * const pstrFilteredOut = NULL);
+ static bool RPCExecuteCommandLine(std::string &strResult, const std::string &strCommand, std::string * const pstrFilteredOut = NULL) {
+ return RPCParseCommandLine(strResult, strCommand, true, pstrFilteredOut);
+ }
void setClientModel(ClientModel *model);
@@ -140,6 +143,7 @@ private:
ClientModel *clientModel;
QStringList history;
int historyPtr;
+ QString cmdBeforeBrowsing;
QList<NodeId> cachedNodeids;
const PlatformStyle *platformStyle;
RPCTimerInterface *rpcTimerInterface;
diff --git a/src/qt/test/rpcnestedtests.cpp b/src/qt/test/rpcnestedtests.cpp
index fb044489d7..fbec5722b6 100644
--- a/src/qt/test/rpcnestedtests.cpp
+++ b/src/qt/test/rpcnestedtests.cpp
@@ -61,8 +61,10 @@ void RPCNestedTests::rpcNestedTests()
std::string result;
std::string result2;
- RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo()[chain]"); //simple result filtering with path
+ std::string filtered;
+ RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo()[chain]", &filtered); //simple result filtering with path
QVERIFY(result=="main");
+ QVERIFY(filtered == "getblockchaininfo()[chain]");
RPCConsole::RPCExecuteCommandLine(result, "getblock(getbestblockhash())"); //simple 2 level nesting
RPCConsole::RPCExecuteCommandLine(result, "getblock(getblock(getbestblockhash())[hash], true)");
@@ -87,8 +89,30 @@ void RPCNestedTests::rpcNestedTests()
(RPCConsole::RPCExecuteCommandLine(result2, "createrawtransaction( [], {} , 0 )")); //whitespace between parametres is allowed
QVERIFY(result == result2);
- RPCConsole::RPCExecuteCommandLine(result, "getblock(getbestblockhash())[tx][0]");
+ RPCConsole::RPCExecuteCommandLine(result, "getblock(getbestblockhash())[tx][0]", &filtered);
QVERIFY(result == "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b");
+ QVERIFY(filtered == "getblock(getbestblockhash())[tx][0]");
+
+ RPCConsole::RPCParseCommandLine(result, "importprivkey", false, &filtered);
+ QVERIFY(filtered == "importprivkey(…)");
+ RPCConsole::RPCParseCommandLine(result, "signmessagewithprivkey abc", false, &filtered);
+ QVERIFY(filtered == "signmessagewithprivkey(…)");
+ RPCConsole::RPCParseCommandLine(result, "signmessagewithprivkey abc,def", false, &filtered);
+ QVERIFY(filtered == "signmessagewithprivkey(…)");
+ RPCConsole::RPCParseCommandLine(result, "signrawtransaction(abc)", false, &filtered);
+ QVERIFY(filtered == "signrawtransaction(…)");
+ RPCConsole::RPCParseCommandLine(result, "walletpassphrase(help())", false, &filtered);
+ QVERIFY(filtered == "walletpassphrase(…)");
+ RPCConsole::RPCParseCommandLine(result, "walletpassphrasechange(help(walletpassphrasechange(abc)))", false, &filtered);
+ QVERIFY(filtered == "walletpassphrasechange(…)");
+ RPCConsole::RPCParseCommandLine(result, "help(encryptwallet(abc, def))", false, &filtered);
+ QVERIFY(filtered == "help(encryptwallet(…))");
+ RPCConsole::RPCParseCommandLine(result, "help(importprivkey())", false, &filtered);
+ QVERIFY(filtered == "help(importprivkey(…))");
+ RPCConsole::RPCParseCommandLine(result, "help(importprivkey(help()))", false, &filtered);
+ QVERIFY(filtered == "help(importprivkey(…))");
+ RPCConsole::RPCParseCommandLine(result, "help(importprivkey(abc), walletpassphrase(def))", false, &filtered);
+ QVERIFY(filtered == "help(importprivkey(…), walletpassphrase(…))");
RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest");
QVERIFY(result == "[]");
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index fef0f9e580..c25e8be13c 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -3405,16 +3405,8 @@ std::string CWallet::GetWalletHelpString(bool showDebug)
return strUsage;
}
-bool CWallet::InitLoadWallet()
+CWallet* CWallet::CreateWalletFromFile(const std::string walletFile)
{
- if (GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) {
- pwalletMain = NULL;
- LogPrintf("Wallet disabled!\n");
- return true;
- }
-
- std::string walletFile = GetArg("-wallet", DEFAULT_WALLET_DAT);
-
// needed to restore wallet transaction meta data after -zapwallettxes
std::vector<CWalletTx> vWtx;
@@ -3424,7 +3416,8 @@ bool CWallet::InitLoadWallet()
CWallet *tempWallet = new CWallet(walletFile);
DBErrors nZapWalletRet = tempWallet->ZapWalletTx(vWtx);
if (nZapWalletRet != DB_LOAD_OK) {
- return InitError(strprintf(_("Error loading %s: Wallet corrupted"), walletFile));
+ InitError(strprintf(_("Error loading %s: Wallet corrupted"), walletFile));
+ return NULL;
}
delete tempWallet;
@@ -3439,23 +3432,29 @@ bool CWallet::InitLoadWallet()
DBErrors nLoadWalletRet = walletInstance->LoadWallet(fFirstRun);
if (nLoadWalletRet != DB_LOAD_OK)
{
- if (nLoadWalletRet == DB_CORRUPT)
- return InitError(strprintf(_("Error loading %s: Wallet corrupted"), walletFile));
+ if (nLoadWalletRet == DB_CORRUPT) {
+ InitError(strprintf(_("Error loading %s: Wallet corrupted"), walletFile));
+ return NULL;
+ }
else if (nLoadWalletRet == DB_NONCRITICAL_ERROR)
{
InitWarning(strprintf(_("Error reading %s! All keys read correctly, but transaction data"
" or address book entries might be missing or incorrect."),
walletFile));
}
- else if (nLoadWalletRet == DB_TOO_NEW)
- return InitError(strprintf(_("Error loading %s: Wallet requires newer version of %s"),
- walletFile, _(PACKAGE_NAME)));
+ else if (nLoadWalletRet == DB_TOO_NEW) {
+ InitError(strprintf(_("Error loading %s: Wallet requires newer version of %s"), walletFile, _(PACKAGE_NAME)));
+ return NULL;
+ }
else if (nLoadWalletRet == DB_NEED_REWRITE)
{
- return InitError(strprintf(_("Wallet needed to be rewritten: restart %s to complete"), _(PACKAGE_NAME)));
+ InitError(strprintf(_("Wallet needed to be rewritten: restart %s to complete"), _(PACKAGE_NAME)));
+ return NULL;
+ }
+ else {
+ InitError(strprintf(_("Error loading %s"), walletFile));
+ return NULL;
}
- else
- return InitError(strprintf(_("Error loading %s"), walletFile));
}
if (GetBoolArg("-upgradewallet", fFirstRun))
@@ -3471,7 +3470,8 @@ bool CWallet::InitLoadWallet()
LogPrintf("Allowing wallet upgrade up to %i\n", nMaxVersion);
if (nMaxVersion < walletInstance->GetVersion())
{
- return InitError(_("Cannot downgrade wallet"));
+ InitError(_("Cannot downgrade wallet"));
+ return NULL;
}
walletInstance->SetMaxVersion(nMaxVersion);
}
@@ -3488,18 +3488,24 @@ bool CWallet::InitLoadWallet()
CPubKey newDefaultKey;
if (walletInstance->GetKeyFromPool(newDefaultKey)) {
walletInstance->SetDefaultKey(newDefaultKey);
- if (!walletInstance->SetAddressBook(walletInstance->vchDefaultKey.GetID(), "", "receive"))
- return InitError(_("Cannot write default address") += "\n");
+ if (!walletInstance->SetAddressBook(walletInstance->vchDefaultKey.GetID(), "", "receive")) {
+ InitError(_("Cannot write default address") += "\n");
+ return NULL;
+ }
}
walletInstance->SetBestChain(chainActive.GetLocator());
}
else if (IsArgSet("-usehd")) {
bool useHD = GetBoolArg("-usehd", DEFAULT_USE_HD_WALLET);
- if (walletInstance->IsHDEnabled() && !useHD)
- return InitError(strprintf(_("Error loading %s: You can't disable HD on a already existing HD wallet"), walletFile));
- if (!walletInstance->IsHDEnabled() && useHD)
- return InitError(strprintf(_("Error loading %s: You can't enable HD on a already existing non-HD wallet"), walletFile));
+ if (walletInstance->IsHDEnabled() && !useHD) {
+ InitError(strprintf(_("Error loading %s: You can't disable HD on a already existing HD wallet"), walletFile));
+ return NULL;
+ }
+ if (!walletInstance->IsHDEnabled() && useHD) {
+ InitError(strprintf(_("Error loading %s: You can't enable HD on a already existing non-HD wallet"), walletFile));
+ return NULL;
+ }
}
LogPrintf(" wallet %15dms\n", GetTimeMillis() - nStart);
@@ -3529,8 +3535,10 @@ bool CWallet::InitLoadWallet()
while (block && block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA) && block->pprev->nTx > 0 && pindexRescan != block)
block = block->pprev;
- if (pindexRescan != block)
- return InitError(_("Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)"));
+ if (pindexRescan != block) {
+ InitError(_("Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)"));
+ return NULL;
+ }
}
uiInterface.InitMessage(_("Rescanning..."));
@@ -3575,11 +3583,30 @@ bool CWallet::InitLoadWallet()
LogPrintf("mapAddressBook.size() = %u\n", walletInstance->mapAddressBook.size());
}
- pwalletMain = walletInstance;
+ return walletInstance;
+}
+
+bool CWallet::InitLoadWallet()
+{
+ if (GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) {
+ pwalletMain = NULL;
+ LogPrintf("Wallet disabled!\n");
+ return true;
+ }
+
+ std::string walletFile = GetArg("-wallet", DEFAULT_WALLET_DAT);
+
+ CWallet * const pwallet = CreateWalletFromFile(walletFile);
+ if (!pwallet) {
+ return false;
+ }
+ pwalletMain = pwallet;
return true;
}
+std::atomic<bool> CWallet::fFlushThreadRunning(false);
+
void CWallet::postInitProcess(boost::thread_group& threadGroup)
{
// Add wallet transactions that aren't already in a block to mempool
@@ -3587,7 +3614,9 @@ void CWallet::postInitProcess(boost::thread_group& threadGroup)
ReacceptWalletTransactions();
// Run a thread to flush wallet periodically
- threadGroup.create_thread(boost::bind(&ThreadFlushWalletDB, boost::ref(this->strWalletFile)));
+ if (!CWallet::fFlushThreadRunning.exchange(true)) {
+ threadGroup.create_thread(ThreadFlushWalletDB);
+ }
}
bool CWallet::ParameterInteraction()
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index a97a5e5a7e..79ef96c911 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -18,6 +18,7 @@
#include "wallet/rpcwallet.h"
#include <algorithm>
+#include <atomic>
#include <map>
#include <set>
#include <stdexcept>
@@ -558,6 +559,8 @@ private:
class CWallet : public CCryptoKeyStore, public CValidationInterface
{
private:
+ static std::atomic<bool> fFlushThreadRunning;
+
/**
* Select a set of coins such that nValueRet >= nTargetValue and at least
* all coins from coinControl are selected; Never select unconfirmed coins
@@ -920,6 +923,7 @@ public:
static std::string GetWalletHelpString(bool showDebug);
/* Initializes the wallet, returns a new CWallet instance or a null pointer in case of an error */
+ static CWallet* CreateWalletFromFile(const std::string walletFile);
static bool InitLoadWallet();
/**
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index 0395e4a072..855fe7f74f 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -768,7 +768,7 @@ DBErrors CWalletDB::ZapWalletTx(CWallet* pwallet, vector<CWalletTx>& vWtx)
return DB_LOAD_OK;
}
-void ThreadFlushWalletDB(const string& strFile)
+void ThreadFlushWalletDB()
{
// Make this thread recognisable as the wallet flushing thread
RenameThread("bitcoin-wallet");
@@ -810,6 +810,7 @@ void ThreadFlushWalletDB(const string& strFile)
if (nRefCount == 0)
{
boost::this_thread::interruption_point();
+ const std::string& strFile = pwalletMain->strWalletFile;
map<string, int>::iterator _mi = bitdb.mapFileUseCount.find(strFile);
if (_mi != bitdb.mapFileUseCount.end())
{
diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h
index eb25ac613d..efb5e54786 100644
--- a/src/wallet/walletdb.h
+++ b/src/wallet/walletdb.h
@@ -182,6 +182,6 @@ private:
};
-void ThreadFlushWalletDB(const std::string& strFile);
+void ThreadFlushWalletDB();
#endif // BITCOIN_WALLET_WALLETDB_H