aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/index/base.h2
-rw-r--r--src/net_processing.cpp2
-rw-r--r--src/qt/test/rpcnestedtests.cpp23
-rw-r--r--src/rpc/misc.cpp2
-rw-r--r--src/rpc/server.cpp5
-rw-r--r--src/rpc/util.cpp109
-rw-r--r--src/rpc/util.h9
-rw-r--r--src/sync.h4
-rw-r--r--src/test/rpc_tests.cpp35
-rw-r--r--src/txorphanage.h4
-rw-r--r--src/wallet/rpcwallet.cpp2
-rw-r--r--src/wallet/wallet.h2
12 files changed, 175 insertions, 24 deletions
diff --git a/src/index/base.h b/src/index/base.h
index 8559e3cb64..ac3c429a5a 100644
--- a/src/index/base.h
+++ b/src/index/base.h
@@ -109,7 +109,7 @@ public:
/// sync once and only needs to process blocks in the ValidationInterface
/// queue. If the index is catching up from far behind, this method does
/// not block and immediately returns false.
- bool BlockUntilSyncedToCurrentChain() const;
+ bool BlockUntilSyncedToCurrentChain() const LOCKS_EXCLUDED(::cs_main);
void Interrupt();
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 4108de2c8a..d98d47fd2a 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -448,7 +448,7 @@ private:
/** Determine whether or not a peer can request a transaction, and return it (or nullptr if not found or not allowed). */
CTransactionRef FindTxForGetData(const CNode& peer, const GenTxid& gtxid, const std::chrono::seconds mempool_req, const std::chrono::seconds now) LOCKS_EXCLUDED(cs_main);
- void ProcessGetData(CNode& pfrom, Peer& peer, const std::atomic<bool>& interruptMsgProc) EXCLUSIVE_LOCKS_REQUIRED(!cs_main, peer.m_getdata_requests_mutex);
+ void ProcessGetData(CNode& pfrom, Peer& peer, const std::atomic<bool>& interruptMsgProc) EXCLUSIVE_LOCKS_REQUIRED(peer.m_getdata_requests_mutex) LOCKS_EXCLUDED(::cs_main);
/** Relay map (txid or wtxid -> CTransactionRef) */
typedef std::map<uint256, CTransactionRef> MapRelay;
diff --git a/src/qt/test/rpcnestedtests.cpp b/src/qt/test/rpcnestedtests.cpp
index 0d9928d363..9e6e98b274 100644
--- a/src/qt/test/rpcnestedtests.cpp
+++ b/src/qt/test/rpcnestedtests.cpp
@@ -11,8 +11,10 @@
#include <univalue.h>
#include <util/system.h>
-#include <QDir>
-#include <QtGlobal>
+#include <QTest>
+
+#include <string>
+#include <stdexcept>
static RPCHelpMan rpcNestedTest_rpc()
{
@@ -24,9 +26,9 @@ static RPCHelpMan rpcNestedTest_rpc()
{"arg2", RPCArg::Type::STR, RPCArg::Optional::OMITTED, ""},
{"arg3", RPCArg::Type::STR, RPCArg::Optional::OMITTED, ""},
},
- {},
+ RPCResult{RPCResult::Type::ANY, "", ""},
RPCExamples{""},
- [](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue {
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue {
return request.params.write(0, 0);
},
};
@@ -68,13 +70,13 @@ void RPCNestedTests::rpcNestedTests()
RPCConsole::RPCExecuteCommandLine(m_node, result, "getblockchaininfo "); //whitespace at the end will be tolerated
QVERIFY(result.substr(0,1) == "{");
- (RPCConsole::RPCExecuteCommandLine(m_node, result, "getblockchaininfo()[\"chain\"]")); //Quote path identifier are allowed, but look after a child containing the quotes in the key
+ RPCConsole::RPCExecuteCommandLine(m_node, result, "getblockchaininfo()[\"chain\"]"); //Quote path identifier are allowed, but look after a child containing the quotes in the key
QVERIFY(result == "null");
- (RPCConsole::RPCExecuteCommandLine(m_node, result, "createrawtransaction [] {} 0")); //parameter not in brackets are allowed
- (RPCConsole::RPCExecuteCommandLine(m_node, result2, "createrawtransaction([],{},0)")); //parameter in brackets are allowed
+ RPCConsole::RPCExecuteCommandLine(m_node, result, "createrawtransaction [] {} 0"); //parameter not in brackets are allowed
+ RPCConsole::RPCExecuteCommandLine(m_node, result2, "createrawtransaction([],{},0)"); //parameter in brackets are allowed
QVERIFY(result == result2);
- (RPCConsole::RPCExecuteCommandLine(m_node, result2, "createrawtransaction( [], {} , 0 )")); //whitespace between parameters is allowed
+ RPCConsole::RPCExecuteCommandLine(m_node, result2, "createrawtransaction( [], {} , 0 )"); //whitespace between parameters is allowed
QVERIFY(result == result2);
RPCConsole::RPCExecuteCommandLine(m_node, result, "getblock(getbestblockhash())[tx][0]", &filtered);
@@ -123,11 +125,10 @@ void RPCNestedTests::rpcNestedTests()
RPCConsole::RPCExecuteCommandLine(m_node, result, "rpcNestedTest( abc , cba )");
QVERIFY(result == "[\"abc\",\"cba\"]");
- // do the QVERIFY_EXCEPTION_THROWN checks only with Qt5.3 and higher (QVERIFY_EXCEPTION_THROWN was introduced in Qt5.3)
QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(m_node, result, "getblockchaininfo() .\n"), std::runtime_error); //invalid syntax
QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(m_node, result, "getblockchaininfo() getblockchaininfo()"), std::runtime_error); //invalid syntax
- (RPCConsole::RPCExecuteCommandLine(m_node, result, "getblockchaininfo(")); //tolerate non closing brackets if we have no arguments
- (RPCConsole::RPCExecuteCommandLine(m_node, result, "getblockchaininfo()()()")); //tolerate non command brackets
+ RPCConsole::RPCExecuteCommandLine(m_node, result, "getblockchaininfo("); //tolerate non closing brackets if we have no arguments
+ RPCConsole::RPCExecuteCommandLine(m_node, result, "getblockchaininfo()()()"); //tolerate non command brackets
QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(m_node, result, "getblockchaininfo(True)"), UniValue); //invalid argument
QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(m_node, result, "a(getblockchaininfo(True))"), UniValue); //method not found
QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(m_node, result, "rpcNestedTest abc,,abc"), std::runtime_error); //don't tolerate empty arguments when using ,
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp
index 1df5c51718..8e98919391 100644
--- a/src/rpc/misc.cpp
+++ b/src/rpc/misc.cpp
@@ -628,7 +628,7 @@ static RPCHelpMan echo(const std::string& name)
{"arg8", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, ""},
{"arg9", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, ""},
},
- RPCResult{RPCResult::Type::NONE, "", "Returns whatever was passed in"},
+ RPCResult{RPCResult::Type::ANY, "", "Returns whatever was passed in"},
RPCExamples{""},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp
index 2f05c8842f..5d816ba5bb 100644
--- a/src/rpc/server.cpp
+++ b/src/rpc/server.cpp
@@ -137,8 +137,9 @@ static RPCHelpMan help()
{
{"command", RPCArg::Type::STR, /* default */ "all commands", "The command to get help on"},
},
- RPCResult{
- RPCResult::Type::STR, "", "The help text"
+ {
+ RPCResult{RPCResult::Type::STR, "", "The help text"},
+ RPCResult{RPCResult::Type::ANY, "", ""},
},
RPCExamples{""},
[&](const RPCHelpMan& self, const JSONRPCRequest& jsonRequest) -> UniValue
diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp
index 44e58cb75f..ba3105ca01 100644
--- a/src/rpc/util.cpp
+++ b/src/rpc/util.cpp
@@ -113,17 +113,80 @@ std::vector<unsigned char> ParseHexO(const UniValue& o, std::string strKey)
return ParseHexV(find_value(o, strKey), strKey);
}
+namespace {
+
+/**
+ * Quote an argument for shell.
+ *
+ * @note This is intended for help, not for security-sensitive purposes.
+ */
+std::string ShellQuote(const std::string& s)
+{
+ std::string result;
+ result.reserve(s.size() * 2);
+ for (const char ch: s) {
+ if (ch == '\'') {
+ result += "'\''";
+ } else {
+ result += ch;
+ }
+ }
+ return "'" + result + "'";
+}
+
+/**
+ * Shell-quotes the argument if it needs quoting, else returns it literally, to save typing.
+ *
+ * @note This is intended for help, not for security-sensitive purposes.
+ */
+std::string ShellQuoteIfNeeded(const std::string& s)
+{
+ for (const char ch: s) {
+ if (ch == ' ' || ch == '\'' || ch == '"') {
+ return ShellQuote(s);
+ }
+ }
+
+ return s;
+}
+
+}
+
std::string HelpExampleCli(const std::string& methodname, const std::string& args)
{
return "> bitcoin-cli " + methodname + " " + args + "\n";
}
+std::string HelpExampleCliNamed(const std::string& methodname, const RPCArgList& args)
+{
+ std::string result = "> bitcoin-cli -named " + methodname;
+ for (const auto& argpair: args) {
+ const auto& value = argpair.second.isStr()
+ ? argpair.second.get_str()
+ : argpair.second.write();
+ result += " " + argpair.first + "=" + ShellQuoteIfNeeded(value);
+ }
+ result += "\n";
+ return result;
+}
+
std::string HelpExampleRpc(const std::string& methodname, const std::string& args)
{
return "> curl --user myusername --data-binary '{\"jsonrpc\": \"1.0\", \"id\": \"curltest\", "
"\"method\": \"" + methodname + "\", \"params\": [" + args + "]}' -H 'content-type: text/plain;' http://127.0.0.1:8332/\n";
}
+std::string HelpExampleRpcNamed(const std::string& methodname, const RPCArgList& args)
+{
+ UniValue params(UniValue::VOBJ);
+ for (const auto& param: args) {
+ params.pushKV(param.first, param.second);
+ }
+
+ return "> curl --user myusername --data-binary '{\"jsonrpc\": \"1.0\", \"id\": \"curltest\", "
+ "\"method\": \"" + methodname + "\", \"params\": " + params.write() + "}' -H 'content-type: text/plain;' http://127.0.0.1:8332/\n";
+}
+
// Converts a hex string to a public key if possible
CPubKey HexToPubKey(const std::string& hex_in)
{
@@ -442,6 +505,7 @@ std::string RPCResults::ToDescriptionString() const
{
std::string result;
for (const auto& r : m_results) {
+ if (r.m_type == RPCResult::Type::ANY) continue; // for testing only
if (r.m_cond.empty()) {
result += "\nResult:\n";
} else {
@@ -459,7 +523,7 @@ std::string RPCExamples::ToDescriptionString() const
return m_examples.empty() ? m_examples : "\nExamples:\n" + m_examples;
}
-UniValue RPCHelpMan::HandleRequest(const JSONRPCRequest& request)
+UniValue RPCHelpMan::HandleRequest(const JSONRPCRequest& request) const
{
if (request.mode == JSONRPCRequest::GET_ARGS) {
return GetArgMap();
@@ -471,7 +535,9 @@ UniValue RPCHelpMan::HandleRequest(const JSONRPCRequest& request)
if (request.mode == JSONRPCRequest::GET_HELP || !IsValidNumArgs(request.params.size())) {
throw std::runtime_error(ToString());
}
- return m_fun(*this, request);
+ const UniValue ret = m_fun(*this, request);
+ CHECK_NONFATAL(std::any_of(m_results.m_results.begin(), m_results.m_results.end(), [ret](const RPCResult& res) { return res.MatchesType(ret); }));
+ return ret;
}
bool RPCHelpMan::IsValidNumArgs(size_t num_args) const
@@ -677,6 +743,9 @@ void RPCResult::ToSections(Sections& sections, const OuterType outer_type, const
sections.PushSection({indent + "..." + maybe_separator, m_description});
return;
}
+ case Type::ANY: {
+ CHECK_NONFATAL(false); // Only for testing
+ }
case Type::NONE: {
sections.PushSection({indent + "null" + maybe_separator, Description("json null")});
return;
@@ -742,6 +811,42 @@ void RPCResult::ToSections(Sections& sections, const OuterType outer_type, const
CHECK_NONFATAL(false);
}
+bool RPCResult::MatchesType(const UniValue& result) const
+{
+ switch (m_type) {
+ case Type::ELISION: {
+ return false;
+ }
+ case Type::ANY: {
+ return true;
+ }
+ case Type::NONE: {
+ return UniValue::VNULL == result.getType();
+ }
+ case Type::STR:
+ case Type::STR_HEX: {
+ return UniValue::VSTR == result.getType();
+ }
+ case Type::NUM:
+ case Type::STR_AMOUNT:
+ case Type::NUM_TIME: {
+ return UniValue::VNUM == result.getType();
+ }
+ case Type::BOOL: {
+ return UniValue::VBOOL == result.getType();
+ }
+ case Type::ARR_FIXED:
+ case Type::ARR: {
+ return UniValue::VARR == result.getType();
+ }
+ case Type::OBJ_DYN:
+ case Type::OBJ: {
+ return UniValue::VOBJ == result.getType();
+ }
+ } // no default case, so the compiler can warn about missing cases
+ CHECK_NONFATAL(false);
+}
+
std::string RPCArg::ToStringObj(const bool oneline) const
{
std::string res;
diff --git a/src/rpc/util.h b/src/rpc/util.h
index 94c2d2d626..6e783e19fb 100644
--- a/src/rpc/util.h
+++ b/src/rpc/util.h
@@ -78,8 +78,12 @@ extern std::vector<unsigned char> ParseHexV(const UniValue& v, std::string strNa
extern std::vector<unsigned char> ParseHexO(const UniValue& o, std::string strKey);
extern CAmount AmountFromValue(const UniValue& value);
+
+using RPCArgList = std::vector<std::pair<std::string, UniValue>>;
extern std::string HelpExampleCli(const std::string& methodname, const std::string& args);
+extern std::string HelpExampleCliNamed(const std::string& methodname, const RPCArgList& args);
extern std::string HelpExampleRpc(const std::string& methodname, const std::string& args);
+extern std::string HelpExampleRpcNamed(const std::string& methodname, const RPCArgList& args);
CPubKey HexToPubKey(const std::string& hex_in);
CPubKey AddrToPubKey(const FillableSigningProvider& keystore, const std::string& addr_in);
@@ -223,6 +227,7 @@ struct RPCResult {
NUM,
BOOL,
NONE,
+ ANY, //!< Special type to disable type checks (for testing only)
STR_AMOUNT, //!< Special string to represent a floating point amount
STR_HEX, //!< Special string with only hex chars
OBJ_DYN, //!< Special dictionary with keys that are not literals
@@ -295,6 +300,8 @@ struct RPCResult {
std::string ToStringObj() const;
/** Return the description string, including the result type. */
std::string ToDescriptionString() const;
+ /** Check whether the result JSON type matches. */
+ bool MatchesType(const UniValue& result) const;
};
struct RPCResults {
@@ -333,7 +340,7 @@ public:
using RPCMethodImpl = std::function<UniValue(const RPCHelpMan&, const JSONRPCRequest&)>;
RPCHelpMan(std::string name, std::string description, std::vector<RPCArg> args, RPCResults results, RPCExamples examples, RPCMethodImpl fun);
- UniValue HandleRequest(const JSONRPCRequest& request);
+ UniValue HandleRequest(const JSONRPCRequest& request) const;
std::string ToString() const;
/** Return the named args that need to be converted from string to another JSON type */
UniValue GetArgMap() const;
diff --git a/src/sync.h b/src/sync.h
index 53213c2089..146c228592 100644
--- a/src/sync.h
+++ b/src/sync.h
@@ -56,7 +56,7 @@ std::string LocksHeld();
template <typename MutexType>
void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) EXCLUSIVE_LOCKS_REQUIRED(cs);
template <typename MutexType>
-void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) EXCLUSIVE_LOCKS_REQUIRED(!cs);
+void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) LOCKS_EXCLUDED(cs);
void DeleteLock(void* cs);
bool LockStackEmpty();
@@ -74,7 +74,7 @@ inline void CheckLastCritical(void* cs, std::string& lockname, const char* guard
template <typename MutexType>
inline void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) EXCLUSIVE_LOCKS_REQUIRED(cs) {}
template <typename MutexType>
-void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) EXCLUSIVE_LOCKS_REQUIRED(!cs) {}
+void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) LOCKS_EXCLUDED(cs) {}
inline void DeleteLock(void* cs) {}
inline bool LockStackEmpty() { return true; }
#endif
diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp
index 67e70b3bc3..7c50c72041 100644
--- a/src/test/rpc_tests.cpp
+++ b/src/test/rpc_tests.cpp
@@ -431,4 +431,39 @@ BOOST_AUTO_TEST_CASE(rpc_getblockstats_calculate_percentiles_by_weight)
}
}
+BOOST_AUTO_TEST_CASE(help_example)
+{
+ // test different argument types
+ const RPCArgList& args = {{"foo", "bar"}, {"b", true}, {"n", 1}};
+ BOOST_CHECK_EQUAL(HelpExampleCliNamed("test", args), "> bitcoin-cli -named test foo=bar b=true n=1\n");
+ BOOST_CHECK_EQUAL(HelpExampleRpcNamed("test", args), "> curl --user myusername --data-binary '{\"jsonrpc\": \"1.0\", \"id\": \"curltest\", \"method\": \"test\", \"params\": {\"foo\":\"bar\",\"b\":true,\"n\":1}}' -H 'content-type: text/plain;' http://127.0.0.1:8332/\n");
+
+ // test shell escape
+ BOOST_CHECK_EQUAL(HelpExampleCliNamed("test", {{"foo", "b'ar"}}), "> bitcoin-cli -named test foo='b'''ar'\n");
+ BOOST_CHECK_EQUAL(HelpExampleCliNamed("test", {{"foo", "b\"ar"}}), "> bitcoin-cli -named test foo='b\"ar'\n");
+ BOOST_CHECK_EQUAL(HelpExampleCliNamed("test", {{"foo", "b ar"}}), "> bitcoin-cli -named test foo='b ar'\n");
+
+ // test object params
+ UniValue obj_value(UniValue::VOBJ);
+ obj_value.pushKV("foo", "bar");
+ obj_value.pushKV("b", false);
+ obj_value.pushKV("n", 1);
+ BOOST_CHECK_EQUAL(HelpExampleCliNamed("test", {{"name", obj_value}}), "> bitcoin-cli -named test name='{\"foo\":\"bar\",\"b\":false,\"n\":1}'\n");
+ BOOST_CHECK_EQUAL(HelpExampleRpcNamed("test", {{"name", obj_value}}), "> curl --user myusername --data-binary '{\"jsonrpc\": \"1.0\", \"id\": \"curltest\", \"method\": \"test\", \"params\": {\"name\":{\"foo\":\"bar\",\"b\":false,\"n\":1}}}' -H 'content-type: text/plain;' http://127.0.0.1:8332/\n");
+
+ // test array params
+ UniValue arr_value(UniValue::VARR);
+ arr_value.push_back("bar");
+ arr_value.push_back(false);
+ arr_value.push_back(1);
+ BOOST_CHECK_EQUAL(HelpExampleCliNamed("test", {{"name", arr_value}}), "> bitcoin-cli -named test name='[\"bar\",false,1]'\n");
+ BOOST_CHECK_EQUAL(HelpExampleRpcNamed("test", {{"name", arr_value}}), "> curl --user myusername --data-binary '{\"jsonrpc\": \"1.0\", \"id\": \"curltest\", \"method\": \"test\", \"params\": {\"name\":[\"bar\",false,1]}}' -H 'content-type: text/plain;' http://127.0.0.1:8332/\n");
+
+ // test types don't matter for shell
+ BOOST_CHECK_EQUAL(HelpExampleCliNamed("foo", {{"arg", true}}), HelpExampleCliNamed("foo", {{"arg", "true"}}));
+
+ // test types matter for Rpc
+ BOOST_CHECK_NE(HelpExampleRpcNamed("foo", {{"arg", true}}), HelpExampleRpcNamed("foo", {{"arg", "true"}}));
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/txorphanage.h b/src/txorphanage.h
index df55cdb3be..dc9fa87dbb 100644
--- a/src/txorphanage.h
+++ b/src/txorphanage.h
@@ -24,7 +24,7 @@ public:
bool AddTx(const CTransactionRef& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(g_cs_orphans);
/** Check if we already have an orphan transaction (by txid or wtxid) */
- bool HaveTx(const GenTxid& gtxid) const EXCLUSIVE_LOCKS_REQUIRED(!g_cs_orphans);
+ bool HaveTx(const GenTxid& gtxid) const LOCKS_EXCLUDED(::g_cs_orphans);
/** Get an orphan transaction and its orginating peer
* (Transaction ref will be nullptr if not found)
@@ -38,7 +38,7 @@ public:
void EraseForPeer(NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(g_cs_orphans);
/** Erase all orphans included in or invalidated by a new block */
- void EraseForBlock(const CBlock& block) EXCLUSIVE_LOCKS_REQUIRED(!g_cs_orphans);
+ void EraseForBlock(const CBlock& block) LOCKS_EXCLUDED(::g_cs_orphans);
/** Limit the orphanage to the given maximum */
unsigned int LimitOrphans(unsigned int max_orphans) EXCLUSIVE_LOCKS_REQUIRED(g_cs_orphans);
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index df26f039a0..45f292055e 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -2711,6 +2711,8 @@ static RPCHelpMan createwallet()
RPCExamples{
HelpExampleCli("createwallet", "\"testwallet\"")
+ HelpExampleRpc("createwallet", "\"testwallet\"")
+ + HelpExampleCliNamed("createwallet", {{"wallet_name", "descriptors"}, {"avoid_reuse", true}, {"descriptors", true}, {"load_on_startup", true}})
+ + HelpExampleRpcNamed("createwallet", {{"wallet_name", "descriptors"}, {"avoid_reuse", true}, {"descriptors", true}, {"load_on_startup", true}})
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 6031d36b97..192fd60dc2 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -1181,7 +1181,7 @@ public:
* Obviously holding cs_main/cs_wallet when going into this call may cause
* deadlock
*/
- void BlockUntilSyncedToCurrentChain() const EXCLUSIVE_LOCKS_REQUIRED(!::cs_main, !cs_wallet);
+ void BlockUntilSyncedToCurrentChain() const LOCKS_EXCLUDED(::cs_main) EXCLUSIVE_LOCKS_REQUIRED(!cs_wallet);
/** set a single wallet flag */
void SetWalletFlag(uint64_t flags);