aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am5
-rw-r--r--src/Makefile.test.include2
-rw-r--r--src/attributes.h15
-rw-r--r--src/base58.cpp4
-rw-r--r--src/base58.h4
-rw-r--r--src/bench/prevector.cpp12
-rw-r--r--src/core_io.h4
-rw-r--r--src/hash.h2
-rw-r--r--src/httprpc.cpp22
-rw-r--r--src/init.cpp13
-rw-r--r--src/interfaces/node.cpp303
-rw-r--r--src/node/interfaces.cpp (renamed from src/interfaces/chain.cpp)286
-rw-r--r--src/node/transaction.h2
-rw-r--r--src/outputtype.h2
-rw-r--r--src/policy/policy.cpp17
-rw-r--r--src/policy/policy.h12
-rw-r--r--src/psbt.h8
-rw-r--r--src/pubkey.h9
-rw-r--r--src/qt/askpassphrasedialog.cpp2
-rw-r--r--src/qt/bantablemodel.cpp3
-rw-r--r--src/qt/guiutil.cpp3
-rw-r--r--src/qt/notificator.cpp5
-rw-r--r--src/script/descriptor.cpp2
-rw-r--r--src/script/interpreter.cpp6
-rw-r--r--src/span.h37
-rw-r--r--src/sync.cpp56
-rw-r--r--src/sync.h14
-rw-r--r--src/test/coins_tests.cpp2
-rw-r--r--src/test/fuzz/addition_overflow.cpp2
-rw-r--r--src/test/fuzz/addrman.cpp14
-rw-r--r--src/test/fuzz/multiplication_overflow.cpp2
-rw-r--r--src/test/fuzz/util.h47
-rw-r--r--src/test/sync_tests.cpp53
-rw-r--r--src/test/util/setup_common.cpp3
-rw-r--r--src/txmempool.cpp19
-rw-r--r--src/txmempool.h17
-rw-r--r--src/util/bip32.h2
-rw-r--r--src/util/moneystr.h2
-rw-r--r--src/util/strencodings.cpp2
-rw-r--r--src/util/strencodings.h14
-rw-r--r--src/util/string.h6
-rw-r--r--src/util/system.h8
-rw-r--r--src/validation.cpp6
-rw-r--r--src/wallet/interfaces.cpp (renamed from src/interfaces/wallet.cpp)25
-rw-r--r--src/wallet/rpcwallet.cpp6
-rw-r--r--src/wallet/wallet.cpp56
-rw-r--r--src/wallet/wallet.h13
-rw-r--r--src/wallet/walletdb.cpp2
48 files changed, 639 insertions, 512 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 7d70d02a4f..4a080ef1fb 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -298,14 +298,13 @@ libbitcoin_server_a_SOURCES = \
index/blockfilterindex.cpp \
index/txindex.cpp \
init.cpp \
- interfaces/chain.cpp \
- interfaces/node.cpp \
miner.cpp \
net.cpp \
net_processing.cpp \
node/coin.cpp \
node/coinstats.cpp \
node/context.cpp \
+ node/interfaces.cpp \
node/psbt.cpp \
node/transaction.cpp \
node/ui_interface.cpp \
@@ -358,13 +357,13 @@ endif
libbitcoin_wallet_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(SQLITE_CFLAGS)
libbitcoin_wallet_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_wallet_a_SOURCES = \
- interfaces/wallet.cpp \
wallet/coincontrol.cpp \
wallet/context.cpp \
wallet/crypter.cpp \
wallet/db.cpp \
wallet/feebumper.cpp \
wallet/fees.cpp \
+ wallet/interfaces.cpp \
wallet/load.cpp \
wallet/rpcdump.cpp \
wallet/rpcwallet.cpp \
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index 87166ecb79..f4c726b0b2 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -1105,7 +1105,7 @@ test_fuzz_script_interpreter_SOURCES = test/fuzz/script_interpreter.cpp
test_fuzz_script_assets_test_minimizer_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_script_assets_test_minimizer_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_script_assets_test_minimizer_LDADD = $(FUZZ_SUITE_LD_COMMON)
-test_fuzz_script_assets_test_minimizer_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_script_assets_test_minimizer_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
test_fuzz_script_assets_test_minimizer_SOURCES = test/fuzz/script_assets_test_minimizer.cpp
test_fuzz_script_ops_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
diff --git a/src/attributes.h b/src/attributes.h
index 45099bd8b8..995c24e13f 100644
--- a/src/attributes.h
+++ b/src/attributes.h
@@ -6,17 +6,14 @@
#ifndef BITCOIN_ATTRIBUTES_H
#define BITCOIN_ATTRIBUTES_H
-#if defined(__has_cpp_attribute)
-# if __has_cpp_attribute(nodiscard)
-# define NODISCARD [[nodiscard]]
-# endif
-#endif
-#ifndef NODISCARD
-# if defined(_MSC_VER) && _MSC_VER >= 1700
-# define NODISCARD _Check_return_
+#if defined(__clang__)
+# if __has_attribute(lifetimebound)
+# define LIFETIMEBOUND [[clang::lifetimebound]]
# else
-# define NODISCARD __attribute__((warn_unused_result))
+# define LIFETIMEBOUND
# endif
+#else
+# define LIFETIMEBOUND
#endif
#endif // BITCOIN_ATTRIBUTES_H
diff --git a/src/base58.cpp b/src/base58.cpp
index 0dc6044145..780846c6c5 100644
--- a/src/base58.cpp
+++ b/src/base58.cpp
@@ -35,7 +35,7 @@ static const int8_t mapBase58[256] = {
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
};
-NODISCARD static bool DecodeBase58(const char* psz, std::vector<unsigned char>& vch, int max_ret_len)
+[[nodiscard]] static bool DecodeBase58(const char* psz, std::vector<unsigned char>& vch, int max_ret_len)
{
// Skip leading spaces.
while (*psz && IsSpace(*psz))
@@ -141,7 +141,7 @@ std::string EncodeBase58Check(Span<const unsigned char> input)
return EncodeBase58(vch);
}
-NODISCARD static bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet, int max_ret_len)
+[[nodiscard]] static bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet, int max_ret_len)
{
if (!DecodeBase58(psz, vchRet, max_ret_len > std::numeric_limits<int>::max() - 4 ? std::numeric_limits<int>::max() : max_ret_len + 4) ||
(vchRet.size() < 4)) {
diff --git a/src/base58.h b/src/base58.h
index 468c3e2589..60551a12ae 100644
--- a/src/base58.h
+++ b/src/base58.h
@@ -29,7 +29,7 @@ std::string EncodeBase58(Span<const unsigned char> input);
* Decode a base58-encoded string (str) into a byte vector (vchRet).
* return true if decoding is successful.
*/
-NODISCARD bool DecodeBase58(const std::string& str, std::vector<unsigned char>& vchRet, int max_ret_len);
+[[nodiscard]] bool DecodeBase58(const std::string& str, std::vector<unsigned char>& vchRet, int max_ret_len);
/**
* Encode a byte span into a base58-encoded string, including checksum
@@ -40,6 +40,6 @@ std::string EncodeBase58Check(Span<const unsigned char> input);
* Decode a base58-encoded string (str) that includes a checksum into a byte
* vector (vchRet), return true if decoding is successful
*/
-NODISCARD bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRet, int max_ret_len);
+[[nodiscard]] bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRet, int max_ret_len);
#endif // BITCOIN_BASE58_H
diff --git a/src/bench/prevector.cpp b/src/bench/prevector.cpp
index a2dbefa54a..73af244ce0 100644
--- a/src/bench/prevector.cpp
+++ b/src/bench/prevector.cpp
@@ -9,24 +9,16 @@
#include <bench/bench.h>
-// GCC 4.8 is missing some C++11 type_traits,
-// https://www.gnu.org/software/gcc/gcc-5/changes.html
-#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 5
-#define IS_TRIVIALLY_CONSTRUCTIBLE std::has_trivial_default_constructor
-#else
-#define IS_TRIVIALLY_CONSTRUCTIBLE std::is_trivially_default_constructible
-#endif
-
struct nontrivial_t {
int x;
nontrivial_t() :x(-1) {}
SERIALIZE_METHODS(nontrivial_t, obj) { READWRITE(obj.x); }
};
-static_assert(!IS_TRIVIALLY_CONSTRUCTIBLE<nontrivial_t>::value,
+static_assert(!std::is_trivially_default_constructible<nontrivial_t>::value,
"expected nontrivial_t to not be trivially constructible");
typedef unsigned char trivial_t;
-static_assert(IS_TRIVIALLY_CONSTRUCTIBLE<trivial_t>::value,
+static_assert(std::is_trivially_default_constructible<trivial_t>::value,
"expected trivial_t to be trivially constructible");
template <typename T>
diff --git a/src/core_io.h b/src/core_io.h
index 80ec80cd50..aaee9c445d 100644
--- a/src/core_io.h
+++ b/src/core_io.h
@@ -22,8 +22,8 @@ class UniValue;
// core_read.cpp
CScript ParseScript(const std::string& s);
std::string ScriptToAsmStr(const CScript& script, const bool fAttemptSighashDecode = false);
-NODISCARD bool DecodeHexTx(CMutableTransaction& tx, const std::string& hex_tx, bool try_no_witness = false, bool try_witness = true);
-NODISCARD bool DecodeHexBlk(CBlock&, const std::string& strHexBlk);
+[[nodiscard]] bool DecodeHexTx(CMutableTransaction& tx, const std::string& hex_tx, bool try_no_witness = false, bool try_witness = true);
+[[nodiscard]] bool DecodeHexBlk(CBlock&, const std::string& strHexBlk);
bool DecodeHexBlockHeader(CBlockHeader&, const std::string& hex_header);
/**
diff --git a/src/hash.h b/src/hash.h
index 6d876076ee..083ac12523 100644
--- a/src/hash.h
+++ b/src/hash.h
@@ -197,7 +197,7 @@ uint256 SerializeHash(const T& obj, int nType=SER_GETHASH, int nVersion=PROTOCOL
}
/** Single-SHA256 a 32-byte input (represented as uint256). */
-NODISCARD uint256 SHA256Uint256(const uint256& input);
+[[nodiscard]] uint256 SHA256Uint256(const uint256& input);
unsigned int MurmurHash3(unsigned int nHashSeed, Span<const unsigned char> vDataToHash);
diff --git a/src/httprpc.cpp b/src/httprpc.cpp
index f1b9997371..cb8b220895 100644
--- a/src/httprpc.cpp
+++ b/src/httprpc.cpp
@@ -68,6 +68,8 @@ private:
static std::string strRPCUserColonPass;
/* Stored RPC timer interface (for unregistration) */
static std::unique_ptr<HTTPRPCTimerInterface> httpRPCTimerInterface;
+/* List of -rpcauth values */
+static std::vector<std::vector<std::string>> g_rpcauth;
/* RPC Auth Whitelist */
static std::map<std::string, std::set<std::string>> g_rpc_whitelist;
static bool g_rpc_whitelist_default = false;
@@ -99,15 +101,7 @@ static bool multiUserAuthorized(std::string strUserPass)
std::string strUser = strUserPass.substr(0, strUserPass.find(':'));
std::string strPass = strUserPass.substr(strUserPass.find(':') + 1);
- for (const std::string& strRPCAuth : gArgs.GetArgs("-rpcauth")) {
- //Search for multi-user login/pass "rpcauth" from config
- std::vector<std::string> vFields;
- boost::split(vFields, strRPCAuth, boost::is_any_of(":$"));
- if (vFields.size() != 3) {
- //Incorrect formatting in config file
- continue;
- }
-
+ for (const auto& vFields : g_rpcauth) {
std::string strName = vFields[0];
if (!TimingResistantEqual(strName, strUser)) {
continue;
@@ -259,6 +253,16 @@ static bool InitRPCAuthentication()
if (gArgs.GetArg("-rpcauth","") != "")
{
LogPrintf("Using rpcauth authentication.\n");
+ for (const std::string& rpcauth : gArgs.GetArgs("-rpcauth")) {
+ std::vector<std::string> fields;
+ boost::split(fields, rpcauth, boost::is_any_of(":$"));
+ if (fields.size() == 3) {
+ g_rpcauth.push_back(fields);
+ } else {
+ LogPrintf("Invalid -rpcauth argument.\n");
+ return false;
+ }
+ }
}
g_rpc_whitelist_default = gArgs.GetBoolArg("-rpcwhitelistdefault", gArgs.IsArgSet("-rpcwhitelist"));
diff --git a/src/init.cpp b/src/init.cpp
index 1e41616e94..9137050323 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -113,7 +113,7 @@ static fs::path GetPidFile(const ArgsManager& args)
return AbsPathForConfigVal(fs::path(args.GetArg("-pid", BITCOIN_PID_FILENAME)));
}
-NODISCARD static bool CreatePidFile(const ArgsManager& args)
+[[nodiscard]] static bool CreatePidFile(const ArgsManager& args)
{
fsbridge::ofstream file{GetPidFile(args)};
if (file) {
@@ -1389,16 +1389,9 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA
assert(!node.connman);
node.connman = MakeUnique<CConnman>(GetRand(std::numeric_limits<uint64_t>::max()), GetRand(std::numeric_limits<uint64_t>::max()), args.GetBoolArg("-networkactive", true));
- // Make mempool generally available in the node context. For example the connection manager, wallet, or RPC threads,
- // which are all started after this, may use it from the node context.
assert(!node.mempool);
- node.mempool = MakeUnique<CTxMemPool>(&::feeEstimator);
- if (node.mempool) {
- int ratio = std::min<int>(std::max<int>(args.GetArg("-checkmempool", chainparams.DefaultConsistencyChecks() ? 1 : 0), 0), 1000000);
- if (ratio != 0) {
- node.mempool->setSanityCheck(1.0 / ratio);
- }
- }
+ int check_ratio = std::min<int>(std::max<int>(args.GetArg("-checkmempool", chainparams.DefaultConsistencyChecks() ? 1 : 0), 0), 1000000);
+ node.mempool = MakeUnique<CTxMemPool>(&::feeEstimator, check_ratio);
assert(!node.chainman);
node.chainman = &g_chainman;
diff --git a/src/interfaces/node.cpp b/src/interfaces/node.cpp
deleted file mode 100644
index 2c5f8627e6..0000000000
--- a/src/interfaces/node.cpp
+++ /dev/null
@@ -1,303 +0,0 @@
-// Copyright (c) 2018-2020 The Bitcoin Core developers
-// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-#include <interfaces/node.h>
-
-#include <addrdb.h>
-#include <banman.h>
-#include <chain.h>
-#include <chainparams.h>
-#include <init.h>
-#include <interfaces/chain.h>
-#include <interfaces/handler.h>
-#include <interfaces/wallet.h>
-#include <net.h>
-#include <net_processing.h>
-#include <netaddress.h>
-#include <netbase.h>
-#include <node/context.h>
-#include <node/ui_interface.h>
-#include <policy/feerate.h>
-#include <policy/fees.h>
-#include <policy/settings.h>
-#include <primitives/block.h>
-#include <rpc/server.h>
-#include <shutdown.h>
-#include <support/allocators/secure.h>
-#include <sync.h>
-#include <txmempool.h>
-#include <util/check.h>
-#include <util/ref.h>
-#include <util/system.h>
-#include <util/translation.h>
-#include <validation.h>
-#include <warnings.h>
-
-#if defined(HAVE_CONFIG_H)
-#include <config/bitcoin-config.h>
-#endif
-
-#include <univalue.h>
-
-#include <boost/signals2/signal.hpp>
-
-namespace interfaces {
-namespace {
-
-class NodeImpl : public Node
-{
-public:
- NodeImpl(NodeContext* context) { setContext(context); }
- void initLogging() override { InitLogging(*Assert(m_context->args)); }
- void initParameterInteraction() override { InitParameterInteraction(*Assert(m_context->args)); }
- bilingual_str getWarnings() override { return GetWarnings(true); }
- uint32_t getLogCategories() override { return LogInstance().GetCategoryMask(); }
- bool baseInitialize() override
- {
- return AppInitBasicSetup(gArgs) && AppInitParameterInteraction(gArgs) && AppInitSanityChecks() &&
- AppInitLockDataDirectory() && AppInitInterfaces(*m_context);
- }
- bool appInitMain(interfaces::BlockAndHeaderTipInfo* tip_info) override
- {
- return AppInitMain(m_context_ref, *m_context, tip_info);
- }
- void appShutdown() override
- {
- Interrupt(*m_context);
- Shutdown(*m_context);
- }
- void startShutdown() override
- {
- StartShutdown();
- // Stop RPC for clean shutdown if any of waitfor* commands is executed.
- if (gArgs.GetBoolArg("-server", false)) {
- InterruptRPC();
- StopRPC();
- }
- }
- bool shutdownRequested() override { return ShutdownRequested(); }
- void mapPort(bool use_upnp) override
- {
- if (use_upnp) {
- StartMapPort();
- } else {
- InterruptMapPort();
- StopMapPort();
- }
- }
- bool getProxy(Network net, proxyType& proxy_info) override { return GetProxy(net, proxy_info); }
- size_t getNodeCount(CConnman::NumConnections flags) override
- {
- return m_context->connman ? m_context->connman->GetNodeCount(flags) : 0;
- }
- bool getNodesStats(NodesStats& stats) override
- {
- stats.clear();
-
- if (m_context->connman) {
- std::vector<CNodeStats> stats_temp;
- m_context->connman->GetNodeStats(stats_temp);
-
- stats.reserve(stats_temp.size());
- for (auto& node_stats_temp : stats_temp) {
- stats.emplace_back(std::move(node_stats_temp), false, CNodeStateStats());
- }
-
- // Try to retrieve the CNodeStateStats for each node.
- TRY_LOCK(::cs_main, lockMain);
- if (lockMain) {
- for (auto& node_stats : stats) {
- std::get<1>(node_stats) =
- GetNodeStateStats(std::get<0>(node_stats).nodeid, std::get<2>(node_stats));
- }
- }
- return true;
- }
- return false;
- }
- bool getBanned(banmap_t& banmap) override
- {
- if (m_context->banman) {
- m_context->banman->GetBanned(banmap);
- return true;
- }
- return false;
- }
- bool ban(const CNetAddr& net_addr, int64_t ban_time_offset) override
- {
- if (m_context->banman) {
- m_context->banman->Ban(net_addr, ban_time_offset);
- return true;
- }
- return false;
- }
- bool unban(const CSubNet& ip) override
- {
- if (m_context->banman) {
- m_context->banman->Unban(ip);
- return true;
- }
- return false;
- }
- bool disconnectByAddress(const CNetAddr& net_addr) override
- {
- if (m_context->connman) {
- return m_context->connman->DisconnectNode(net_addr);
- }
- return false;
- }
- bool disconnectById(NodeId id) override
- {
- if (m_context->connman) {
- return m_context->connman->DisconnectNode(id);
- }
- return false;
- }
- int64_t getTotalBytesRecv() override { return m_context->connman ? m_context->connman->GetTotalBytesRecv() : 0; }
- int64_t getTotalBytesSent() override { return m_context->connman ? m_context->connman->GetTotalBytesSent() : 0; }
- size_t getMempoolSize() override { return m_context->mempool ? m_context->mempool->size() : 0; }
- size_t getMempoolDynamicUsage() override { return m_context->mempool ? m_context->mempool->DynamicMemoryUsage() : 0; }
- bool getHeaderTip(int& height, int64_t& block_time) override
- {
- LOCK(::cs_main);
- if (::pindexBestHeader) {
- height = ::pindexBestHeader->nHeight;
- block_time = ::pindexBestHeader->GetBlockTime();
- return true;
- }
- return false;
- }
- int getNumBlocks() override
- {
- LOCK(::cs_main);
- return ::ChainActive().Height();
- }
- uint256 getBestBlockHash() override
- {
- const CBlockIndex* tip = WITH_LOCK(::cs_main, return ::ChainActive().Tip());
- return tip ? tip->GetBlockHash() : Params().GenesisBlock().GetHash();
- }
- int64_t getLastBlockTime() override
- {
- LOCK(::cs_main);
- if (::ChainActive().Tip()) {
- return ::ChainActive().Tip()->GetBlockTime();
- }
- return Params().GenesisBlock().GetBlockTime(); // Genesis block's time of current network
- }
- double getVerificationProgress() override
- {
- const CBlockIndex* tip;
- {
- LOCK(::cs_main);
- tip = ::ChainActive().Tip();
- }
- return GuessVerificationProgress(Params().TxData(), tip);
- }
- bool isInitialBlockDownload() override { return ::ChainstateActive().IsInitialBlockDownload(); }
- bool getReindex() override { return ::fReindex; }
- bool getImporting() override { return ::fImporting; }
- void setNetworkActive(bool active) override
- {
- if (m_context->connman) {
- m_context->connman->SetNetworkActive(active);
- }
- }
- bool getNetworkActive() override { return m_context->connman && m_context->connman->GetNetworkActive(); }
- CFeeRate estimateSmartFee(int num_blocks, bool conservative, int* returned_target = nullptr) override
- {
- FeeCalculation fee_calc;
- CFeeRate result = ::feeEstimator.estimateSmartFee(num_blocks, &fee_calc, conservative);
- if (returned_target) {
- *returned_target = fee_calc.returnedTarget;
- }
- return result;
- }
- CFeeRate getDustRelayFee() override { return ::dustRelayFee; }
- UniValue executeRpc(const std::string& command, const UniValue& params, const std::string& uri) override
- {
- JSONRPCRequest req(m_context_ref);
- req.params = params;
- req.strMethod = command;
- req.URI = uri;
- return ::tableRPC.execute(req);
- }
- std::vector<std::string> listRpcCommands() override { return ::tableRPC.listCommands(); }
- void rpcSetTimerInterfaceIfUnset(RPCTimerInterface* iface) override { RPCSetTimerInterfaceIfUnset(iface); }
- void rpcUnsetTimerInterface(RPCTimerInterface* iface) override { RPCUnsetTimerInterface(iface); }
- bool getUnspentOutput(const COutPoint& output, Coin& coin) override
- {
- LOCK(::cs_main);
- return ::ChainstateActive().CoinsTip().GetCoin(output, coin);
- }
- WalletClient& walletClient() override
- {
- return *Assert(m_context->wallet_client);
- }
- std::unique_ptr<Handler> handleInitMessage(InitMessageFn fn) override
- {
- return MakeHandler(::uiInterface.InitMessage_connect(fn));
- }
- std::unique_ptr<Handler> handleMessageBox(MessageBoxFn fn) override
- {
- return MakeHandler(::uiInterface.ThreadSafeMessageBox_connect(fn));
- }
- std::unique_ptr<Handler> handleQuestion(QuestionFn fn) override
- {
- return MakeHandler(::uiInterface.ThreadSafeQuestion_connect(fn));
- }
- std::unique_ptr<Handler> handleShowProgress(ShowProgressFn fn) override
- {
- return MakeHandler(::uiInterface.ShowProgress_connect(fn));
- }
- std::unique_ptr<Handler> handleNotifyNumConnectionsChanged(NotifyNumConnectionsChangedFn fn) override
- {
- return MakeHandler(::uiInterface.NotifyNumConnectionsChanged_connect(fn));
- }
- std::unique_ptr<Handler> handleNotifyNetworkActiveChanged(NotifyNetworkActiveChangedFn fn) override
- {
- return MakeHandler(::uiInterface.NotifyNetworkActiveChanged_connect(fn));
- }
- std::unique_ptr<Handler> handleNotifyAlertChanged(NotifyAlertChangedFn fn) override
- {
- return MakeHandler(::uiInterface.NotifyAlertChanged_connect(fn));
- }
- std::unique_ptr<Handler> handleBannedListChanged(BannedListChangedFn fn) override
- {
- return MakeHandler(::uiInterface.BannedListChanged_connect(fn));
- }
- std::unique_ptr<Handler> handleNotifyBlockTip(NotifyBlockTipFn fn) override
- {
- return MakeHandler(::uiInterface.NotifyBlockTip_connect([fn](SynchronizationState sync_state, const CBlockIndex* block) {
- fn(sync_state, BlockTip{block->nHeight, block->GetBlockTime(), block->GetBlockHash()},
- GuessVerificationProgress(Params().TxData(), block));
- }));
- }
- std::unique_ptr<Handler> handleNotifyHeaderTip(NotifyHeaderTipFn fn) override
- {
- return MakeHandler(
- ::uiInterface.NotifyHeaderTip_connect([fn](SynchronizationState sync_state, const CBlockIndex* block) {
- fn(sync_state, BlockTip{block->nHeight, block->GetBlockTime(), block->GetBlockHash()},
- /* verification progress is unused when a header was received */ 0);
- }));
- }
- NodeContext* context() override { return m_context; }
- void setContext(NodeContext* context) override
- {
- m_context = context;
- if (context) {
- m_context_ref.Set(*context);
- } else {
- m_context_ref.Clear();
- }
- }
- NodeContext* m_context{nullptr};
- util::Ref m_context_ref;
-};
-
-} // namespace
-
-std::unique_ptr<Node> MakeNode(NodeContext* context) { return MakeUnique<NodeImpl>(context); }
-
-} // namespace interfaces
diff --git a/src/interfaces/chain.cpp b/src/node/interfaces.cpp
index 4c5ebe66fc..77a5957a56 100644
--- a/src/interfaces/chain.cpp
+++ b/src/node/interfaces.cpp
@@ -2,18 +2,25 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <interfaces/chain.h>
-
+#include <addrdb.h>
+#include <banman.h>
+#include <boost/signals2/signal.hpp>
#include <chain.h>
#include <chainparams.h>
+#include <init.h>
+#include <interfaces/chain.h>
#include <interfaces/handler.h>
+#include <interfaces/node.h>
#include <interfaces/wallet.h>
#include <net.h>
#include <net_processing.h>
+#include <netaddress.h>
+#include <netbase.h>
#include <node/coin.h>
#include <node/context.h>
#include <node/transaction.h>
#include <node/ui_interface.h>
+#include <policy/feerate.h>
#include <policy/fees.h>
#include <policy/policy.h>
#include <policy/rbf.h>
@@ -23,20 +30,287 @@
#include <rpc/protocol.h>
#include <rpc/server.h>
#include <shutdown.h>
+#include <support/allocators/secure.h>
#include <sync.h>
#include <timedata.h>
#include <txmempool.h>
#include <uint256.h>
#include <univalue.h>
+#include <util/check.h>
+#include <util/ref.h>
#include <util/system.h>
+#include <util/translation.h>
#include <validation.h>
#include <validationinterface.h>
+#include <warnings.h>
+
+#if defined(HAVE_CONFIG_H)
+#include <config/bitcoin-config.h>
+#endif
#include <memory>
#include <utility>
-namespace interfaces {
+using interfaces::BlockTip;
+using interfaces::Chain;
+using interfaces::FoundBlock;
+using interfaces::Handler;
+using interfaces::MakeHandler;
+using interfaces::Node;
+using interfaces::WalletClient;
+
+namespace node {
namespace {
+class NodeImpl : public Node
+{
+public:
+ NodeImpl(NodeContext* context) { setContext(context); }
+ void initLogging() override { InitLogging(*Assert(m_context->args)); }
+ void initParameterInteraction() override { InitParameterInteraction(*Assert(m_context->args)); }
+ bilingual_str getWarnings() override { return GetWarnings(true); }
+ uint32_t getLogCategories() override { return LogInstance().GetCategoryMask(); }
+ bool baseInitialize() override
+ {
+ return AppInitBasicSetup(gArgs) && AppInitParameterInteraction(gArgs) && AppInitSanityChecks() &&
+ AppInitLockDataDirectory() && AppInitInterfaces(*m_context);
+ }
+ bool appInitMain(interfaces::BlockAndHeaderTipInfo* tip_info) override
+ {
+ return AppInitMain(m_context_ref, *m_context, tip_info);
+ }
+ void appShutdown() override
+ {
+ Interrupt(*m_context);
+ Shutdown(*m_context);
+ }
+ void startShutdown() override
+ {
+ StartShutdown();
+ // Stop RPC for clean shutdown if any of waitfor* commands is executed.
+ if (gArgs.GetBoolArg("-server", false)) {
+ InterruptRPC();
+ StopRPC();
+ }
+ }
+ bool shutdownRequested() override { return ShutdownRequested(); }
+ void mapPort(bool use_upnp) override
+ {
+ if (use_upnp) {
+ StartMapPort();
+ } else {
+ InterruptMapPort();
+ StopMapPort();
+ }
+ }
+ bool getProxy(Network net, proxyType& proxy_info) override { return GetProxy(net, proxy_info); }
+ size_t getNodeCount(CConnman::NumConnections flags) override
+ {
+ return m_context->connman ? m_context->connman->GetNodeCount(flags) : 0;
+ }
+ bool getNodesStats(NodesStats& stats) override
+ {
+ stats.clear();
+
+ if (m_context->connman) {
+ std::vector<CNodeStats> stats_temp;
+ m_context->connman->GetNodeStats(stats_temp);
+
+ stats.reserve(stats_temp.size());
+ for (auto& node_stats_temp : stats_temp) {
+ stats.emplace_back(std::move(node_stats_temp), false, CNodeStateStats());
+ }
+
+ // Try to retrieve the CNodeStateStats for each node.
+ TRY_LOCK(::cs_main, lockMain);
+ if (lockMain) {
+ for (auto& node_stats : stats) {
+ std::get<1>(node_stats) =
+ GetNodeStateStats(std::get<0>(node_stats).nodeid, std::get<2>(node_stats));
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+ bool getBanned(banmap_t& banmap) override
+ {
+ if (m_context->banman) {
+ m_context->banman->GetBanned(banmap);
+ return true;
+ }
+ return false;
+ }
+ bool ban(const CNetAddr& net_addr, int64_t ban_time_offset) override
+ {
+ if (m_context->banman) {
+ m_context->banman->Ban(net_addr, ban_time_offset);
+ return true;
+ }
+ return false;
+ }
+ bool unban(const CSubNet& ip) override
+ {
+ if (m_context->banman) {
+ m_context->banman->Unban(ip);
+ return true;
+ }
+ return false;
+ }
+ bool disconnectByAddress(const CNetAddr& net_addr) override
+ {
+ if (m_context->connman) {
+ return m_context->connman->DisconnectNode(net_addr);
+ }
+ return false;
+ }
+ bool disconnectById(NodeId id) override
+ {
+ if (m_context->connman) {
+ return m_context->connman->DisconnectNode(id);
+ }
+ return false;
+ }
+ int64_t getTotalBytesRecv() override { return m_context->connman ? m_context->connman->GetTotalBytesRecv() : 0; }
+ int64_t getTotalBytesSent() override { return m_context->connman ? m_context->connman->GetTotalBytesSent() : 0; }
+ size_t getMempoolSize() override { return m_context->mempool ? m_context->mempool->size() : 0; }
+ size_t getMempoolDynamicUsage() override { return m_context->mempool ? m_context->mempool->DynamicMemoryUsage() : 0; }
+ bool getHeaderTip(int& height, int64_t& block_time) override
+ {
+ LOCK(::cs_main);
+ if (::pindexBestHeader) {
+ height = ::pindexBestHeader->nHeight;
+ block_time = ::pindexBestHeader->GetBlockTime();
+ return true;
+ }
+ return false;
+ }
+ int getNumBlocks() override
+ {
+ LOCK(::cs_main);
+ return ::ChainActive().Height();
+ }
+ uint256 getBestBlockHash() override
+ {
+ const CBlockIndex* tip = WITH_LOCK(::cs_main, return ::ChainActive().Tip());
+ return tip ? tip->GetBlockHash() : Params().GenesisBlock().GetHash();
+ }
+ int64_t getLastBlockTime() override
+ {
+ LOCK(::cs_main);
+ if (::ChainActive().Tip()) {
+ return ::ChainActive().Tip()->GetBlockTime();
+ }
+ return Params().GenesisBlock().GetBlockTime(); // Genesis block's time of current network
+ }
+ double getVerificationProgress() override
+ {
+ const CBlockIndex* tip;
+ {
+ LOCK(::cs_main);
+ tip = ::ChainActive().Tip();
+ }
+ return GuessVerificationProgress(Params().TxData(), tip);
+ }
+ bool isInitialBlockDownload() override { return ::ChainstateActive().IsInitialBlockDownload(); }
+ bool getReindex() override { return ::fReindex; }
+ bool getImporting() override { return ::fImporting; }
+ void setNetworkActive(bool active) override
+ {
+ if (m_context->connman) {
+ m_context->connman->SetNetworkActive(active);
+ }
+ }
+ bool getNetworkActive() override { return m_context->connman && m_context->connman->GetNetworkActive(); }
+ CFeeRate estimateSmartFee(int num_blocks, bool conservative, int* returned_target = nullptr) override
+ {
+ FeeCalculation fee_calc;
+ CFeeRate result = ::feeEstimator.estimateSmartFee(num_blocks, &fee_calc, conservative);
+ if (returned_target) {
+ *returned_target = fee_calc.returnedTarget;
+ }
+ return result;
+ }
+ CFeeRate getDustRelayFee() override { return ::dustRelayFee; }
+ UniValue executeRpc(const std::string& command, const UniValue& params, const std::string& uri) override
+ {
+ JSONRPCRequest req(m_context_ref);
+ req.params = params;
+ req.strMethod = command;
+ req.URI = uri;
+ return ::tableRPC.execute(req);
+ }
+ std::vector<std::string> listRpcCommands() override { return ::tableRPC.listCommands(); }
+ void rpcSetTimerInterfaceIfUnset(RPCTimerInterface* iface) override { RPCSetTimerInterfaceIfUnset(iface); }
+ void rpcUnsetTimerInterface(RPCTimerInterface* iface) override { RPCUnsetTimerInterface(iface); }
+ bool getUnspentOutput(const COutPoint& output, Coin& coin) override
+ {
+ LOCK(::cs_main);
+ return ::ChainstateActive().CoinsTip().GetCoin(output, coin);
+ }
+ WalletClient& walletClient() override
+ {
+ return *Assert(m_context->wallet_client);
+ }
+ std::unique_ptr<Handler> handleInitMessage(InitMessageFn fn) override
+ {
+ return MakeHandler(::uiInterface.InitMessage_connect(fn));
+ }
+ std::unique_ptr<Handler> handleMessageBox(MessageBoxFn fn) override
+ {
+ return MakeHandler(::uiInterface.ThreadSafeMessageBox_connect(fn));
+ }
+ std::unique_ptr<Handler> handleQuestion(QuestionFn fn) override
+ {
+ return MakeHandler(::uiInterface.ThreadSafeQuestion_connect(fn));
+ }
+ std::unique_ptr<Handler> handleShowProgress(ShowProgressFn fn) override
+ {
+ return MakeHandler(::uiInterface.ShowProgress_connect(fn));
+ }
+ std::unique_ptr<Handler> handleNotifyNumConnectionsChanged(NotifyNumConnectionsChangedFn fn) override
+ {
+ return MakeHandler(::uiInterface.NotifyNumConnectionsChanged_connect(fn));
+ }
+ std::unique_ptr<Handler> handleNotifyNetworkActiveChanged(NotifyNetworkActiveChangedFn fn) override
+ {
+ return MakeHandler(::uiInterface.NotifyNetworkActiveChanged_connect(fn));
+ }
+ std::unique_ptr<Handler> handleNotifyAlertChanged(NotifyAlertChangedFn fn) override
+ {
+ return MakeHandler(::uiInterface.NotifyAlertChanged_connect(fn));
+ }
+ std::unique_ptr<Handler> handleBannedListChanged(BannedListChangedFn fn) override
+ {
+ return MakeHandler(::uiInterface.BannedListChanged_connect(fn));
+ }
+ std::unique_ptr<Handler> handleNotifyBlockTip(NotifyBlockTipFn fn) override
+ {
+ return MakeHandler(::uiInterface.NotifyBlockTip_connect([fn](SynchronizationState sync_state, const CBlockIndex* block) {
+ fn(sync_state, BlockTip{block->nHeight, block->GetBlockTime(), block->GetBlockHash()},
+ GuessVerificationProgress(Params().TxData(), block));
+ }));
+ }
+ std::unique_ptr<Handler> handleNotifyHeaderTip(NotifyHeaderTipFn fn) override
+ {
+ return MakeHandler(
+ ::uiInterface.NotifyHeaderTip_connect([fn](SynchronizationState sync_state, const CBlockIndex* block) {
+ fn(sync_state, BlockTip{block->nHeight, block->GetBlockTime(), block->GetBlockHash()},
+ /* verification progress is unused when a header was received */ 0);
+ }));
+ }
+ NodeContext* context() override { return m_context; }
+ void setContext(NodeContext* context) override
+ {
+ m_context = context;
+ if (context) {
+ m_context_ref.Set(*context);
+ } else {
+ m_context_ref.Clear();
+ }
+ }
+ NodeContext* m_context{nullptr};
+ util::Ref m_context_ref;
+};
bool FillBlock(const CBlockIndex* index, const FoundBlock& block, UniqueLock<RecursiveMutex>& lock)
{
@@ -411,7 +685,9 @@ public:
NodeContext& m_node;
};
} // namespace
+} // namespace node
-std::unique_ptr<Chain> MakeChain(NodeContext& node) { return MakeUnique<ChainImpl>(node); }
-
+namespace interfaces {
+std::unique_ptr<Node> MakeNode(NodeContext* context) { return MakeUnique<node::NodeImpl>(context); }
+std::unique_ptr<Chain> MakeChain(NodeContext& context) { return MakeUnique<node::ChainImpl>(context); }
} // namespace interfaces
diff --git a/src/node/transaction.h b/src/node/transaction.h
index 6491700d44..0c016ff04e 100644
--- a/src/node/transaction.h
+++ b/src/node/transaction.h
@@ -36,6 +36,6 @@ static const CFeeRate DEFAULT_MAX_RAW_TX_FEE_RATE{COIN / 10};
* @param[in] wait_callback wait until callbacks have been processed to avoid stale result due to a sequentially RPC.
* return error
*/
-NODISCARD TransactionError BroadcastTransaction(NodeContext& node, CTransactionRef tx, std::string& err_string, const CAmount& max_tx_fee, bool relay, bool wait_callback);
+[[nodiscard]] TransactionError BroadcastTransaction(NodeContext& node, CTransactionRef tx, std::string& err_string, const CAmount& max_tx_fee, bool relay, bool wait_callback);
#endif // BITCOIN_NODE_TRANSACTION_H
diff --git a/src/outputtype.h b/src/outputtype.h
index 77a16b1d05..bb7f39323b 100644
--- a/src/outputtype.h
+++ b/src/outputtype.h
@@ -22,7 +22,7 @@ enum class OutputType {
extern const std::array<OutputType, 3> OUTPUT_TYPES;
-NODISCARD bool ParseOutputType(const std::string& str, OutputType& output_type);
+[[nodiscard]] bool ParseOutputType(const std::string& str, OutputType& output_type);
const std::string& FormatOutputType(OutputType type);
/**
diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp
index 91997aa883..4e33fd6cb5 100644
--- a/src/policy/policy.cpp
+++ b/src/policy/policy.cpp
@@ -92,14 +92,15 @@ bool IsStandardTx(const CTransaction& tx, bool permit_bare_multisig, const CFeeR
for (const CTxIn& txin : tx.vin)
{
- // Biggest 'standard' txin is a 15-of-15 P2SH multisig with compressed
- // keys (remember the 520 byte limit on redeemScript size). That works
- // out to a (15*(33+1))+3=513 byte redeemScript, 513+1+15*(73+1)+3=1627
- // bytes of scriptSig, which we round off to 1650 bytes for some minor
- // future-proofing. That's also enough to spend a 20-of-20
- // CHECKMULTISIG scriptPubKey, though such a scriptPubKey is not
- // considered standard.
- if (txin.scriptSig.size() > 1650) {
+ // Biggest 'standard' txin involving only keys is a 15-of-15 P2SH
+ // multisig with compressed keys (remember the 520 byte limit on
+ // redeemScript size). That works out to a (15*(33+1))+3=513 byte
+ // redeemScript, 513+1+15*(73+1)+3=1627 bytes of scriptSig, which
+ // we round off to 1650(MAX_STANDARD_SCRIPTSIG_SIZE) bytes for
+ // some minor future-proofing. That's also enough to spend a
+ // 20-of-20 CHECKMULTISIG scriptPubKey, though such a scriptPubKey
+ // is not considered standard.
+ if (txin.scriptSig.size() > MAX_STANDARD_SCRIPTSIG_SIZE) {
reason = "scriptsig-size";
return false;
}
diff --git a/src/policy/policy.h b/src/policy/policy.h
index 8090dff4c6..726a14a27e 100644
--- a/src/policy/policy.h
+++ b/src/policy/policy.h
@@ -38,12 +38,14 @@ static const unsigned int DEFAULT_BYTES_PER_SIGOP = 20;
static const bool DEFAULT_PERMIT_BAREMULTISIG = true;
/** The maximum number of witness stack items in a standard P2WSH script */
static const unsigned int MAX_STANDARD_P2WSH_STACK_ITEMS = 100;
-/** The maximum size of each witness stack item in a standard P2WSH script */
+/** The maximum size in bytes of each witness stack item in a standard P2WSH script */
static const unsigned int MAX_STANDARD_P2WSH_STACK_ITEM_SIZE = 80;
-/** The maximum size of each witness stack item in a standard BIP 342 script (Taproot, leaf version 0xc0) */
+/** The maximum size in bytes of each witness stack item in a standard BIP 342 script (Taproot, leaf version 0xc0) */
static const unsigned int MAX_STANDARD_TAPSCRIPT_STACK_ITEM_SIZE = 80;
-/** The maximum size of a standard witnessScript */
+/** The maximum size in bytes of a standard witnessScript */
static const unsigned int MAX_STANDARD_P2WSH_SCRIPT_SIZE = 3600;
+/** The maximum size of a standard ScriptSig */
+static const unsigned int MAX_STANDARD_SCRIPTSIG_SIZE = 1650;
/** Min feerate for defining dust. Historically this has been based on the
* minRelayTxFee, however changing the dust limit changes which transactions are
* standard and should be done with care and ideally rarely. It makes sense to
@@ -103,7 +105,9 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs,
/**
* Check if the transaction is over standard P2WSH resources limit:
* 3600bytes witnessScript size, 80bytes per witness stack element, 100 witness stack elements
- * These limits are adequate for multi-signature up to n-of-100 using OP_CHECKSIG, OP_ADD, and OP_EQUAL,
+ * These limits are adequate for multisignatures up to n-of-100 using OP_CHECKSIG, OP_ADD, and OP_EQUAL.
+ *
+ * Also enforce a maximum stack item size limit and no annexes for tapscript spends.
*/
bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs);
diff --git a/src/psbt.h b/src/psbt.h
index 0951b76f83..b566726ee3 100644
--- a/src/psbt.h
+++ b/src/psbt.h
@@ -398,7 +398,7 @@ struct PartiallySignedTransaction
/** Merge psbt into this. The two psbts must have the same underlying CTransaction (i.e. the
* same actual Bitcoin transaction.) Returns true if the merge succeeded, false otherwise. */
- NODISCARD bool Merge(const PartiallySignedTransaction& psbt);
+ [[nodiscard]] bool Merge(const PartiallySignedTransaction& psbt);
bool AddInput(const CTxIn& txin, PSBTInput& psbtin);
bool AddOutput(const CTxOut& txout, const PSBTOutput& psbtout);
PartiallySignedTransaction() {}
@@ -605,11 +605,11 @@ bool FinalizeAndExtractPSBT(PartiallySignedTransaction& psbtx, CMutableTransacti
* @param[in] psbtxs the PSBTs to combine
* @return error (OK if we successfully combined the transactions, other error if they were not compatible)
*/
-NODISCARD TransactionError CombinePSBTs(PartiallySignedTransaction& out, const std::vector<PartiallySignedTransaction>& psbtxs);
+[[nodiscard]] TransactionError CombinePSBTs(PartiallySignedTransaction& out, const std::vector<PartiallySignedTransaction>& psbtxs);
//! Decode a base64ed PSBT into a PartiallySignedTransaction
-NODISCARD bool DecodeBase64PSBT(PartiallySignedTransaction& decoded_psbt, const std::string& base64_psbt, std::string& error);
+[[nodiscard]] bool DecodeBase64PSBT(PartiallySignedTransaction& decoded_psbt, const std::string& base64_psbt, std::string& error);
//! Decode a raw (binary blob) PSBT into a PartiallySignedTransaction
-NODISCARD bool DecodeRawPSBT(PartiallySignedTransaction& decoded_psbt, const std::string& raw_psbt, std::string& error);
+[[nodiscard]] bool DecodeRawPSBT(PartiallySignedTransaction& decoded_psbt, const std::string& raw_psbt, std::string& error);
#endif // BITCOIN_PSBT_H
diff --git a/src/pubkey.h b/src/pubkey.h
index 0f784b86e4..80d0c18540 100644
--- a/src/pubkey.h
+++ b/src/pubkey.h
@@ -170,6 +170,15 @@ public:
/*
* Check syntactic correctness.
*
+ * When setting a pubkey (Set()) or deserializing fails (its header bytes
+ * don't match the length of the data), the size is set to 0. Thus,
+ * by checking size, one can observe whether Set() or deserialization has
+ * failed.
+ *
+ * This does not check for more than that. In particular, it does not verify
+ * that the coordinates correspond to a point on the curve (see IsFullyValid()
+ * for that instead).
+ *
* Note that this is consensus critical as CheckECDSASignature() calls it!
*/
bool IsValid() const
diff --git a/src/qt/askpassphrasedialog.cpp b/src/qt/askpassphrasedialog.cpp
index 3b4967421a..3be8b664dd 100644
--- a/src/qt/askpassphrasedialog.cpp
+++ b/src/qt/askpassphrasedialog.cpp
@@ -199,6 +199,8 @@ void AskPassphraseDialog::textChanged()
acceptable = !ui->passEdit2->text().isEmpty() && !ui->passEdit3->text().isEmpty();
break;
case Unlock: // Old passphrase x1
+ acceptable = !ui->passEdit1->text().isEmpty();
+ break;
case ChangePass: // Old passphrase x1, new passphrase x2
acceptable = !ui->passEdit1->text().isEmpty() && !ui->passEdit2->text().isEmpty() && !ui->passEdit3->text().isEmpty();
break;
diff --git a/src/qt/bantablemodel.cpp b/src/qt/bantablemodel.cpp
index 2739b21a9d..2676de96d7 100644
--- a/src/qt/bantablemodel.cpp
+++ b/src/qt/bantablemodel.cpp
@@ -11,6 +11,7 @@
#include <QDateTime>
#include <QList>
+#include <QLocale>
#include <QModelIndex>
#include <QVariant>
@@ -122,7 +123,7 @@ QVariant BanTableModel::data(const QModelIndex &index, int role) const
case Bantime:
QDateTime date = QDateTime::fromMSecsSinceEpoch(0);
date = date.addSecs(rec->banEntry.nBanUntil);
- return date.toString(Qt::SystemLocaleLongDate);
+ return QLocale::system().toString(date, QLocale::LongFormat);
}
}
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index 70e76f765b..53ffb27f50 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -43,6 +43,7 @@
#include <QKeyEvent>
#include <QLineEdit>
#include <QList>
+#include <QLocale>
#include <QMenu>
#include <QMouseEvent>
#include <QProgressDialog>
@@ -67,7 +68,7 @@ namespace GUIUtil {
QString dateTimeStr(const QDateTime &date)
{
- return date.date().toString(Qt::SystemLocaleShortDate) + QString(" ") + date.toString("hh:mm");
+ return QLocale::system().toString(date.date(), QLocale::ShortFormat) + QString(" ") + date.toString("hh:mm");
}
QString dateTimeStr(qint64 nTime)
diff --git a/src/qt/notificator.cpp b/src/qt/notificator.cpp
index 4b91c19761..d518a2065c 100644
--- a/src/qt/notificator.cpp
+++ b/src/qt/notificator.cpp
@@ -17,12 +17,7 @@
#include <stdint.h>
#include <QtDBus>
#endif
-// Include ApplicationServices.h after QtDbus to avoid redefinition of check().
-// This affects at least OSX 10.6. See /usr/include/AssertMacros.h for details.
-// Note: This could also be worked around using:
-// #define __ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES 0
#ifdef Q_OS_MAC
-#include <ApplicationServices/ApplicationServices.h>
#include <qt/macnotificationhandler.h>
#endif
diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp
index 6c0a98cca2..8d8fa185ba 100644
--- a/src/script/descriptor.cpp
+++ b/src/script/descriptor.cpp
@@ -731,7 +731,7 @@ enum class ParseScriptContext {
};
/** Parse a key path, being passed a split list of elements (the first element is ignored). */
-NODISCARD bool ParseKeyPath(const std::vector<Span<const char>>& split, KeyPath& out, std::string& error)
+[[nodiscard]] bool ParseKeyPath(const std::vector<Span<const char>>& split, KeyPath& out, std::string& error)
{
for (size_t i = 1; i < split.size(); ++i) {
Span<const char> elem = split[i];
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp
index 5735e7df66..bb5a7158a5 100644
--- a/src/script/interpreter.cpp
+++ b/src/script/interpreter.cpp
@@ -1834,9 +1834,13 @@ static bool ExecuteWitnessScript(const Span<const valtype>& stack_span, const CS
static bool VerifyTaprootCommitment(const std::vector<unsigned char>& control, const std::vector<unsigned char>& program, const CScript& script, uint256& tapleaf_hash)
{
const int path_len = (control.size() - TAPROOT_CONTROL_BASE_SIZE) / TAPROOT_CONTROL_NODE_SIZE;
+ //! The inner pubkey (x-only, so no Y coordinate parity).
const XOnlyPubKey p{uint256(std::vector<unsigned char>(control.begin() + 1, control.begin() + TAPROOT_CONTROL_BASE_SIZE))};
+ //! The output pubkey (taken from the scriptPubKey).
const XOnlyPubKey q{uint256(program)};
+ // Compute the tapleaf hash.
tapleaf_hash = (CHashWriter(HASHER_TAPLEAF) << uint8_t(control[0] & TAPROOT_LEAF_MASK) << script).GetSHA256();
+ // Compute the Merkle root from the leaf and the provided path.
uint256 k = tapleaf_hash;
for (int i = 0; i < path_len; ++i) {
CHashWriter ss_branch{HASHER_TAPBRANCH};
@@ -1848,7 +1852,9 @@ static bool VerifyTaprootCommitment(const std::vector<unsigned char>& control, c
}
k = ss_branch.GetSHA256();
}
+ // Compute the tweak from the Merkle root and the inner pubkey.
k = (CHashWriter(HASHER_TAPTWEAK) << MakeSpan(p) << k).GetSHA256();
+ // Verify that the output pubkey matches the tweaked inner pubkey, after correcting for parity.
return q.CheckPayToContract(p, k, control[0] & 1);
}
diff --git a/src/span.h b/src/span.h
index 4afb383a59..830164514b 100644
--- a/src/span.h
+++ b/src/span.h
@@ -18,6 +18,16 @@
#define ASSERT_IF_DEBUG(x)
#endif
+#if defined(__clang__)
+#if __has_attribute(lifetimebound)
+#define SPAN_ATTR_LIFETIMEBOUND [[clang::lifetimebound]]
+#else
+#define SPAN_ATTR_LIFETIMEBOUND
+#endif
+#else
+#define SPAN_ATTR_LIFETIMEBOUND
+#endif
+
/** A Span is an object that can refer to a contiguous sequence of objects.
*
* It implements a subset of C++20's std::span.
@@ -84,6 +94,14 @@ class Span
C* m_data;
std::size_t m_size;
+ template <class T>
+ struct is_Span_int : public std::false_type {};
+ template <class T>
+ struct is_Span_int<Span<T>> : public std::true_type {};
+ template <class T>
+ struct is_Span : public is_Span_int<typename std::remove_cv<T>::type>{};
+
+
public:
constexpr Span() noexcept : m_data(nullptr), m_size(0) {}
@@ -134,8 +152,19 @@ public:
* To prevent surprises, only Spans for constant value types are supported when passing in temporaries.
* Note that this restriction does not exist when converting arrays or other Spans (see above).
*/
- template <typename V, typename std::enable_if<(std::is_const<C>::value || std::is_lvalue_reference<V>::value) && std::is_convertible<typename std::remove_pointer<decltype(std::declval<V&>().data())>::type (*)[], C (*)[]>::value && std::is_convertible<decltype(std::declval<V&>().size()), std::size_t>::value, int>::type = 0>
- constexpr Span(V&& v) noexcept : m_data(v.data()), m_size(v.size()) {}
+ template <typename V>
+ constexpr Span(V& other SPAN_ATTR_LIFETIMEBOUND,
+ typename std::enable_if<!is_Span<V>::value &&
+ std::is_convertible<typename std::remove_pointer<decltype(std::declval<V&>().data())>::type (*)[], C (*)[]>::value &&
+ std::is_convertible<decltype(std::declval<V&>().size()), std::size_t>::value, std::nullptr_t>::type = nullptr)
+ : m_data(other.data()), m_size(other.size()){}
+
+ template <typename V>
+ constexpr Span(const V& other SPAN_ATTR_LIFETIMEBOUND,
+ typename std::enable_if<!is_Span<V>::value &&
+ std::is_convertible<typename std::remove_pointer<decltype(std::declval<const V&>().data())>::type (*)[], C (*)[]>::value &&
+ std::is_convertible<decltype(std::declval<const V&>().size()), std::size_t>::value, std::nullptr_t>::type = nullptr)
+ : m_data(other.data()), m_size(other.size()){}
constexpr C* data() const noexcept { return m_data; }
constexpr C* begin() const noexcept { return m_data; }
@@ -192,9 +221,9 @@ public:
/** MakeSpan for arrays: */
template <typename A, int N> Span<A> constexpr MakeSpan(A (&a)[N]) { return Span<A>(a, N); }
/** MakeSpan for temporaries / rvalue references, only supporting const output. */
-template <typename V> constexpr auto MakeSpan(V&& v) -> typename std::enable_if<!std::is_lvalue_reference<V>::value, Span<const typename std::remove_pointer<decltype(v.data())>::type>>::type { return std::forward<V>(v); }
+template <typename V> constexpr auto MakeSpan(V&& v SPAN_ATTR_LIFETIMEBOUND) -> typename std::enable_if<!std::is_lvalue_reference<V>::value, Span<const typename std::remove_pointer<decltype(v.data())>::type>>::type { return std::forward<V>(v); }
/** MakeSpan for (lvalue) references, supporting mutable output. */
-template <typename V> constexpr auto MakeSpan(V& v) -> Span<typename std::remove_pointer<decltype(v.data())>::type> { return v; }
+template <typename V> constexpr auto MakeSpan(V& v SPAN_ATTR_LIFETIMEBOUND) -> Span<typename std::remove_pointer<decltype(v.data())>::type> { return v; }
/** Pop the last element off a span, and return a reference to that element. */
template <typename T>
diff --git a/src/sync.cpp b/src/sync.cpp
index 322198a852..f07916041a 100644
--- a/src/sync.cpp
+++ b/src/sync.cpp
@@ -13,10 +13,14 @@
#include <util/strencodings.h>
#include <util/threadnames.h>
+#include <boost/thread/mutex.hpp>
+
#include <map>
+#include <mutex>
#include <set>
#include <system_error>
#include <thread>
+#include <type_traits>
#include <unordered_map>
#include <utility>
#include <vector>
@@ -135,16 +139,52 @@ static void potential_deadlock_detected(const LockPair& mismatch, const LockStac
throw std::logic_error(strprintf("potential deadlock detected: %s -> %s -> %s", mutex_b, mutex_a, mutex_b));
}
-static void push_lock(void* c, const CLockLocation& locklocation)
+static void double_lock_detected(const void* mutex, const LockStack& lock_stack)
{
+ LogPrintf("DOUBLE LOCK DETECTED\n");
+ LogPrintf("Lock order:\n");
+ for (const LockStackItem& i : lock_stack) {
+ if (i.first == mutex) {
+ LogPrintf(" (*)"); /* Continued */
+ }
+ LogPrintf(" %s\n", i.second.ToString());
+ }
+ if (g_debug_lockorder_abort) {
+ tfm::format(std::cerr,
+ "Assertion failed: detected double lock for %s, details in debug log.\n",
+ lock_stack.back().second.ToString());
+ abort();
+ }
+ throw std::logic_error("double lock detected");
+}
+
+template <typename MutexType>
+static void push_lock(MutexType* c, const CLockLocation& locklocation)
+{
+ constexpr bool is_recursive_mutex =
+ std::is_base_of<RecursiveMutex, MutexType>::value ||
+ std::is_base_of<std::recursive_mutex, MutexType>::value;
+
LockData& lockdata = GetLockData();
std::lock_guard<std::mutex> lock(lockdata.dd_mutex);
LockStack& lock_stack = lockdata.m_lock_stacks[std::this_thread::get_id()];
lock_stack.emplace_back(c, locklocation);
- for (const LockStackItem& i : lock_stack) {
- if (i.first == c)
- break;
+ for (size_t j = 0; j < lock_stack.size() - 1; ++j) {
+ const LockStackItem& i = lock_stack[j];
+ if (i.first == c) {
+ if (is_recursive_mutex) {
+ break;
+ }
+ // It is not a recursive mutex and it appears in the stack two times:
+ // at position `j` and at the end (which we added just before this loop).
+ // Can't allow locking the same (non-recursive) mutex two times from the
+ // same thread as that results in an undefined behavior.
+ auto lock_stack_copy = lock_stack;
+ lock_stack.pop_back();
+ double_lock_detected(c, lock_stack_copy);
+ // double_lock_detected() does not return.
+ }
const LockPair p1 = std::make_pair(i.first, c);
if (lockdata.lockorders.count(p1))
@@ -175,10 +215,16 @@ static void pop_lock()
}
}
-void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry)
+template <typename MutexType>
+void EnterCritical(const char* pszName, const char* pszFile, int nLine, MutexType* cs, bool fTry)
{
push_lock(cs, CLockLocation(pszName, pszFile, nLine, fTry, util::ThreadGetInternalName()));
}
+template void EnterCritical(const char*, const char*, int, Mutex*, bool);
+template void EnterCritical(const char*, const char*, int, RecursiveMutex*, bool);
+template void EnterCritical(const char*, const char*, int, std::mutex*, bool);
+template void EnterCritical(const char*, const char*, int, std::recursive_mutex*, bool);
+template void EnterCritical(const char*, const char*, int, boost::mutex*, bool);
void CheckLastCritical(void* cs, std::string& lockname, const char* guardname, const char* file, int line)
{
diff --git a/src/sync.h b/src/sync.h
index 41f4e43bdd..0948083c7f 100644
--- a/src/sync.h
+++ b/src/sync.h
@@ -48,7 +48,8 @@ LEAVE_CRITICAL_SECTION(mutex); // no RAII
///////////////////////////////
#ifdef DEBUG_LOCKORDER
-void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false);
+template <typename MutexType>
+void EnterCritical(const char* pszName, const char* pszFile, int nLine, MutexType* cs, bool fTry = false);
void LeaveCritical();
void CheckLastCritical(void* cs, std::string& lockname, const char* guardname, const char* file, int line);
std::string LocksHeld();
@@ -66,7 +67,8 @@ bool LockStackEmpty();
*/
extern bool g_debug_lockorder_abort;
#else
-inline void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false) {}
+template <typename MutexType>
+inline void EnterCritical(const char* pszName, const char* pszFile, int nLine, MutexType* cs, bool fTry = false) {}
inline void LeaveCritical() {}
inline void CheckLastCritical(void* cs, std::string& lockname, const char* guardname, const char* file, int line) {}
template <typename MutexType>
@@ -135,7 +137,7 @@ class SCOPED_LOCKABLE UniqueLock : public Base
private:
void Enter(const char* pszName, const char* pszFile, int nLine)
{
- EnterCritical(pszName, pszFile, nLine, (void*)(Base::mutex()));
+ EnterCritical(pszName, pszFile, nLine, Base::mutex());
#ifdef DEBUG_LOCKCONTENTION
if (!Base::try_lock()) {
PrintLockContention(pszName, pszFile, nLine);
@@ -148,7 +150,7 @@ private:
bool TryEnter(const char* pszName, const char* pszFile, int nLine)
{
- EnterCritical(pszName, pszFile, nLine, (void*)(Base::mutex()), true);
+ EnterCritical(pszName, pszFile, nLine, Base::mutex(), true);
Base::try_lock();
if (!Base::owns_lock())
LeaveCritical();
@@ -205,7 +207,7 @@ public:
~reverse_lock() {
templock.swap(lock);
- EnterCritical(lockname.c_str(), file.c_str(), line, (void*)lock.mutex());
+ EnterCritical(lockname.c_str(), file.c_str(), line, lock.mutex());
lock.lock();
}
@@ -236,7 +238,7 @@ using DebugLock = UniqueLock<typename std::remove_reference<typename std::remove
#define ENTER_CRITICAL_SECTION(cs) \
{ \
- EnterCritical(#cs, __FILE__, __LINE__, (void*)(&cs)); \
+ EnterCritical(#cs, __FILE__, __LINE__, &cs); \
(cs).lock(); \
}
diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp
index 173ec5e3d9..6bfcf242d0 100644
--- a/src/test/coins_tests.cpp
+++ b/src/test/coins_tests.cpp
@@ -38,7 +38,7 @@ class CCoinsViewTest : public CCoinsView
std::map<COutPoint, Coin> map_;
public:
- NODISCARD bool GetCoin(const COutPoint& outpoint, Coin& coin) const override
+ [[nodiscard]] bool GetCoin(const COutPoint& outpoint, Coin& coin) const override
{
std::map<COutPoint, Coin>::const_iterator it = map_.find(outpoint);
if (it == map_.end()) {
diff --git a/src/test/fuzz/addition_overflow.cpp b/src/test/fuzz/addition_overflow.cpp
index a455992b13..7350ec7838 100644
--- a/src/test/fuzz/addition_overflow.cpp
+++ b/src/test/fuzz/addition_overflow.cpp
@@ -14,7 +14,7 @@
#if __has_builtin(__builtin_add_overflow)
#define HAVE_BUILTIN_ADD_OVERFLOW
#endif
-#elif defined(__GNUC__) && (__GNUC__ >= 5)
+#elif defined(__GNUC__)
#define HAVE_BUILTIN_ADD_OVERFLOW
#endif
diff --git a/src/test/fuzz/addrman.cpp b/src/test/fuzz/addrman.cpp
index 0ceeea2d36..ae595be742 100644
--- a/src/test/fuzz/addrman.cpp
+++ b/src/test/fuzz/addrman.cpp
@@ -22,12 +22,22 @@ void initialize()
SelectParams(CBaseChainParams::REGTEST);
}
+class CAddrManDeterministic : public CAddrMan
+{
+public:
+ void MakeDeterministic(const uint256& random_seed)
+ {
+ insecure_rand = FastRandomContext{random_seed};
+ Clear();
+ }
+};
+
void test_one_input(const std::vector<uint8_t>& buffer)
{
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
-
SetMockTime(ConsumeTime(fuzzed_data_provider));
- CAddrMan addr_man;
+ CAddrManDeterministic addr_man;
+ addr_man.MakeDeterministic(ConsumeUInt256(fuzzed_data_provider));
if (fuzzed_data_provider.ConsumeBool()) {
addr_man.m_asmap = ConsumeRandomLengthBitVector(fuzzed_data_provider);
if (!SanityCheckASMap(addr_man.m_asmap)) {
diff --git a/src/test/fuzz/multiplication_overflow.cpp b/src/test/fuzz/multiplication_overflow.cpp
index a4b158c18b..08dc660a19 100644
--- a/src/test/fuzz/multiplication_overflow.cpp
+++ b/src/test/fuzz/multiplication_overflow.cpp
@@ -14,7 +14,7 @@
#if __has_builtin(__builtin_mul_overflow)
#define HAVE_BUILTIN_MUL_OVERFLOW
#endif
-#elif defined(__GNUC__) && (__GNUC__ >= 5)
+#elif defined(__GNUC__)
#define HAVE_BUILTIN_MUL_OVERFLOW
#endif
diff --git a/src/test/fuzz/util.h b/src/test/fuzz/util.h
index e99ed8d72d..cf666a8b93 100644
--- a/src/test/fuzz/util.h
+++ b/src/test/fuzz/util.h
@@ -35,23 +35,23 @@
#include <string>
#include <vector>
-NODISCARD inline std::vector<uint8_t> ConsumeRandomLengthByteVector(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length = 4096) noexcept
+[[nodiscard]] inline std::vector<uint8_t> ConsumeRandomLengthByteVector(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length = 4096) noexcept
{
const std::string s = fuzzed_data_provider.ConsumeRandomLengthString(max_length);
return {s.begin(), s.end()};
}
-NODISCARD inline std::vector<bool> ConsumeRandomLengthBitVector(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length = 4096) noexcept
+[[nodiscard]] inline std::vector<bool> ConsumeRandomLengthBitVector(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length = 4096) noexcept
{
return BytesToBits(ConsumeRandomLengthByteVector(fuzzed_data_provider, max_length));
}
-NODISCARD inline CDataStream ConsumeDataStream(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length = 4096) noexcept
+[[nodiscard]] inline CDataStream ConsumeDataStream(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length = 4096) noexcept
{
return {ConsumeRandomLengthByteVector(fuzzed_data_provider, max_length), SER_NETWORK, INIT_PROTO_VERSION};
}
-NODISCARD inline std::vector<std::string> ConsumeRandomLengthStringVector(FuzzedDataProvider& fuzzed_data_provider, const size_t max_vector_size = 16, const size_t max_string_length = 16) noexcept
+[[nodiscard]] inline std::vector<std::string> ConsumeRandomLengthStringVector(FuzzedDataProvider& fuzzed_data_provider, const size_t max_vector_size = 16, const size_t max_string_length = 16) noexcept
{
const size_t n_elements = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, max_vector_size);
std::vector<std::string> r;
@@ -62,7 +62,7 @@ NODISCARD inline std::vector<std::string> ConsumeRandomLengthStringVector(Fuzzed
}
template <typename T>
-NODISCARD inline std::vector<T> ConsumeRandomLengthIntegralVector(FuzzedDataProvider& fuzzed_data_provider, const size_t max_vector_size = 16) noexcept
+[[nodiscard]] inline std::vector<T> ConsumeRandomLengthIntegralVector(FuzzedDataProvider& fuzzed_data_provider, const size_t max_vector_size = 16) noexcept
{
const size_t n_elements = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, max_vector_size);
std::vector<T> r;
@@ -73,7 +73,7 @@ NODISCARD inline std::vector<T> ConsumeRandomLengthIntegralVector(FuzzedDataProv
}
template <typename T>
-NODISCARD inline std::optional<T> ConsumeDeserializable(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length = 4096) noexcept
+[[nodiscard]] inline std::optional<T> ConsumeDeserializable(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length = 4096) noexcept
{
const std::vector<uint8_t> buffer = ConsumeRandomLengthByteVector(fuzzed_data_provider, max_length);
CDataStream ds{buffer, SER_NETWORK, INIT_PROTO_VERSION};
@@ -86,35 +86,36 @@ NODISCARD inline std::optional<T> ConsumeDeserializable(FuzzedDataProvider& fuzz
return obj;
}
-NODISCARD inline opcodetype ConsumeOpcodeType(FuzzedDataProvider& fuzzed_data_provider) noexcept
+[[nodiscard]] inline opcodetype ConsumeOpcodeType(FuzzedDataProvider& fuzzed_data_provider) noexcept
{
return static_cast<opcodetype>(fuzzed_data_provider.ConsumeIntegralInRange<uint32_t>(0, MAX_OPCODE));
}
-NODISCARD inline CAmount ConsumeMoney(FuzzedDataProvider& fuzzed_data_provider) noexcept
+[[nodiscard]] inline CAmount ConsumeMoney(FuzzedDataProvider& fuzzed_data_provider) noexcept
{
return fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(0, MAX_MONEY);
}
-NODISCARD inline int64_t ConsumeTime(FuzzedDataProvider& fuzzed_data_provider) noexcept
+[[nodiscard]] inline int64_t ConsumeTime(FuzzedDataProvider& fuzzed_data_provider) noexcept
{
- static const int64_t time_min = ParseISO8601DateTime("1970-01-01T00:00:00Z");
+ // Avoid t=0 (1970-01-01T00:00:00Z) since SetMockTime(0) is a no-op.
+ static const int64_t time_min = ParseISO8601DateTime("1970-01-01T00:00:01Z");
static const int64_t time_max = ParseISO8601DateTime("9999-12-31T23:59:59Z");
return fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(time_min, time_max);
}
-NODISCARD inline CScript ConsumeScript(FuzzedDataProvider& fuzzed_data_provider) noexcept
+[[nodiscard]] inline CScript ConsumeScript(FuzzedDataProvider& fuzzed_data_provider) noexcept
{
const std::vector<uint8_t> b = ConsumeRandomLengthByteVector(fuzzed_data_provider);
return {b.begin(), b.end()};
}
-NODISCARD inline CScriptNum ConsumeScriptNum(FuzzedDataProvider& fuzzed_data_provider) noexcept
+[[nodiscard]] inline CScriptNum ConsumeScriptNum(FuzzedDataProvider& fuzzed_data_provider) noexcept
{
return CScriptNum{fuzzed_data_provider.ConsumeIntegral<int64_t>()};
}
-NODISCARD inline uint160 ConsumeUInt160(FuzzedDataProvider& fuzzed_data_provider) noexcept
+[[nodiscard]] inline uint160 ConsumeUInt160(FuzzedDataProvider& fuzzed_data_provider) noexcept
{
const std::vector<uint8_t> v160 = fuzzed_data_provider.ConsumeBytes<uint8_t>(160 / 8);
if (v160.size() != 160 / 8) {
@@ -123,7 +124,7 @@ NODISCARD inline uint160 ConsumeUInt160(FuzzedDataProvider& fuzzed_data_provider
return uint160{v160};
}
-NODISCARD inline uint256 ConsumeUInt256(FuzzedDataProvider& fuzzed_data_provider) noexcept
+[[nodiscard]] inline uint256 ConsumeUInt256(FuzzedDataProvider& fuzzed_data_provider) noexcept
{
const std::vector<uint8_t> v256 = fuzzed_data_provider.ConsumeBytes<uint8_t>(256 / 8);
if (v256.size() != 256 / 8) {
@@ -132,12 +133,12 @@ NODISCARD inline uint256 ConsumeUInt256(FuzzedDataProvider& fuzzed_data_provider
return uint256{v256};
}
-NODISCARD inline arith_uint256 ConsumeArithUInt256(FuzzedDataProvider& fuzzed_data_provider) noexcept
+[[nodiscard]] inline arith_uint256 ConsumeArithUInt256(FuzzedDataProvider& fuzzed_data_provider) noexcept
{
return UintToArith256(ConsumeUInt256(fuzzed_data_provider));
}
-NODISCARD inline CTxMemPoolEntry ConsumeTxMemPoolEntry(FuzzedDataProvider& fuzzed_data_provider, const CTransaction& tx) noexcept
+[[nodiscard]] inline CTxMemPoolEntry ConsumeTxMemPoolEntry(FuzzedDataProvider& fuzzed_data_provider, const CTransaction& tx) noexcept
{
// Avoid:
// policy/feerate.cpp:28:34: runtime error: signed integer overflow: 34873208148477500 * 1000 cannot be represented in type 'long'
@@ -152,7 +153,7 @@ NODISCARD inline CTxMemPoolEntry ConsumeTxMemPoolEntry(FuzzedDataProvider& fuzze
return CTxMemPoolEntry{MakeTransactionRef(tx), fee, time, entry_height, spends_coinbase, sig_op_cost, {}};
}
-NODISCARD inline CTxDestination ConsumeTxDestination(FuzzedDataProvider& fuzzed_data_provider) noexcept
+[[nodiscard]] inline CTxDestination ConsumeTxDestination(FuzzedDataProvider& fuzzed_data_provider) noexcept
{
CTxDestination tx_destination;
switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 5)) {
@@ -190,7 +191,7 @@ NODISCARD inline CTxDestination ConsumeTxDestination(FuzzedDataProvider& fuzzed_
}
template <typename T>
-NODISCARD bool MultiplicationOverflow(const T i, const T j) noexcept
+[[nodiscard]] bool MultiplicationOverflow(const T i, const T j) noexcept
{
static_assert(std::is_integral<T>::value, "Integral required.");
if (std::numeric_limits<T>::is_signed) {
@@ -213,7 +214,7 @@ NODISCARD bool MultiplicationOverflow(const T i, const T j) noexcept
}
template <class T>
-NODISCARD bool AdditionOverflow(const T i, const T j) noexcept
+[[nodiscard]] bool AdditionOverflow(const T i, const T j) noexcept
{
static_assert(std::is_integral<T>::value, "Integral required.");
if (std::numeric_limits<T>::is_signed) {
@@ -223,7 +224,7 @@ NODISCARD bool AdditionOverflow(const T i, const T j) noexcept
return std::numeric_limits<T>::max() - i < j;
}
-NODISCARD inline bool ContainsSpentInput(const CTransaction& tx, const CCoinsViewCache& inputs) noexcept
+[[nodiscard]] inline bool ContainsSpentInput(const CTransaction& tx, const CCoinsViewCache& inputs) noexcept
{
for (const CTxIn& tx_in : tx.vin) {
const Coin& coin = inputs.AccessCoin(tx_in.prevout);
@@ -238,7 +239,7 @@ NODISCARD inline bool ContainsSpentInput(const CTransaction& tx, const CCoinsVie
* Returns a byte vector of specified size regardless of the number of remaining bytes available
* from the fuzzer. Pads with zero value bytes if needed to achieve the specified size.
*/
-NODISCARD inline std::vector<uint8_t> ConsumeFixedLengthByteVector(FuzzedDataProvider& fuzzed_data_provider, const size_t length) noexcept
+[[nodiscard]] inline std::vector<uint8_t> ConsumeFixedLengthByteVector(FuzzedDataProvider& fuzzed_data_provider, const size_t length) noexcept
{
std::vector<uint8_t> result(length);
const std::vector<uint8_t> random_bytes = fuzzed_data_provider.ConsumeBytes<uint8_t>(length);
@@ -419,7 +420,7 @@ public:
}
};
-NODISCARD inline FuzzedFileProvider ConsumeFile(FuzzedDataProvider& fuzzed_data_provider) noexcept
+[[nodiscard]] inline FuzzedFileProvider ConsumeFile(FuzzedDataProvider& fuzzed_data_provider) noexcept
{
return {fuzzed_data_provider};
}
@@ -440,7 +441,7 @@ public:
}
};
-NODISCARD inline FuzzedAutoFileProvider ConsumeAutoFile(FuzzedDataProvider& fuzzed_data_provider) noexcept
+[[nodiscard]] inline FuzzedAutoFileProvider ConsumeAutoFile(FuzzedDataProvider& fuzzed_data_provider) noexcept
{
return {fuzzed_data_provider};
}
diff --git a/src/test/sync_tests.cpp b/src/test/sync_tests.cpp
index 19029ebd3c..14145ced7e 100644
--- a/src/test/sync_tests.cpp
+++ b/src/test/sync_tests.cpp
@@ -6,6 +6,9 @@
#include <test/util/setup_common.h>
#include <boost/test/unit_test.hpp>
+#include <boost/thread/mutex.hpp>
+
+#include <mutex>
namespace {
template <typename MutexType>
@@ -29,6 +32,36 @@ void TestPotentialDeadLockDetected(MutexType& mutex1, MutexType& mutex2)
BOOST_CHECK(!error_thrown);
#endif
}
+
+#ifdef DEBUG_LOCKORDER
+template <typename MutexType>
+void TestDoubleLock2(MutexType& m)
+{
+ ENTER_CRITICAL_SECTION(m);
+ LEAVE_CRITICAL_SECTION(m);
+}
+
+template <typename MutexType>
+void TestDoubleLock(bool should_throw)
+{
+ const bool prev = g_debug_lockorder_abort;
+ g_debug_lockorder_abort = false;
+
+ MutexType m;
+ ENTER_CRITICAL_SECTION(m);
+ if (should_throw) {
+ BOOST_CHECK_EXCEPTION(TestDoubleLock2(m), std::logic_error,
+ HasReason("double lock detected"));
+ } else {
+ BOOST_CHECK_NO_THROW(TestDoubleLock2(m));
+ }
+ LEAVE_CRITICAL_SECTION(m);
+
+ BOOST_CHECK(LockStackEmpty());
+
+ g_debug_lockorder_abort = prev;
+}
+#endif /* DEBUG_LOCKORDER */
} // namespace
BOOST_FIXTURE_TEST_SUITE(sync_tests, BasicTestingSetup)
@@ -55,4 +88,24 @@ BOOST_AUTO_TEST_CASE(potential_deadlock_detected)
#endif
}
+/* Double lock would produce an undefined behavior. Thus, we only do that if
+ * DEBUG_LOCKORDER is activated to detect it. We don't want non-DEBUG_LOCKORDER
+ * build to produce tests that exhibit known undefined behavior. */
+#ifdef DEBUG_LOCKORDER
+BOOST_AUTO_TEST_CASE(double_lock_mutex)
+{
+ TestDoubleLock<Mutex>(true /* should throw */);
+}
+
+BOOST_AUTO_TEST_CASE(double_lock_boost_mutex)
+{
+ TestDoubleLock<boost::mutex>(true /* should throw */);
+}
+
+BOOST_AUTO_TEST_CASE(double_lock_recursive_mutex)
+{
+ TestDoubleLock<RecursiveMutex>(false /* should not throw */);
+}
+#endif /* DEBUG_LOCKORDER */
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp
index 2d3137e1e2..adf5970206 100644
--- a/src/test/util/setup_common.cpp
+++ b/src/test/util/setup_common.cpp
@@ -141,8 +141,7 @@ TestingSetup::TestingSetup(const std::string& chainName, const std::vector<const
pblocktree.reset(new CBlockTreeDB(1 << 20, true));
- m_node.mempool = MakeUnique<CTxMemPool>(&::feeEstimator);
- m_node.mempool->setSanityCheck(1.0);
+ m_node.mempool = MakeUnique<CTxMemPool>(&::feeEstimator, 1);
m_node.chainman = &::g_chainman;
m_node.chainman->InitializeChainstate(*m_node.mempool);
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index 0c2b731967..d18182c07d 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -331,15 +331,10 @@ void CTxMemPoolEntry::UpdateAncestorState(int64_t modifySize, CAmount modifyFee,
assert(int(nSigOpCostWithAncestors) >= 0);
}
-CTxMemPool::CTxMemPool(CBlockPolicyEstimator* estimator)
- : nTransactionsUpdated(0), minerPolicyEstimator(estimator), m_epoch(0), m_has_epoch_guard(false)
+CTxMemPool::CTxMemPool(CBlockPolicyEstimator* estimator, int check_ratio)
+ : m_check_ratio(check_ratio), minerPolicyEstimator(estimator)
{
_clear(); //lock free clear
-
- // Sanity checks off by default for performance, because otherwise
- // accepting transactions becomes O(N^2) where N is the number
- // of transactions in the pool
- nCheckFrequency = 0;
}
bool CTxMemPool::isSpent(const COutPoint& outpoint) const
@@ -523,7 +518,7 @@ void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMem
if (it2 != mapTx.end())
continue;
const Coin &coin = pcoins->AccessCoin(txin.prevout);
- if (nCheckFrequency != 0) assert(!coin.IsSpent());
+ if (m_check_ratio != 0) assert(!coin.IsSpent());
if (coin.IsSpent() || (coin.IsCoinBase() && ((signed long)nMemPoolHeight) - coin.nHeight < COINBASE_MATURITY)) {
txToRemove.insert(it);
break;
@@ -619,13 +614,11 @@ static void CheckInputsAndUpdateCoins(const CTransaction& tx, CCoinsViewCache& m
void CTxMemPool::check(const CCoinsViewCache *pcoins) const
{
- LOCK(cs);
- if (nCheckFrequency == 0)
- return;
+ if (m_check_ratio == 0) return;
- if (GetRand(std::numeric_limits<uint32_t>::max()) >= nCheckFrequency)
- return;
+ if (GetRand(m_check_ratio) >= 1) return;
+ LOCK(cs);
LogPrint(BCLog::MEMPOOL, "Checking mempool with %u transactions and %u inputs\n", (unsigned int)mapTx.size(), (unsigned int)mapNextTx.size());
uint64_t checkTotal = 0;
diff --git a/src/txmempool.h b/src/txmempool.h
index f513f14af6..78ad62aae6 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -488,8 +488,8 @@ public:
class CTxMemPool
{
private:
- uint32_t nCheckFrequency GUARDED_BY(cs); //!< Value n means that n times in 2^32 we check.
- std::atomic<unsigned int> nTransactionsUpdated; //!< Used by getblocktemplate to trigger CreateNewBlock() invocation
+ const int m_check_ratio; //!< Value n means that 1 times in n we check.
+ std::atomic<unsigned int> nTransactionsUpdated{0}; //!< Used by getblocktemplate to trigger CreateNewBlock() invocation
CBlockPolicyEstimator* minerPolicyEstimator;
uint64_t totalTxSize; //!< sum of all mempool tx's virtual sizes. Differs from serialized tx size since witness data is discounted. Defined in BIP 141.
@@ -498,8 +498,8 @@ private:
mutable int64_t lastRollingFeeUpdate;
mutable bool blockSinceLastRollingFeeBump;
mutable double rollingMinimumFeeRate; //!< minimum fee to get into the pool, decreases exponentially
- mutable uint64_t m_epoch;
- mutable bool m_has_epoch_guard;
+ mutable uint64_t m_epoch{0};
+ mutable bool m_has_epoch_guard{false};
// In-memory counter for external mempool tracking purposes.
// This number is incremented once every time a transaction
@@ -601,8 +601,14 @@ public:
std::map<uint256, CAmount> mapDeltas;
/** Create a new CTxMemPool.
+ * Sanity checks will be off by default for performance, because otherwise
+ * accepting transactions becomes O(N^2) where N is the number of transactions
+ * in the pool.
+ *
+ * @param[in] estimator is used to estimate appropriate transaction fees.
+ * @param[in] check_ratio is the ratio used to determine how often sanity checks will run.
*/
- explicit CTxMemPool(CBlockPolicyEstimator* estimator = nullptr);
+ explicit CTxMemPool(CBlockPolicyEstimator* estimator = nullptr, int check_ratio = 0);
/**
* If sanity-checking is turned on, check makes sure the pool is
@@ -611,7 +617,6 @@ public:
* check does nothing.
*/
void check(const CCoinsViewCache *pcoins) const;
- void setSanityCheck(double dFrequency = 1.0) { LOCK(cs); nCheckFrequency = static_cast<uint32_t>(dFrequency * 4294967295.0); }
// addUnchecked must updated state for all ancestors of a given transaction,
// to track size/count of descendant transactions. First version of
diff --git a/src/util/bip32.h b/src/util/bip32.h
index 347e83db9e..8f86f2aaa6 100644
--- a/src/util/bip32.h
+++ b/src/util/bip32.h
@@ -10,7 +10,7 @@
#include <vector>
/** Parse an HD keypaths like "m/7/0'/2000". */
-NODISCARD bool ParseHDKeypath(const std::string& keypath_str, std::vector<uint32_t>& keypath);
+[[nodiscard]] bool ParseHDKeypath(const std::string& keypath_str, std::vector<uint32_t>& keypath);
/** Write HD keypaths as strings */
std::string WriteHDKeypath(const std::vector<uint32_t>& keypath);
diff --git a/src/util/moneystr.h b/src/util/moneystr.h
index 9d2b6da0fc..da7f673cda 100644
--- a/src/util/moneystr.h
+++ b/src/util/moneystr.h
@@ -19,6 +19,6 @@
*/
std::string FormatMoney(const CAmount& n);
/** Parse an amount denoted in full coins. E.g. "0.0034" supplied on the command line. **/
-NODISCARD bool ParseMoney(const std::string& str, CAmount& nRet);
+[[nodiscard]] bool ParseMoney(const std::string& str, CAmount& nRet);
#endif // BITCOIN_UTIL_MONEYSTR_H
diff --git a/src/util/strencodings.cpp b/src/util/strencodings.cpp
index 3236184b0b..f3d54a2ac9 100644
--- a/src/util/strencodings.cpp
+++ b/src/util/strencodings.cpp
@@ -280,7 +280,7 @@ std::string DecodeBase32(const std::string& str, bool* pf_invalid)
return std::string((const char*)vchRet.data(), vchRet.size());
}
-NODISCARD static bool ParsePrechecks(const std::string& str)
+[[nodiscard]] static bool ParsePrechecks(const std::string& str)
{
if (str.empty()) // No empty string allowed
return false;
diff --git a/src/util/strencodings.h b/src/util/strencodings.h
index 1a217dd12d..8ee43c620b 100644
--- a/src/util/strencodings.h
+++ b/src/util/strencodings.h
@@ -101,42 +101,42 @@ constexpr inline bool IsSpace(char c) noexcept {
* @returns true if the entire string could be parsed as valid integer,
* false if not the entire string could be parsed or when overflow or underflow occurred.
*/
-NODISCARD bool ParseInt32(const std::string& str, int32_t *out);
+[[nodiscard]] bool ParseInt32(const std::string& str, int32_t *out);
/**
* Convert string to signed 64-bit integer with strict parse error feedback.
* @returns true if the entire string could be parsed as valid integer,
* false if not the entire string could be parsed or when overflow or underflow occurred.
*/
-NODISCARD bool ParseInt64(const std::string& str, int64_t *out);
+[[nodiscard]] bool ParseInt64(const std::string& str, int64_t *out);
/**
* Convert decimal string to unsigned 8-bit integer with strict parse error feedback.
* @returns true if the entire string could be parsed as valid integer,
* false if not the entire string could be parsed or when overflow or underflow occurred.
*/
-NODISCARD bool ParseUInt8(const std::string& str, uint8_t *out);
+[[nodiscard]] bool ParseUInt8(const std::string& str, uint8_t *out);
/**
* Convert decimal string to unsigned 32-bit integer with strict parse error feedback.
* @returns true if the entire string could be parsed as valid integer,
* false if not the entire string could be parsed or when overflow or underflow occurred.
*/
-NODISCARD bool ParseUInt32(const std::string& str, uint32_t *out);
+[[nodiscard]] bool ParseUInt32(const std::string& str, uint32_t *out);
/**
* Convert decimal string to unsigned 64-bit integer with strict parse error feedback.
* @returns true if the entire string could be parsed as valid integer,
* false if not the entire string could be parsed or when overflow or underflow occurred.
*/
-NODISCARD bool ParseUInt64(const std::string& str, uint64_t *out);
+[[nodiscard]] bool ParseUInt64(const std::string& str, uint64_t *out);
/**
* Convert string to double with strict parse error feedback.
* @returns true if the entire string could be parsed as valid double,
* false if not the entire string could be parsed or when overflow or underflow occurred.
*/
-NODISCARD bool ParseDouble(const std::string& str, double *out);
+[[nodiscard]] bool ParseDouble(const std::string& str, double *out);
/**
* Convert a span of bytes to a lower-case hexadecimal string.
@@ -170,7 +170,7 @@ bool TimingResistantEqual(const T& a, const T& b)
* @returns true on success, false on error.
* @note The result must be in the range (-10^18,10^18), otherwise an overflow error will trigger.
*/
-NODISCARD bool ParseFixedPoint(const std::string &val, int decimals, int64_t *amount_out);
+[[nodiscard]] bool ParseFixedPoint(const std::string &val, int decimals, int64_t *amount_out);
/** Convert from one power-of-2 number base to another. */
template<int frombits, int tobits, bool pad, typename O, typename I>
diff --git a/src/util/string.h b/src/util/string.h
index a0c87bd00c..5ffdc80d88 100644
--- a/src/util/string.h
+++ b/src/util/string.h
@@ -15,7 +15,7 @@
#include <string>
#include <vector>
-NODISCARD inline std::string TrimString(const std::string& str, const std::string& pattern = " \f\n\r\t\v")
+[[nodiscard]] inline std::string TrimString(const std::string& str, const std::string& pattern = " \f\n\r\t\v")
{
std::string::size_type front = str.find_first_not_of(pattern);
if (front == std::string::npos) {
@@ -59,7 +59,7 @@ inline std::string Join(const std::vector<std::string>& list, const std::string&
/**
* Check if a string does not contain any embedded NUL (\0) characters
*/
-NODISCARD inline bool ValidAsCString(const std::string& str) noexcept
+[[nodiscard]] inline bool ValidAsCString(const std::string& str) noexcept
{
return str.size() == strlen(str.c_str());
}
@@ -80,7 +80,7 @@ std::string ToString(const T& t)
* Check whether a container begins with the given prefix.
*/
template <typename T1, size_t PREFIX_LEN>
-NODISCARD inline bool HasPrefix(const T1& obj,
+[[nodiscard]] inline bool HasPrefix(const T1& obj,
const std::array<uint8_t, PREFIX_LEN>& prefix)
{
return obj.size() >= PREFIX_LEN &&
diff --git a/src/util/system.h b/src/util/system.h
index 1df194ca84..2be8bb754b 100644
--- a/src/util/system.h
+++ b/src/util/system.h
@@ -60,7 +60,7 @@ bool FileCommit(FILE *file);
bool TruncateFile(FILE *file, unsigned int length);
int RaiseFileDescriptorLimit(int nMinFD);
void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length);
-bool RenameOver(fs::path src, fs::path dest);
+[[nodiscard]] bool RenameOver(fs::path src, fs::path dest);
bool LockDirectory(const fs::path& directory, const std::string lockfile_name, bool probe_only=false);
void UnlockDirectory(const fs::path& directory, const std::string& lockfile_name);
bool DirIsWritable(const fs::path& directory);
@@ -188,7 +188,7 @@ protected:
std::map<OptionsCategory, std::map<std::string, Arg>> m_available_args GUARDED_BY(cs_args);
std::list<SectionInfo> m_config_sections GUARDED_BY(cs_args);
- NODISCARD bool ReadConfigStream(std::istream& stream, const std::string& filepath, std::string& error, bool ignore_invalid_keys = false);
+ [[nodiscard]] bool ReadConfigStream(std::istream& stream, const std::string& filepath, std::string& error, bool ignore_invalid_keys = false);
/**
* Returns true if settings values from the default section should be used,
@@ -220,8 +220,8 @@ public:
*/
void SelectConfigNetwork(const std::string& network);
- NODISCARD bool ParseParameters(int argc, const char* const argv[], std::string& error);
- NODISCARD bool ReadConfigFiles(std::string& error, bool ignore_invalid_keys = false);
+ [[nodiscard]] bool ParseParameters(int argc, const char* const argv[], std::string& error);
+ [[nodiscard]] bool ReadConfigFiles(std::string& error, bool ignore_invalid_keys = false);
/**
* Log warnings for options in m_section_only_args when
diff --git a/src/validation.cpp b/src/validation.cpp
index 71402ef263..d8f7bfc913 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -696,7 +696,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
return state.Invalid(TxValidationResult::TX_INPUTS_NOT_STANDARD, "bad-txns-nonstandard-inputs");
}
- // Check for non-standard witness in P2WSH
+ // Check for non-standard witnesses.
if (tx.HasWitness() && fRequireStandard && !IsWitnessStandard(tx, m_view))
return state.Invalid(TxValidationResult::TX_WITNESS_MUTATED, "bad-witness-nonstandard");
@@ -5110,7 +5110,9 @@ bool DumpMempool(const CTxMemPool& pool)
if (!FileCommit(file.Get()))
throw std::runtime_error("FileCommit failed");
file.fclose();
- RenameOver(GetDataDir() / "mempool.dat.new", GetDataDir() / "mempool.dat");
+ if (!RenameOver(GetDataDir() / "mempool.dat.new", GetDataDir() / "mempool.dat")) {
+ throw std::runtime_error("Rename failed");
+ }
int64_t last = GetTimeMicros();
LogPrintf("Dumped mempool: %gs to copy, %gs to dump\n", (mid-start)*MICRO, (last-mid)*MICRO);
} catch (const std::exception& e) {
diff --git a/src/interfaces/wallet.cpp b/src/wallet/interfaces.cpp
index f68016b557..3fbba9ab92 100644
--- a/src/interfaces/wallet.cpp
+++ b/src/wallet/interfaces.cpp
@@ -31,9 +31,22 @@
#include <utility>
#include <vector>
-namespace interfaces {
-namespace {
+using interfaces::Chain;
+using interfaces::FoundBlock;
+using interfaces::Handler;
+using interfaces::MakeHandler;
+using interfaces::Wallet;
+using interfaces::WalletAddress;
+using interfaces::WalletBalances;
+using interfaces::WalletClient;
+using interfaces::WalletOrderForm;
+using interfaces::WalletTx;
+using interfaces::WalletTxOut;
+using interfaces::WalletTxStatus;
+using interfaces::WalletValueMap;
+namespace wallet {
+namespace {
//! Construct wallet tx struct.
WalletTx MakeWalletTx(CWallet& wallet, const CWalletTx& wtx)
{
@@ -561,14 +574,14 @@ public:
std::vector<std::unique_ptr<Handler>> m_rpc_handlers;
std::list<CRPCCommand> m_rpc_commands;
};
-
} // namespace
+} // namespace wallet
-std::unique_ptr<Wallet> MakeWallet(const std::shared_ptr<CWallet>& wallet) { return wallet ? MakeUnique<WalletImpl>(wallet) : nullptr; }
+namespace interfaces {
+std::unique_ptr<Wallet> MakeWallet(const std::shared_ptr<CWallet>& wallet) { return wallet ? MakeUnique<wallet::WalletImpl>(wallet) : nullptr; }
std::unique_ptr<WalletClient> MakeWalletClient(Chain& chain, ArgsManager& args)
{
- return MakeUnique<WalletClientImpl>(chain, args);
+ return MakeUnique<wallet::WalletClientImpl>(chain, args);
}
-
} // namespace interfaces
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index e66377c13c..7ea6a214b2 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -2789,7 +2789,7 @@ static RPCHelpMan unloadwallet()
"Unloads the wallet referenced by the request endpoint otherwise unloads the wallet specified in the argument.\n"
"Specifying the wallet name on a wallet endpoint is invalid.",
{
- {"wallet_name", RPCArg::Type::STR, /* default */ "the wallet name from the RPC endpoint", "The name of the wallet to unload. Must be provided in the RPC endpoint or this parameter (but not both)."},
+ {"wallet_name", RPCArg::Type::STR, /* default */ "the wallet name from the RPC endpoint", "The name of the wallet to unload. If provided both here and in the RPC endpoint, the two must be identical."},
{"load_on_startup", RPCArg::Type::BOOL, /* default */ "null", "Save wallet name to persistent settings and load on startup. True to add wallet to startup list, false to remove, null to leave unchanged."},
},
RPCResult{RPCResult::Type::OBJ, "", "", {
@@ -2803,8 +2803,8 @@ static RPCHelpMan unloadwallet()
{
std::string wallet_name;
if (GetWalletNameFromJSONRPCRequest(request, wallet_name)) {
- if (!request.params[0].isNull()) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Both the RPC endpoint wallet and wallet_name parameter were provided (only one allowed)");
+ if (!(request.params[0].isNull() || request.params[0].get_str() == wallet_name)) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "RPC endpoint wallet and wallet_name parameter specify different wallets");
}
} else {
wallet_name = request.params[0].get_str();
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 3019d53c6c..65b54f39b4 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -419,7 +419,7 @@ bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase,
return false;
if (!crypter.Encrypt(_vMasterKey, pMasterKey.second.vchCryptedKey))
return false;
- WalletBatch(*database).WriteMasterKey(pMasterKey.first, pMasterKey.second);
+ WalletBatch(GetDatabase()).WriteMasterKey(pMasterKey.first, pMasterKey.second);
if (fWasLocked)
Lock();
return true;
@@ -432,7 +432,7 @@ bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase,
void CWallet::chainStateFlushed(const CBlockLocator& loc)
{
- WalletBatch batch(*database);
+ WalletBatch batch(GetDatabase());
batch.WriteBestBlock(loc);
}
@@ -444,7 +444,7 @@ void CWallet::SetMinVersion(enum WalletFeature nVersion, WalletBatch* batch_in)
nWalletVersion = nVersion;
{
- WalletBatch* batch = batch_in ? batch_in : new WalletBatch(*database);
+ WalletBatch* batch = batch_in ? batch_in : new WalletBatch(GetDatabase());
if (nWalletVersion > 40000)
batch->WriteMinVersion(nWalletVersion);
if (!batch_in)
@@ -484,12 +484,12 @@ bool CWallet::HasWalletSpend(const uint256& txid) const
void CWallet::Flush()
{
- database->Flush();
+ GetDatabase().Flush();
}
void CWallet::Close()
{
- database->Close();
+ GetDatabase().Close();
}
void CWallet::SyncMetaData(std::pair<TxSpends::iterator, TxSpends::iterator> range)
@@ -615,7 +615,7 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
{
LOCK(cs_wallet);
mapMasterKeys[++nMasterKeyMaxID] = kMasterKey;
- WalletBatch* encrypted_batch = new WalletBatch(*database);
+ WalletBatch* encrypted_batch = new WalletBatch(GetDatabase());
if (!encrypted_batch->TxnBegin()) {
delete encrypted_batch;
encrypted_batch = nullptr;
@@ -667,12 +667,12 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
// Need to completely rewrite the wallet file; if we don't, bdb might keep
// bits of the unencrypted private key in slack space in the database file.
- database->Rewrite();
+ GetDatabase().Rewrite();
// BDB seems to have a bad habit of writing old data into
// slack space in .dat files; that is bad if the old data is
// unencrypted private keys. So:
- database->ReloadDbEnv();
+ GetDatabase().ReloadDbEnv();
}
NotifyStatusChanged(this);
@@ -683,7 +683,7 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
DBErrors CWallet::ReorderTransactions()
{
LOCK(cs_wallet);
- WalletBatch batch(*database);
+ WalletBatch batch(GetDatabase());
// Old wallets didn't have any defined order for transactions
// Probably a bad idea to change the output of this
@@ -744,7 +744,7 @@ int64_t CWallet::IncOrderPosNext(WalletBatch* batch)
if (batch) {
batch->WriteOrderPosNext(nOrderPosNext);
} else {
- WalletBatch(*database).WriteOrderPosNext(nOrderPosNext);
+ WalletBatch(GetDatabase()).WriteOrderPosNext(nOrderPosNext);
}
return nRet;
}
@@ -774,7 +774,7 @@ bool CWallet::MarkReplaced(const uint256& originalHash, const uint256& newHash)
wtx.mapValue["replaced_by_txid"] = newHash.ToString();
- WalletBatch batch(*database);
+ WalletBatch batch(GetDatabase());
bool success = true;
if (!batch.WriteTx(wtx)) {
@@ -846,7 +846,7 @@ CWalletTx* CWallet::AddToWallet(CTransactionRef tx, const CWalletTx::Confirmatio
{
LOCK(cs_wallet);
- WalletBatch batch(*database, fFlushOnClose);
+ WalletBatch batch(GetDatabase(), fFlushOnClose);
uint256 hash = tx->GetHash();
@@ -1045,7 +1045,7 @@ bool CWallet::AbandonTransaction(const uint256& hashTx)
{
LOCK(cs_wallet);
- WalletBatch batch(*database);
+ WalletBatch batch(GetDatabase());
std::set<uint256> todo;
std::set<uint256> done;
@@ -1108,7 +1108,7 @@ void CWallet::MarkConflicted(const uint256& hashBlock, int conflicting_height, c
return;
// Do not flush the wallet here for performance reasons
- WalletBatch batch(*database, false);
+ WalletBatch batch(GetDatabase(), false);
std::set<uint256> todo;
std::set<uint256> done;
@@ -1446,13 +1446,13 @@ void CWallet::SetWalletFlag(uint64_t flags)
{
LOCK(cs_wallet);
m_wallet_flags |= flags;
- if (!WalletBatch(*database).WriteWalletFlags(m_wallet_flags))
+ if (!WalletBatch(GetDatabase()).WriteWalletFlags(m_wallet_flags))
throw std::runtime_error(std::string(__func__) + ": writing wallet flags failed");
}
void CWallet::UnsetWalletFlag(uint64_t flag)
{
- WalletBatch batch(*database);
+ WalletBatch batch(GetDatabase());
UnsetWalletFlagWithDB(batch, flag);
}
@@ -1491,7 +1491,7 @@ bool CWallet::AddWalletFlags(uint64_t flags)
LOCK(cs_wallet);
// We should never be writing unknown non-tolerable wallet flags
assert(((flags & KNOWN_WALLET_FLAGS) >> 32) == (flags >> 32));
- if (!WalletBatch(*database).WriteWalletFlags(flags)) {
+ if (!WalletBatch(GetDatabase()).WriteWalletFlags(flags)) {
throw std::runtime_error(std::string(__func__) + ": writing wallet flags failed");
}
@@ -1582,7 +1582,7 @@ bool CWallet::ImportScriptPubKeys(const std::string& label, const std::set<CScri
return false;
}
if (apply_label) {
- WalletBatch batch(*database);
+ WalletBatch batch(GetDatabase());
for (const CScript& script : script_pub_keys) {
CTxDestination dest;
ExtractDestination(script, dest);
@@ -3177,10 +3177,10 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
LOCK(cs_wallet);
fFirstRunRet = false;
- DBErrors nLoadWalletRet = WalletBatch(*database).LoadWallet(this);
+ DBErrors nLoadWalletRet = WalletBatch(GetDatabase()).LoadWallet(this);
if (nLoadWalletRet == DBErrors::NEED_REWRITE)
{
- if (database->Rewrite("\x04pool"))
+ if (GetDatabase().Rewrite("\x04pool"))
{
for (const auto& spk_man_pair : m_spk_managers) {
spk_man_pair.second->RewriteDB();
@@ -3204,7 +3204,7 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
DBErrors CWallet::ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256>& vHashOut)
{
AssertLockHeld(cs_wallet);
- DBErrors nZapSelectTxRet = WalletBatch(*database).ZapSelectTx(vHashIn, vHashOut);
+ DBErrors nZapSelectTxRet = WalletBatch(GetDatabase()).ZapSelectTx(vHashIn, vHashOut);
for (const uint256& hash : vHashOut) {
const auto& it = mapWallet.find(hash);
wtxOrdered.erase(it->second.m_it_wtxOrdered);
@@ -3216,7 +3216,7 @@ DBErrors CWallet::ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256
if (nZapSelectTxRet == DBErrors::NEED_REWRITE)
{
- if (database->Rewrite("\x04pool"))
+ if (GetDatabase().Rewrite("\x04pool"))
{
for (const auto& spk_man_pair : m_spk_managers) {
spk_man_pair.second->RewriteDB();
@@ -3254,14 +3254,14 @@ bool CWallet::SetAddressBookWithDB(WalletBatch& batch, const CTxDestination& add
bool CWallet::SetAddressBook(const CTxDestination& address, const std::string& strName, const std::string& strPurpose)
{
- WalletBatch batch(*database);
+ WalletBatch batch(GetDatabase());
return SetAddressBookWithDB(batch, address, strName, strPurpose);
}
bool CWallet::DelAddressBook(const CTxDestination& address)
{
bool is_mine;
- WalletBatch batch(*database);
+ WalletBatch batch(GetDatabase());
{
LOCK(cs_wallet);
// If we want to delete receiving addresses, we need to take care that DestData "used" (and possibly newer DestData) gets preserved (and the "deleted" address transformed into a change entry instead of actually being deleted)
@@ -4008,7 +4008,7 @@ std::shared_ptr<CWallet> CWallet::Create(interfaces::Chain& chain, const std::st
int rescan_height = 0;
if (!gArgs.GetBoolArg("-rescan", false))
{
- WalletBatch batch(*walletInstance->database);
+ WalletBatch batch(walletInstance->GetDatabase());
CBlockLocator locator;
if (batch.ReadBestBlock(locator)) {
if (const Optional<int> fork_height = chain.findLocatorFork(locator)) {
@@ -4071,7 +4071,7 @@ std::shared_ptr<CWallet> CWallet::Create(interfaces::Chain& chain, const std::st
}
}
walletInstance->chainStateFlushed(chain.getTipLocator());
- walletInstance->database->IncrementUpdateCounter();
+ walletInstance->GetDatabase().IncrementUpdateCounter();
}
{
@@ -4149,7 +4149,7 @@ void CWallet::postInitProcess()
bool CWallet::BackupWallet(const std::string& strDest) const
{
- return database->Backup(strDest);
+ return GetDatabase().Backup(strDest);
}
CKeyPool::CKeyPool()
@@ -4452,7 +4452,7 @@ void CWallet::SetupDescriptorScriptPubKeyMans()
void CWallet::AddActiveScriptPubKeyMan(uint256 id, OutputType type, bool internal)
{
- WalletBatch batch(*database);
+ WalletBatch batch(GetDatabase());
if (!batch.WriteActiveScriptPubKeyMan(static_cast<uint8_t>(type), id, internal)) {
throw std::runtime_error(std::string(__func__) + ": writing active ScriptPubKeyMan id failed");
}
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 69cf6b66a4..e6beb111fb 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -695,7 +695,7 @@ private:
std::string m_name;
/** Internal database handle. */
- std::unique_ptr<WalletDatabase> database;
+ std::unique_ptr<WalletDatabase> const m_database;
/**
* The following is used to keep track of how far behind the wallet is
@@ -729,14 +729,11 @@ public:
*/
mutable RecursiveMutex cs_wallet;
- /** Get database handle used by this wallet. Ideally this function would
- * not be necessary.
- */
- WalletDatabase& GetDBHandle()
+ WalletDatabase& GetDatabase() const override
{
- return *database;
+ assert(static_cast<bool>(m_database));
+ return *m_database;
}
- WalletDatabase& GetDatabase() const override { return *database; }
/**
* Select a set of coins such that nValueRet >= nTargetValue and at least
@@ -758,7 +755,7 @@ public:
CWallet(interfaces::Chain* chain, const std::string& name, std::unique_ptr<WalletDatabase> database)
: m_chain(chain),
m_name(name),
- database(std::move(database))
+ m_database(std::move(database))
{
}
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index 45807ae6fd..c0521d3386 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -945,7 +945,7 @@ void MaybeCompactWalletDB()
}
for (const std::shared_ptr<CWallet>& pwallet : GetWallets()) {
- WalletDatabase& dbh = pwallet->GetDBHandle();
+ WalletDatabase& dbh = pwallet->GetDatabase();
unsigned int nUpdateCounter = dbh.nUpdateCounter;