aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am1
-rw-r--r--src/attributes.h22
-rw-r--r--src/base58.h10
-rw-r--r--src/bench/base58.cpp2
-rw-r--r--src/bench/prevector.cpp10
-rw-r--r--src/blockencodings.h9
-rw-r--r--src/compat.h10
-rw-r--r--src/core_io.h7
-rw-r--r--src/httpserver.cpp12
-rw-r--r--src/init.cpp12
-rw-r--r--src/interfaces/node.cpp1
-rw-r--r--src/miner.cpp5
-rw-r--r--src/netaddress.cpp10
-rw-r--r--src/netaddress.h1
-rw-r--r--src/outputtype.h3
-rw-r--r--src/prevector.h8
-rw-r--r--src/rest.cpp5
-rw-r--r--src/rpc/blockchain.cpp1
-rw-r--r--src/rpc/util.h2
-rw-r--r--src/script/descriptor.cpp2
-rw-r--r--src/test/blockencodings_tests.cpp45
-rw-r--r--src/test/coins_tests.cpp9
-rw-r--r--src/test/dbwrapper_tests.cpp8
-rw-r--r--src/test/getarg_tests.cpp2
-rw-r--r--src/test/util_tests.cpp46
-rw-r--r--src/util/moneystr.h11
-rw-r--r--src/util/strencodings.cpp2
-rw-r--r--src/util/strencodings.h18
-rw-r--r--src/util/system.cpp43
-rw-r--r--src/util/system.h15
-rw-r--r--src/wallet/db.cpp47
-rw-r--r--src/wallet/db.h20
-rw-r--r--src/wallet/wallet.cpp8
33 files changed, 282 insertions, 125 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 8dd0d31839..09daaebd23 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -95,6 +95,7 @@ endif
BITCOIN_CORE_H = \
addrdb.h \
addrman.h \
+ attributes.h \
base58.h \
bech32.h \
bloom.h \
diff --git a/src/attributes.h b/src/attributes.h
new file mode 100644
index 0000000000..45099bd8b8
--- /dev/null
+++ b/src/attributes.h
@@ -0,0 +1,22 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2018 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#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_
+# else
+# define NODISCARD __attribute__((warn_unused_result))
+# endif
+#endif
+
+#endif // BITCOIN_ATTRIBUTES_H
diff --git a/src/base58.h b/src/base58.h
index 9d3f90652e..d6e0299a1e 100644
--- a/src/base58.h
+++ b/src/base58.h
@@ -14,6 +14,8 @@
#ifndef BITCOIN_BASE58_H
#define BITCOIN_BASE58_H
+#include <attributes.h>
+
#include <string>
#include <vector>
@@ -33,13 +35,13 @@ std::string EncodeBase58(const std::vector<unsigned char>& vch);
* return true if decoding is successful.
* psz cannot be nullptr.
*/
-bool DecodeBase58(const char* psz, std::vector<unsigned char>& vchRet);
+NODISCARD bool DecodeBase58(const char* psz, std::vector<unsigned char>& vchRet);
/**
* Decode a base58-encoded string (str) into a byte vector (vchRet).
* return true if decoding is successful.
*/
-bool DecodeBase58(const std::string& str, std::vector<unsigned char>& vchRet);
+NODISCARD bool DecodeBase58(const std::string& str, std::vector<unsigned char>& vchRet);
/**
* Encode a byte vector into a base58-encoded string, including checksum
@@ -50,12 +52,12 @@ std::string EncodeBase58Check(const std::vector<unsigned char>& vchIn);
* Decode a base58-encoded string (psz) that includes a checksum into a byte
* vector (vchRet), return true if decoding is successful
*/
-bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet);
+NODISCARD bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet);
/**
* Decode a base58-encoded string (str) that includes a checksum into a byte
* vector (vchRet), return true if decoding is successful
*/
-bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRet);
+NODISCARD bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRet);
#endif // BITCOIN_BASE58_H
diff --git a/src/bench/base58.cpp b/src/bench/base58.cpp
index a555376e40..e7702ec461 100644
--- a/src/bench/base58.cpp
+++ b/src/bench/base58.cpp
@@ -49,7 +49,7 @@ static void Base58Decode(benchmark::State& state)
const char* addr = "17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYhem";
std::vector<unsigned char> vch;
while (state.KeepRunning()) {
- DecodeBase58(addr, vch);
+ (void) DecodeBase58(addr, vch);
}
}
diff --git a/src/bench/prevector.cpp b/src/bench/prevector.cpp
index 8cc404b9e2..00e5d7e7a0 100644
--- a/src/bench/prevector.cpp
+++ b/src/bench/prevector.cpp
@@ -2,13 +2,21 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <compat.h>
#include <prevector.h>
#include <serialize.h>
#include <streams.h>
+#include <type_traits>
#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) {}
diff --git a/src/blockencodings.h b/src/blockencodings.h
index fad1f56f54..0c2b83ebcf 100644
--- a/src/blockencodings.h
+++ b/src/blockencodings.h
@@ -52,12 +52,12 @@ public:
}
}
- uint16_t offset = 0;
+ int32_t offset = 0;
for (size_t j = 0; j < indexes.size(); j++) {
- if (uint64_t(indexes[j]) + uint64_t(offset) > std::numeric_limits<uint16_t>::max())
+ if (int32_t(indexes[j]) + offset > std::numeric_limits<uint16_t>::max())
throw std::ios_base::failure("indexes overflowed 16 bits");
indexes[j] = indexes[j] + offset;
- offset = indexes[j] + 1;
+ offset = int32_t(indexes[j]) + 1;
}
} else {
for (size_t i = 0; i < indexes.size(); i++) {
@@ -186,6 +186,9 @@ public:
READWRITE(prefilledtxn);
+ if (BlockTxCount() > std::numeric_limits<uint16_t>::max())
+ throw std::ios_base::failure("indexes overflowed 16 bits");
+
if (ser_action.ForRead())
FillShortTxIDSelector();
}
diff --git a/src/compat.h b/src/compat.h
index d228611160..049579c365 100644
--- a/src/compat.h
+++ b/src/compat.h
@@ -10,16 +10,6 @@
#include <config/bitcoin-config.h>
#endif
-#include <type_traits>
-
-// 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
-
#ifdef WIN32
#ifdef _WIN32_WINNT
#undef _WIN32_WINNT
diff --git a/src/core_io.h b/src/core_io.h
index 2c3b64d81e..6f87161f46 100644
--- a/src/core_io.h
+++ b/src/core_io.h
@@ -6,6 +6,7 @@
#define BITCOIN_CORE_IO_H
#include <amount.h>
+#include <attributes.h>
#include <string>
#include <vector>
@@ -22,8 +23,8 @@ class UniValue;
// core_read.cpp
CScript ParseScript(const std::string& s);
std::string ScriptToAsmStr(const CScript& script, const bool fAttemptSighashDecode = false);
-bool DecodeHexTx(CMutableTransaction& tx, const std::string& hex_tx, bool try_no_witness = false, bool try_witness = true);
-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);
/**
@@ -36,7 +37,7 @@ bool DecodeHexBlockHeader(CBlockHeader&, const std::string& hex_header);
*/
bool ParseHashStr(const std::string& strHex, uint256& result);
std::vector<unsigned char> ParseHexUV(const UniValue& v, const std::string& strName);
-bool DecodePSBT(PartiallySignedTransaction& psbt, const std::string& base64_tx, std::string& error);
+NODISCARD bool DecodePSBT(PartiallySignedTransaction& psbt, const std::string& base64_tx, std::string& error);
int ParseSighashString(const UniValue& sighash);
// core_write.cpp
diff --git a/src/httpserver.cpp b/src/httpserver.cpp
index 91ebc4680c..00434169cd 100644
--- a/src/httpserver.cpp
+++ b/src/httpserver.cpp
@@ -300,9 +300,12 @@ static bool HTTPBindAddresses(struct evhttp* http)
std::vector<std::pair<std::string, uint16_t> > endpoints;
// Determine what addresses to bind to
- if (!gArgs.IsArgSet("-rpcallowip")) { // Default to loopback if not allowing external IPs
+ if (!(gArgs.IsArgSet("-rpcallowip") && gArgs.IsArgSet("-rpcbind"))) { // Default to loopback if not allowing external IPs
endpoints.push_back(std::make_pair("::1", http_port));
endpoints.push_back(std::make_pair("127.0.0.1", http_port));
+ if (gArgs.IsArgSet("-rpcallowip")) {
+ LogPrintf("WARNING: option -rpcallowip was specified without -rpcbind; this doesn't usually make sense\n");
+ }
if (gArgs.IsArgSet("-rpcbind")) {
LogPrintf("WARNING: option -rpcbind was ignored because -rpcallowip was not specified, refusing to allow everyone to connect\n");
}
@@ -313,9 +316,6 @@ static bool HTTPBindAddresses(struct evhttp* http)
SplitHostPort(strRPCBind, port, host);
endpoints.push_back(std::make_pair(host, port));
}
- } else { // No specific bind address specified, bind to any
- endpoints.push_back(std::make_pair("::", http_port));
- endpoints.push_back(std::make_pair("0.0.0.0", http_port));
}
// Bind addresses
@@ -323,6 +323,10 @@ static bool HTTPBindAddresses(struct evhttp* http)
LogPrint(BCLog::HTTP, "Binding RPC on address %s port %i\n", i->first, i->second);
evhttp_bound_socket *bind_handle = evhttp_bind_socket_with_handle(http, i->first.empty() ? nullptr : i->first.c_str(), i->second);
if (bind_handle) {
+ CNetAddr addr;
+ if (i->first.empty() || (LookupHost(i->first.c_str(), addr, false) && addr.IsBindAny())) {
+ LogPrintf("WARNING: the RPC server is not safe to expose to untrusted networks such as the public internet\n");
+ }
boundSockets.push_back(bind_handle);
} else {
LogPrintf("Binding RPC on address %s port %i failed.\n", i->first, i->second);
diff --git a/src/init.cpp b/src/init.cpp
index 3ab97be329..31212a355b 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -500,7 +500,7 @@ void SetupServerArgs()
gArgs.AddArg("-rest", strprintf("Accept public REST requests (default: %u)", DEFAULT_REST_ENABLE), false, OptionsCategory::RPC);
gArgs.AddArg("-rpcallowip=<ip>", "Allow JSON-RPC connections from specified source. Valid for <ip> are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24). This option can be specified multiple times", false, OptionsCategory::RPC);
gArgs.AddArg("-rpcauth=<userpw>", "Username and hashed password for JSON-RPC connections. The field <userpw> comes in the format: <USERNAME>:<SALT>$<HASH>. A canonical python script is included in share/rpcauth. The client then connects normally using the rpcuser=<USERNAME>/rpcpassword=<PASSWORD> pair of arguments. This option can be specified multiple times", false, OptionsCategory::RPC);
- gArgs.AddArg("-rpcbind=<addr>[:port]", "Bind to given address to listen for JSON-RPC connections. This option is ignored unless -rpcallowip is also passed. Port is optional and overrides -rpcport. Use [host]:port notation for IPv6. This option can be specified multiple times (default: 127.0.0.1 and ::1 i.e., localhost, or if -rpcallowip has been specified, 0.0.0.0 and :: i.e., all addresses)", false, OptionsCategory::RPC);
+ gArgs.AddArg("-rpcbind=<addr>[:port]", "Bind to given address to listen for JSON-RPC connections. Do not expose the RPC server to untrusted networks such as the public internet! This option is ignored unless -rpcallowip is also passed. Port is optional and overrides -rpcport. Use [host]:port notation for IPv6. This option can be specified multiple times (default: 127.0.0.1 and ::1 i.e., localhost)", false, OptionsCategory::RPC);
gArgs.AddArg("-rpccookiefile=<loc>", "Location of the auth cookie. Relative paths will be prefixed by a net-specific datadir location. (default: data dir)", false, OptionsCategory::RPC);
gArgs.AddArg("-rpcpassword=<pw>", "Password for JSON-RPC connections", false, OptionsCategory::RPC);
gArgs.AddArg("-rpcport=<port>", strprintf("Listen for JSON-RPC connections on <port> (default: %u, testnet: %u, regtest: %u)", defaultBaseParams->RPCPort(), testnetBaseParams->RPCPort(), regtestBaseParams->RPCPort()), false, OptionsCategory::RPC);
@@ -803,7 +803,15 @@ void InitParameterInteraction()
// Warn if network-specific options (-addnode, -connect, etc) are
// specified in default section of config file, but not overridden
// on the command line or in this network's section of the config file.
- gArgs.WarnForSectionOnlyArgs();
+ std::string network = gArgs.GetChainName();
+ for (const auto& arg : gArgs.GetUnsuitableSectionOnlyArgs()) {
+ InitWarning(strprintf(_("Config setting for %s only applied on %s network when in [%s] section."), arg, network, network));
+ }
+
+ // Warn if unrecognized section name are present in the config file.
+ for (const auto& section : gArgs.GetUnrecognizedSections()) {
+ InitWarning(strprintf(_("Section [%s] is not recognized."), section));
+ }
}
static std::string ResolveErrMsg(const char * const optname, const std::string& strBind)
diff --git a/src/interfaces/node.cpp b/src/interfaces/node.cpp
index 1919e16a66..bd7e414ff3 100644
--- a/src/interfaces/node.cpp
+++ b/src/interfaces/node.cpp
@@ -35,7 +35,6 @@
#endif
#include <atomic>
-#include <boost/thread/thread.hpp>
#include <univalue.h>
class CWallet;
diff --git a/src/miner.cpp b/src/miner.cpp
index feb86cab66..96c9cd6d2a 100644
--- a/src/miner.cpp
+++ b/src/miner.cpp
@@ -70,9 +70,8 @@ static BlockAssembler::Options DefaultOptions()
// If -blockmaxweight is not given, limit to DEFAULT_BLOCK_MAX_WEIGHT
BlockAssembler::Options options;
options.nBlockMaxWeight = gArgs.GetArg("-blockmaxweight", DEFAULT_BLOCK_MAX_WEIGHT);
- if (gArgs.IsArgSet("-blockmintxfee")) {
- CAmount n = 0;
- ParseMoney(gArgs.GetArg("-blockmintxfee", ""), n);
+ CAmount n = 0;
+ if (gArgs.IsArgSet("-blockmintxfee") && ParseMoney(gArgs.GetArg("-blockmintxfee", ""), n)) {
options.blockMinFeeRate = CFeeRate(n);
} else {
options.blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE);
diff --git a/src/netaddress.cpp b/src/netaddress.cpp
index e1af4eff62..72be77dfd9 100644
--- a/src/netaddress.cpp
+++ b/src/netaddress.cpp
@@ -83,6 +83,16 @@ unsigned int CNetAddr::GetByte(int n) const
return ip[15-n];
}
+bool CNetAddr::IsBindAny() const
+{
+ const int cmplen = IsIPv4() ? 4 : 16;
+ for (int i = 0; i < cmplen; ++i) {
+ if (GetByte(i)) return false;
+ }
+
+ return true;
+}
+
bool CNetAddr::IsIPv4() const
{
return (memcmp(ip, pchIPv4, sizeof(pchIPv4)) == 0);
diff --git a/src/netaddress.h b/src/netaddress.h
index cc0e4d4f12..86c13b3465 100644
--- a/src/netaddress.h
+++ b/src/netaddress.h
@@ -55,6 +55,7 @@ class CNetAddr
bool SetInternal(const std::string& name);
bool SetSpecial(const std::string &strName); // for Tor addresses
+ bool IsBindAny() const; // INADDR_ANY equivalent
bool IsIPv4() const; // IPv4 mapped address (::FFFF:0:0/96, 0.0.0.0/0)
bool IsIPv6() const; // IPv6 address (not mapped IPv4, not Tor)
bool IsRFC1918() const; // IPv4 private networks (10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12)
diff --git a/src/outputtype.h b/src/outputtype.h
index 4c4d93bc8b..6c30fd1950 100644
--- a/src/outputtype.h
+++ b/src/outputtype.h
@@ -6,6 +6,7 @@
#ifndef BITCOIN_OUTPUTTYPE_H
#define BITCOIN_OUTPUTTYPE_H
+#include <attributes.h>
#include <keystore.h>
#include <script/standard.h>
@@ -26,7 +27,7 @@ enum class OutputType {
CHANGE_AUTO,
};
-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/prevector.h b/src/prevector.h
index aa77573746..99e5751634 100644
--- a/src/prevector.h
+++ b/src/prevector.h
@@ -15,8 +15,6 @@
#include <iterator>
#include <type_traits>
-#include <compat.h>
-
#pragma pack(push, 1)
/** Implements a drop-in replacement for std::vector<T> which stores up to N
* elements directly (without heap allocation). The types Size and Diff are
@@ -198,11 +196,7 @@ private:
T* item_ptr(difference_type pos) { return is_direct() ? direct_ptr(pos) : indirect_ptr(pos); }
const T* item_ptr(difference_type pos) const { return is_direct() ? direct_ptr(pos) : indirect_ptr(pos); }
- void fill(T* dst, ptrdiff_t count) {
- std::fill_n(dst, count, T{});
- }
-
- void fill(T* dst, ptrdiff_t count, const T& value) {
+ void fill(T* dst, ptrdiff_t count, const T& value = T{}) {
std::fill_n(dst, count, value);
}
diff --git a/src/rest.cpp b/src/rest.cpp
index 6c7e0384cb..4988e6ed26 100644
--- a/src/rest.cpp
+++ b/src/rest.cpp
@@ -3,20 +3,21 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <attributes.h>
#include <chain.h>
#include <chainparams.h>
#include <core_io.h>
+#include <httpserver.h>
#include <index/txindex.h>
#include <primitives/block.h>
#include <primitives/transaction.h>
-#include <validation.h>
-#include <httpserver.h>
#include <rpc/blockchain.h>
#include <rpc/server.h>
#include <streams.h>
#include <sync.h>
#include <txmempool.h>
#include <util/strencodings.h>
+#include <validation.h>
#include <version.h>
#include <boost/algorithm/string.hpp>
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index 3db4fe0e80..e3d9357358 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -39,7 +39,6 @@
#include <univalue.h>
-#include <boost/algorithm/string.hpp>
#include <boost/thread/thread.hpp> // boost::thread::interrupt
#include <memory>
diff --git a/src/rpc/util.h b/src/rpc/util.h
index b07922c05a..b1ab64247c 100644
--- a/src/rpc/util.h
+++ b/src/rpc/util.h
@@ -9,8 +9,6 @@
#include <script/standard.h>
#include <univalue.h>
-#include <boost/variant/static_visitor.hpp>
-
#include <string>
#include <vector>
diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp
index 90c4ddcc11..d343972c40 100644
--- a/src/script/descriptor.cpp
+++ b/src/script/descriptor.cpp
@@ -478,7 +478,7 @@ std::vector<Span<const char>> Split(const Span<const char>& sp, char sep)
}
/** Parse a key path, being passed a split list of elements (the first element is ignored). */
-bool ParseKeyPath(const std::vector<Span<const char>>& split, KeyPath& out)
+NODISCARD bool ParseKeyPath(const std::vector<Span<const char>>& split, KeyPath& out)
{
for (size_t i = 1; i < split.size(); ++i) {
Span<const char> elem = split[i];
diff --git a/src/test/blockencodings_tests.cpp b/src/test/blockencodings_tests.cpp
index 5131fe8235..309b8d2d06 100644
--- a/src/test/blockencodings_tests.cpp
+++ b/src/test/blockencodings_tests.cpp
@@ -344,4 +344,49 @@ BOOST_AUTO_TEST_CASE(TransactionsRequestSerializationTest) {
BOOST_CHECK_EQUAL(req1.indexes[3], req2.indexes[3]);
}
+BOOST_AUTO_TEST_CASE(TransactionsRequestDeserializationMaxTest) {
+ // Check that the highest legal index is decoded correctly
+ BlockTransactionsRequest req0;
+ req0.blockhash = InsecureRand256();
+ req0.indexes.resize(1);
+ req0.indexes[0] = 0xffff;
+ CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
+ stream << req0;
+
+ BlockTransactionsRequest req1;
+ stream >> req1;
+ BOOST_CHECK_EQUAL(req0.indexes.size(), req1.indexes.size());
+ BOOST_CHECK_EQUAL(req0.indexes[0], req1.indexes[0]);
+}
+
+BOOST_AUTO_TEST_CASE(TransactionsRequestDeserializationOverflowTest) {
+ // Any set of index deltas that starts with N values that sum to (0x10000 - N)
+ // causes the edge-case overflow that was originally not checked for. Such
+ // a request cannot be created by serializing a real BlockTransactionsRequest
+ // due to the overflow, so here we'll serialize from raw deltas.
+ BlockTransactionsRequest req0;
+ req0.blockhash = InsecureRand256();
+ req0.indexes.resize(3);
+ req0.indexes[0] = 0x7000;
+ req0.indexes[1] = 0x10000 - 0x7000 - 2;
+ req0.indexes[2] = 0;
+ CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
+ stream << req0.blockhash;
+ WriteCompactSize(stream, req0.indexes.size());
+ WriteCompactSize(stream, req0.indexes[0]);
+ WriteCompactSize(stream, req0.indexes[1]);
+ WriteCompactSize(stream, req0.indexes[2]);
+
+ BlockTransactionsRequest req1;
+ try {
+ stream >> req1;
+ // before patch: deserialize above succeeds and this check fails, demonstrating the overflow
+ BOOST_CHECK(req1.indexes[1] < req1.indexes[2]);
+ // this shouldn't be reachable before or after patch
+ BOOST_CHECK(0);
+ } catch(std::ios_base::failure &) {
+ // deserialize should fail
+ }
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp
index 521312f1b7..d3cbaedf00 100644
--- a/src/test/coins_tests.cpp
+++ b/src/test/coins_tests.cpp
@@ -2,17 +2,18 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <attributes.h>
#include <coins.h>
+#include <consensus/validation.h>
#include <script/standard.h>
+#include <test/test_bitcoin.h>
#include <uint256.h>
#include <undo.h>
#include <util/strencodings.h>
-#include <test/test_bitcoin.h>
#include <validation.h>
-#include <consensus/validation.h>
-#include <vector>
#include <map>
+#include <vector>
#include <boost/test/unit_test.hpp>
@@ -36,7 +37,7 @@ class CCoinsViewTest : public CCoinsView
std::map<COutPoint, Coin> map_;
public:
- 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/dbwrapper_tests.cpp b/src/test/dbwrapper_tests.cpp
index 9957ac074b..1034d4ade2 100644
--- a/src/test/dbwrapper_tests.cpp
+++ b/src/test/dbwrapper_tests.cpp
@@ -102,15 +102,15 @@ BOOST_AUTO_TEST_CASE(dbwrapper_iterator)
char key_res;
uint256 val_res;
- it->GetKey(key_res);
- it->GetValue(val_res);
+ BOOST_REQUIRE(it->GetKey(key_res));
+ BOOST_REQUIRE(it->GetValue(val_res));
BOOST_CHECK_EQUAL(key_res, key);
BOOST_CHECK_EQUAL(val_res.ToString(), in.ToString());
it->Next();
- it->GetKey(key_res);
- it->GetValue(val_res);
+ BOOST_REQUIRE(it->GetKey(key_res));
+ BOOST_REQUIRE(it->GetValue(val_res));
BOOST_CHECK_EQUAL(key_res, key2);
BOOST_CHECK_EQUAL(val_res.ToString(), in2.ToString());
diff --git a/src/test/getarg_tests.cpp b/src/test/getarg_tests.cpp
index 0432ede3e0..14ddf4d10e 100644
--- a/src/test/getarg_tests.cpp
+++ b/src/test/getarg_tests.cpp
@@ -28,7 +28,7 @@ static void ResetArgs(const std::string& strArg)
vecChar.push_back(s.c_str());
std::string error;
- gArgs.ParseParameters(vecChar.size(), vecChar.data(), error);
+ BOOST_CHECK(gArgs.ParseParameters(vecChar.size(), vecChar.data(), error));
}
static void SetupArgs(const std::vector<std::string>& args)
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index ff19b12a9c..9acebdd820 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -187,7 +187,7 @@ struct TestArgsManager : public ArgsManager
m_config_args.clear();
}
std::string error;
- ReadConfigStream(streamConfig, error);
+ BOOST_REQUIRE(ReadConfigStream(streamConfig, error));
}
void SetNetworkOnlyArg(const std::string arg)
{
@@ -210,13 +210,13 @@ BOOST_AUTO_TEST_CASE(util_ParseParameters)
std::string error;
testArgs.SetupArgs(4, avail_args);
- testArgs.ParseParameters(0, (char**)argv_test, error);
+ BOOST_CHECK(testArgs.ParseParameters(0, (char**)argv_test, error));
BOOST_CHECK(testArgs.GetOverrideArgs().empty() && testArgs.GetConfigArgs().empty());
- testArgs.ParseParameters(1, (char**)argv_test, error);
+ BOOST_CHECK(testArgs.ParseParameters(1, (char**)argv_test, error));
BOOST_CHECK(testArgs.GetOverrideArgs().empty() && testArgs.GetConfigArgs().empty());
- testArgs.ParseParameters(7, (char**)argv_test, error);
+ BOOST_CHECK(testArgs.ParseParameters(7, (char**)argv_test, error));
// expectation: -ignored is ignored (program name argument),
// -a, -b and -ccc end up in map, -d ignored because it is after
// a non-option argument (non-GNU option parsing)
@@ -242,7 +242,7 @@ BOOST_AUTO_TEST_CASE(util_GetBoolArg)
"ignored", "-a", "-nob", "-c=0", "-d=1", "-e=false", "-f=true"};
std::string error;
testArgs.SetupArgs(6, avail_args);
- testArgs.ParseParameters(7, (char**)argv_test, error);
+ BOOST_CHECK(testArgs.ParseParameters(7, (char**)argv_test, error));
// Each letter should be set.
for (const char opt : "abcdef")
@@ -278,7 +278,7 @@ BOOST_AUTO_TEST_CASE(util_GetBoolArgEdgeCases)
const char *argv_test[] = {"ignored", "-nofoo", "-foo", "-nobar=0"};
testArgs.SetupArgs(2, avail_args);
std::string error;
- testArgs.ParseParameters(4, (char**)argv_test, error);
+ BOOST_CHECK(testArgs.ParseParameters(4, (char**)argv_test, error));
// This was passed twice, second one overrides the negative setting.
BOOST_CHECK(!testArgs.IsArgNegated("-foo"));
@@ -290,7 +290,7 @@ BOOST_AUTO_TEST_CASE(util_GetBoolArgEdgeCases)
// Config test
const char *conf_test = "nofoo=1\nfoo=1\nnobar=0\n";
- testArgs.ParseParameters(1, (char**)argv_test, error);
+ BOOST_CHECK(testArgs.ParseParameters(1, (char**)argv_test, error));
testArgs.ReadConfigString(conf_test);
// This was passed twice, second one overrides the negative setting,
@@ -305,7 +305,7 @@ BOOST_AUTO_TEST_CASE(util_GetBoolArgEdgeCases)
// Combined test
const char *combo_test_args[] = {"ignored", "-nofoo", "-bar"};
const char *combo_test_conf = "foo=1\nnobar=1\n";
- testArgs.ParseParameters(3, (char**)combo_test_args, error);
+ BOOST_CHECK(testArgs.ParseParameters(3, (char**)combo_test_args, error));
testArgs.ReadConfigString(combo_test_conf);
// Command line overrides, but doesn't erase old setting
@@ -557,38 +557,38 @@ BOOST_AUTO_TEST_CASE(util_GetChainName)
const char* testnetconf = "testnet=1\nregtest=0\n[test]\nregtest=1";
std::string error;
- test_args.ParseParameters(0, (char**)argv_testnet, error);
+ BOOST_CHECK(test_args.ParseParameters(0, (char**)argv_testnet, error));
BOOST_CHECK_EQUAL(test_args.GetChainName(), "main");
- test_args.ParseParameters(2, (char**)argv_testnet, error);
+ BOOST_CHECK(test_args.ParseParameters(2, (char**)argv_testnet, error));
BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
- test_args.ParseParameters(2, (char**)argv_regtest, error);
+ BOOST_CHECK(test_args.ParseParameters(2, (char**)argv_regtest, error));
BOOST_CHECK_EQUAL(test_args.GetChainName(), "regtest");
- test_args.ParseParameters(3, (char**)argv_test_no_reg, error);
+ BOOST_CHECK(test_args.ParseParameters(3, (char**)argv_test_no_reg, error));
BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
- test_args.ParseParameters(3, (char**)argv_both, error);
+ BOOST_CHECK(test_args.ParseParameters(3, (char**)argv_both, error));
BOOST_CHECK_THROW(test_args.GetChainName(), std::runtime_error);
- test_args.ParseParameters(0, (char**)argv_testnet, error);
+ BOOST_CHECK(test_args.ParseParameters(0, (char**)argv_testnet, error));
test_args.ReadConfigString(testnetconf);
BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
- test_args.ParseParameters(2, (char**)argv_testnet, error);
+ BOOST_CHECK(test_args.ParseParameters(2, (char**)argv_testnet, error));
test_args.ReadConfigString(testnetconf);
BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
- test_args.ParseParameters(2, (char**)argv_regtest, error);
+ BOOST_CHECK(test_args.ParseParameters(2, (char**)argv_regtest, error));
test_args.ReadConfigString(testnetconf);
BOOST_CHECK_THROW(test_args.GetChainName(), std::runtime_error);
- test_args.ParseParameters(3, (char**)argv_test_no_reg, error);
+ BOOST_CHECK(test_args.ParseParameters(3, (char**)argv_test_no_reg, error));
test_args.ReadConfigString(testnetconf);
BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
- test_args.ParseParameters(3, (char**)argv_both, error);
+ BOOST_CHECK(test_args.ParseParameters(3, (char**)argv_both, error));
test_args.ReadConfigString(testnetconf);
BOOST_CHECK_THROW(test_args.GetChainName(), std::runtime_error);
@@ -596,23 +596,23 @@ BOOST_AUTO_TEST_CASE(util_GetChainName)
// [test] regtest=1 potentially relevant) doesn't break things
test_args.SelectConfigNetwork("test");
- test_args.ParseParameters(0, (char**)argv_testnet, error);
+ BOOST_CHECK(test_args.ParseParameters(0, (char**)argv_testnet, error));
test_args.ReadConfigString(testnetconf);
BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
- test_args.ParseParameters(2, (char**)argv_testnet, error);
+ BOOST_CHECK(test_args.ParseParameters(2, (char**)argv_testnet, error));
test_args.ReadConfigString(testnetconf);
BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
- test_args.ParseParameters(2, (char**)argv_regtest, error);
+ BOOST_CHECK(test_args.ParseParameters(2, (char**)argv_regtest, error));
test_args.ReadConfigString(testnetconf);
BOOST_CHECK_THROW(test_args.GetChainName(), std::runtime_error);
- test_args.ParseParameters(2, (char**)argv_test_no_reg, error);
+ BOOST_CHECK(test_args.ParseParameters(2, (char**)argv_test_no_reg, error));
test_args.ReadConfigString(testnetconf);
BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
- test_args.ParseParameters(3, (char**)argv_both, error);
+ BOOST_CHECK(test_args.ParseParameters(3, (char**)argv_both, error));
test_args.ReadConfigString(testnetconf);
BOOST_CHECK_THROW(test_args.GetChainName(), std::runtime_error);
}
diff --git a/src/util/moneystr.h b/src/util/moneystr.h
index 9133f46d5d..b8e2812a96 100644
--- a/src/util/moneystr.h
+++ b/src/util/moneystr.h
@@ -9,16 +9,17 @@
#ifndef BITCOIN_UTIL_MONEYSTR_H
#define BITCOIN_UTIL_MONEYSTR_H
-#include <stdint.h>
-#include <string>
-
#include <amount.h>
+#include <attributes.h>
+
+#include <cstdint>
+#include <string>
/* Do not use these functions to represent or parse monetary amounts to or from
* JSON but use AmountFromValue and ValueFromAmount for that.
*/
std::string FormatMoney(const CAmount& n);
-bool ParseMoney(const std::string& str, CAmount& nRet);
-bool ParseMoney(const char* pszIn, CAmount& nRet);
+NODISCARD bool ParseMoney(const std::string& str, CAmount& nRet);
+NODISCARD bool ParseMoney(const char* pszIn, CAmount& nRet);
#endif // BITCOIN_UTIL_MONEYSTR_H
diff --git a/src/util/strencodings.cpp b/src/util/strencodings.cpp
index 2a2df43337..46146be66f 100644
--- a/src/util/strencodings.cpp
+++ b/src/util/strencodings.cpp
@@ -263,7 +263,7 @@ std::string DecodeBase32(const std::string& str)
return std::string((const char*)vchRet.data(), vchRet.size());
}
-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 87ccf40a1b..7d16d7dcfd 100644
--- a/src/util/strencodings.h
+++ b/src/util/strencodings.h
@@ -9,7 +9,9 @@
#ifndef BITCOIN_UTIL_STRENCODINGS_H
#define BITCOIN_UTIL_STRENCODINGS_H
-#include <stdint.h>
+#include <attributes.h>
+
+#include <cstdint>
#include <string>
#include <vector>
@@ -92,35 +94,35 @@ 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.
*/
-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.
*/
-bool ParseInt64(const std::string& str, int64_t *out);
+NODISCARD bool ParseInt64(const std::string& str, int64_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.
*/
-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.
*/
-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.
*/
-bool ParseDouble(const std::string& str, double *out);
+NODISCARD bool ParseDouble(const std::string& str, double *out);
template<typename T>
std::string HexStr(const T itbegin, const T itend, bool fSpaces=false)
@@ -173,7 +175,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.
*/
-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>
@@ -200,7 +202,7 @@ bool ConvertBits(const O& outfn, I it, I end) {
}
/** Parse an HD keypaths like "m/7/0'/2000". */
-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);
/**
* Converts the given character to its lowercase equivalent.
diff --git a/src/util/system.cpp b/src/util/system.cpp
index f6f36c2238..8e201ec590 100644
--- a/src/util/system.cpp
+++ b/src/util/system.cpp
@@ -73,7 +73,6 @@
#include <malloc.h>
#endif
-#include <boost/thread.hpp>
#include <openssl/crypto.h>
#include <openssl/rand.h>
#include <openssl/conf.h>
@@ -372,15 +371,17 @@ ArgsManager::ArgsManager() :
// nothing to do
}
-void ArgsManager::WarnForSectionOnlyArgs()
+const std::set<std::string> ArgsManager::GetUnsuitableSectionOnlyArgs() const
{
+ std::set<std::string> unsuitables;
+
LOCK(cs_args);
// if there's no section selected, don't worry
- if (m_network.empty()) return;
+ if (m_network.empty()) return std::set<std::string> {};
// if it's okay to use the default section for this network, don't worry
- if (m_network == CBaseChainParams::MAIN) return;
+ if (m_network == CBaseChainParams::MAIN) return std::set<std::string> {};
for (const auto& arg : m_network_only_args) {
std::pair<bool, std::string> found_result;
@@ -398,8 +399,28 @@ void ArgsManager::WarnForSectionOnlyArgs()
if (!found_result.first) continue;
// otherwise, issue a warning
- LogPrintf("Warning: Config setting for %s only applied on %s network when in [%s] section.\n", arg, m_network, m_network);
+ unsuitables.insert(arg);
}
+ return unsuitables;
+}
+
+
+const std::set<std::string> ArgsManager::GetUnrecognizedSections() const
+{
+ // Section names to be recognized in the config file.
+ static const std::set<std::string> available_sections{
+ CBaseChainParams::REGTEST,
+ CBaseChainParams::TESTNET,
+ CBaseChainParams::MAIN
+ };
+ std::set<std::string> diff;
+
+ LOCK(cs_args);
+ std::set_difference(
+ m_config_sections.begin(), m_config_sections.end(),
+ available_sections.begin(), available_sections.end(),
+ std::inserter(diff, diff.end()));
+ return diff;
}
void ArgsManager::SelectConfigNetwork(const std::string& network)
@@ -820,7 +841,7 @@ static std::string TrimString(const std::string& str, const std::string& pattern
return str.substr(front, end - front + 1);
}
-static bool GetConfigOptions(std::istream& stream, std::string& error, std::vector<std::pair<std::string, std::string>> &options)
+static bool GetConfigOptions(std::istream& stream, std::string& error, std::vector<std::pair<std::string, std::string>>& options, std::set<std::string>& sections)
{
std::string str, prefix;
std::string::size_type pos;
@@ -835,7 +856,9 @@ static bool GetConfigOptions(std::istream& stream, std::string& error, std::vect
str = TrimString(str, pattern);
if (!str.empty()) {
if (*str.begin() == '[' && *str.rbegin() == ']') {
- prefix = str.substr(1, str.size() - 2) + '.';
+ const std::string section = str.substr(1, str.size() - 2);
+ sections.insert(section);
+ prefix = section + '.';
} else if (*str.begin() == '-') {
error = strprintf("parse error on line %i: %s, options in configuration file must be specified without leading -", linenr, str);
return false;
@@ -847,6 +870,9 @@ static bool GetConfigOptions(std::istream& stream, std::string& error, std::vect
return false;
}
options.emplace_back(name, value);
+ if ((pos = name.rfind('.')) != std::string::npos) {
+ sections.insert(name.substr(0, pos));
+ }
} else {
error = strprintf("parse error on line %i: %s", linenr, str);
if (str.size() >= 2 && str.substr(0, 2) == "no") {
@@ -864,7 +890,8 @@ bool ArgsManager::ReadConfigStream(std::istream& stream, std::string& error, boo
{
LOCK(cs_args);
std::vector<std::pair<std::string, std::string>> options;
- if (!GetConfigOptions(stream, error, options)) {
+ m_config_sections.clear();
+ if (!GetConfigOptions(stream, error, options, m_config_sections)) {
return false;
}
for (const std::pair<std::string, std::string>& option : options) {
diff --git a/src/util/system.h b/src/util/system.h
index 5634b8dd61..dca32cc6fc 100644
--- a/src/util/system.h
+++ b/src/util/system.h
@@ -14,6 +14,7 @@
#include <config/bitcoin-config.h>
#endif
+#include <attributes.h>
#include <compat.h>
#include <fs.h>
#include <logging.h>
@@ -148,8 +149,9 @@ protected:
std::string m_network GUARDED_BY(cs_args);
std::set<std::string> m_network_only_args GUARDED_BY(cs_args);
std::map<OptionsCategory, std::map<std::string, Arg>> m_available_args GUARDED_BY(cs_args);
+ std::set<std::string> m_config_sections GUARDED_BY(cs_args);
- bool ReadConfigStream(std::istream& stream, std::string& error, bool ignore_invalid_keys = false);
+ NODISCARD bool ReadConfigStream(std::istream& stream, std::string& error, bool ignore_invalid_keys = false);
public:
ArgsManager();
@@ -159,8 +161,8 @@ public:
*/
void SelectConfigNetwork(const std::string& network);
- bool ParseParameters(int argc, const char* const argv[], std::string& error);
- 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
@@ -168,7 +170,12 @@ public:
* on the command line or in a network-specific section in the
* config file.
*/
- void WarnForSectionOnlyArgs();
+ const std::set<std::string> GetUnsuitableSectionOnlyArgs() const;
+
+ /**
+ * Log warnings for unrecognized section names in the config file.
+ */
+ const std::set<std::string> GetUnrecognizedSections() const;
/**
* Return a vector of strings of the given argument
diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp
index 74787eb5d2..d75e30d336 100644
--- a/src/wallet/db.cpp
+++ b/src/wallet/db.cpp
@@ -56,9 +56,8 @@ bool WalletDatabaseFileId::operator==(const WalletDatabaseFileId& rhs) const
return memcmp(value, &rhs.value, sizeof(value)) == 0;
}
-BerkeleyEnvironment* GetWalletEnv(const fs::path& wallet_path, std::string& database_filename)
+static void SplitWalletPath(const fs::path& wallet_path, fs::path& env_directory, std::string& database_filename)
{
- fs::path env_directory;
if (fs::is_regular_file(wallet_path)) {
// Special case for backwards compatibility: if wallet path points to an
// existing file, treat it as the path to a BDB data file in a parent
@@ -71,6 +70,23 @@ BerkeleyEnvironment* GetWalletEnv(const fs::path& wallet_path, std::string& data
env_directory = wallet_path;
database_filename = "wallet.dat";
}
+}
+
+bool IsWalletLoaded(const fs::path& wallet_path)
+{
+ fs::path env_directory;
+ std::string database_filename;
+ SplitWalletPath(wallet_path, env_directory, database_filename);
+ LOCK(cs_db);
+ auto env = g_dbenvs.find(env_directory.string());
+ if (env == g_dbenvs.end()) return false;
+ return env->second.IsDatabaseLoaded(database_filename);
+}
+
+BerkeleyEnvironment* GetWalletEnv(const fs::path& wallet_path, std::string& database_filename)
+{
+ fs::path env_directory;
+ SplitWalletPath(wallet_path, env_directory, database_filename);
LOCK(cs_db);
// Note: An unused temporary BerkeleyEnvironment object may be created inside the
// emplace function if the key already exists. This is a little inefficient,
@@ -90,13 +106,13 @@ void BerkeleyEnvironment::Close()
fDbEnvInit = false;
- for (auto& db : mapDb) {
+ for (auto& db : m_databases) {
auto count = mapFileUseCount.find(db.first);
assert(count == mapFileUseCount.end() || count->second == 0);
- if (db.second) {
- db.second->close(0);
- delete db.second;
- db.second = nullptr;
+ BerkeleyDatabase& database = db.second.get();
+ if (database.m_db) {
+ database.m_db->close(0);
+ database.m_db.reset();
}
}
@@ -463,7 +479,7 @@ BerkeleyBatch::BerkeleyBatch(BerkeleyDatabase& database, const char* pszMode, bo
if (!env->Open(false /* retry */))
throw std::runtime_error("BerkeleyBatch: Failed to open database environment.");
- pdb = env->mapDb[strFilename];
+ pdb = database.m_db.get();
if (pdb == nullptr) {
int ret;
std::unique_ptr<Db> pdb_temp = MakeUnique<Db>(env->dbenv.get(), 0);
@@ -508,7 +524,7 @@ BerkeleyBatch::BerkeleyBatch(BerkeleyDatabase& database, const char* pszMode, bo
}
pdb = pdb_temp.release();
- env->mapDb[strFilename] = pdb;
+ database.m_db.reset(pdb);
if (fCreate && !Exists(std::string("version"))) {
bool fTmp = fReadOnly;
@@ -563,12 +579,13 @@ void BerkeleyEnvironment::CloseDb(const std::string& strFile)
{
{
LOCK(cs_db);
- if (mapDb[strFile] != nullptr) {
+ auto it = m_databases.find(strFile);
+ assert(it != m_databases.end());
+ BerkeleyDatabase& database = it->second.get();
+ if (database.m_db) {
// Close the database handle
- Db* pdb = mapDb[strFile];
- pdb->close(0);
- delete pdb;
- mapDb[strFile] = nullptr;
+ database.m_db->close(0);
+ database.m_db.reset();
}
}
}
@@ -586,7 +603,7 @@ void BerkeleyEnvironment::ReloadDbEnv()
});
std::vector<std::string> filenames;
- for (auto it : mapDb) {
+ for (auto it : m_databases) {
filenames.push_back(it.first);
}
// Close the individual Db's
diff --git a/src/wallet/db.h b/src/wallet/db.h
index 8f96483a18..e453d441d7 100644
--- a/src/wallet/db.h
+++ b/src/wallet/db.h
@@ -31,6 +31,8 @@ struct WalletDatabaseFileId {
bool operator==(const WalletDatabaseFileId& rhs) const;
};
+class BerkeleyDatabase;
+
class BerkeleyEnvironment
{
private:
@@ -43,7 +45,7 @@ private:
public:
std::unique_ptr<DbEnv> dbenv;
std::map<std::string, int> mapFileUseCount;
- std::map<std::string, Db*> mapDb;
+ std::map<std::string, std::reference_wrapper<BerkeleyDatabase>> m_databases;
std::unordered_map<std::string, WalletDatabaseFileId> m_fileids;
std::condition_variable_any m_db_in_use;
@@ -54,6 +56,7 @@ public:
void MakeMock();
bool IsMock() const { return fMockDb; }
bool IsInitialized() const { return fDbEnvInit; }
+ bool IsDatabaseLoaded(const std::string& db_filename) const { return m_databases.find(db_filename) != m_databases.end(); }
fs::path Directory() const { return strPath; }
/**
@@ -95,6 +98,9 @@ public:
}
};
+/** Return whether a wallet database is currently loaded. */
+bool IsWalletLoaded(const fs::path& wallet_path);
+
/** Get BerkeleyEnvironment and database filename given a wallet path. */
BerkeleyEnvironment* GetWalletEnv(const fs::path& wallet_path, std::string& database_filename);
@@ -115,6 +121,8 @@ public:
nUpdateCounter(0), nLastSeen(0), nLastFlushed(0), nLastWalletUpdate(0)
{
env = GetWalletEnv(wallet_path, strFile);
+ auto inserted = env->m_databases.emplace(strFile, std::ref(*this));
+ assert(inserted.second);
if (mock) {
env->Close();
env->Reset();
@@ -122,6 +130,13 @@ public:
}
}
+ ~BerkeleyDatabase() {
+ if (env) {
+ size_t erased = env->m_databases.erase(strFile);
+ assert(erased == 1);
+ }
+ }
+
/** Return object for accessing database at specified path. */
static std::unique_ptr<BerkeleyDatabase> Create(const fs::path& path)
{
@@ -161,6 +176,9 @@ public:
unsigned int nLastFlushed;
int64_t nLastWalletUpdate;
+ /** Database pointer. This is initialized lazily and reset during flushes, so it can be null. */
+ std::unique_ptr<Db> m_db;
+
private:
/** BerkeleyDB specific */
BerkeleyEnvironment *env;
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 8ea4c5c495..360d0f177c 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -3872,11 +3872,9 @@ bool CWallet::Verify(interfaces::Chain& chain, const WalletLocation& location, b
}
// Make sure that the wallet path doesn't clash with an existing wallet path
- for (auto wallet : GetWallets()) {
- if (wallet->GetLocation().GetPath() == wallet_path) {
- error_string = strprintf("Error loading wallet %s. Duplicate -wallet filename specified.", location.GetName());
- return false;
- }
+ if (IsWalletLoaded(wallet_path)) {
+ error_string = strprintf("Error loading wallet %s. Duplicate -wallet filename specified.", location.GetName());
+ return false;
}
try {