aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am2
-rw-r--r--src/Makefile.test.include5
-rw-r--r--src/bech32.cpp52
-rw-r--r--src/bech32.h39
-rw-r--r--src/bench/bech32.cpp2
-rw-r--r--src/bench/coin_selection.cpp5
-rw-r--r--src/bench/wallet_balance.cpp5
-rw-r--r--src/bitcoin-cli.cpp16
-rw-r--r--src/bitcoind.cpp1
-rw-r--r--src/chainparams.h4
-rw-r--r--src/coins.h3
-rw-r--r--src/compat/glibc_compat.cpp7
-rw-r--r--src/compat/glibc_sanity.cpp45
-rw-r--r--src/compat/sanity.h1
-rw-r--r--src/httpserver.cpp8
-rw-r--r--src/i2p.cpp4
-rw-r--r--src/i2p.h8
-rw-r--r--src/init.cpp3
-rw-r--r--src/interfaces/chain.h8
-rw-r--r--src/key_io.cpp30
-rw-r--r--src/miner.cpp3
-rw-r--r--src/miner.h6
-rw-r--r--src/net.cpp28
-rw-r--r--src/net.h12
-rw-r--r--src/net_processing.cpp305
-rw-r--r--src/net_processing.h7
-rw-r--r--src/netbase.cpp145
-rw-r--r--src/netbase.h147
-rw-r--r--src/node/interfaces.cpp11
-rw-r--r--src/node/psbt.h20
-rw-r--r--src/node/transaction.cpp8
-rw-r--r--src/optional.h20
-rw-r--r--src/psbt.h5
-rw-r--r--src/qt/addressbookpage.cpp2
-rw-r--r--src/qt/bitcoin.cpp8
-rw-r--r--src/qt/optionsdialog.h2
-rw-r--r--src/qt/psbtoperationsdialog.cpp2
-rw-r--r--src/qt/qrimagewidget.cpp4
-rw-r--r--src/qt/sendcoinsdialog.cpp2
-rw-r--r--src/qt/test/addressbooktests.cpp2
-rw-r--r--src/qt/test/wallettests.cpp2
-rw-r--r--src/qt/transactionview.cpp2
-rw-r--r--src/qt/walletview.cpp2
-rw-r--r--src/rpc/net.cpp2
-rw-r--r--src/rpc/rawtransaction.cpp6
-rw-r--r--src/script/descriptor.cpp19
-rw-r--r--src/script/descriptor.h4
-rw-r--r--src/signet.cpp12
-rw-r--r--src/signet.h4
-rw-r--r--src/test/addrman_tests.cpp2
-rw-r--r--src/test/bech32_tests.cpp58
-rw-r--r--src/test/data/key_io_invalid.json146
-rw-r--r--src/test/data/key_io_valid.json571
-rw-r--r--src/test/descriptor_tests.cpp27
-rw-r--r--src/test/fuzz/addrman.cpp2
-rw-r--r--src/test/fuzz/asmap_direct.cpp3
-rw-r--r--src/test/fuzz/autofile.cpp1
-rw-r--r--src/test/fuzz/bech32.cpp32
-rw-r--r--src/test/fuzz/buffered_file.cpp1
-rw-r--r--src/test/fuzz/cuckoocache.cpp2
-rw-r--r--src/test/fuzz/deserialize.cpp4
-rw-r--r--src/test/fuzz/net.cpp2
-rw-r--r--src/test/fuzz/netbase_dns_lookup.cpp26
-rw-r--r--src/test/fuzz/node_eviction.cpp3
-rw-r--r--src/test/fuzz/p2p_transport_deserializer.cpp3
-rw-r--r--src/test/fuzz/parse_numbers.cpp6
-rw-r--r--src/test/fuzz/psbt.cpp4
-rw-r--r--src/test/fuzz/script_descriptor_cache.cpp2
-rw-r--r--src/test/fuzz/socks5.cpp3
-rw-r--r--src/test/fuzz/string.cpp3
-rw-r--r--src/test/fuzz/system.cpp4
-rw-r--r--src/test/fuzz/tx_pool.cpp284
-rw-r--r--src/test/fuzz/util.cpp78
-rw-r--r--src/test/fuzz/util.h45
-rw-r--r--src/test/fuzz/validation_load_mempool.cpp34
-rw-r--r--src/test/fuzz/versionbits.cpp345
-rw-r--r--src/test/net_tests.cpp7
-rw-r--r--src/test/netbase_tests.cpp19
-rw-r--r--src/test/sanity_tests.cpp1
-rw-r--r--src/test/sock_tests.cpp31
-rw-r--r--src/test/util_tests.cpp106
-rw-r--r--src/txmempool.cpp9
-rw-r--r--src/txmempool.h8
-rw-r--r--src/util/check.h2
-rw-r--r--src/util/sock.cpp10
-rw-r--r--src/util/sock.h5
-rw-r--r--src/util/strencodings.cpp32
-rw-r--r--src/util/strencodings.h9
-rw-r--r--src/util/system.cpp12
-rw-r--r--src/util/system.h4
-rw-r--r--src/util/tokenpipe.cpp1
-rw-r--r--src/validation.cpp20
-rw-r--r--src/validation.h13
-rw-r--r--src/wallet/coincontrol.h11
-rw-r--r--src/wallet/coinselection.cpp5
-rw-r--r--src/wallet/db.h4
-rw-r--r--src/wallet/init.cpp2
-rw-r--r--src/wallet/load.cpp2
-rw-r--r--src/wallet/rpcdump.cpp2
-rw-r--r--src/wallet/rpcsigner.cpp3
-rw-r--r--src/wallet/rpcwallet.cpp16
-rw-r--r--src/wallet/scriptpubkeyman.cpp6
-rw-r--r--src/wallet/test/coinselector_tests.cpp22
-rw-r--r--src/wallet/test/wallet_tests.cpp6
-rw-r--r--src/wallet/wallet.cpp86
-rw-r--r--src/wallet/wallet.h28
-rw-r--r--src/wallet/walletdb.cpp3
107 files changed, 2132 insertions, 1084 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 8f37e055ff..9903c2e9b3 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -182,7 +182,6 @@ BITCOIN_CORE_H = \
node/ui_interface.h \
node/utxo_snapshot.h \
noui.h \
- optional.h \
outputtype.h \
policy/feerate.h \
policy/fees.h \
@@ -553,7 +552,6 @@ libbitcoin_util_a_SOURCES = \
support/lockedpool.cpp \
chainparamsbase.cpp \
clientversion.cpp \
- compat/glibc_sanity.cpp \
compat/glibcxx_sanity.cpp \
compat/strnlen.cpp \
fs.cpp \
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index 625d825259..e00f17a83f 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -297,7 +297,10 @@ test_fuzz_fuzz_SOURCES = \
test/fuzz/transaction.cpp \
test/fuzz/tx_in.cpp \
test/fuzz/tx_out.cpp \
- test/fuzz/txrequest.cpp
+ test/fuzz/tx_pool.cpp \
+ test/fuzz/txrequest.cpp \
+ test/fuzz/validation_load_mempool.cpp \
+ test/fuzz/versionbits.cpp
endif # ENABLE_FUZZ_BINARY
nodist_test_test_bitcoin_SOURCES = $(GENERATED_TEST_FILES)
diff --git a/src/bech32.cpp b/src/bech32.cpp
index 1e0471f110..288b14e023 100644
--- a/src/bech32.cpp
+++ b/src/bech32.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017 Pieter Wuille
+// Copyright (c) 2017, 2021 Pieter Wuille
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -7,15 +7,18 @@
#include <assert.h>
+namespace bech32
+{
+
namespace
{
typedef std::vector<uint8_t> data;
-/** The Bech32 character set for encoding. */
+/** The Bech32 and Bech32m character set for encoding. */
const char* CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
-/** The Bech32 character set for decoding. */
+/** The Bech32 and Bech32m character set for decoding. */
const int8_t CHARSET_REV[128] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
@@ -27,6 +30,12 @@ const int8_t CHARSET_REV[128] = {
1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1
};
+/* Determine the final constant to use for the specified encoding. */
+uint32_t EncodingConstant(Encoding encoding) {
+ assert(encoding == Encoding::BECH32 || encoding == Encoding::BECH32M);
+ return encoding == Encoding::BECH32 ? 1 : 0x2bc830a3;
+}
+
/** This function will compute what 6 5-bit values to XOR into the last 6 input values, in order to
* make the checksum 0. These 6 values are packed together in a single 30-bit integer. The higher
* bits correspond to earlier values. */
@@ -111,21 +120,24 @@ data ExpandHRP(const std::string& hrp)
}
/** Verify a checksum. */
-bool VerifyChecksum(const std::string& hrp, const data& values)
+Encoding VerifyChecksum(const std::string& hrp, const data& values)
{
// PolyMod computes what value to xor into the final values to make the checksum 0. However,
// if we required that the checksum was 0, it would be the case that appending a 0 to a valid
// list of values would result in a new valid list. For that reason, Bech32 requires the
- // resulting checksum to be 1 instead.
- return PolyMod(Cat(ExpandHRP(hrp), values)) == 1;
+ // resulting checksum to be 1 instead. In Bech32m, this constant was amended.
+ const uint32_t check = PolyMod(Cat(ExpandHRP(hrp), values));
+ if (check == EncodingConstant(Encoding::BECH32)) return Encoding::BECH32;
+ if (check == EncodingConstant(Encoding::BECH32M)) return Encoding::BECH32M;
+ return Encoding::INVALID;
}
/** Create a checksum. */
-data CreateChecksum(const std::string& hrp, const data& values)
+data CreateChecksum(Encoding encoding, const std::string& hrp, const data& values)
{
data enc = Cat(ExpandHRP(hrp), values);
enc.resize(enc.size() + 6); // Append 6 zeroes
- uint32_t mod = PolyMod(enc) ^ 1; // Determine what to XOR into those 6 zeroes.
+ uint32_t mod = PolyMod(enc) ^ EncodingConstant(encoding); // Determine what to XOR into those 6 zeroes.
data ret(6);
for (size_t i = 0; i < 6; ++i) {
// Convert the 5-bit groups in mod to checksum values.
@@ -136,16 +148,13 @@ data CreateChecksum(const std::string& hrp, const data& values)
} // namespace
-namespace bech32
-{
-
-/** Encode a Bech32 string. */
-std::string Encode(const std::string& hrp, const data& values) {
- // First ensure that the HRP is all lowercase. BIP-173 requires an encoder
- // to return a lowercase Bech32 string, but if given an uppercase HRP, the
+/** Encode a Bech32 or Bech32m string. */
+std::string Encode(Encoding encoding, const std::string& hrp, const data& values) {
+ // First ensure that the HRP is all lowercase. BIP-173 and BIP350 require an encoder
+ // to return a lowercase Bech32/Bech32m string, but if given an uppercase HRP, the
// result will always be invalid.
for (const char& c : hrp) assert(c < 'A' || c > 'Z');
- data checksum = CreateChecksum(hrp, values);
+ data checksum = CreateChecksum(encoding, hrp, values);
data combined = Cat(values, checksum);
std::string ret = hrp + '1';
ret.reserve(ret.size() + combined.size());
@@ -155,8 +164,8 @@ std::string Encode(const std::string& hrp, const data& values) {
return ret;
}
-/** Decode a Bech32 string. */
-std::pair<std::string, data> Decode(const std::string& str) {
+/** Decode a Bech32 or Bech32m string. */
+DecodeResult Decode(const std::string& str) {
bool lower = false, upper = false;
for (size_t i = 0; i < str.size(); ++i) {
unsigned char c = str[i];
@@ -183,10 +192,9 @@ std::pair<std::string, data> Decode(const std::string& str) {
for (size_t i = 0; i < pos; ++i) {
hrp += LowerCase(str[i]);
}
- if (!VerifyChecksum(hrp, values)) {
- return {};
- }
- return {hrp, data(values.begin(), values.end() - 6)};
+ Encoding result = VerifyChecksum(hrp, values);
+ if (result == Encoding::INVALID) return {};
+ return {result, std::move(hrp), data(values.begin(), values.end() - 6)};
}
} // namespace bech32
diff --git a/src/bech32.h b/src/bech32.h
index fb39cd352b..e9450ccc2b 100644
--- a/src/bech32.h
+++ b/src/bech32.h
@@ -1,13 +1,14 @@
-// Copyright (c) 2017 Pieter Wuille
+// Copyright (c) 2017, 2021 Pieter Wuille
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-// Bech32 is a string encoding format used in newer address types.
-// The output consists of a human-readable part (alphanumeric), a
-// separator character (1), and a base32 data section, the last
-// 6 characters of which are a checksum.
+// Bech32 and Bech32m are string encoding formats used in newer
+// address types. The outputs consist of a human-readable part
+// (alphanumeric), a separator character (1), and a base32 data
+// section, the last 6 characters of which are a checksum. The
+// module is namespaced under bech32 for historical reasons.
//
-// For more information, see BIP 173.
+// For more information, see BIP 173 and BIP 350.
#ifndef BITCOIN_BECH32_H
#define BITCOIN_BECH32_H
@@ -19,11 +20,29 @@
namespace bech32
{
-/** Encode a Bech32 string. If hrp contains uppercase characters, this will cause an assertion error. */
-std::string Encode(const std::string& hrp, const std::vector<uint8_t>& values);
+enum class Encoding {
+ INVALID, //!< Failed decoding
-/** Decode a Bech32 string. Returns (hrp, data). Empty hrp means failure. */
-std::pair<std::string, std::vector<uint8_t>> Decode(const std::string& str);
+ BECH32, //!< Bech32 encoding as defined in BIP173
+ BECH32M, //!< Bech32m encoding as defined in BIP350
+};
+
+/** Encode a Bech32 or Bech32m string. If hrp contains uppercase characters, this will cause an
+ * assertion error. Encoding must be one of BECH32 or BECH32M. */
+std::string Encode(Encoding encoding, const std::string& hrp, const std::vector<uint8_t>& values);
+
+struct DecodeResult
+{
+ Encoding encoding; //!< What encoding was detected in the result; Encoding::INVALID if failed.
+ std::string hrp; //!< The human readable part
+ std::vector<uint8_t> data; //!< The payload (excluding checksum)
+
+ DecodeResult() : encoding(Encoding::INVALID) {}
+ DecodeResult(Encoding enc, std::string&& h, std::vector<uint8_t>&& d) : encoding(enc), hrp(std::move(h)), data(std::move(d)) {}
+};
+
+/** Decode a Bech32 or Bech32m string. */
+DecodeResult Decode(const std::string& str);
} // namespace bech32
diff --git a/src/bench/bech32.cpp b/src/bench/bech32.cpp
index c74d8d51b3..8e10862a37 100644
--- a/src/bench/bech32.cpp
+++ b/src/bench/bech32.cpp
@@ -19,7 +19,7 @@ static void Bech32Encode(benchmark::Bench& bench)
tmp.reserve(1 + 32 * 8 / 5);
ConvertBits<8, 5, true>([&](unsigned char c) { tmp.push_back(c); }, v.begin(), v.end());
bench.batch(v.size()).unit("byte").run([&] {
- bech32::Encode("bc", tmp);
+ bech32::Encode(bech32::Encoding::BECH32, "bc", tmp);
});
}
diff --git a/src/bench/coin_selection.cpp b/src/bench/coin_selection.cpp
index 376e70ffba..80acdec044 100644
--- a/src/bench/coin_selection.cpp
+++ b/src/bench/coin_selection.cpp
@@ -49,7 +49,10 @@ static void CoinSelection(benchmark::Bench& bench)
}
const CoinEligibilityFilter filter_standard(1, 6, 0);
- const CoinSelectionParams coin_selection_params(true, 34, 148, CFeeRate(0), 0, false);
+ const CoinSelectionParams coin_selection_params(/* use_bnb= */ true, /* change_output_size= */ 34,
+ /* change_spend_size= */ 148, /* effective_feerate= */ CFeeRate(0),
+ /* long_term_feerate= */ CFeeRate(0), /* discard_feerate= */ CFeeRate(0),
+ /* tx_no_inputs_size= */ 0, /* avoid_partial= */ false);
bench.run([&] {
std::set<CInputCoin> setCoinsRet;
CAmount nValueRet;
diff --git a/src/bench/wallet_balance.cpp b/src/bench/wallet_balance.cpp
index c96ef209e3..d7cc167885 100644
--- a/src/bench/wallet_balance.cpp
+++ b/src/bench/wallet_balance.cpp
@@ -5,13 +5,14 @@
#include <bench/bench.h>
#include <interfaces/chain.h>
#include <node/context.h>
-#include <optional.h>
#include <test/util/mining.h>
#include <test/util/setup_common.h>
#include <test/util/wallet.h>
#include <validationinterface.h>
#include <wallet/wallet.h>
+#include <optional>
+
static void WalletBalance(benchmark::Bench& bench, const bool set_dirty, const bool add_watchonly, const bool add_mine)
{
const auto test_setup = MakeNoLogFileContext<const TestingSetup>();
@@ -26,7 +27,7 @@ static void WalletBalance(benchmark::Bench& bench, const bool set_dirty, const b
}
auto handler = test_setup->m_node.chain->handleNotifications({&wallet, [](CWallet*) {}});
- const Optional<std::string> address_mine{add_mine ? Optional<std::string>{getnewaddress(wallet)} : nullopt};
+ const std::optional<std::string> address_mine{add_mine ? std::optional<std::string>{getnewaddress(wallet)} : std::nullopt};
if (add_watchonly) importaddress(wallet, ADDRESS_WATCHONLY);
for (int i = 0; i < 100; ++i) {
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
index dc4b142f83..4f3d7a4ffe 100644
--- a/src/bitcoin-cli.cpp
+++ b/src/bitcoin-cli.cpp
@@ -9,7 +9,6 @@
#include <chainparamsbase.h>
#include <clientversion.h>
-#include <optional.h>
#include <rpc/client.h>
#include <rpc/mining.h>
#include <rpc/protocol.h>
@@ -24,6 +23,7 @@
#include <cmath>
#include <functional>
#include <memory>
+#include <optional>
#include <stdio.h>
#include <string>
#include <tuple>
@@ -611,16 +611,16 @@ public:
}
};
-static UniValue CallRPC(BaseRequestHandler* rh, const std::string& strMethod, const std::vector<std::string>& args, const Optional<std::string>& rpcwallet = {})
+static UniValue CallRPC(BaseRequestHandler* rh, const std::string& strMethod, const std::vector<std::string>& args, const std::optional<std::string>& rpcwallet = {})
{
std::string host;
// In preference order, we choose the following for the port:
// 1. -rpcport
// 2. port in -rpcconnect (ie following : in ipv4 or ]: in ipv6)
// 3. default port for chain
- int port = BaseParams().RPCPort();
+ uint16_t port{BaseParams().RPCPort()};
SplitHostPort(gArgs.GetArg("-rpcconnect", DEFAULT_RPCCONNECT), port, host);
- port = gArgs.GetArg("-rpcport", port);
+ port = static_cast<uint16_t>(gArgs.GetArg("-rpcport", port));
// Obtain event base
raii_event_base base = obtain_event_base();
@@ -708,6 +708,8 @@ static UniValue CallRPC(BaseRequestHandler* rh, const std::string& strMethod, co
} else {
throw std::runtime_error("Authorization failed: Incorrect rpcuser or rpcpassword");
}
+ } else if (response.status == HTTP_SERVICE_UNAVAILABLE) {
+ throw std::runtime_error(strprintf("Server response: %s", response.body));
} else if (response.status >= 400 && response.status != HTTP_BAD_REQUEST && response.status != HTTP_NOT_FOUND && response.status != HTTP_INTERNAL_SERVER_ERROR)
throw std::runtime_error(strprintf("server returned HTTP error %d", response.status));
else if (response.body.empty())
@@ -733,7 +735,7 @@ static UniValue CallRPC(BaseRequestHandler* rh, const std::string& strMethod, co
* @returns the RPC response as a UniValue object.
* @throws a CConnectionFailed std::runtime_error if connection failed or RPC server still in warmup.
*/
-static UniValue ConnectAndCallRPC(BaseRequestHandler* rh, const std::string& strMethod, const std::vector<std::string>& args, const Optional<std::string>& rpcwallet = {})
+static UniValue ConnectAndCallRPC(BaseRequestHandler* rh, const std::string& strMethod, const std::vector<std::string>& args, const std::optional<std::string>& rpcwallet = {})
{
UniValue response(UniValue::VOBJ);
// Execute and handle connection failures with -rpcwait.
@@ -817,7 +819,7 @@ static void GetWalletBalances(UniValue& result)
*/
static UniValue GetNewAddress()
{
- Optional<std::string> wallet_name{};
+ std::optional<std::string> wallet_name{};
if (gArgs.IsArgSet("-rpcwallet")) wallet_name = gArgs.GetArg("-rpcwallet", "");
DefaultRequestHandler rh;
return ConnectAndCallRPC(&rh, "getnewaddress", /* args=*/{}, wallet_name);
@@ -922,7 +924,7 @@ static int CommandLineRPC(int argc, char *argv[])
}
if (nRet == 0) {
// Perform RPC call
- Optional<std::string> wallet_name{};
+ std::optional<std::string> wallet_name{};
if (gArgs.IsArgSet("-rpcwallet")) wallet_name = gArgs.GetArg("-rpcwallet", "");
const UniValue reply = ConnectAndCallRPC(rh.get(), method, args, wallet_name);
diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp
index 32f06aec2c..1b4ca3e9a8 100644
--- a/src/bitcoind.cpp
+++ b/src/bitcoind.cpp
@@ -25,6 +25,7 @@
#include <util/url.h>
#include <functional>
+#include <optional>
const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr;
UrlDecodeFn* const URL_DECODE = urlDecode;
diff --git a/src/chainparams.h b/src/chainparams.h
index 4d24dcdb7c..013f075be6 100644
--- a/src/chainparams.h
+++ b/src/chainparams.h
@@ -84,7 +84,7 @@ public:
const Consensus::Params& GetConsensus() const { return consensus; }
const CMessageHeader::MessageStartChars& MessageStart() const { return pchMessageStart; }
- int GetDefaultPort() const { return nDefaultPort; }
+ uint16_t GetDefaultPort() const { return nDefaultPort; }
const CBlock& GenesisBlock() const { return genesis; }
/** Default value for -checkmempool and -checkblockindex argument */
@@ -121,7 +121,7 @@ protected:
Consensus::Params consensus;
CMessageHeader::MessageStartChars pchMessageStart;
- int nDefaultPort;
+ uint16_t nDefaultPort;
uint64_t nPruneAfterHeight;
uint64_t m_assumed_blockchain_size;
uint64_t m_assumed_chain_state_size;
diff --git a/src/coins.h b/src/coins.h
index feb441fd6a..5a6f73652b 100644
--- a/src/coins.h
+++ b/src/coins.h
@@ -75,6 +75,9 @@ public:
::Unserialize(s, Using<TxOutCompression>(out));
}
+ /** Either this coin never existed (see e.g. coinEmpty in coins.cpp), or it
+ * did exist and has been spent.
+ */
bool IsSpent() const {
return out.IsNull();
}
diff --git a/src/compat/glibc_compat.cpp b/src/compat/glibc_compat.cpp
index 8a51f310f7..ff581d4a9e 100644
--- a/src/compat/glibc_compat.cpp
+++ b/src/compat/glibc_compat.cpp
@@ -9,13 +9,6 @@
#include <cstddef>
#include <cstdint>
-// Prior to GLIBC_2.14, memcpy was aliased to memmove.
-extern "C" void* memmove(void* a, const void* b, size_t c);
-extern "C" void* memcpy(void* a, const void* b, size_t c)
-{
- return memmove(a, b, c);
-}
-
#if defined(__i386__) || defined(__arm__)
extern "C" int64_t __udivmoddi4(uint64_t u, uint64_t v, uint64_t* rp);
diff --git a/src/compat/glibc_sanity.cpp b/src/compat/glibc_sanity.cpp
deleted file mode 100644
index 06d0dd6fba..0000000000
--- a/src/compat/glibc_sanity.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright (c) 2009-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.
-
-#if defined(HAVE_CONFIG_H)
-#include <config/bitcoin-config.h>
-#endif
-
-#include <cstddef>
-
-extern "C" void* memcpy(void* a, const void* b, size_t c);
-void* memcpy_int(void* a, const void* b, size_t c)
-{
- return memcpy(a, b, c);
-}
-
-namespace
-{
-// trigger: Use the memcpy_int wrapper which calls our internal memcpy.
-// A direct call to memcpy may be optimized away by the compiler.
-// test: Fill an array with a sequence of integers. memcpy to a new empty array.
-// Verify that the arrays are equal. Use an odd size to decrease the odds of
-// the call being optimized away.
-template <unsigned int T>
-bool sanity_test_memcpy()
-{
- unsigned int memcpy_test[T];
- unsigned int memcpy_verify[T] = {};
- for (unsigned int i = 0; i != T; ++i)
- memcpy_test[i] = i;
-
- memcpy_int(memcpy_verify, memcpy_test, sizeof(memcpy_test));
-
- for (unsigned int i = 0; i != T; ++i) {
- if (memcpy_verify[i] != i)
- return false;
- }
- return true;
-}
-} // namespace
-
-bool glibc_sanity_test()
-{
- return sanity_test_memcpy<1025>();
-}
diff --git a/src/compat/sanity.h b/src/compat/sanity.h
index 909c4f6da8..8efa416102 100644
--- a/src/compat/sanity.h
+++ b/src/compat/sanity.h
@@ -5,7 +5,6 @@
#ifndef BITCOIN_COMPAT_SANITY_H
#define BITCOIN_COMPAT_SANITY_H
-bool glibc_sanity_test();
bool glibcxx_sanity_test();
#endif // BITCOIN_COMPAT_SANITY_H
diff --git a/src/httpserver.cpp b/src/httpserver.cpp
index 0a8e58ab67..12395f5b24 100644
--- a/src/httpserver.cpp
+++ b/src/httpserver.cpp
@@ -262,7 +262,7 @@ static void http_request_cb(struct evhttp_request* req, void* arg)
item.release(); /* if true, queue took ownership */
else {
LogPrintf("WARNING: request rejected because http work queue depth exceeded, it can be increased with the -rpcworkqueue= setting\n");
- item->req->WriteReply(HTTP_INTERNAL_SERVER_ERROR, "Work queue depth exceeded");
+ item->req->WriteReply(HTTP_SERVICE_UNAVAILABLE, "Work queue depth exceeded");
}
} else {
hreq->WriteReply(HTTP_NOT_FOUND);
@@ -290,8 +290,8 @@ static bool ThreadHTTP(struct event_base* base)
/** Bind HTTP server to specified addresses */
static bool HTTPBindAddresses(struct evhttp* http)
{
- int http_port = gArgs.GetArg("-rpcport", BaseParams().RPCPort());
- std::vector<std::pair<std::string, uint16_t> > endpoints;
+ uint16_t http_port{static_cast<uint16_t>(gArgs.GetArg("-rpcport", BaseParams().RPCPort()))};
+ std::vector<std::pair<std::string, uint16_t>> endpoints;
// Determine what addresses to bind to
if (!(gArgs.IsArgSet("-rpcallowip") && gArgs.IsArgSet("-rpcbind"))) { // Default to loopback if not allowing external IPs
@@ -305,7 +305,7 @@ static bool HTTPBindAddresses(struct evhttp* http)
}
} else if (gArgs.IsArgSet("-rpcbind")) { // Specific bind address
for (const std::string& strRPCBind : gArgs.GetArgs("-rpcbind")) {
- int port = http_port;
+ uint16_t port{http_port};
std::string host;
SplitHostPort(strRPCBind, port, host);
endpoints.push_back(std::make_pair(host, port));
diff --git a/src/i2p.cpp b/src/i2p.cpp
index 42270deaeb..d16c620d88 100644
--- a/src/i2p.cpp
+++ b/src/i2p.cpp
@@ -153,7 +153,7 @@ bool Session::Accept(Connection& conn)
}
const std::string& peer_dest =
- conn.sock.RecvUntilTerminator('\n', MAX_WAIT_FOR_IO, *m_interrupt);
+ conn.sock.RecvUntilTerminator('\n', MAX_WAIT_FOR_IO, *m_interrupt, MAX_MSG_SIZE);
conn.peer = CService(DestB64ToAddr(peer_dest), Params().GetDefaultPort());
@@ -252,7 +252,7 @@ Session::Reply Session::SendRequestAndGetReply(const Sock& sock,
// signaled.
static constexpr auto recv_timeout = 3min;
- reply.full = sock.RecvUntilTerminator('\n', recv_timeout, *m_interrupt);
+ reply.full = sock.RecvUntilTerminator('\n', recv_timeout, *m_interrupt, MAX_MSG_SIZE);
for (const auto& kv : spanparsing::Split(reply.full, ' ')) {
const auto& pos = std::find(kv.begin(), kv.end(), '=');
diff --git a/src/i2p.h b/src/i2p.h
index 8fafe0a4d0..1ebe7d0329 100644
--- a/src/i2p.h
+++ b/src/i2p.h
@@ -41,6 +41,14 @@ struct Connection {
namespace sam {
/**
+ * The maximum size of an incoming message from the I2P SAM proxy (in bytes).
+ * Used to avoid a runaway proxy from sending us an "unlimited" amount of data without a terminator.
+ * The longest known message is ~1400 bytes, so this is high enough not to be triggered during
+ * normal operation, yet low enough to avoid a malicious proxy from filling our memory.
+ */
+static constexpr size_t MAX_MSG_SIZE{65536};
+
+/**
* I2P SAM session.
*/
class Session
diff --git a/src/init.cpp b/src/init.cpp
index b91a94bc25..7d5420e3be 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -585,6 +585,7 @@ void SetupServerArgs(NodeContext& node)
argsman.AddArg("-daemonwait", strprintf("Wait for initialization to be finished before exiting. This implies -daemon (default: %d)", DEFAULT_DAEMONWAIT), ArgsManager::ALLOW_BOOL, OptionsCategory::OPTIONS);
#else
hidden_args.emplace_back("-daemon");
+ hidden_args.emplace_back("-daemonwait");
#endif
// Add the hidden options
@@ -772,7 +773,7 @@ static bool InitSanityCheck()
return InitError(Untranslated("Elliptic curve cryptography sanity check failure. Aborting."));
}
- if (!glibc_sanity_test() || !glibcxx_sanity_test())
+ if (!glibcxx_sanity_test())
return false;
if (!Random_SanityCheck()) {
diff --git a/src/interfaces/chain.h b/src/interfaces/chain.h
index ebc5466173..3395741b1b 100644
--- a/src/interfaces/chain.h
+++ b/src/interfaces/chain.h
@@ -5,12 +5,12 @@
#ifndef BITCOIN_INTERFACES_CHAIN_H
#define BITCOIN_INTERFACES_CHAIN_H
-#include <optional.h> // For Optional and nullopt
#include <primitives/transaction.h> // For CTransactionRef
#include <util/settings.h> // For util::SettingsValue
#include <functional>
#include <memory>
+#include <optional>
#include <stddef.h>
#include <stdint.h>
#include <string>
@@ -94,7 +94,7 @@ public:
//! Get current chain height, not including genesis block (returns 0 if
//! chain only contains genesis block, nullopt if chain does not contain
//! any blocks)
- virtual Optional<int> getHeight() = 0;
+ virtual std::optional<int> getHeight() = 0;
//! Get block hash. Height must be valid or this function will abort.
virtual uint256 getBlockHash(int height) = 0;
@@ -109,7 +109,7 @@ public:
//! Return height of the highest block on chain in common with the locator,
//! which will either be the original block used to create the locator,
//! or one of its ancestors.
- virtual Optional<int> findLocatorFork(const CBlockLocator& locator) = 0;
+ virtual std::optional<int> findLocatorFork(const CBlockLocator& locator) = 0;
//! Check if transaction will be final given chain height current time.
virtual bool checkFinalTx(const CTransaction& tx) = 0;
@@ -154,7 +154,7 @@ public:
//! Return true if data is available for all blocks in the specified range
//! of blocks. This checks all blocks that are ancestors of block_hash in
//! the height range from min_height to max_height, inclusive.
- virtual bool hasBlocks(const uint256& block_hash, int min_height = 0, Optional<int> max_height = {}) = 0;
+ virtual bool hasBlocks(const uint256& block_hash, int min_height = 0, std::optional<int> max_height = {}) = 0;
//! Check if transaction is RBF opt in.
virtual RBFTransactionState isRBFOptIn(const CTransaction& tx) = 0;
diff --git a/src/key_io.cpp b/src/key_io.cpp
index e27673fd16..dbcbfa1f29 100644
--- a/src/key_io.cpp
+++ b/src/key_io.cpp
@@ -43,7 +43,7 @@ public:
std::vector<unsigned char> data = {0};
data.reserve(33);
ConvertBits<8, 5, true>([&](unsigned char c) { data.push_back(c); }, id.begin(), id.end());
- return bech32::Encode(m_params.Bech32HRP(), data);
+ return bech32::Encode(bech32::Encoding::BECH32, m_params.Bech32HRP(), data);
}
std::string operator()(const WitnessV0ScriptHash& id) const
@@ -51,7 +51,7 @@ public:
std::vector<unsigned char> data = {0};
data.reserve(53);
ConvertBits<8, 5, true>([&](unsigned char c) { data.push_back(c); }, id.begin(), id.end());
- return bech32::Encode(m_params.Bech32HRP(), data);
+ return bech32::Encode(bech32::Encoding::BECH32, m_params.Bech32HRP(), data);
}
std::string operator()(const WitnessUnknown& id) const
@@ -62,7 +62,7 @@ public:
std::vector<unsigned char> data = {(unsigned char)id.version};
data.reserve(1 + (id.length * 8 + 4) / 5);
ConvertBits<8, 5, true>([&](unsigned char c) { data.push_back(c); }, id.program, id.program + id.length);
- return bech32::Encode(m_params.Bech32HRP(), data);
+ return bech32::Encode(bech32::Encoding::BECH32M, m_params.Bech32HRP(), data);
}
std::string operator()(const CNoDestination& no) const { return {}; }
@@ -95,20 +95,26 @@ CTxDestination DecodeDestination(const std::string& str, const CChainParams& par
error_str = "Invalid prefix for Base58-encoded address";
}
data.clear();
- auto bech = bech32::Decode(str);
- if (bech.second.size() > 0) {
+ const auto dec = bech32::Decode(str);
+ if ((dec.encoding == bech32::Encoding::BECH32 || dec.encoding == bech32::Encoding::BECH32M) && dec.data.size() > 0) {
+ // Bech32 decoding
error_str = "";
-
- if (bech.first != params.Bech32HRP()) {
+ if (dec.hrp != params.Bech32HRP()) {
error_str = "Invalid prefix for Bech32 address";
return CNoDestination();
}
-
- // Bech32 decoding
- int version = bech.second[0]; // The first 5 bit symbol is the witness version (0-16)
+ int version = dec.data[0]; // The first 5 bit symbol is the witness version (0-16)
+ if (version == 0 && dec.encoding != bech32::Encoding::BECH32) {
+ error_str = "Version 0 witness address must use Bech32 checksum";
+ return CNoDestination();
+ }
+ if (version != 0 && dec.encoding != bech32::Encoding::BECH32M) {
+ error_str = "Version 1+ witness address must use Bech32m checksum";
+ return CNoDestination();
+ }
// The rest of the symbols are converted witness program bytes.
- data.reserve(((bech.second.size() - 1) * 5) / 8);
- if (ConvertBits<5, 8, false>([&](unsigned char c) { data.push_back(c); }, bech.second.begin() + 1, bech.second.end())) {
+ data.reserve(((dec.data.size() - 1) * 5) / 8);
+ if (ConvertBits<5, 8, false>([&](unsigned char c) { data.push_back(c); }, dec.data.begin() + 1, dec.data.end())) {
if (version == 0) {
{
WitnessV0KeyHash keyid;
diff --git a/src/miner.cpp b/src/miner.cpp
index fbaef0f224..fe7a54c052 100644
--- a/src/miner.cpp
+++ b/src/miner.cpp
@@ -96,9 +96,6 @@ void BlockAssembler::resetBlock()
nFees = 0;
}
-Optional<int64_t> BlockAssembler::m_last_block_num_txs{nullopt};
-Optional<int64_t> BlockAssembler::m_last_block_weight{nullopt};
-
std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(CChainState& chainstate, const CScript& scriptPubKeyIn)
{
int64_t nTimeStart = GetTimeMicros();
diff --git a/src/miner.h b/src/miner.h
index a67fec6dd8..023635814c 100644
--- a/src/miner.h
+++ b/src/miner.h
@@ -6,12 +6,12 @@
#ifndef BITCOIN_MINER_H
#define BITCOIN_MINER_H
-#include <optional.h>
#include <primitives/block.h>
#include <txmempool.h>
#include <validation.h>
#include <memory>
+#include <optional>
#include <stdint.h>
#include <boost/multi_index_container.hpp>
@@ -160,8 +160,8 @@ public:
/** Construct a new block template with coinbase to scriptPubKeyIn */
std::unique_ptr<CBlockTemplate> CreateNewBlock(CChainState& chainstate, const CScript& scriptPubKeyIn);
- static Optional<int64_t> m_last_block_num_txs;
- static Optional<int64_t> m_last_block_weight;
+ inline static std::optional<int64_t> m_last_block_num_txs{};
+ inline static std::optional<int64_t> m_last_block_weight{};
private:
// utility functions
diff --git a/src/net.cpp b/src/net.cpp
index 1e4a6a9aa7..3b1ebede98 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -18,7 +18,6 @@
#include <net_permissions.h>
#include <netbase.h>
#include <node/ui_interface.h>
-#include <optional.h>
#include <protocol.h>
#include <random.h>
#include <scheduler.h>
@@ -39,6 +38,7 @@
#include <algorithm>
#include <cstdint>
#include <functional>
+#include <optional>
#include <unordered_map>
#include <math.h>
@@ -113,7 +113,7 @@ void CConnman::AddAddrFetch(const std::string& strDest)
uint16_t GetListenPort()
{
- return (uint16_t)(gArgs.GetArg("-port", Params().GetDefaultPort()));
+ return static_cast<uint16_t>(gArgs.GetArg("-port", Params().GetDefaultPort()));
}
// find 'best' local address for a particular peer
@@ -193,7 +193,7 @@ bool IsPeerAddrLocalGood(CNode *pnode)
IsReachable(addrLocal.GetNetwork());
}
-Optional<CAddress> GetLocalAddrForPeer(CNode *pnode)
+std::optional<CAddress> GetLocalAddrForPeer(CNode *pnode)
{
CAddress addrLocal = GetLocalAddress(&pnode->addr, pnode->GetLocalServices());
if (gArgs.GetBoolArg("-addrmantest", false)) {
@@ -215,7 +215,7 @@ Optional<CAddress> GetLocalAddrForPeer(CNode *pnode)
return addrLocal;
}
// Address is unroutable. Don't advertise.
- return nullopt;
+ return std::nullopt;
}
// learn a new local address
@@ -394,7 +394,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
pszDest ? 0.0 : (double)(GetAdjustedTime() - addrConnect.nTime)/3600.0);
// Resolve
- const int default_port = Params().GetDefaultPort();
+ const uint16_t default_port{Params().GetDefaultPort()};
if (pszDest) {
std::vector<CService> resolved;
if (Lookup(pszDest, resolved, default_port, fNameLookup && !HaveNameProxy(), 256) && !resolved.empty()) {
@@ -462,7 +462,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
return nullptr;
}
std::string host;
- int port = default_port;
+ uint16_t port{default_port};
SplitHostPort(std::string(pszDest), port, host);
bool proxyConnectionFailed;
connected = ConnectThroughProxy(proxy, host, port, *sock, nConnectTimeout,
@@ -632,7 +632,7 @@ bool CNode::ReceiveMsgBytes(Span<const uint8_t> msg_bytes, bool& complete)
if (m_deserializer->Complete()) {
// decompose a transport agnostic CNetMessage from the deserializer
uint32_t out_err_raw_size{0};
- Optional<CNetMessage> result{m_deserializer->GetMessage(time, out_err_raw_size)};
+ std::optional<CNetMessage> result{m_deserializer->GetMessage(time, out_err_raw_size)};
if (!result) {
// Message deserialization failed. Drop the message but don't disconnect the peer.
// store the size of the corrupt message
@@ -723,10 +723,10 @@ const uint256& V1TransportDeserializer::GetMessageHash() const
return data_hash;
}
-Optional<CNetMessage> V1TransportDeserializer::GetMessage(const std::chrono::microseconds time, uint32_t& out_err_raw_size)
+std::optional<CNetMessage> V1TransportDeserializer::GetMessage(const std::chrono::microseconds time, uint32_t& out_err_raw_size)
{
// decompose a single CNetMessage from the TransportDeserializer
- Optional<CNetMessage> msg(std::move(vRecv));
+ std::optional<CNetMessage> msg(std::move(vRecv));
// store command string, time, and sizes
msg->m_command = hdr.GetCommand();
@@ -747,12 +747,12 @@ Optional<CNetMessage> V1TransportDeserializer::GetMessage(const std::chrono::mic
HexStr(hdr.pchChecksum),
m_node_id);
out_err_raw_size = msg->m_raw_message_size;
- msg = nullopt;
+ msg = std::nullopt;
} else if (!hdr.IsCommandValid()) {
LogPrint(BCLog::NET, "HEADER ERROR - COMMAND (%s, %u bytes), peer=%d\n",
hdr.GetCommand(), msg->m_message_size, m_node_id);
out_err_raw_size = msg->m_raw_message_size;
- msg = nullopt;
+ msg.reset();
}
// Always reset the network deserializer (prepare for the next message)
@@ -879,7 +879,7 @@ static void EraseLastKElements(std::vector<T> &elements, Comparator comparator,
elements.erase(elements.end() - eraseSize, elements.end());
}
-[[nodiscard]] Optional<NodeId> SelectNodeToEvict(std::vector<NodeEvictionCandidate>&& vEvictionCandidates)
+[[nodiscard]] std::optional<NodeId> SelectNodeToEvict(std::vector<NodeEvictionCandidate>&& vEvictionCandidates)
{
// Protect connections with certain characteristics
@@ -918,7 +918,7 @@ static void EraseLastKElements(std::vector<T> &elements, Comparator comparator,
total_protect_size -= initial_size - vEvictionCandidates.size();
EraseLastKElements(vEvictionCandidates, ReverseCompareNodeTimeConnected, total_protect_size);
- if (vEvictionCandidates.empty()) return nullopt;
+ if (vEvictionCandidates.empty()) return std::nullopt;
// If any remaining peers are preferred for eviction consider only them.
// This happens after the other preferences since if a peer is really the best by other criteria (esp relaying blocks)
@@ -989,7 +989,7 @@ bool CConnman::AttemptToEvictConnection()
vEvictionCandidates.push_back(candidate);
}
}
- const Optional<NodeId> node_id_to_evict = SelectNodeToEvict(std::move(vEvictionCandidates));
+ const std::optional<NodeId> node_id_to_evict = SelectNodeToEvict(std::move(vEvictionCandidates));
if (!node_id_to_evict) {
return false;
}
diff --git a/src/net.h b/src/net.h
index beef47f045..5228c4fbd3 100644
--- a/src/net.h
+++ b/src/net.h
@@ -18,7 +18,6 @@
#include <net_permissions.h>
#include <netaddress.h>
#include <netbase.h>
-#include <optional.h>
#include <policy/feerate.h>
#include <protocol.h>
#include <random.h>
@@ -35,6 +34,7 @@
#include <deque>
#include <map>
#include <memory>
+#include <optional>
#include <thread>
#include <vector>
@@ -200,7 +200,7 @@ enum
bool IsPeerAddrLocalGood(CNode *pnode);
/** Returns a local address that we should advertise to this peer */
-Optional<CAddress> GetLocalAddrForPeer(CNode *pnode);
+std::optional<CAddress> GetLocalAddrForPeer(CNode *pnode);
/**
* Mark a network as reachable or unreachable (no automatic connects to it)
@@ -229,7 +229,7 @@ extern std::string strSubVersion;
struct LocalServiceInfo {
int nScore;
- int nPort;
+ uint16_t nPort;
};
extern RecursiveMutex cs_mapLocalHost;
@@ -311,7 +311,7 @@ public:
/** read and deserialize data, advances msg_bytes data pointer */
virtual int Read(Span<const uint8_t>& msg_bytes) = 0;
// decomposes a message from the context
- virtual Optional<CNetMessage> GetMessage(std::chrono::microseconds time, uint32_t& out_err) = 0;
+ virtual std::optional<CNetMessage> GetMessage(std::chrono::microseconds time, uint32_t& out_err) = 0;
virtual ~TransportDeserializer() {}
};
@@ -375,7 +375,7 @@ public:
}
return ret;
}
- Optional<CNetMessage> GetMessage(std::chrono::microseconds time, uint32_t& out_err_raw_size) override;
+ std::optional<CNetMessage> GetMessage(std::chrono::microseconds time, uint32_t& out_err_raw_size) override;
};
/** The TransportSerializer prepares messages for the network transport
@@ -1283,6 +1283,6 @@ struct NodeEvictionCandidate
bool m_is_local;
};
-[[nodiscard]] Optional<NodeId> SelectNodeToEvict(std::vector<NodeEvictionCandidate>&& vEvictionCandidates);
+[[nodiscard]] std::optional<NodeId> SelectNodeToEvict(std::vector<NodeEvictionCandidate>&& vEvictionCandidates);
#endif // BITCOIN_NET_H
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index c569acd3cb..e561f02c4a 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -34,6 +34,7 @@
#include <validation.h>
#include <memory>
+#include <optional>
#include <typeinfo>
/** How long to cache transactions in mapRelay for normal relay */
@@ -246,6 +247,7 @@ public:
bool GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats) override;
bool IgnoresIncomingTxs() override { return m_ignore_incoming_txs; }
void SendPings() override;
+ void RelayTransaction(const uint256& txid, const uint256& wtxid) override;
void SetBestHeight(int height) override { m_best_height = height; };
void Misbehaving(const NodeId pnode, const int howmuch, const std::string& message) override;
void ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv,
@@ -259,7 +261,7 @@ private:
void EvictExtraOutboundPeers(int64_t time_in_seconds) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/** Retrieve unbroadcast transactions from the mempool and reattempt sending to peers */
- void ReattemptInitialBroadcast(CScheduler& scheduler) const;
+ void ReattemptInitialBroadcast(CScheduler& scheduler);
/** Get a shared pointer to the Peer object.
* May return an empty shared_ptr if the Peer object can't be found. */
@@ -474,22 +476,19 @@ private:
size_t vExtraTxnForCompactIt GUARDED_BY(g_cs_orphans) = 0;
void ProcessBlockAvailability(NodeId nodeid) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
- void UpdateBlockAvailability(NodeId nodeid, const uint256 &hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
- bool CanDirectFetch(const Consensus::Params &consensusParams) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
- bool BlockRequestAllowed(const CBlockIndex* pindex, const Consensus::Params& consensusParams) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ void UpdateBlockAvailability(NodeId nodeid, const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ bool CanDirectFetch() EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ bool BlockRequestAllowed(const CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
bool AlreadyHaveBlock(const uint256& block_hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
- void ProcessGetBlockData(CNode& pfrom, Peer& peer, const CChainParams& chainparams, const CInv& inv, CConnman& connman);
- bool PrepareBlockFilterRequest(CNode& peer, const CChainParams& chain_params,
+ void ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv& inv);
+ bool PrepareBlockFilterRequest(CNode& peer,
BlockFilterType filter_type, uint32_t start_height,
const uint256& stop_hash, uint32_t max_height_diff,
const CBlockIndex*& stop_index,
BlockFilterIndex*& filter_index);
- void ProcessGetCFilters(CNode& peer, CDataStream& vRecv, const CChainParams& chain_params,
- CConnman& connman);
- void ProcessGetCFHeaders(CNode& peer, CDataStream& vRecv, const CChainParams& chain_params,
- CConnman& connman);
- void ProcessGetCFCheckPt(CNode& peer, CDataStream& vRecv, const CChainParams& chain_params,
- CConnman& connman);
+ void ProcessGetCFilters(CNode& peer, CDataStream& vRecv);
+ void ProcessGetCFHeaders(CNode& peer, CDataStream& vRecv);
+ void ProcessGetCFCheckPt(CNode& peer, CDataStream& vRecv);
};
} // namespace
@@ -575,16 +574,16 @@ struct CNodeState {
*/
struct ChainSyncTimeoutState {
//! A timeout used for checking whether our peer has sufficiently synced
- int64_t m_timeout;
+ int64_t m_timeout{0};
//! A header with the work we require on our peer's chain
- const CBlockIndex * m_work_header;
+ const CBlockIndex* m_work_header{nullptr};
//! After timeout is reached, set to true after sending getheaders
- bool m_sent_getheaders;
+ bool m_sent_getheaders{false};
//! Whether this peer is protected from disconnection due to a bad/slow chain
- bool m_protect;
+ bool m_protect{false};
};
- ChainSyncTimeoutState m_chain_sync{0, nullptr, false, false};
+ ChainSyncTimeoutState m_chain_sync;
//! Time of last new block announcement
int64_t m_last_block_announcement{0};
@@ -598,11 +597,7 @@ struct CNodeState {
//! Whether this peer relays txs via wtxid
bool m_wtxid_relay{false};
- CNodeState(bool is_inbound)
- : m_is_inbound(is_inbound)
- {
- m_recently_announced_invs.reset();
- }
+ CNodeState(bool is_inbound) : m_is_inbound(is_inbound) {}
};
/** Map maintaining per-node state. */
@@ -732,9 +727,9 @@ bool PeerManagerImpl::TipMayBeStale()
return m_last_tip_update < GetTime() - consensusParams.nPowTargetSpacing * 3 && mapBlocksInFlight.empty();
}
-bool PeerManagerImpl::CanDirectFetch(const Consensus::Params &consensusParams)
+bool PeerManagerImpl::CanDirectFetch()
{
- return m_chainman.ActiveChain().Tip()->GetBlockTime() > GetAdjustedTime() - consensusParams.nPowTargetSpacing * 20;
+ return m_chainman.ActiveChain().Tip()->GetBlockTime() > GetAdjustedTime() - m_chainparams.GetConsensus().nPowTargetSpacing * 20;
}
static bool PeerHasHeader(CNodeState *state, const CBlockIndex *pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
@@ -952,7 +947,7 @@ void PeerManagerImpl::InitializeNode(CNode *pnode)
}
}
-void PeerManagerImpl::ReattemptInitialBroadcast(CScheduler& scheduler) const
+void PeerManagerImpl::ReattemptInitialBroadcast(CScheduler& scheduler)
{
std::set<uint256> unbroadcast_txids = m_mempool.GetUnbroadcastTxs();
@@ -961,7 +956,7 @@ void PeerManagerImpl::ReattemptInitialBroadcast(CScheduler& scheduler) const
if (tx != nullptr) {
LOCK(cs_main);
- RelayTransaction(txid, tx->GetWitnessHash(), m_connman);
+ RelayTransaction(txid, tx->GetWitnessHash());
} else {
m_mempool.RemoveUnbroadcastTx(txid, true);
}
@@ -1197,13 +1192,13 @@ bool PeerManagerImpl::MaybePunishNodeForTx(NodeId nodeid, const TxValidationStat
// active chain if they are no more than a month older (both in time, and in
// best equivalent proof of work) than the best header chain we know about and
// we fully-validated them at some point.
-bool PeerManagerImpl::BlockRequestAllowed(const CBlockIndex* pindex, const Consensus::Params& consensusParams)
+bool PeerManagerImpl::BlockRequestAllowed(const CBlockIndex* pindex)
{
AssertLockHeld(cs_main);
if (m_chainman.ActiveChain().Contains(pindex)) return true;
return pindex->IsValid(BLOCK_VALID_SCRIPTS) && (pindexBestHeader != nullptr) &&
- (pindexBestHeader->GetBlockTime() - pindex->GetBlockTime() < STALE_RELAY_AGE_LIMIT) &&
- (GetBlockProofEquivalentTime(*pindexBestHeader, *pindex, *pindexBestHeader, consensusParams) < STALE_RELAY_AGE_LIMIT);
+ (pindexBestHeader->GetBlockTime() - pindex->GetBlockTime() < STALE_RELAY_AGE_LIMIT) &&
+ (GetBlockProofEquivalentTime(*pindexBestHeader, *pindex, *pindexBestHeader, m_chainparams.GetConsensus()) < STALE_RELAY_AGE_LIMIT);
}
std::unique_ptr<PeerManager> PeerManager::make(const CChainParams& chainparams, CConnman& connman, BanMan* banman,
@@ -1463,9 +1458,9 @@ void PeerManagerImpl::SendPings()
for(auto& it : m_peer_map) it.second->m_ping_queued = true;
}
-void RelayTransaction(const uint256& txid, const uint256& wtxid, const CConnman& connman)
+void PeerManagerImpl::RelayTransaction(const uint256& txid, const uint256& wtxid)
{
- connman.ForEachNode([&txid, &wtxid](CNode* pnode) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {
+ m_connman.ForEachNode([&txid, &wtxid](CNode* pnode) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {
AssertLockHeld(::cs_main);
CNodeState* state = State(pnode->GetId());
@@ -1533,13 +1528,11 @@ static void RelayAddress(const CNode& originator,
connman.ForEachNodeThen(std::move(sortfunc), std::move(pushfunc));
}
-void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CChainParams& chainparams, const CInv& inv, CConnman& connman)
+void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv& inv)
{
- bool send = false;
std::shared_ptr<const CBlock> a_recent_block;
std::shared_ptr<const CBlockHeaderAndShortTxIDs> a_recent_compact_block;
bool fWitnessesPresentInARecentCompactBlock;
- const Consensus::Params& consensusParams = chainparams.GetConsensus();
{
LOCK(cs_most_recent_block);
a_recent_block = most_recent_block;
@@ -1565,126 +1558,124 @@ void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CChain
} // release cs_main before calling ActivateBestChain
if (need_activate_chain) {
BlockValidationState state;
- if (!m_chainman.ActiveChainstate().ActivateBestChain(state, chainparams, a_recent_block)) {
+ if (!m_chainman.ActiveChainstate().ActivateBestChain(state, m_chainparams, a_recent_block)) {
LogPrint(BCLog::NET, "failed to activate chain (%s)\n", state.ToString());
}
}
LOCK(cs_main);
const CBlockIndex* pindex = m_chainman.m_blockman.LookupBlockIndex(inv.hash);
- if (pindex) {
- send = BlockRequestAllowed(pindex, consensusParams);
- if (!send) {
- LogPrint(BCLog::NET, "%s: ignoring request from peer=%i for old block that isn't in the main chain\n", __func__, pfrom.GetId());
- }
+ if (!pindex) {
+ return;
+ }
+ if (!BlockRequestAllowed(pindex)) {
+ LogPrint(BCLog::NET, "%s: ignoring request from peer=%i for old block that isn't in the main chain\n", __func__, pfrom.GetId());
+ return;
}
const CNetMsgMaker msgMaker(pfrom.GetCommonVersion());
// disconnect node in case we have reached the outbound limit for serving historical blocks
- if (send &&
- connman.OutboundTargetReached(true) &&
+ if (m_connman.OutboundTargetReached(true) &&
(((pindexBestHeader != nullptr) && (pindexBestHeader->GetBlockTime() - pindex->GetBlockTime() > HISTORICAL_BLOCK_AGE)) || inv.IsMsgFilteredBlk()) &&
!pfrom.HasPermission(PF_DOWNLOAD) // nodes with the download permission may exceed target
) {
LogPrint(BCLog::NET, "historical block serving limit reached, disconnect peer=%d\n", pfrom.GetId());
-
- //disconnect node
pfrom.fDisconnect = true;
- send = false;
+ return;
}
// Avoid leaking prune-height by never sending blocks below the NODE_NETWORK_LIMITED threshold
- if (send && !pfrom.HasPermission(PF_NOBAN) && (
+ if (!pfrom.HasPermission(PF_NOBAN) && (
(((pfrom.GetLocalServices() & NODE_NETWORK_LIMITED) == NODE_NETWORK_LIMITED) && ((pfrom.GetLocalServices() & NODE_NETWORK) != NODE_NETWORK) && (m_chainman.ActiveChain().Tip()->nHeight - pindex->nHeight > (int)NODE_NETWORK_LIMITED_MIN_BLOCKS + 2 /* add two blocks buffer extension for possible races */) )
)) {
- LogPrint(BCLog::NET, "Ignore block request below NODE_NETWORK_LIMITED threshold from peer=%d\n", pfrom.GetId());
-
+ LogPrint(BCLog::NET, "Ignore block request below NODE_NETWORK_LIMITED threshold, disconnect peer=%d\n", pfrom.GetId());
//disconnect node and prevent it from stalling (would otherwise wait for the missing block)
pfrom.fDisconnect = true;
- send = false;
+ return;
}
// Pruned nodes may have deleted the block, so check whether
// it's available before trying to send.
- if (send && (pindex->nStatus & BLOCK_HAVE_DATA))
- {
- std::shared_ptr<const CBlock> pblock;
- if (a_recent_block && a_recent_block->GetHash() == pindex->GetBlockHash()) {
- pblock = a_recent_block;
- } else if (inv.IsMsgWitnessBlk()) {
- // Fast-path: in this case it is possible to serve the block directly from disk,
- // as the network format matches the format on disk
- std::vector<uint8_t> block_data;
- if (!ReadRawBlockFromDisk(block_data, pindex, chainparams.MessageStart())) {
- assert(!"cannot load block from disk");
- }
- connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::BLOCK, MakeSpan(block_data)));
- // Don't set pblock as we've sent the block
- } else {
- // Send block from disk
- std::shared_ptr<CBlock> pblockRead = std::make_shared<CBlock>();
- if (!ReadBlockFromDisk(*pblockRead, pindex, consensusParams))
- assert(!"cannot load block from disk");
- pblock = pblockRead;
+ if (!(pindex->nStatus & BLOCK_HAVE_DATA)) {
+ return;
+ }
+ std::shared_ptr<const CBlock> pblock;
+ if (a_recent_block && a_recent_block->GetHash() == pindex->GetBlockHash()) {
+ pblock = a_recent_block;
+ } else if (inv.IsMsgWitnessBlk()) {
+ // Fast-path: in this case it is possible to serve the block directly from disk,
+ // as the network format matches the format on disk
+ std::vector<uint8_t> block_data;
+ if (!ReadRawBlockFromDisk(block_data, pindex, m_chainparams.MessageStart())) {
+ assert(!"cannot load block from disk");
+ }
+ m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::BLOCK, MakeSpan(block_data)));
+ // Don't set pblock as we've sent the block
+ } else {
+ // Send block from disk
+ std::shared_ptr<CBlock> pblockRead = std::make_shared<CBlock>();
+ if (!ReadBlockFromDisk(*pblockRead, pindex, m_chainparams.GetConsensus())) {
+ assert(!"cannot load block from disk");
}
- if (pblock) {
- if (inv.IsMsgBlk()) {
- connman.PushMessage(&pfrom, msgMaker.Make(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::BLOCK, *pblock));
- } else if (inv.IsMsgWitnessBlk()) {
- connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::BLOCK, *pblock));
- } else if (inv.IsMsgFilteredBlk()) {
- bool sendMerkleBlock = false;
- CMerkleBlock merkleBlock;
- if (pfrom.m_tx_relay != nullptr) {
- LOCK(pfrom.m_tx_relay->cs_filter);
- if (pfrom.m_tx_relay->pfilter) {
- sendMerkleBlock = true;
- merkleBlock = CMerkleBlock(*pblock, *pfrom.m_tx_relay->pfilter);
- }
- }
- if (sendMerkleBlock) {
- connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::MERKLEBLOCK, merkleBlock));
- // CMerkleBlock just contains hashes, so also push any transactions in the block the client did not see
- // This avoids hurting performance by pointlessly requiring a round-trip
- // Note that there is currently no way for a node to request any single transactions we didn't send here -
- // they must either disconnect and retry or request the full block.
- // Thus, the protocol spec specified allows for us to provide duplicate txn here,
- // however we MUST always provide at least what the remote peer needs
- typedef std::pair<unsigned int, uint256> PairType;
- for (PairType& pair : merkleBlock.vMatchedTxn)
- connman.PushMessage(&pfrom, msgMaker.Make(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::TX, *pblock->vtx[pair.first]));
+ pblock = pblockRead;
+ }
+ if (pblock) {
+ if (inv.IsMsgBlk()) {
+ m_connman.PushMessage(&pfrom, msgMaker.Make(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::BLOCK, *pblock));
+ } else if (inv.IsMsgWitnessBlk()) {
+ m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::BLOCK, *pblock));
+ } else if (inv.IsMsgFilteredBlk()) {
+ bool sendMerkleBlock = false;
+ CMerkleBlock merkleBlock;
+ if (pfrom.m_tx_relay != nullptr) {
+ LOCK(pfrom.m_tx_relay->cs_filter);
+ if (pfrom.m_tx_relay->pfilter) {
+ sendMerkleBlock = true;
+ merkleBlock = CMerkleBlock(*pblock, *pfrom.m_tx_relay->pfilter);
}
- // else
- // no response
- } else if (inv.IsMsgCmpctBlk()) {
- // If a peer is asking for old blocks, we're almost guaranteed
- // they won't have a useful mempool to match against a compact block,
- // and we don't feel like constructing the object for them, so
- // instead we respond with the full, non-compact block.
- bool fPeerWantsWitness = State(pfrom.GetId())->fWantsCmpctWitness;
- int nSendFlags = fPeerWantsWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS;
- if (CanDirectFetch(consensusParams) && pindex->nHeight >= m_chainman.ActiveChain().Height() - MAX_CMPCTBLOCK_DEPTH) {
- if ((fPeerWantsWitness || !fWitnessesPresentInARecentCompactBlock) && a_recent_compact_block && a_recent_compact_block->header.GetHash() == pindex->GetBlockHash()) {
- connman.PushMessage(&pfrom, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, *a_recent_compact_block));
- } else {
- CBlockHeaderAndShortTxIDs cmpctblock(*pblock, fPeerWantsWitness);
- connman.PushMessage(&pfrom, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, cmpctblock));
- }
+ }
+ if (sendMerkleBlock) {
+ m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::MERKLEBLOCK, merkleBlock));
+ // CMerkleBlock just contains hashes, so also push any transactions in the block the client did not see
+ // This avoids hurting performance by pointlessly requiring a round-trip
+ // Note that there is currently no way for a node to request any single transactions we didn't send here -
+ // they must either disconnect and retry or request the full block.
+ // Thus, the protocol spec specified allows for us to provide duplicate txn here,
+ // however we MUST always provide at least what the remote peer needs
+ typedef std::pair<unsigned int, uint256> PairType;
+ for (PairType& pair : merkleBlock.vMatchedTxn)
+ m_connman.PushMessage(&pfrom, msgMaker.Make(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::TX, *pblock->vtx[pair.first]));
+ }
+ // else
+ // no response
+ } else if (inv.IsMsgCmpctBlk()) {
+ // If a peer is asking for old blocks, we're almost guaranteed
+ // they won't have a useful mempool to match against a compact block,
+ // and we don't feel like constructing the object for them, so
+ // instead we respond with the full, non-compact block.
+ bool fPeerWantsWitness = State(pfrom.GetId())->fWantsCmpctWitness;
+ int nSendFlags = fPeerWantsWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS;
+ if (CanDirectFetch() && pindex->nHeight >= m_chainman.ActiveChain().Height() - MAX_CMPCTBLOCK_DEPTH) {
+ if ((fPeerWantsWitness || !fWitnessesPresentInARecentCompactBlock) && a_recent_compact_block && a_recent_compact_block->header.GetHash() == pindex->GetBlockHash()) {
+ m_connman.PushMessage(&pfrom, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, *a_recent_compact_block));
} else {
- connman.PushMessage(&pfrom, msgMaker.Make(nSendFlags, NetMsgType::BLOCK, *pblock));
+ CBlockHeaderAndShortTxIDs cmpctblock(*pblock, fPeerWantsWitness);
+ m_connman.PushMessage(&pfrom, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, cmpctblock));
}
+ } else {
+ m_connman.PushMessage(&pfrom, msgMaker.Make(nSendFlags, NetMsgType::BLOCK, *pblock));
}
}
+ }
- {
- LOCK(peer.m_block_inv_mutex);
- // Trigger the peer node to send a getblocks request for the next batch of inventory
- if (inv.hash == peer.m_continuation_block) {
- // Send immediately. This must send even if redundant,
- // and we want it right after the last block so they don't
- // wait for other stuff first.
- std::vector<CInv> vInv;
- vInv.push_back(CInv(MSG_BLOCK, m_chainman.ActiveChain().Tip()->GetBlockHash()));
- connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::INV, vInv));
- peer.m_continuation_block.SetNull();
- }
+ {
+ LOCK(peer.m_block_inv_mutex);
+ // Trigger the peer node to send a getblocks request for the next batch of inventory
+ if (inv.hash == peer.m_continuation_block) {
+ // Send immediately. This must send even if redundant,
+ // and we want it right after the last block so they don't
+ // wait for other stuff first.
+ std::vector<CInv> vInv;
+ vInv.push_back(CInv(MSG_BLOCK, m_chainman.ActiveChain().Tip()->GetBlockHash()));
+ m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::INV, vInv));
+ peer.m_continuation_block.SetNull();
}
}
}
@@ -1783,7 +1774,7 @@ void PeerManagerImpl::ProcessGetData(CNode& pfrom, Peer& peer, const std::atomic
if (it != peer.m_getdata_requests.end() && !pfrom.fPauseSend) {
const CInv &inv = *it++;
if (inv.IsGenBlkMsg()) {
- ProcessGetBlockData(pfrom, peer, m_chainparams, inv, m_connman);
+ ProcessGetBlockData(pfrom, peer, inv);
}
// else: If the first item on the queue is an unknown type, we erase it
// and continue processing the queue on the next call.
@@ -1931,10 +1922,9 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, const Peer& peer,
m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETHEADERS, m_chainman.ActiveChain().GetLocator(pindexLast), uint256()));
}
- bool fCanDirectFetch = CanDirectFetch(m_chainparams.GetConsensus());
// If this set of headers is valid and ends in a block with at least as
// much work as our tip, download as much as possible.
- if (fCanDirectFetch && pindexLast->IsValid(BLOCK_VALID_TREE) && m_chainman.ActiveChain().Tip()->nChainWork <= pindexLast->nChainWork) {
+ if (CanDirectFetch() && pindexLast->IsValid(BLOCK_VALID_TREE) && m_chainman.ActiveChain().Tip()->nChainWork <= pindexLast->nChainWork) {
std::vector<const CBlockIndex*> vToFetch;
const CBlockIndex *pindexWalk = pindexLast;
// Calculate all the blocks we'd need to switch to pindexLast, up to a limit.
@@ -2045,7 +2035,7 @@ void PeerManagerImpl::ProcessOrphanTx(std::set<uint256>& orphan_work_set)
if (result.m_result_type == MempoolAcceptResult::ResultType::VALID) {
LogPrint(BCLog::MEMPOOL, " accepted orphan tx %s\n", orphanHash.ToString());
- RelayTransaction(orphanHash, porphanTx->GetWitnessHash(), m_connman);
+ RelayTransaction(orphanHash, porphanTx->GetWitnessHash());
m_orphanage.AddChildrenToWorkSet(*porphanTx, orphan_work_set);
m_orphanage.EraseTx(orphanHash);
for (const CTransactionRef& removedTx : result.m_replaced_transactions.value()) {
@@ -2107,7 +2097,6 @@ void PeerManagerImpl::ProcessOrphanTx(std::set<uint256>& orphan_work_set)
* May disconnect from the peer in the case of a bad request.
*
* @param[in] peer The peer that we received the request from
- * @param[in] chain_params Chain parameters
* @param[in] filter_type The filter type the request is for. Must be basic filters.
* @param[in] start_height The start height for the request
* @param[in] stop_hash The stop_hash for the request
@@ -2116,11 +2105,11 @@ void PeerManagerImpl::ProcessOrphanTx(std::set<uint256>& orphan_work_set)
* @param[out] filter_index The filter index, if the request can be serviced.
* @return True if the request can be serviced.
*/
-bool PeerManagerImpl::PrepareBlockFilterRequest(CNode& peer, const CChainParams& chain_params,
- BlockFilterType filter_type, uint32_t start_height,
- const uint256& stop_hash, uint32_t max_height_diff,
- const CBlockIndex*& stop_index,
- BlockFilterIndex*& filter_index)
+bool PeerManagerImpl::PrepareBlockFilterRequest(CNode& peer,
+ BlockFilterType filter_type, uint32_t start_height,
+ const uint256& stop_hash, uint32_t max_height_diff,
+ const CBlockIndex*& stop_index,
+ BlockFilterIndex*& filter_index)
{
const bool supported_filter_type =
(filter_type == BlockFilterType::BASIC &&
@@ -2137,7 +2126,7 @@ bool PeerManagerImpl::PrepareBlockFilterRequest(CNode& peer, const CChainParams&
stop_index = m_chainman.m_blockman.LookupBlockIndex(stop_hash);
// Check that the stop block exists and the peer would be allowed to fetch it.
- if (!stop_index || !BlockRequestAllowed(stop_index, chain_params.GetConsensus())) {
+ if (!stop_index || !BlockRequestAllowed(stop_index)) {
LogPrint(BCLog::NET, "peer %d requested invalid block hash: %s\n",
peer.GetId(), stop_hash.ToString());
peer.fDisconnect = true;
@@ -2176,11 +2165,8 @@ bool PeerManagerImpl::PrepareBlockFilterRequest(CNode& peer, const CChainParams&
*
* @param[in] peer The peer that we received the request from
* @param[in] vRecv The raw message received
- * @param[in] chain_params Chain parameters
- * @param[in] connman Pointer to the connection manager
*/
-void PeerManagerImpl::ProcessGetCFilters(CNode& peer, CDataStream& vRecv, const CChainParams& chain_params,
- CConnman& connman)
+void PeerManagerImpl::ProcessGetCFilters(CNode& peer, CDataStream& vRecv)
{
uint8_t filter_type_ser;
uint32_t start_height;
@@ -2192,7 +2178,7 @@ void PeerManagerImpl::ProcessGetCFilters(CNode& peer, CDataStream& vRecv, const
const CBlockIndex* stop_index;
BlockFilterIndex* filter_index;
- if (!PrepareBlockFilterRequest(peer, chain_params, filter_type, start_height, stop_hash,
+ if (!PrepareBlockFilterRequest(peer, filter_type, start_height, stop_hash,
MAX_GETCFILTERS_SIZE, stop_index, filter_index)) {
return;
}
@@ -2207,7 +2193,7 @@ void PeerManagerImpl::ProcessGetCFilters(CNode& peer, CDataStream& vRecv, const
for (const auto& filter : filters) {
CSerializedNetMsg msg = CNetMsgMaker(peer.GetCommonVersion())
.Make(NetMsgType::CFILTER, filter);
- connman.PushMessage(&peer, std::move(msg));
+ m_connman.PushMessage(&peer, std::move(msg));
}
}
@@ -2218,11 +2204,8 @@ void PeerManagerImpl::ProcessGetCFilters(CNode& peer, CDataStream& vRecv, const
*
* @param[in] peer The peer that we received the request from
* @param[in] vRecv The raw message received
- * @param[in] chain_params Chain parameters
- * @param[in] connman Pointer to the connection manager
*/
-void PeerManagerImpl::ProcessGetCFHeaders(CNode& peer, CDataStream& vRecv, const CChainParams& chain_params,
- CConnman& connman)
+void PeerManagerImpl::ProcessGetCFHeaders(CNode& peer, CDataStream& vRecv)
{
uint8_t filter_type_ser;
uint32_t start_height;
@@ -2234,7 +2217,7 @@ void PeerManagerImpl::ProcessGetCFHeaders(CNode& peer, CDataStream& vRecv, const
const CBlockIndex* stop_index;
BlockFilterIndex* filter_index;
- if (!PrepareBlockFilterRequest(peer, chain_params, filter_type, start_height, stop_hash,
+ if (!PrepareBlockFilterRequest(peer, filter_type, start_height, stop_hash,
MAX_GETCFHEADERS_SIZE, stop_index, filter_index)) {
return;
}
@@ -2263,7 +2246,7 @@ void PeerManagerImpl::ProcessGetCFHeaders(CNode& peer, CDataStream& vRecv, const
stop_index->GetBlockHash(),
prev_header,
filter_hashes);
- connman.PushMessage(&peer, std::move(msg));
+ m_connman.PushMessage(&peer, std::move(msg));
}
/**
@@ -2273,11 +2256,8 @@ void PeerManagerImpl::ProcessGetCFHeaders(CNode& peer, CDataStream& vRecv, const
*
* @param[in] peer The peer that we received the request from
* @param[in] vRecv The raw message received
- * @param[in] chain_params Chain parameters
- * @param[in] connman Pointer to the connection manager
*/
-void PeerManagerImpl::ProcessGetCFCheckPt(CNode& peer, CDataStream& vRecv, const CChainParams& chain_params,
- CConnman& connman)
+void PeerManagerImpl::ProcessGetCFCheckPt(CNode& peer, CDataStream& vRecv)
{
uint8_t filter_type_ser;
uint256 stop_hash;
@@ -2288,7 +2268,7 @@ void PeerManagerImpl::ProcessGetCFCheckPt(CNode& peer, CDataStream& vRecv, const
const CBlockIndex* stop_index;
BlockFilterIndex* filter_index;
- if (!PrepareBlockFilterRequest(peer, chain_params, filter_type, /*start_height=*/0, stop_hash,
+ if (!PrepareBlockFilterRequest(peer, filter_type, /*start_height=*/0, stop_hash,
/*max_height_diff=*/std::numeric_limits<uint32_t>::max(),
stop_index, filter_index)) {
return;
@@ -2314,7 +2294,7 @@ void PeerManagerImpl::ProcessGetCFCheckPt(CNode& peer, CDataStream& vRecv, const
filter_type_ser,
stop_index->GetBlockHash(),
headers);
- connman.PushMessage(&peer, std::move(msg));
+ m_connman.PushMessage(&peer, std::move(msg));
}
void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv,
@@ -2952,7 +2932,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
return;
}
- if (!BlockRequestAllowed(pindex, m_chainparams.GetConsensus())) {
+ if (!BlockRequestAllowed(pindex)) {
LogPrint(BCLog::NET, "%s: ignoring request from peer=%i for old block header that isn't in the main chain\n", __func__, pfrom.GetId());
return;
}
@@ -3049,7 +3029,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
LogPrintf("Not relaying non-mempool transaction %s from forcerelay peer=%d\n", tx.GetHash().ToString(), pfrom.GetId());
} else {
LogPrintf("Force relaying tx %s from peer=%d\n", tx.GetHash().ToString(), pfrom.GetId());
- RelayTransaction(tx.GetHash(), tx.GetWitnessHash(), m_connman);
+ RelayTransaction(tx.GetHash(), tx.GetWitnessHash());
}
}
return;
@@ -3064,7 +3044,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// requests for it.
m_txrequest.ForgetTxHash(tx.GetHash());
m_txrequest.ForgetTxHash(tx.GetWitnessHash());
- RelayTransaction(tx.GetHash(), tx.GetWitnessHash(), m_connman);
+ RelayTransaction(tx.GetHash(), tx.GetWitnessHash());
m_orphanage.AddChildrenToWorkSet(tx, peer->m_orphan_work_set);
pfrom.nLastTXTime = GetTime();
@@ -3290,8 +3270,9 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
}
// If we're not close to tip yet, give up and let parallel block fetch work its magic
- if (!fAlreadyInFlight && !CanDirectFetch(m_chainparams.GetConsensus()))
+ if (!fAlreadyInFlight && !CanDirectFetch()) {
return;
+ }
if (IsWitnessEnabled(pindex->pprev, m_chainparams.GetConsensus()) && !nodestate->fSupportsDesiredCmpctVersion) {
// Don't bother trying to process compact blocks from v1 peers
@@ -3784,17 +3765,17 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
}
if (msg_type == NetMsgType::GETCFILTERS) {
- ProcessGetCFilters(pfrom, vRecv, m_chainparams, m_connman);
+ ProcessGetCFilters(pfrom, vRecv);
return;
}
if (msg_type == NetMsgType::GETCFHEADERS) {
- ProcessGetCFHeaders(pfrom, vRecv, m_chainparams, m_connman);
+ ProcessGetCFHeaders(pfrom, vRecv);
return;
}
if (msg_type == NetMsgType::GETCFCHECKPT) {
- ProcessGetCFCheckPt(pfrom, vRecv, m_chainparams, m_connman);
+ ProcessGetCFCheckPt(pfrom, vRecv);
return;
}
@@ -4109,7 +4090,7 @@ void PeerManagerImpl::CheckForStaleTipAndEvictPeers()
m_stale_tip_check_time = time_in_seconds + STALE_CHECK_INTERVAL;
}
- if (!m_initial_sync_finished && CanDirectFetch(m_chainparams.GetConsensus())) {
+ if (!m_initial_sync_finished && CanDirectFetch()) {
m_connman.StartExtraBlockRelayPeers();
m_initial_sync_finished = true;
}
@@ -4222,7 +4203,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
if (pto->m_next_local_addr_send != 0us) {
pto->m_addr_known->reset();
}
- if (Optional<CAddress> local_addr = GetLocalAddrForPeer(pto)) {
+ if (std::optional<CAddress> local_addr = GetLocalAddrForPeer(pto)) {
FastRandomContext insecure_rand;
pto->PushAddress(*local_addr, insecure_rand);
}
diff --git a/src/net_processing.h b/src/net_processing.h
index 6f900410a7..f6f2d73721 100644
--- a/src/net_processing.h
+++ b/src/net_processing.h
@@ -47,6 +47,10 @@ public:
/** Whether this node ignores txs received over p2p. */
virtual bool IgnoresIncomingTxs() = 0;
+ /** Relay transaction to all peers. */
+ virtual void RelayTransaction(const uint256& txid, const uint256& wtxid)
+ EXCLUSIVE_LOCKS_REQUIRED(cs_main) = 0;
+
/** Send ping message to all peers */
virtual void SendPings() = 0;
@@ -71,7 +75,4 @@ public:
const std::chrono::microseconds time_received, const std::atomic<bool>& interruptMsgProc) = 0;
};
-/** Relay transaction to every node */
-void RelayTransaction(const uint256& txid, const uint256& wtxid, const CConnman& connman) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
-
#endif // BITCOIN_NET_PROCESSING_H
diff --git a/src/netbase.cpp b/src/netbase.cpp
index b95bb05e71..49e455aa84 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -166,21 +166,6 @@ static bool LookupIntern(const std::string& name, std::vector<CNetAddr>& vIP, un
return (vIP.size() > 0);
}
-/**
- * Resolve a host string to its corresponding network addresses.
- *
- * @param name The string representing a host. Could be a name or a numerical
- * IP address (IPv6 addresses in their bracketed form are
- * allowed).
- * @param[out] vIP The resulting network addresses to which the specified host
- * string resolved.
- *
- * @returns Whether or not the specified host string successfully resolved to
- * any resulting network addresses.
- *
- * @see Lookup(const char *, std::vector<CService>&, int, bool, unsigned int)
- * for additional parameter descriptions.
- */
bool LookupHost(const std::string& name, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions, bool fAllowLookup, DNSLookupFn dns_lookup_function)
{
if (!ValidAsCString(name)) {
@@ -196,12 +181,6 @@ bool LookupHost(const std::string& name, std::vector<CNetAddr>& vIP, unsigned in
return LookupIntern(strHost, vIP, nMaxSolutions, fAllowLookup, dns_lookup_function);
}
- /**
- * Resolve a host string to its first corresponding network address.
- *
- * @see LookupHost(const std::string&, std::vector<CNetAddr>&, unsigned int, bool) for
- * additional parameter descriptions.
- */
bool LookupHost(const std::string& name, CNetAddr& addr, bool fAllowLookup, DNSLookupFn dns_lookup_function)
{
if (!ValidAsCString(name)) {
@@ -215,32 +194,12 @@ bool LookupHost(const std::string& name, CNetAddr& addr, bool fAllowLookup, DNSL
return true;
}
-/**
- * Resolve a service string to its corresponding service.
- *
- * @param name The string representing a service. Could be a name or a
- * numerical IP address (IPv6 addresses should be in their
- * disambiguated bracketed form), optionally followed by a port
- * number. (e.g. example.com:8333 or
- * [2001:db8:85a3:8d3:1319:8a2e:370:7348]:420)
- * @param[out] vAddr The resulting services to which the specified service string
- * resolved.
- * @param portDefault The default port for resulting services if not specified
- * by the service string.
- * @param fAllowLookup Whether or not hostname lookups are permitted. If yes,
- * external queries may be performed.
- * @param nMaxSolutions The maximum number of results we want, specifying 0
- * means "as many solutions as we get."
- *
- * @returns Whether or not the service string successfully resolved to any
- * resulting services.
- */
-bool Lookup(const std::string& name, std::vector<CService>& vAddr, int portDefault, bool fAllowLookup, unsigned int nMaxSolutions, DNSLookupFn dns_lookup_function)
+bool Lookup(const std::string& name, std::vector<CService>& vAddr, uint16_t portDefault, bool fAllowLookup, unsigned int nMaxSolutions, DNSLookupFn dns_lookup_function)
{
if (name.empty() || !ValidAsCString(name)) {
return false;
}
- int port = portDefault;
+ uint16_t port{portDefault};
std::string hostname;
SplitHostPort(name, port, hostname);
@@ -254,13 +213,7 @@ bool Lookup(const std::string& name, std::vector<CService>& vAddr, int portDefau
return true;
}
-/**
- * Resolve a service string to its first corresponding service.
- *
- * @see Lookup(const char *, std::vector<CService>&, int, bool, unsigned int)
- * for additional parameter descriptions.
- */
-bool Lookup(const std::string& name, CService& addr, int portDefault, bool fAllowLookup, DNSLookupFn dns_lookup_function)
+bool Lookup(const std::string& name, CService& addr, uint16_t portDefault, bool fAllowLookup, DNSLookupFn dns_lookup_function)
{
if (!ValidAsCString(name)) {
return false;
@@ -273,17 +226,7 @@ bool Lookup(const std::string& name, CService& addr, int portDefault, bool fAllo
return true;
}
-/**
- * Resolve a service string with a numeric IP to its first corresponding
- * service.
- *
- * @returns The resulting CService if the resolution was successful, [::]:0
- * otherwise.
- *
- * @see Lookup(const char *, CService&, int, bool) for additional parameter
- * descriptions.
- */
-CService LookupNumeric(const std::string& name, int portDefault, DNSLookupFn dns_lookup_function)
+CService LookupNumeric(const std::string& name, uint16_t portDefault, DNSLookupFn dns_lookup_function)
{
if (!ValidAsCString(name)) {
return {};
@@ -420,25 +363,7 @@ static std::string Socks5ErrorString(uint8_t err)
}
}
-/**
- * Connect to a specified destination service through an already connected
- * SOCKS5 proxy.
- *
- * @param strDest The destination fully-qualified domain name.
- * @param port The destination port.
- * @param auth The credentials with which to authenticate with the specified
- * SOCKS5 proxy.
- * @param sock The SOCKS5 proxy socket.
- *
- * @returns Whether or not the operation succeeded.
- *
- * @note The specified SOCKS5 proxy socket must already be connected to the
- * SOCKS5 proxy.
- *
- * @see <a href="https://www.ietf.org/rfc/rfc1928.txt">RFC1928: SOCKS Protocol
- * Version 5</a>
- */
-bool Socks5(const std::string& strDest, int port, const ProxyCredentials* auth, const Sock& sock)
+bool Socks5(const std::string& strDest, uint16_t port, const ProxyCredentials* auth, const Sock& sock)
{
IntrRecvError recvr;
LogPrint(BCLog::NET, "SOCKS5 connecting %s\n", strDest);
@@ -612,18 +537,6 @@ static void LogConnectFailure(bool manual_connection, const char* fmt, const Arg
}
}
-/**
- * Try to connect to the specified service on the specified socket.
- *
- * @param addrConnect The service to which to connect.
- * @param hSocket The socket on which to connect.
- * @param nTimeout Wait this many milliseconds for the connection to be
- * established.
- * @param manual_connection Whether or not the connection was manually requested
- * (e.g. through the addnode RPC)
- *
- * @returns Whether or not a connection was successfully made.
- */
bool ConnectSocketDirectly(const CService &addrConnect, const SOCKET& hSocket, int nTimeout, bool manual_connection)
{
// Create a sockaddr from the specified service.
@@ -722,22 +635,6 @@ bool GetProxy(enum Network net, proxyType &proxyInfoOut) {
return true;
}
-/**
- * Set the name proxy to use for all connections to nodes specified by a
- * hostname. After setting this proxy, connecting to a node specified by a
- * hostname won't result in a local lookup of said hostname, rather, connect to
- * the node by asking the name proxy for a proxy connection to the hostname,
- * effectively delegating the hostname lookup to the specified proxy.
- *
- * This delegation increases privacy for those who set the name proxy as they no
- * longer leak their external hostname queries to their DNS servers.
- *
- * @returns Whether or not the operation succeeded.
- *
- * @note SOCKS5's support for UDP-over-SOCKS5 has been considered, but no SOCK5
- * server in common use (most notably Tor) actually implements UDP
- * support, and a DNS resolver is beyond the scope of this project.
- */
bool SetNameProxy(const proxyType &addrProxy) {
if (!addrProxy.IsValid())
return false;
@@ -768,22 +665,7 @@ bool IsProxy(const CNetAddr &addr) {
return false;
}
-/**
- * Connect to a specified destination service through a SOCKS5 proxy by first
- * connecting to the SOCKS5 proxy.
- *
- * @param proxy The SOCKS5 proxy.
- * @param strDest The destination service to which to connect.
- * @param port The destination port.
- * @param sock The socket on which to connect to the SOCKS5 proxy.
- * @param nTimeout Wait this many milliseconds for the connection to the SOCKS5
- * proxy to be established.
- * @param[out] outProxyConnectionFailed Whether or not the connection to the
- * SOCKS5 proxy failed.
- *
- * @returns Whether or not the operation succeeded.
- */
-bool ConnectThroughProxy(const proxyType& proxy, const std::string& strDest, int port, const Sock& sock, int nTimeout, bool& outProxyConnectionFailed)
+bool ConnectThroughProxy(const proxyType& proxy, const std::string& strDest, uint16_t port, const Sock& sock, int nTimeout, bool& outProxyConnectionFailed)
{
// first connect to proxy server
if (!ConnectSocketDirectly(proxy.proxy, sock.Get(), nTimeout, true)) {
@@ -795,28 +677,17 @@ bool ConnectThroughProxy(const proxyType& proxy, const std::string& strDest, int
ProxyCredentials random_auth;
static std::atomic_int counter(0);
random_auth.username = random_auth.password = strprintf("%i", counter++);
- if (!Socks5(strDest, (uint16_t)port, &random_auth, sock)) {
+ if (!Socks5(strDest, port, &random_auth, sock)) {
return false;
}
} else {
- if (!Socks5(strDest, (uint16_t)port, 0, sock)) {
+ if (!Socks5(strDest, port, 0, sock)) {
return false;
}
}
return true;
}
-/**
- * Parse and resolve a specified subnet string into the appropriate internal
- * representation.
- *
- * @param strSubnet A string representation of a subnet of the form `network
- * address [ "/", ( CIDR-style suffix | netmask ) ]`(e.g.
- * `2001:db8::/32`, `192.0.2.0/255.255.255.0`, or `8.8.8.8`).
- * @param ret The resulting internal representation of a subnet.
- *
- * @returns Whether the operation succeeded or not.
- */
bool LookupSubNet(const std::string& strSubnet, CSubNet& ret, DNSLookupFn dns_lookup_function)
{
if (!ValidAsCString(strSubnet)) {
diff --git a/src/netbase.h b/src/netbase.h
index 227da1a63b..08172b9984 100644
--- a/src/netbase.h
+++ b/src/netbase.h
@@ -76,6 +76,22 @@ std::vector<std::string> GetNetworkNames(bool append_unroutable = false);
bool SetProxy(enum Network net, const proxyType &addrProxy);
bool GetProxy(enum Network net, proxyType &proxyInfoOut);
bool IsProxy(const CNetAddr &addr);
+/**
+ * Set the name proxy to use for all connections to nodes specified by a
+ * hostname. After setting this proxy, connecting to a node specified by a
+ * hostname won't result in a local lookup of said hostname, rather, connect to
+ * the node by asking the name proxy for a proxy connection to the hostname,
+ * effectively delegating the hostname lookup to the specified proxy.
+ *
+ * This delegation increases privacy for those who set the name proxy as they no
+ * longer leak their external hostname queries to their DNS servers.
+ *
+ * @returns Whether or not the operation succeeded.
+ *
+ * @note SOCKS5's support for UDP-over-SOCKS5 has been considered, but no SOCK5
+ * server in common use (most notably Tor) actually implements UDP
+ * support, and a DNS resolver is beyond the scope of this project.
+ */
bool SetNameProxy(const proxyType &addrProxy);
bool HaveNameProxy();
bool GetNameProxy(proxyType &nameProxyOut);
@@ -83,11 +99,83 @@ bool GetNameProxy(proxyType &nameProxyOut);
using DNSLookupFn = std::function<std::vector<CNetAddr>(const std::string&, bool)>;
extern DNSLookupFn g_dns_lookup;
+/**
+ * Resolve a host string to its corresponding network addresses.
+ *
+ * @param name The string representing a host. Could be a name or a numerical
+ * IP address (IPv6 addresses in their bracketed form are
+ * allowed).
+ * @param[out] vIP The resulting network addresses to which the specified host
+ * string resolved.
+ *
+ * @returns Whether or not the specified host string successfully resolved to
+ * any resulting network addresses.
+ *
+ * @see Lookup(const std::string&, std::vector<CService>&, uint16_t, bool, unsigned int, DNSLookupFn)
+ * for additional parameter descriptions.
+ */
bool LookupHost(const std::string& name, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions, bool fAllowLookup, DNSLookupFn dns_lookup_function = g_dns_lookup);
+
+/**
+ * Resolve a host string to its first corresponding network address.
+ *
+ * @see LookupHost(const std::string&, std::vector<CNetAddr>&, uint16_t, bool, DNSLookupFn)
+ * for additional parameter descriptions.
+ */
bool LookupHost(const std::string& name, CNetAddr& addr, bool fAllowLookup, DNSLookupFn dns_lookup_function = g_dns_lookup);
-bool Lookup(const std::string& name, CService& addr, int portDefault, bool fAllowLookup, DNSLookupFn dns_lookup_function = g_dns_lookup);
-bool Lookup(const std::string& name, std::vector<CService>& vAddr, int portDefault, bool fAllowLookup, unsigned int nMaxSolutions, DNSLookupFn dns_lookup_function = g_dns_lookup);
-CService LookupNumeric(const std::string& name, int portDefault = 0, DNSLookupFn dns_lookup_function = g_dns_lookup);
+
+/**
+ * Resolve a service string to its corresponding service.
+ *
+ * @param name The string representing a service. Could be a name or a
+ * numerical IP address (IPv6 addresses should be in their
+ * disambiguated bracketed form), optionally followed by a uint16_t port
+ * number. (e.g. example.com:8333 or
+ * [2001:db8:85a3:8d3:1319:8a2e:370:7348]:420)
+ * @param[out] vAddr The resulting services to which the specified service string
+ * resolved.
+ * @param portDefault The default port for resulting services if not specified
+ * by the service string.
+ * @param fAllowLookup Whether or not hostname lookups are permitted. If yes,
+ * external queries may be performed.
+ * @param nMaxSolutions The maximum number of results we want, specifying 0
+ * means "as many solutions as we get."
+ *
+ * @returns Whether or not the service string successfully resolved to any
+ * resulting services.
+ */
+bool Lookup(const std::string& name, std::vector<CService>& vAddr, uint16_t portDefault, bool fAllowLookup, unsigned int nMaxSolutions, DNSLookupFn dns_lookup_function = g_dns_lookup);
+
+/**
+ * Resolve a service string to its first corresponding service.
+ *
+ * @see Lookup(const std::string&, std::vector<CService>&, uint16_t, bool, unsigned int, DNSLookupFn)
+ * for additional parameter descriptions.
+ */
+bool Lookup(const std::string& name, CService& addr, uint16_t portDefault, bool fAllowLookup, DNSLookupFn dns_lookup_function = g_dns_lookup);
+
+/**
+ * Resolve a service string with a numeric IP to its first corresponding
+ * service.
+ *
+ * @returns The resulting CService if the resolution was successful, [::]:0 otherwise.
+ *
+ * @see Lookup(const std::string&, std::vector<CService>&, uint16_t, bool, unsigned int, DNSLookupFn)
+ * for additional parameter descriptions.
+ */
+CService LookupNumeric(const std::string& name, uint16_t portDefault = 0, DNSLookupFn dns_lookup_function = g_dns_lookup);
+
+/**
+ * Parse and resolve a specified subnet string into the appropriate internal
+ * representation.
+ *
+ * @param strSubnet A string representation of a subnet of the form `network
+ * address [ "/", ( CIDR-style suffix | netmask ) ]`(e.g.
+ * `2001:db8::/32`, `192.0.2.0/255.255.255.0`, or `8.8.8.8`).
+ * @param ret The resulting internal representation of a subnet.
+ *
+ * @returns Whether the operation succeeded or not.
+ */
bool LookupSubNet(const std::string& strSubnet, CSubNet& subnet, DNSLookupFn dns_lookup_function = g_dns_lookup);
/**
@@ -102,14 +190,61 @@ std::unique_ptr<Sock> CreateSockTCP(const CService& address_family);
*/
extern std::function<std::unique_ptr<Sock>(const CService&)> CreateSock;
-bool ConnectSocketDirectly(const CService &addrConnect, const SOCKET& hSocketRet, int nTimeout, bool manual_connection);
-bool ConnectThroughProxy(const proxyType& proxy, const std::string& strDest, int port, const Sock& sock, int nTimeout, bool& outProxyConnectionFailed);
+/**
+ * Try to connect to the specified service on the specified socket.
+ *
+ * @param addrConnect The service to which to connect.
+ * @param hSocket The socket on which to connect.
+ * @param nTimeout Wait this many milliseconds for the connection to be
+ * established.
+ * @param manual_connection Whether or not the connection was manually requested
+ * (e.g. through the addnode RPC)
+ *
+ * @returns Whether or not a connection was successfully made.
+ */
+bool ConnectSocketDirectly(const CService &addrConnect, const SOCKET& hSocket, int nTimeout, bool manual_connection);
+
+/**
+ * Connect to a specified destination service through a SOCKS5 proxy by first
+ * connecting to the SOCKS5 proxy.
+ *
+ * @param proxy The SOCKS5 proxy.
+ * @param strDest The destination service to which to connect.
+ * @param port The destination port.
+ * @param sock The socket on which to connect to the SOCKS5 proxy.
+ * @param nTimeout Wait this many milliseconds for the connection to the SOCKS5
+ * proxy to be established.
+ * @param[out] outProxyConnectionFailed Whether or not the connection to the
+ * SOCKS5 proxy failed.
+ *
+ * @returns Whether or not the operation succeeded.
+ */
+bool ConnectThroughProxy(const proxyType& proxy, const std::string& strDest, uint16_t port, const Sock& sock, int nTimeout, bool& outProxyConnectionFailed);
+
/** Disable or enable blocking-mode for a socket */
bool SetSocketNonBlocking(const SOCKET& hSocket, bool fNonBlocking);
/** Set the TCP_NODELAY flag on a socket */
bool SetSocketNoDelay(const SOCKET& hSocket);
void InterruptSocks5(bool interrupt);
-bool Socks5(const std::string& strDest, int port, const ProxyCredentials* auth, const Sock& socket);
+/**
+ * Connect to a specified destination service through an already connected
+ * SOCKS5 proxy.
+ *
+ * @param strDest The destination fully-qualified domain name.
+ * @param port The destination port.
+ * @param auth The credentials with which to authenticate with the specified
+ * SOCKS5 proxy.
+ * @param sock The SOCKS5 proxy socket.
+ *
+ * @returns Whether or not the operation succeeded.
+ *
+ * @note The specified SOCKS5 proxy socket must already be connected to the
+ * SOCKS5 proxy.
+ *
+ * @see <a href="https://www.ietf.org/rfc/rfc1928.txt">RFC1928: SOCKS Protocol
+ * Version 5</a>
+ */
+bool Socks5(const std::string& strDest, uint16_t port, const ProxyCredentials* auth, const Sock& socket);
#endif // BITCOIN_NETBASE_H
diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp
index 9406ef07c5..50c8c29175 100644
--- a/src/node/interfaces.cpp
+++ b/src/node/interfaces.cpp
@@ -50,6 +50,7 @@
#endif
#include <memory>
+#include <optional>
#include <utility>
using interfaces::BlockTip;
@@ -415,7 +416,7 @@ class ChainImpl : public Chain
{
public:
explicit ChainImpl(NodeContext& node) : m_node(node) {}
- Optional<int> getHeight() override
+ std::optional<int> getHeight() override
{
LOCK(::cs_main);
const CChain& active = Assert(m_node.chainman)->ActiveChain();
@@ -423,7 +424,7 @@ public:
if (height >= 0) {
return height;
}
- return nullopt;
+ return std::nullopt;
}
uint256 getBlockHash(int height) override
{
@@ -452,7 +453,7 @@ public:
assert(std::addressof(::ChainActive()) == std::addressof(m_node.chainman->ActiveChain()));
return CheckFinalTx(m_node.chainman->ActiveChain().Tip(), tx);
}
- Optional<int> findLocatorFork(const CBlockLocator& locator) override
+ std::optional<int> findLocatorFork(const CBlockLocator& locator) override
{
LOCK(cs_main);
const CChain& active = Assert(m_node.chainman)->ActiveChain();
@@ -460,7 +461,7 @@ public:
if (CBlockIndex* fork = m_node.chainman->m_blockman.FindForkInGlobalIndex(active, locator)) {
return fork->nHeight;
}
- return nullopt;
+ return std::nullopt;
}
bool findBlock(const uint256& hash, const FoundBlock& block) override
{
@@ -518,7 +519,7 @@ public:
assert(std::addressof(g_chainman) == std::addressof(*m_node.chainman));
return GuessVerificationProgress(Params().TxData(), m_node.chainman->m_blockman.LookupBlockIndex(block_hash));
}
- bool hasBlocks(const uint256& block_hash, int min_height, Optional<int> max_height) override
+ bool hasBlocks(const uint256& block_hash, int min_height, std::optional<int> max_height) override
{
// hasBlocks returns true if all ancestors of block_hash in specified
// range have block data (are not pruned), false if any ancestors in
diff --git a/src/node/psbt.h b/src/node/psbt.h
index 7384dc415c..def4385c09 100644
--- a/src/node/psbt.h
+++ b/src/node/psbt.h
@@ -7,6 +7,8 @@
#include <psbt.h>
+#include <optional>
+
/**
* Holds an analysis of one input from a PSBT
*/
@@ -25,18 +27,18 @@ struct PSBTInputAnalysis {
* Holds the results of AnalyzePSBT (miscellaneous information about a PSBT)
*/
struct PSBTAnalysis {
- Optional<size_t> estimated_vsize; //!< Estimated weight of the transaction
- Optional<CFeeRate> estimated_feerate; //!< Estimated feerate (fee / weight) of the transaction
- Optional<CAmount> fee; //!< Amount of fee being paid by the transaction
- std::vector<PSBTInputAnalysis> inputs; //!< More information about the individual inputs of the transaction
- PSBTRole next; //!< Which of the BIP 174 roles needs to handle the transaction next
- std::string error; //!< Error message
+ std::optional<size_t> estimated_vsize; //!< Estimated weight of the transaction
+ std::optional<CFeeRate> estimated_feerate; //!< Estimated feerate (fee / weight) of the transaction
+ std::optional<CAmount> fee; //!< Amount of fee being paid by the transaction
+ std::vector<PSBTInputAnalysis> inputs; //!< More information about the individual inputs of the transaction
+ PSBTRole next; //!< Which of the BIP 174 roles needs to handle the transaction next
+ std::string error; //!< Error message
void SetInvalid(std::string err_msg)
{
- estimated_vsize = nullopt;
- estimated_feerate = nullopt;
- fee = nullopt;
+ estimated_vsize = std::nullopt;
+ estimated_feerate = std::nullopt;
+ fee = std::nullopt;
inputs.clear();
next = PSBTRole::CREATOR;
error = err_msg;
diff --git a/src/node/transaction.cpp b/src/node/transaction.cpp
index 97763f4fa2..f47e85aceb 100644
--- a/src/node/transaction.cpp
+++ b/src/node/transaction.cpp
@@ -29,9 +29,9 @@ static TransactionError HandleATMPError(const TxValidationState& state, std::str
TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef tx, std::string& err_string, const CAmount& max_tx_fee, bool relay, bool wait_callback)
{
// BroadcastTransaction can be called by either sendrawtransaction RPC or wallet RPCs.
- // node.connman is assigned both before chain clients and before RPC server is accepting calls,
- // and reset after chain clients and RPC sever are stopped. node.connman should never be null here.
- assert(node.connman);
+ // node.peerman is assigned both before chain clients and before RPC server is accepting calls,
+ // and reset after chain clients and RPC sever are stopped. node.peerman should never be null here.
+ assert(node.peerman);
assert(node.mempool);
std::promise<void> promise;
uint256 hashTx = tx->GetHash();
@@ -101,7 +101,7 @@ TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef t
node.mempool->AddUnbroadcastTx(hashTx);
LOCK(cs_main);
- RelayTransaction(hashTx, tx->GetWitnessHash(), *node.connman);
+ node.peerman->RelayTransaction(hashTx, tx->GetWitnessHash());
}
return TransactionError::OK;
diff --git a/src/optional.h b/src/optional.h
deleted file mode 100644
index 583c56eabd..0000000000
--- a/src/optional.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright (c) 2017-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.
-
-#ifndef BITCOIN_OPTIONAL_H
-#define BITCOIN_OPTIONAL_H
-
-#include <optional>
-#include <utility>
-
-//! Substitute for C++17 std::optional
-//! DEPRECATED use std::optional in new code.
-template <typename T>
-using Optional = std::optional<T>;
-
-//! Substitute for C++17 std::nullopt
-//! DEPRECATED use std::nullopt in new code.
-static auto& nullopt = std::nullopt;
-
-#endif // BITCOIN_OPTIONAL_H
diff --git a/src/psbt.h b/src/psbt.h
index b566726ee3..96ae39fdb8 100644
--- a/src/psbt.h
+++ b/src/psbt.h
@@ -7,13 +7,14 @@
#include <attributes.h>
#include <node/transaction.h>
-#include <optional.h>
#include <policy/feerate.h>
#include <primitives/transaction.h>
#include <pubkey.h>
#include <script/sign.h>
#include <script/signingprovider.h>
+#include <optional>
+
// Magic bytes
static constexpr uint8_t PSBT_MAGIC_BYTES[5] = {'p', 's', 'b', 't', 0xff};
@@ -389,7 +390,7 @@ struct PSBTOutput
/** A version of CTransaction with the PSBT format*/
struct PartiallySignedTransaction
{
- Optional<CMutableTransaction> tx;
+ std::optional<CMutableTransaction> tx;
std::vector<PSBTInput> inputs;
std::vector<PSBTOutput> outputs;
std::map<std::vector<unsigned char>, std::vector<unsigned char>> unknown;
diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp
index ab6168a541..9927e925ac 100644
--- a/src/qt/addressbookpage.cpp
+++ b/src/qt/addressbookpage.cpp
@@ -295,7 +295,7 @@ void AddressBookPage::on_exportButton_clicked()
// CSV is currently the only supported format
QString filename = GUIUtil::getSaveFileName(this,
tr("Export Address List"), QString(),
- tr("Comma separated file (*.csv)"), nullptr);
+ tr("Comma separated file", "Name of CSV file format") + QLatin1String(" (*.csv)"), nullptr);
if (filename.isNull())
return;
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index f25b415820..791a29f7a0 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -52,7 +52,6 @@
#include <QThread>
#include <QTimer>
#include <QTranslator>
-#include <QtGlobal>
#if defined(QT_STATICPLUGIN)
#include <QtPlugin>
@@ -467,13 +466,6 @@ int GuiMain(int argc, char* argv[])
QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
-#if (QT_VERSION <= QT_VERSION_CHECK(5, 9, 8)) && defined(Q_OS_MACOS)
- const auto os_name = QSysInfo::prettyProductName();
- if (os_name.startsWith("macOS 11") || os_name.startsWith("macOS 10.16")) {
- QApplication::setStyle("fusion");
- }
-#endif
-
BitcoinApplication app;
QFontDatabase::addApplicationFont(":/fonts/monospace");
diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h
index 1cc96035c6..ba35ff3b67 100644
--- a/src/qt/optionsdialog.h
+++ b/src/qt/optionsdialog.h
@@ -67,7 +67,7 @@ private Q_SLOTS:
void updateDefaultProxyNets();
Q_SIGNALS:
- void proxyIpChecks(QValidatedLineEdit *pUiProxyIp, int nProxyPort);
+ void proxyIpChecks(QValidatedLineEdit *pUiProxyIp, uint16_t nProxyPort);
private:
Ui::OptionsDialog *ui;
diff --git a/src/qt/psbtoperationsdialog.cpp b/src/qt/psbtoperationsdialog.cpp
index d1f8d56100..17746b395b 100644
--- a/src/qt/psbtoperationsdialog.cpp
+++ b/src/qt/psbtoperationsdialog.cpp
@@ -141,7 +141,7 @@ void PSBTOperationsDialog::saveTransaction() {
filename_suggestion.append(".psbt");
QString filename = GUIUtil::getSaveFileName(this,
tr("Save Transaction Data"), filename_suggestion,
- tr("Partially Signed Transaction (Binary) (*.psbt)"), &selected_filter);
+ tr("Partially Signed Transaction (Binary)", "Name of binary PSBT file format") + QLatin1String(" (*.psbt)"), &selected_filter);
if (filename.isEmpty()) {
return;
}
diff --git a/src/qt/qrimagewidget.cpp b/src/qt/qrimagewidget.cpp
index 490826cbbb..a71c8831e9 100644
--- a/src/qt/qrimagewidget.cpp
+++ b/src/qt/qrimagewidget.cpp
@@ -120,7 +120,9 @@ void QRImageWidget::saveImage()
{
if (!GUIUtil::HasPixmap(this))
return;
- QString fn = GUIUtil::getSaveFileName(this, tr("Save QR Code"), QString(), tr("PNG Image (*.png)"), nullptr);
+ QString fn = GUIUtil::getSaveFileName(
+ this, tr("Save QR Code"), QString(),
+ tr("PNG Image", "Name of PNG file format") + QLatin1String(" (*.png)"), nullptr);
if (!fn.isEmpty())
{
exportImage().save(fn);
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
index e401f46696..95e1ce2210 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -430,7 +430,7 @@ void SendCoinsDialog::on_sendButton_clicked()
fileNameSuggestion.append(".psbt");
QString filename = GUIUtil::getSaveFileName(this,
tr("Save Transaction Data"), fileNameSuggestion,
- tr("Partially Signed Transaction (Binary) (*.psbt)"), &selectedFilter);
+ tr("Partially Signed Transaction (Binary)", "Name of binary PSBT file format") + QLatin1String(" (*.psbt)"), &selectedFilter);
if (filename.isEmpty()) {
return;
}
diff --git a/src/qt/test/addressbooktests.cpp b/src/qt/test/addressbooktests.cpp
index 35fcb2b0ca..a026069232 100644
--- a/src/qt/test/addressbooktests.cpp
+++ b/src/qt/test/addressbooktests.cpp
@@ -112,7 +112,7 @@ void TestAddAddressesToSendBook(interfaces::Node& node)
ClientModel clientModel(node, &optionsModel);
AddWallet(wallet);
WalletModel walletModel(interfaces::MakeWallet(wallet), clientModel, platformStyle.get());
- RemoveWallet(wallet, nullopt);
+ RemoveWallet(wallet, std::nullopt);
EditAddressDialog editAddressDialog(EditAddressDialog::NewSendingAddress);
editAddressDialog.setModel(walletModel.getAddressTableModel());
diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp
index d6d2d0e3df..1107c44dc9 100644
--- a/src/qt/test/wallettests.cpp
+++ b/src/qt/test/wallettests.cpp
@@ -167,7 +167,7 @@ void TestGUI(interfaces::Node& node)
ClientModel clientModel(node, &optionsModel);
AddWallet(wallet);
WalletModel walletModel(interfaces::MakeWallet(wallet), clientModel, platformStyle.get());
- RemoveWallet(wallet, nullopt);
+ RemoveWallet(wallet, std::nullopt);
sendCoinsDialog.setModel(&walletModel);
transactionView.setModel(&walletModel);
diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp
index f99a3e286d..42e08c6af7 100644
--- a/src/qt/transactionview.cpp
+++ b/src/qt/transactionview.cpp
@@ -357,7 +357,7 @@ void TransactionView::exportClicked()
// CSV is currently the only supported format
QString filename = GUIUtil::getSaveFileName(this,
tr("Export Transaction History"), QString(),
- tr("Comma separated file (*.csv)"), nullptr);
+ tr("Comma separated file", "Name of CSV file format") + QLatin1String(" (*.csv)"), nullptr);
if (filename.isNull())
return;
diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp
index b1e6b43e60..8612893683 100644
--- a/src/qt/walletview.cpp
+++ b/src/qt/walletview.cpp
@@ -273,7 +273,7 @@ void WalletView::backupWallet()
{
QString filename = GUIUtil::getSaveFileName(this,
tr("Backup Wallet"), QString(),
- tr("Wallet Data (*.dat)"), nullptr);
+ tr("Wallet Data", "Name of wallet data file format") + QLatin1String(" (*.dat)"), nullptr);
if (filename.isEmpty())
return;
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index cf4d46cf2c..d4c1ab4b53 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -914,7 +914,7 @@ static RPCHelpMan addpeeraddress()
UniValue obj(UniValue::VOBJ);
std::string addr_string = request.params[0].get_str();
- uint16_t port = request.params[1].get_int();
+ uint16_t port{static_cast<uint16_t>(request.params[1].get_int())};
CNetAddr net_addr;
if (!LookupHost(addr_string, net_addr, false)) {
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index 47c776bbd1..2f92a321f8 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -1828,13 +1828,13 @@ static RPCHelpMan analyzepsbt()
}
if (!inputs_result.empty()) result.pushKV("inputs", inputs_result);
- if (psbta.estimated_vsize != nullopt) {
+ if (psbta.estimated_vsize != std::nullopt) {
result.pushKV("estimated_vsize", (int)*psbta.estimated_vsize);
}
- if (psbta.estimated_feerate != nullopt) {
+ if (psbta.estimated_feerate != std::nullopt) {
result.pushKV("estimated_feerate", ValueFromAmount(psbta.estimated_feerate->GetFeePerK()));
}
- if (psbta.fee != nullopt) {
+ if (psbta.fee != std::nullopt) {
result.pushKV("fee", ValueFromAmount(*psbta.fee));
}
result.pushKV("next", PSBTRoleName(psbta.next));
diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp
index 889cb4f06e..30399dca51 100644
--- a/src/script/descriptor.cpp
+++ b/src/script/descriptor.cpp
@@ -17,6 +17,7 @@
#include <util/vector.h>
#include <memory>
+#include <optional>
#include <string>
#include <vector>
@@ -632,7 +633,7 @@ public:
}
}
- Optional<OutputType> GetOutputType() const override { return nullopt; }
+ std::optional<OutputType> GetOutputType() const override { return std::nullopt; }
};
/** A parsed addr(A) descriptor. */
@@ -646,7 +647,7 @@ public:
AddressDescriptor(CTxDestination destination) : DescriptorImpl({}, {}, "addr"), m_destination(std::move(destination)) {}
bool IsSolvable() const final { return false; }
- Optional<OutputType> GetOutputType() const override
+ std::optional<OutputType> GetOutputType() const override
{
switch (m_destination.index()) {
case 1 /* PKHash */:
@@ -655,7 +656,7 @@ public:
case 4 /* WitnessV0KeyHash */:
case 5 /* WitnessUnknown */: return OutputType::BECH32;
case 0 /* CNoDestination */:
- default: return nullopt;
+ default: return std::nullopt;
}
}
bool IsSingleType() const final { return true; }
@@ -672,7 +673,7 @@ public:
RawDescriptor(CScript script) : DescriptorImpl({}, {}, "raw"), m_script(std::move(script)) {}
bool IsSolvable() const final { return false; }
- Optional<OutputType> GetOutputType() const override
+ std::optional<OutputType> GetOutputType() const override
{
CTxDestination dest;
ExtractDestination(m_script, dest);
@@ -683,7 +684,7 @@ public:
case 4 /* WitnessV0KeyHash */:
case 5 /* WitnessUnknown */: return OutputType::BECH32;
case 0 /* CNoDestination */:
- default: return nullopt;
+ default: return std::nullopt;
}
}
bool IsSingleType() const final { return true; }
@@ -711,7 +712,7 @@ protected:
}
public:
PKHDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), {}, "pkh") {}
- Optional<OutputType> GetOutputType() const override { return OutputType::LEGACY; }
+ std::optional<OutputType> GetOutputType() const override { return OutputType::LEGACY; }
bool IsSingleType() const final { return true; }
};
@@ -727,7 +728,7 @@ protected:
}
public:
WPKHDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), {}, "wpkh") {}
- Optional<OutputType> GetOutputType() const override { return OutputType::BECH32; }
+ std::optional<OutputType> GetOutputType() const override { return OutputType::BECH32; }
bool IsSingleType() const final { return true; }
};
@@ -783,7 +784,7 @@ protected:
public:
SHDescriptor(std::unique_ptr<DescriptorImpl> desc) : DescriptorImpl({}, std::move(desc), "sh") {}
- Optional<OutputType> GetOutputType() const override
+ std::optional<OutputType> GetOutputType() const override
{
assert(m_subdescriptor_arg);
if (m_subdescriptor_arg->GetOutputType() == OutputType::BECH32) return OutputType::P2SH_SEGWIT;
@@ -799,7 +800,7 @@ protected:
std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript* script, FlatSigningProvider&) const override { return Vector(GetScriptForDestination(WitnessV0ScriptHash(*script))); }
public:
WSHDescriptor(std::unique_ptr<DescriptorImpl> desc) : DescriptorImpl({}, std::move(desc), "wsh") {}
- Optional<OutputType> GetOutputType() const override { return OutputType::BECH32; }
+ std::optional<OutputType> GetOutputType() const override { return OutputType::BECH32; }
bool IsSingleType() const final { return true; }
};
diff --git a/src/script/descriptor.h b/src/script/descriptor.h
index 46d51fa587..332ae2f230 100644
--- a/src/script/descriptor.h
+++ b/src/script/descriptor.h
@@ -5,12 +5,12 @@
#ifndef BITCOIN_SCRIPT_DESCRIPTOR_H
#define BITCOIN_SCRIPT_DESCRIPTOR_H
-#include <optional.h>
#include <outputtype.h>
#include <script/script.h>
#include <script/sign.h>
#include <script/signingprovider.h>
+#include <optional>
#include <vector>
using ExtPubKeyMap = std::unordered_map<uint32_t, CExtPubKey>;
@@ -124,7 +124,7 @@ struct Descriptor {
virtual void ExpandPrivate(int pos, const SigningProvider& provider, FlatSigningProvider& out) const = 0;
/** @return The OutputType of the scriptPubKey(s) produced by this descriptor. Or nullopt if indeterminate (multiple or none) */
- virtual Optional<OutputType> GetOutputType() const = 0;
+ virtual std::optional<OutputType> GetOutputType() const = 0;
};
/** Parse a `descriptor` string. Included private keys are put in `out`.
diff --git a/src/signet.cpp b/src/signet.cpp
index e68f031aa4..fb41e43752 100644
--- a/src/signet.cpp
+++ b/src/signet.cpp
@@ -65,7 +65,7 @@ static uint256 ComputeModifiedMerkleRoot(const CMutableTransaction& cb, const CB
return ComputeMerkleRoot(std::move(leaves));
}
-Optional<SignetTxs> SignetTxs::Create(const CBlock& block, const CScript& challenge)
+std::optional<SignetTxs> SignetTxs::Create(const CBlock& block, const CScript& challenge)
{
CMutableTransaction tx_to_spend;
tx_to_spend.nVersion = 0;
@@ -83,12 +83,12 @@ Optional<SignetTxs> SignetTxs::Create(const CBlock& block, const CScript& challe
// responses from block coinbase tx
// find and delete signet signature
- if (block.vtx.empty()) return nullopt; // no coinbase tx in block; invalid
+ if (block.vtx.empty()) return std::nullopt; // no coinbase tx in block; invalid
CMutableTransaction modified_cb(*block.vtx.at(0));
const int cidx = GetWitnessCommitmentIndex(block);
if (cidx == NO_WITNESS_COMMITMENT) {
- return nullopt; // require a witness commitment
+ return std::nullopt; // require a witness commitment
}
CScript& witness_commitment = modified_cb.vout.at(cidx).scriptPubKey;
@@ -101,9 +101,9 @@ Optional<SignetTxs> SignetTxs::Create(const CBlock& block, const CScript& challe
VectorReader v(SER_NETWORK, INIT_PROTO_VERSION, signet_solution, 0);
v >> tx_spending.vin[0].scriptSig;
v >> tx_spending.vin[0].scriptWitness.stack;
- if (!v.empty()) return nullopt; // extraneous data encountered
+ if (!v.empty()) return std::nullopt; // extraneous data encountered
} catch (const std::exception&) {
- return nullopt; // parsing error
+ return std::nullopt; // parsing error
}
}
uint256 signet_merkle = ComputeModifiedMerkleRoot(modified_cb, block);
@@ -129,7 +129,7 @@ bool CheckSignetBlockSolution(const CBlock& block, const Consensus::Params& cons
}
const CScript challenge(consensusParams.signet_challenge.begin(), consensusParams.signet_challenge.end());
- const Optional<SignetTxs> signet_txs = SignetTxs::Create(block, challenge);
+ const std::optional<SignetTxs> signet_txs = SignetTxs::Create(block, challenge);
if (!signet_txs) {
LogPrint(BCLog::VALIDATION, "CheckSignetBlockSolution: Errors in block (block solution parse failure)\n");
diff --git a/src/signet.h b/src/signet.h
index 23563a83c4..f876488c0a 100644
--- a/src/signet.h
+++ b/src/signet.h
@@ -9,7 +9,7 @@
#include <primitives/block.h>
#include <primitives/transaction.h>
-#include <optional.h>
+#include <optional>
/**
* Extract signature and check whether a block has a valid solution
@@ -28,7 +28,7 @@ class SignetTxs {
SignetTxs(const T1& to_spend, const T2& to_sign) : m_to_spend{to_spend}, m_to_sign{to_sign} { }
public:
- static Optional<SignetTxs> Create(const CBlock& block, const CScript& challenge);
+ static std::optional<SignetTxs> Create(const CBlock& block, const CScript& challenge);
const CTransaction m_to_spend;
const CTransaction m_to_sign;
diff --git a/src/test/addrman_tests.cpp b/src/test/addrman_tests.cpp
index 37ff8a9afe..d438537606 100644
--- a/src/test/addrman_tests.cpp
+++ b/src/test/addrman_tests.cpp
@@ -100,7 +100,7 @@ static CNetAddr ResolveIP(const std::string& ip)
return addr;
}
-static CService ResolveService(const std::string& ip, const int port = 0)
+static CService ResolveService(const std::string& ip, uint16_t port = 0)
{
CService serv;
BOOST_CHECK_MESSAGE(Lookup(ip, serv, port, false), strprintf("failed to resolve: %s:%i", ip, port));
diff --git a/src/test/bech32_tests.cpp b/src/test/bech32_tests.cpp
index a2098f4f56..2651e46430 100644
--- a/src/test/bech32_tests.cpp
+++ b/src/test/bech32_tests.cpp
@@ -10,7 +10,7 @@
BOOST_FIXTURE_TEST_SUITE(bech32_tests, BasicTestingSetup)
-BOOST_AUTO_TEST_CASE(bip173_testvectors_valid)
+BOOST_AUTO_TEST_CASE(bech32_testvectors_valid)
{
static const std::string CASES[] = {
"A12UEL5L",
@@ -22,15 +22,35 @@ BOOST_AUTO_TEST_CASE(bip173_testvectors_valid)
"?1ezyfcl",
};
for (const std::string& str : CASES) {
- auto ret = bech32::Decode(str);
- BOOST_CHECK(!ret.first.empty());
- std::string recode = bech32::Encode(ret.first, ret.second);
+ const auto dec = bech32::Decode(str);
+ BOOST_CHECK(dec.encoding == bech32::Encoding::BECH32);
+ std::string recode = bech32::Encode(bech32::Encoding::BECH32, dec.hrp, dec.data);
BOOST_CHECK(!recode.empty());
BOOST_CHECK(CaseInsensitiveEqual(str, recode));
}
}
-BOOST_AUTO_TEST_CASE(bip173_testvectors_invalid)
+BOOST_AUTO_TEST_CASE(bech32m_testvectors_valid)
+{
+ static const std::string CASES[] = {
+ "A1LQFN3A",
+ "a1lqfn3a",
+ "an83characterlonghumanreadablepartthatcontainsthetheexcludedcharactersbioandnumber11sg7hg6",
+ "abcdef1l7aum6echk45nj3s0wdvt2fg8x9yrzpqzd3ryx",
+ "11llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllludsr8",
+ "split1checkupstagehandshakeupstreamerranterredcaperredlc445v",
+ "?1v759aa"
+ };
+ for (const std::string& str : CASES) {
+ const auto dec = bech32::Decode(str);
+ BOOST_CHECK(dec.encoding == bech32::Encoding::BECH32M);
+ std::string recode = bech32::Encode(bech32::Encoding::BECH32M, dec.hrp, dec.data);
+ BOOST_CHECK(!recode.empty());
+ BOOST_CHECK(CaseInsensitiveEqual(str, recode));
+ }
+}
+
+BOOST_AUTO_TEST_CASE(bech32_testvectors_invalid)
{
static const std::string CASES[] = {
" 1nwldj5",
@@ -49,8 +69,32 @@ BOOST_AUTO_TEST_CASE(bip173_testvectors_invalid)
"A12uEL5L",
};
for (const std::string& str : CASES) {
- auto ret = bech32::Decode(str);
- BOOST_CHECK(ret.first.empty());
+ const auto dec = bech32::Decode(str);
+ BOOST_CHECK(dec.encoding == bech32::Encoding::INVALID);
+ }
+}
+
+BOOST_AUTO_TEST_CASE(bech32m_testvectors_invalid)
+{
+ static const std::string CASES[] = {
+ " 1xj0phk",
+ "\x7f""1g6xzxy",
+ "\x80""1vctc34",
+ "an84characterslonghumanreadablepartthatcontainsthetheexcludedcharactersbioandnumber11d6pts4",
+ "qyrz8wqd2c9m",
+ "1qyrz8wqd2c9m",
+ "y1b0jsk6g",
+ "lt1igcx5c0",
+ "in1muywd",
+ "mm1crxm3i",
+ "au1s5cgom",
+ "M1VUXWEZ",
+ "16plkw9",
+ "1p2gdwpf"
+ };
+ for (const std::string& str : CASES) {
+ const auto dec = bech32::Decode(str);
+ BOOST_CHECK(dec.encoding == bech32::Encoding::INVALID);
}
}
diff --git a/src/test/data/key_io_invalid.json b/src/test/data/key_io_invalid.json
index 9b52943ac6..abe07dad24 100644
--- a/src/test/data/key_io_invalid.json
+++ b/src/test/data/key_io_invalid.json
@@ -6,177 +6,207 @@
"x"
],
[
- "37qgekLpCCHrQuSjvX3fs496FWTGsHFHizjJAs6NPcR47aefnnCWECAhHV6E3g4YN7u7Yuwod5Y"
+ "2v7k5Bb8Lr1MMgTgW6HAf5YHXi6BzpPjHpQ4srD4RSwHYpzXKiXmLAgiLhkXvp3JF5v7nq45EWr"
],
[
- "dzb7VV1Ui55BARxv7ATxAtCUeJsANKovDGWFVgpTbhq9gvPqP3yv"
+ "RAZzCGtMbiUgMiiyrZySrSpdfnQReFXA3r"
],
[
- "MuNu7ZAEDFiHthiunm7dPjwKqrVNCM3mAz6rP9zFveQu14YA8CxExSJTHcVP9DErn6u84E6Ej7S"
+ "NYamy7tcPQTzoU5iyQojD3sqhiz7zxkvn8"
],
[
- "rPpQpYknyNQ5AEHuY6H8ijJJrYc2nDKKk9jjmKEXsWzyAQcFGpDLU2Zvsmoi8JLR7hAwoy3RQWf"
+ "geaFG555Ex5nyRf7JjW6Pj2GwZA8KYxtJJLbr1eZhVW75STbYBZeRszy3wg4pkKdF4ez9J4wQiz"
],
[
- "4Uc3FmN6NQ6zLBK5QQBXRBUREaaHwCZYsGCueHauuDmJpZKn6jkEskMB2Zi2CNgtb5r6epWEFfUJq"
+ "2Cxmid3c2XQ2zvQ8SA1ha2TKqvqbJS9XFmXRsCneBS3Po7Qqb65z5zNdsoF9AfieXFcpoVPmkmfa"
],
[
- "7aQgR5DFQ25vyXmqZAWmnVCjL3PkBcdVkBUpjrjMTcghHx3E8wb"
+ "gaJ7UVge2njVg9tFTetJrtHgruMm7aQDiSAxfHrVEgzK8N2ooagDVmDkdph434xzc4K96Gjyxcs"
],
[
- "17QpPprjeg69fW1DV8DcYYCKvWjYhXvWkov6MJ1iTTvMFj6weAqW7wybZeH57WTNxXVCRH4veVs"
+ "5JN5BEVQPZ3tAiatz1RGXkrJuE3EC6bervMaPb38wTNgEuZCeqp"
],
[
- "KxuACDviz8Xvpn1xAh9MfopySZNuyajYMZWz16Dv2mHHryznWUp3"
+ "3TnFbyUtBRS5rE1KTW81qLVspjJNaB3uu6uuvLjxhZo2DB6PCGh"
],
[
- "7nK3GSmqdXJQtdohvGfJ7KsSmn3TmGqExug49583bDAL91pVSGq5xS9SHoAYL3Wv3ijKTit65th"
+ "7UgSZGaMaTc4d2mdEgcGBFiMeS6eMsithGUqvBsKTQdGzD7XQDbMEYo3gojdbXEPbUdFF3CQoK72f"
],
[
- "cTivdBmq7bay3RFGEBBuNfMh2P1pDCgRYN2Wbxmgwr4ki3jNUL2va"
+ "9261wfqQqruNDnBDhbbb4tN9oKA1KpRFHeoYeufyJApVGixyAG4V"
],
[
- "gjMV4vjNjyMrna4fsAr8bWxAbwtmMUBXJS3zL4NJt5qjozpbQLmAfK1uA3CquSqsZQMpoD1g2nk"
+ "cS824CTUh18scFmYuqt6BgxuRhdR4dEEnCHs3fzBbcyQgbfasHbw"
],
[
- "emXm1naBMoVzPjbk7xpeTVMFy4oDEe25UmoyGgKEB1gGWsK8kRGs"
+ "tc1q0ywf7wkz6t580n3yemd3ucfw8jxn93tpc6wskt"
],
[
- "7VThQnNRj1o3Zyvc7XHPRrjDf8j2oivPTeDXnRPYWeYGE4pXeRJDZgf28ppti5hsHWXS2GSobdqyo"
+ "bt1pxeeuh96wpm5c6u3kavts2qgwlv6y8um7u7ga6ltlwrhrv7w9vers8lgt3k"
],
[
- "1G9u6oCVCPh2o8m3t55ACiYvG1y5BHewUkDSdiQarDcYXXhFHYdzMdYfUAhfxn5vNZBwpgUNpso"
+ "tb130lvl2lyugsk2tf3zhwcjjv39dmwt2tt7ytqaexy8edwcuwks6p5scll5kz"
],
[
- "31QQ7ZMLkScDiB4VyZjuptr7AEc9j1SjstF7pRoLhHTGkW4Q2y9XELobQmhhWxeRvqcukGd1XCq"
+ "bcrt1rhsveeudk"
],
[
- "DHqKSnpxa8ZdQyH8keAhvLTrfkyBMQxqngcQA5N8LQ9KVt25kmGN"
+ "bc10rmfwl8nxdweeyc4sf89t0tn9fv9w6qpyzsnl2r4k48vjqh03qas9asdje0rlr0phru0wqw0p"
],
[
- "2LUHcJPbwLCy9GLH1qXmfmAwvadWw4bp4PCpDfduLqV17s6iDcy1imUwhQJhAoNoN1XNmweiJP4i"
+ "tb1qjqnfsuatr54e957xzg9sqk7yqcry9lns"
],
[
- "7USRzBXAnmck8fX9HmW7RAb4qt92VFX6soCnts9s74wxm4gguVhtG5of8fZGbNPJA83irHVY6bCos"
+ "bcrt1q8p08mv8echkf3es027u4cdswxlylm3th76ls8v6y4zy4vwsavngpr4e4td"
],
[
- "1DGezo7BfVebZxAbNT3XGujdeHyNNBF3vnficYoTSp4PfK2QaML9bHzAMxke3wdKdHYWmsMTJVu"
+ "BC1QNC2H66VLWTWTW52DP0FYUSNU3QQG5VT4V"
],
[
- "2D12DqDZKwCxxkzs1ZATJWvgJGhQ4cFi3WrizQ5zLAyhN5HxuAJ1yMYaJp8GuYsTLLxTAz6otCfb"
+ "tb1qgk665m2auw09rc7pqyf7aulcuhmatz9xqtr5mxew7zuysacaascqs9v0vn"
],
[
- "8AFJzuTujXjw1Z6M3fWhQ1ujDW7zsV4ePeVjVo7D1egERqSW9nZ"
+ "bcrt17CAPP7"
],
[
- "163Q17qLbTCue8YY3AvjpUhotuaodLm2uqMhpYirsKjVqnxJRWTEoywMVY3NbBAHuhAJ2cF9GAZ"
+ "bc1qxmf2d6aerjzam3rur0zufqxqnyqfts5u302s7x"
],
[
- "2MnmgiRH4eGLyLc9eAqStzk7dFgBjFtUCtu"
+ "tb1qn8x5dnzpexq7nnvrvnhwr9c3wkakpcyu9wwsjzq9pstkwg0t6qhs4l3rv6"
],
[
- "461QQ2sYWxU7H2PV4oBwJGNch8XVTYYbZxU"
+ "BCRT1Q397G2RNVYRL5LK07CE8NCKHVKP8Z4SC9U0MVH9"
],
[
- "2UCtv53VttmQYkVU4VMtXB31REvQg4ABzs41AEKZ8UcB7DAfVzdkV9JDErwGwyj5AUHLkmgZeobs"
+ "bc1pgxwyajq0gdn389f69uwn2fw9q0z5c9s063j5dgkdd23ajaud4hpsercr9h"
],
[
- "cSNjAsnhgtiFMi6MtfvgscMB2Cbhn2v1FUYfviJ1CdjfidvmeW6mn"
+ "tb1z6mnmp5k542l6yk4ul0mp4rq3yvz44lfm"
],
[
- "gmsow2Y6EWAFDFE1CE4Hd3Tpu2BvfmBfG1SXsuRARbnt1WjkZnFh1qGTiptWWbjsq2Q6qvpgJVj"
+ "bcrt17capp7"
],
[
- "nksUKSkzS76v8EsSgozXGMoQFiCoCHzCVajFKAXqzK5on9ZJYVHMD5CKwgmX3S3c7M1U3xabUny"
+ "2D2bqvKseKHdoKjCNvjVULUgmxHu9hjKGwDbPRjTRH59tsHNLeyKwq3vyVBbo9LByY9wiapqjwFY"
],
[
- "L3favK1UzFGgdzYBF2oBT5tbayCo4vtVBLJhg2iYuMeePxWG8SQc"
+ "2SSjAim4wZpeQRe5zTj1qqS6Li9ttJDaZ3ze"
],
[
- "7VxLxGGtYT6N99GdEfi6xz56xdQ8nP2dG1CavuXx7Rf2PrvNMTBNevjkfgs9JmkcGm6EXpj8ipyPZ"
+ "mi9H6MjLwXxy9kxe1x4ToxyLRBsmcZxgVi"
],
[
- "2mbZwFXF6cxShaCo2czTRB62WTx9LxhTtpP"
+ "VciXoxEitcn88jy197J9n9cpJ1pZahzU3SyWUiHqLgcfjttLEEJz"
],
[
- "dB7cwYdcPSgiyAwKWL3JwCVwSk6epU2txw"
+ "KppmwADGoExPT9Eq5hjRWpWFDbzJyfzHFgsfxBiDHNpVBgWPRNuy"
],
[
- "HPhFUhUAh8ZQQisH8QQWafAxtQYju3SFTX"
+ "TN7EQXMxKffzvHo54yHHu9R4ks9f5gWBW3MMVf5k72zAqrgVK9ys"
],
[
- "4ctAH6AkHzq5ioiM1m9T3E2hiYEev5mTsB"
+ "92dbrMEYzP5dD5UhQ6maNkCQ4GLG42BM4Gc6XKZzSSMSfosfkkcB"
],
[
- "Hn1uFi4dNexWrqARpjMqgT6cX1UsNPuV3cHdGg9ExyXw8HTKadbktRDtdeVmY3M1BxJStiL4vjJ"
+ "J7VQxPxyzuWEkRstQWpCz2AgysEz1APgnWCEQrFvkN3umAnCrhQF"
],
[
- "Sq3fDbvutABmnAHHExJDgPLQn44KnNC7UsXuT7KZecpaYDMU9Txs"
+ "tc1qymllj6c96v5qj2504y27ldtner6eh8ldx38t83"
],
[
- "6TqWyrqdgUEYDQU1aChMuFMMEimHX44qHFzCUgGfqxGgZNMUVWJ"
+ "bt1flep4g"
],
[
- "giqJo7oWqFxNKWyrgcBxAVHXnjJ1t6cGoEffce5Y1y7u649Noj5wJ4mmiUAKEVVrYAGg2KPB3Y4"
+ "tb13c553hwygcgj48qwmr9f8q0hgdcfklyaye5sxzcpcjnmxv4z506xs90tchn"
],
[
- "cNzHY5e8vcmM3QVJUcjCyiKMYfeYvyueq5qCMV3kqcySoLyGLYUK"
+ "bcrt1tyddyu"
],
[
- "37uTe568EYc9WLoHEd9jXEvUiWbq5LFLscNyqvAzLU5vBArUJA6eydkLmnMwJDjkL5kXc2VK7ig"
+ "bc10qssq2mknjqf0glwe2f3587wc4jysvs3f8s6chysae6hcl6fxzdm4wxyyscrl5k9f5qmnf05a"
],
[
- "EsYbG4tWWWY45G31nox838qNdzksbPySWc"
+ "tb1q425lmgvxdgtyl2m6xuu2pc354y4fvgg8"
],
[
- "nbuzhfwMoNzA3PaFnyLcRxE9bTJPDkjZ6Rf6Y6o2ckXZfzZzXBT"
+ "bcrt1q9wp8e5d2u3u4g0pll0cy7smeeuqezdun9xl439n3p2gg4fvgfvk3hu52hj"
],
[
- "cQN9PoxZeCWK1x56xnz6QYAsvR11XAce3Ehp3gMUdfSQ53Y2mPzx"
+ "bc1qrz5acazpue8vl4zsaxn8fxtmeuqmyjkq3"
],
[
- "1Gm3N3rkef6iMbx4voBzaxtXcmmiMTqZPhcuAepRzYUJQW4qRpEnHvMojzof42hjFRf8PE2jPde"
+ "tb1qkeuglpgmnex9tv3fr7htzfrh3rwrk23r52rx9halxzmv9fr85lwq0fwhmp"
],
[
- "2TAq2tuN6x6m233bpT7yqdYQPELdTDJn1eU"
+ "bcrt1qd0t2wrhl7s57z99rsyaekpq0dyjcQRSSmz80r4"
],
[
- "ntEtnnGhqPii4joABvBtSEJG6BxjT2tUZqE8PcVYgk3RHpgxgHDCQxNbLJf7ardf1dDk2oCQ7Cf"
+ "BC1QXLFDUCGX90T3E53PQCNKJ2PK25MSF3VLPMVY6T"
],
[
- "Ky1YjoZNgQ196HJV3HpdkecfhRBmRZdMJk89Hi5KGfpfPwS2bUbfd"
+ "tb1qmycg4zszgnk34vaurx3cu8wpvteg9h40yq6cp52gt26gjel03t3su3x3xu"
],
[
- "2A1q1YsMZowabbvta7kTy2Fd6qN4r5ZCeG3qLpvZBMzCixMUdkN2Y4dHB1wPsZAeVXUGD83MfRED"
+ "bcrt1q9hy58r4fnuxqzdqndpmq9pptc9nt2dw3rczf5e"
],
[
- "tc1qw508d6qejxtdg4y5r3zarvary0c5xw7kg3g4ty"
+ "BC1PA7682NAY6JQSLUWAJYTC0ERWTMW7A4RPWLNTUS32LCXWLHVKKKTQ2UL8CG"
],
[
- "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t5"
+ "tb1z850dpxnwz2fzae5h2myatj4yvu6rq5xq"
],
[
- "BC13W508D6QEJXTDG4Y5R3ZARVARY0C5XW7KN40WF2"
+ "bcrt1sp525pzjsmpqvcrawjreww36e9keg876skjvpwt"
],
[
- "bc1rw5uspcuh"
+ "xcAvW5jurCpzSpLxBKEhCewCgwwuGhqJnC"
],
[
- "bc10w508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kw5rljs90"
+ "2Cvv8yp9kXbQt8EKh6Yma95yJ1uwYF9YKXuVhGJyu3dHGVsb2AVpTC62TFACZZ3KDNrALxR2CVNs"
],
[
- "BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P"
+ "niUuL46hCuEVvkAzZKHvD746qbmLmzip9Pv3F6UZV14JxzEXBnTkVxCT4URapChJG6qAEgsZs6G"
],
[
- "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sL5k7"
+ "2UHHgGfiipzvB8Eumnmvq6SowvrMJimjT3NwwG1839XEiUfwtpSdkUrseNsQuagXv21ce7aZu6yo"
],
[
- "bc1zw508d6qejxtdg4y5r3zarvaryvqyzf3du"
+ "8u9djKu4u6o3bsgeR4BKNnLK3akpo64FYzDAmA9239wKeshgF97"
],
[
- "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3pjxtptv"
+ "TC1QPAARXSLVMXHVRR0474LZXQYZWLGFZYPSFVL9E4"
],
[
- "bc1gmk9yu"
+ "bt1pakek0n2267t9yaksxaczgr2syhv9y3xkx0wnsdwchfa6xkmjtvuqg3kgyr"
+ ],
+ [
+ "tb13h83rtwq62udrhwpn87uely7cyxcjrj0azz6a4r3n9s87x5uj98ys6ufp83"
+ ],
+ [
+ "bcrt1rk5vw5qf2"
+ ],
+ [
+ "bc10d3rmtg62h747en5j6fju5g5qyvsransrkty6ghh96pu647wumctejlsngh9pf26cysrys2x2"
+ ],
+ [
+ "tb1qajuy2cdwqgmrzc7la85al5cwcq374tsp"
+ ],
+ [
+ "bcrt1q3udxvj6x20chqh723mn064mzz65yr56ef00xk8czvu3jnx04ydapzk02s5"
+ ],
+ [
+ "bc1qule2szwzyaq4qy0s3aa4mauucyqt6fewe"
+ ],
+ [
+ "tb1ql0qny5vg9gh5tyzke6dw36px5ulkrp24x53x0pl2t5lpwrtejw3s2seej2"
+ ],
+ [
+ "bcrt17CAPP7"
+ ],
+ [
+ "bc1qtvm6davyf725wfedc2d5mrgfewqgcrce8gjrpl"
+ ],
+ [
+ "tb1q5acjgtqrrw3an0dzavxxxzlex8k7aukjzjk9v2u4rmfdqxjphcyq7ge97e"
]
]
diff --git a/src/test/data/key_io_valid.json b/src/test/data/key_io_valid.json
index 8418a6002d..5dee44c04b 100644
--- a/src/test/data/key_io_valid.json
+++ b/src/test/data/key_io_valid.json
@@ -1,533 +1,610 @@
[
[
- "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i",
- "76a91465a16059864a2fdbc7c99a4723a8395bc6f188eb88ac",
+ "1BShJZ8A5q53oJJfMJoEF1gfZCWdZqZwwD",
+ "76a914728d4cc27d19707b0197cfcd7c412d43287864b588ac",
{
- "isPrivkey": false,
- "chain": "main"
+ "chain": "main",
+ "isPrivkey": false
}
],
[
- "3CMNFxN1oHBc4R1EpboAL5yzHGgE611Xou",
- "a91474f209f6ea907e2ea48f74fae05782ae8a66525787",
+ "3L1YkZjdeNSqaZcNKZFXQfyokx3zVYm7r6",
+ "a914c8f37c3cc21561296ad81f4bec6b5de10ebc185187",
{
- "isPrivkey": false,
- "chain": "main"
+ "chain": "main",
+ "isPrivkey": false
}
],
[
- "mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs",
- "76a91453c0307d6851aa0ce7825ba883c6bd9ad242b48688ac",
+ "mhJuoGLgnJC8gdBgBzEigsoyG4omQXejPT",
+ "76a91413a92d1998e081354d36c13ce0c9dc04b865d40a88ac",
{
- "isPrivkey": false,
- "chain": "test"
+ "chain": "test",
+ "isPrivkey": false
}
],
[
- "mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs",
- "76a91453c0307d6851aa0ce7825ba883c6bd9ad242b48688ac",
+ "2N5VpzKEuYvZJbmg6eUNGnfrrD1ir92FWGu",
+ "a91486648cc2faaf05660e72c04c7a837bcc3e986f1787",
{
- "isPrivkey": false,
- "chain": "regtest"
+ "chain": "test",
+ "isPrivkey": false
}
],
[
- "2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br",
- "a9146349a418fc4578d10a372b54b45c280cc8c4382f87",
+ "mtQueCtmAnP3E4aBHXCiFNEQAuPaLMuQNy",
+ "76a9148d74ecd86c845baf9c6d4484d2d00e731b79e34788ac",
{
- "isPrivkey": false,
- "chain": "test"
+ "chain": "signet",
+ "isPrivkey": false
+ }
+ ],
+ [
+ "2NEvWRTHjh89gV52fkperFtwzoFWQiQmiCh",
+ "a914edc895152c67ccff0ba620bcc373b789ec68266f87",
+ {
+ "chain": "signet",
+ "isPrivkey": false
}
],
[
- "5Kd3NBUAdUnhyzenEwVLy9pBKxSwXvE9FMPyR4UKZvpe6E3AgLr",
- "eddbdc1168f1daeadbd3e44c1e3f8f5a284c2029f78ad26af98583a499de5b19",
+ "mngdx94qJFhSf7A7SAEgQSC9fQJuapujJp",
+ "76a9144e9dba545455a80ce94c343d1cac9dec62cbf22288ac",
{
+ "chain": "regtest",
+ "isPrivkey": false
+ }
+ ],
+ [
+ "2NBzRN3pV56k3JUvSHifaHyzjGHv7ZS9FZZ",
+ "a914cd9da5642451273e5b6d088854cc1fad4a8d442187",
+ {
+ "chain": "regtest",
+ "isPrivkey": false
+ }
+ ],
+ [
+ "5KcrFZvJ2p4dM6QVUPu53cKXcCfozA1PJLHm1mNAxkDYhgThLu4",
+ "ed6c796e2f62377410766214f55aa81ac9a6590ad7ed57c509c983bf648409ac",
+ {
+ "chain": "main",
"isCompressed": false,
- "isPrivkey": true,
- "chain": "main"
+ "isPrivkey": true
}
],
[
- "Kz6UJmQACJmLtaQj5A3JAge4kVTNQ8gbvXuwbmCj7bsaabudb3RD",
- "55c9bccb9ed68446d1b75273bbce89d7fe013a8acd1625514420fb2aca1a21c4",
+ "L195WBrf2G3nCnun4CLxrb8XKk9LbCqH43THh4n4QrL5SzRzpq9j",
+ "74f76c106e38d20514a99a86e4fe3bb28319e7dd2ad21dbc170cbb516a5358fa",
{
+ "chain": "main",
"isCompressed": true,
- "isPrivkey": true,
- "chain": "main"
+ "isPrivkey": true
}
],
[
- "9213qJab2HNEpMpYNBa7wHGFKKbkDn24jpANDs2huN3yi4J11ko",
- "36cb93b9ab1bdabf7fb9f2c04f1b9cc879933530ae7842398eef5a63a56800c2",
+ "92z6HnMQR4tWqjfVA3UaUN5EuUMgoVMdCa5rZFYZfmgyD7wxYCw",
+ "b8511e1d74549e305517d48a1d394d1be2cfa5d0f3c0d83f9f450316ffa01276",
{
+ "chain": "test",
"isCompressed": false,
- "isPrivkey": true,
- "chain": "test"
+ "isPrivkey": true
}
],
[
- "9213qJab2HNEpMpYNBa7wHGFKKbkDn24jpANDs2huN3yi4J11ko",
- "36cb93b9ab1bdabf7fb9f2c04f1b9cc879933530ae7842398eef5a63a56800c2",
+ "cTPnaF52x4w4Tq6afPxRHux3wbYb86thS7S45A7r3oZc1AHTQ6Qm",
+ "ad68c48d337181da125de9061933ececcdf7d917631af7d34f7e38082bff9a11",
{
+ "chain": "test",
+ "isCompressed": true,
+ "isPrivkey": true
+ }
+ ],
+ [
+ "924U35yFcYkxe2JXGmuhSRVaShGyhRDZx1ysPmw1sAHuszGMoxq",
+ "3e8dfaf78d4f02b11d0b645648a4f3080d71d0d068979c47f7255c9a29eee01d",
+ {
+ "chain": "signet",
"isCompressed": false,
- "isPrivkey": true,
- "chain": "regtest"
+ "isPrivkey": true
}
],
[
- "cTpB4YiyKiBcPxnefsDpbnDxFDffjqJob8wGCEDXxgQ7zQoMXJdH",
- "b9f4892c9e8282028fea1d2667c4dc5213564d41fc5783896a0d843fc15089f3",
+ "cRy1qCf2LUesGPQagTkYwk2V3PyN2KCPKgxeg6k6KoJPzH7nrVjw",
+ "82d4187690d6b59bcffda27dae52f2ecb87313cfc0904e0b674a27d906a65fde",
{
+ "chain": "signet",
"isCompressed": true,
- "isPrivkey": true,
- "chain": "test"
+ "isPrivkey": true
}
],
[
- "cTpB4YiyKiBcPxnefsDpbnDxFDffjqJob8wGCEDXxgQ7zQoMXJdH",
- "b9f4892c9e8282028fea1d2667c4dc5213564d41fc5783896a0d843fc15089f3",
+ "932NTcHK35Apf2C3K9Zv1ZdeZEmB1x7ZT2Ju3SjoEY6pUgUpT7H",
+ "bd7dba24df9e003e145ae9b4862776413a0bb6fa5b4e42753397f2d9536e58a9",
{
- "isCompressed": true,
- "isPrivkey": true,
- "chain": "regtest"
+ "chain": "regtest",
+ "isCompressed": false,
+ "isPrivkey": true
}
],
[
- "1Ax4gZtb7gAit2TivwejZHYtNNLT18PUXJ",
- "76a9146d23156cbbdcc82a5a47eee4c2c7c583c18b6bf488ac",
+ "cNa75orYQ2oos52zCnMaS5PG6XbNZKc5LpGxTHacrxwWeX4WAK3E",
+ "1d87e3c58b08766fea03598380ec8d59f8c88d5392bf683ab1088bd4caf073ee",
{
- "isPrivkey": false,
- "chain": "main"
+ "chain": "regtest",
+ "isCompressed": true,
+ "isPrivkey": true
}
],
[
- "3QjYXhTkvuj8qPaXHTTWb5wjXhdsLAAWVy",
- "a914fcc5460dd6e2487c7d75b1963625da0e8f4c597587",
+ "bc1q5cuatynjmk4szh40mmunszfzh7zrc5xm9w8ccy",
+ "0014a639d59272ddab015eafdef9380922bf843c50db",
{
+ "chain": "main",
"isPrivkey": false,
- "chain": "main"
+ "tryCaseFlip": true
}
],
[
- "n3ZddxzLvAY9o7184TB4c6FJasAybsw4HZ",
- "76a914f1d470f9b02370fdec2e6b708b08ac431bf7a5f788ac",
+ "bc1qkw7lz3ahms6e0ajv27mzh7g62tchjpmve4afc29u7w49tddydy2syv0087",
+ "0020b3bdf147b7dc3597f64c57b62bf91a52f179076ccd7a9c28bcf3aa55b5a46915",
{
+ "chain": "main",
"isPrivkey": false,
- "chain": "test"
+ "tryCaseFlip": true
}
],
[
- "2NBFNJTktNa7GZusGbDbGKRZTxdK9VVez3n",
- "a914c579342c2c4c9220205e2cdc285617040c924a0a87",
+ "bc1p5rgvqejqh9dh37t9g94dd9cm8vtqns7dndgj423egwggsggcdzmsspvr7j",
+ "5120a0d0c06640b95b78f965416ad6971b3b1609c3cd9b512aaa39439088211868b7",
{
+ "chain": "main",
"isPrivkey": false,
- "chain": "test"
+ "tryCaseFlip": true
}
],
[
- "5K494XZwps2bGyeL71pWid4noiSNA2cfCibrvRWqcHSptoFn7rc",
- "a326b95ebae30164217d7a7f57d72ab2b54e3be64928a19da0210b9568d4015e",
+ "bc1zr4pq63udck",
+ "52021d42",
{
- "isCompressed": false,
- "isPrivkey": true,
- "chain": "main"
+ "chain": "main",
+ "isPrivkey": false,
+ "tryCaseFlip": true
}
],
[
- "L1RrrnXkcKut5DEMwtDthjwRcTTwED36thyL1DebVrKuwvohjMNi",
- "7d998b45c219a1e38e99e7cbd312ef67f77a455a9b50c730c27f02c6f730dfb4",
+ "tb1q74fxwnvhsue0l8wremgq66xzvn48jlc5zthsvz",
+ "0014f552674d978732ff9dc3ced00d68c264ea797f14",
{
- "isCompressed": true,
- "isPrivkey": true,
- "chain": "main"
+ "chain": "test",
+ "isPrivkey": false,
+ "tryCaseFlip": true
}
],
[
- "93DVKyFYwSN6wEo3E2fCrFPUp17FtrtNi2Lf7n4G3garFb16CRj",
- "d6bca256b5abc5602ec2e1c121a08b0da2556587430bcf7e1898af2224885203",
+ "tb1qpt7cqgq8ukv92dcraun9c3n0s3aswrt62vtv8nqmkfpa2tjfghesv9ln74",
+ "00200afd802007e598553703ef265c466f847b070d7a5316c3cc1bb243d52e4945f3",
{
- "isCompressed": false,
- "isPrivkey": true,
- "chain": "test"
+ "chain": "test",
+ "isPrivkey": false,
+ "tryCaseFlip": true
}
],
[
- "cTDVKtMGVYWTHCb1AFjmVbEbWjvKpKqKgMaR3QJxToMSQAhmCeTN",
- "a81ca4e8f90181ec4b61b6a7eb998af17b2cb04de8a03b504b9e34c4c61db7d9",
+ "tb1ph9v3e8nxct57hknlkhkz75p5pnxnkn05cw8ewpxu6tek56g29xgqydzfu7",
+ "5120b9591c9e66c2e9ebda7fb5ec2f50340ccd3b4df4c38f9704dcd2f36a690a2990",
{
- "isCompressed": true,
- "isPrivkey": true,
- "chain": "test"
+ "chain": "test",
+ "isPrivkey": false,
+ "tryCaseFlip": true
}
],
[
- "1C5bSj1iEGUgSTbziymG7Cn18ENQuT36vv",
- "76a9147987ccaa53d02c8873487ef919677cd3db7a691288ac",
+ "tb1ray6e8gxfx49ers6c4c70l3c8lsxtcmlx",
+ "5310e93593a0c9354b91c358ae3cffc707fc",
{
+ "chain": "test",
"isPrivkey": false,
- "chain": "main"
+ "tryCaseFlip": true
}
],
[
- "3AnNxabYGoTxYiTEZwFEnerUoeFXK2Zoks",
- "a91463bcc565f9e68ee0189dd5cc67f1b0e5f02f45cb87",
+ "tb1q0sqzfp3zj42u0perxr6jahhu4y03uw4dypk6sc",
+ "00147c002486229555c7872330f52edefca91f1e3aad",
{
+ "chain": "signet",
"isPrivkey": false,
- "chain": "main"
+ "tryCaseFlip": true
}
],
[
- "n3LnJXCqbPjghuVs8ph9CYsAe4Sh4j97wk",
- "76a914ef66444b5b17f14e8fae6e7e19b045a78c54fd7988ac",
+ "tb1q9jv4qnawnuevqaeadn47gkq05ev78m4qg3zqejykdr9u0cm7yutq6gu5dj",
+ "00202c99504fae9f32c0773d6cebe4580fa659e3eea044440cc89668cbc7e37e2716",
{
+ "chain": "signet",
"isPrivkey": false,
- "chain": "test"
+ "tryCaseFlip": true
}
],
[
- "2NB72XtkjpnATMggui83aEtPawyyKvnbX2o",
- "a914c3e55fceceaa4391ed2a9677f4a4d34eacd021a087",
+ "tb1pxqf7d825wjtcftj7uep8w24jq3tz8vudfaqj20rns8ahqya56gcs92eqtu",
+ "51203013e69d54749784ae5ee642772ab2045623b38d4f41253c7381fb7013b4d231",
{
+ "chain": "signet",
"isPrivkey": false,
- "chain": "test"
+ "tryCaseFlip": true
}
],
[
- "5KaBW9vNtWNhc3ZEDyNCiXLPdVPHCikRxSBWwV9NrpLLa4LsXi9",
- "e75d936d56377f432f404aabb406601f892fd49da90eb6ac558a733c93b47252",
+ "tb1rsrzkyvu2rt0dcgexajtazlw5nft4j7494ay396q6auw9375wxsrsgag884",
+ "532080c562338a1adedc2326ec97d17dd49a57597aa5af4912e81aef1c58fa8e3407",
{
- "isCompressed": false,
- "isPrivkey": true,
- "chain": "main"
+ "chain": "signet",
+ "isPrivkey": false,
+ "tryCaseFlip": true
}
],
[
- "L1axzbSyynNYA8mCAhzxkipKkfHtAXYF4YQnhSKcLV8YXA874fgT",
- "8248bd0375f2f75d7e274ae544fb920f51784480866b102384190b1addfbaa5c",
+ "bcrt1qwf52dt9y2sv0f7fwkcpmtfjf74d4np2saeljt6",
+ "00147268a6aca45418f4f92eb603b5a649f55b598550",
{
- "isCompressed": true,
- "isPrivkey": true,
- "chain": "main"
+ "chain": "regtest",
+ "isPrivkey": false,
+ "tryCaseFlip": true
}
],
[
- "927CnUkUbasYtDwYwVn2j8GdTuACNnKkjZ1rpZd2yBB1CLcnXpo",
- "44c4f6a096eac5238291a94cc24c01e3b19b8d8cef72874a079e00a242237a52",
+ "bcrt1q0lma84unycxl4n96etffthqlf7y5axyp4fxf64kmhymvw8l6pwfs39futd",
+ "00207ff7d3d793260dfaccbacad295dc1f4f894e9881aa4c9d56dbb936c71ffa0b93",
{
- "isCompressed": false,
- "isPrivkey": true,
- "chain": "test"
+ "chain": "regtest",
+ "isPrivkey": false,
+ "tryCaseFlip": true
}
],
[
- "cUcfCMRjiQf85YMzzQEk9d1s5A4K7xL5SmBCLrezqXFuTVefyhY7",
- "d1de707020a9059d6d3abaf85e17967c6555151143db13dbb06db78df0f15c69",
+ "bcrt1p3xat2ryucc2v0adrktqnavfzttvezrr27ngltsa2726p2ehvxz4se722v2",
+ "512089bab50c9cc614c7f5a3b2c13eb1225ad9910c6af4d1f5c3aaf2b41566ec30ab",
{
- "isCompressed": true,
- "isPrivkey": true,
- "chain": "test"
+ "chain": "regtest",
+ "isPrivkey": false,
+ "tryCaseFlip": true
}
],
[
- "1Gqk4Tv79P91Cc1STQtU3s1W6277M2CVWu",
- "76a914adc1cc2081a27206fae25792f28bbc55b831549d88ac",
+ "bcrt1saflydw6e26xhp29euhy5jke5jjqyywk3wvtc9ulgw9dvxyuqy9hdnxthyw755c7ldavy7u",
+ "6028ea7e46bb59568d70a8b9e5c9495b349480423ad1731782f3e8715ac31380216ed9997723bd4a63df",
{
+ "chain": "regtest",
"isPrivkey": false,
- "chain": "main"
+ "tryCaseFlip": true
}
],
[
- "33vt8ViH5jsr115AGkW6cEmEz9MpvJSwDk",
- "a914188f91a931947eddd7432d6e614387e32b24470987",
+ "16y3Q1XVRZqMR9T1XL1FkvNtD2E1bXBuYa",
+ "76a9144171ec673aeb9fcf42af6094a3c82207e3b9a78188ac",
{
- "isPrivkey": false,
- "chain": "main"
+ "chain": "main",
+ "isPrivkey": false
}
],
[
- "mhaMcBxNh5cqXm4aTQ6EcVbKtfL6LGyK2H",
- "76a9141694f5bc1a7295b600f40018a618a6ea48eeb49888ac",
+ "3CmZZnAiHVQgiAKSakf864oJMxN2BP1eLC",
+ "a914798575fc1041b9440c4e63c28e57e597d00b7e4387",
{
- "isPrivkey": false,
- "chain": "test"
+ "chain": "main",
+ "isPrivkey": false
}
],
[
- "2MxgPqX1iThW3oZVk9KoFcE5M4JpiETssVN",
- "a9143b9b3fd7a50d4f08d1a5b0f62f644fa7115ae2f387",
+ "mtCB3SoBo7EYUv8j54kUubGY4x3aJPY8nk",
+ "76a9148b0c5f9ee714e0d1d24642ad63d9d5f398d9b56588ac",
{
- "isPrivkey": false,
- "chain": "test"
+ "chain": "test",
+ "isPrivkey": false
}
],
[
- "5HtH6GdcwCJA4ggWEL1B3jzBBUB8HPiBi9SBc5h9i4Wk4PSeApR",
- "091035445ef105fa1bb125eccfb1882f3fe69592265956ade751fd095033d8d0",
+ "2N5ymzzKpx6EdUR4UdMZ7t9hcuwqtpHwgw5",
+ "a9148badb3c3b5c0d39f906f7618e0018b7eae4baf7387",
{
- "isCompressed": false,
- "isPrivkey": true,
- "chain": "main"
+ "chain": "test",
+ "isPrivkey": false
}
],
[
- "L2xSYmMeVo3Zek3ZTsv9xUrXVAmrWxJ8Ua4cw8pkfbQhcEFhkXT8",
- "ab2b4bcdfc91d34dee0ae2a8c6b6668dadaeb3a88b9859743156f462325187af",
+ "myXnpYbub28zgiJupDdZSWZtDbjcyfJVby",
+ "76a914c59ac57661b57daadd7c0caf7318c14f54c6c0fa88ac",
{
- "isCompressed": true,
- "isPrivkey": true,
- "chain": "main"
+ "chain": "signet",
+ "isPrivkey": false
}
],
[
- "92xFEve1Z9N8Z641KQQS7ByCSb8kGjsDzw6fAmjHN1LZGKQXyMq",
- "b4204389cef18bbe2b353623cbf93e8678fbc92a475b664ae98ed594e6cf0856",
+ "2MtLg8jS5jSXm9evMzTtvpLjy26dBmjFEoT",
+ "a9140c0007e89cea625d3bf9543baa5a470bb7e5b67287",
{
- "isCompressed": false,
- "isPrivkey": true,
- "chain": "test"
+ "chain": "signet",
+ "isPrivkey": false
}
],
[
- "92xFEve1Z9N8Z641KQQS7ByCSb8kGjsDzw6fAmjHN1LZGKQXyMq",
- "b4204389cef18bbe2b353623cbf93e8678fbc92a475b664ae98ed594e6cf0856",
+ "mzCyqdf2UNGdpgkD9NBgLcxdwXRg1i9buY",
+ "76a914cd04311bdd1ef9c5c24e41930e032aade82a863a88ac",
{
- "isCompressed": false,
- "isPrivkey": true,
- "chain": "regtest"
+ "chain": "regtest",
+ "isPrivkey": false
}
],
[
- "cVM65tdYu1YK37tNoAyGoJTR13VBYFva1vg9FLuPAsJijGvG6NEA",
- "e7b230133f1b5489843260236b06edca25f66adb1be455fbd38d4010d48faeef",
+ "2N3zGiwFku2vQjYnAqXv5Qu2ztfYRhh7tbF",
+ "a91475d56d75c88e704d6c72fbe84ac1505abf736b4087",
{
- "isCompressed": true,
- "isPrivkey": true,
- "chain": "test"
+ "chain": "regtest",
+ "isPrivkey": false
}
],
[
- "1JwMWBVLtiqtscbaRHai4pqHokhFCbtoB4",
- "76a914c4c1b72491ede1eedaca00618407ee0b772cad0d88ac",
+ "5JUHCgyxNSHg64wwju72eNsG6ajqo4Z2fHHw9iLDLfh69rSiL7w",
+ "5644d06d88855dacf3192a31df8f4acd8e4c155c52a86d2c1fa48303f5cff053",
{
- "isPrivkey": false,
- "chain": "main"
+ "chain": "main",
+ "isCompressed": false,
+ "isPrivkey": true
}
],
[
- "3QCzvfL4ZRvmJFiWWBVwxfdaNBT8EtxB5y",
- "a914f6fe69bcb548a829cce4c57bf6fff8af3a5981f987",
+ "L2kZaexG69VSriMe9T2m1jkS86iPe3xNbjcdfakRC1PHe7ay78Ji",
+ "a50ee94aefcabf5a5d7c85be5b3844dee03c5604861dbfc77fe388c91e5a30f8",
{
- "isPrivkey": false,
- "chain": "main"
+ "chain": "main",
+ "isCompressed": true,
+ "isPrivkey": true
}
],
[
- "mizXiucXRCsEriQCHUkCqef9ph9qtPbZZ6",
- "76a914261f83568a098a8638844bd7aeca039d5f2352c088ac",
+ "927JwT1ViCr5TD2ZX8CsMNhg17dXmou5xu4y2KiH54zD7i34UJq",
+ "4502a54c0026b0150281d41f40860d1e23870c63cdc32645bbed688f2ee41f64",
{
- "isPrivkey": false,
- "chain": "test"
+ "chain": "test",
+ "isCompressed": false,
+ "isPrivkey": true
}
],
[
- "2NEWDzHWwY5ZZp8CQWbB7ouNMLqCia6YRda",
- "a914e930e1834a4d234702773951d627cce82fbb5d2e87",
+ "cTpGGNPVy2Eagawohbr4aGtRJzpLnjxGsGYh9DUcBM45f3KdKGF6",
+ "ba005a0cb39587aab00bd54c848b59e8adaed47403228567ddc739c2a344ff59",
{
- "isPrivkey": false,
- "chain": "test"
+ "chain": "test",
+ "isCompressed": true,
+ "isPrivkey": true
}
],
[
- "5KQmDryMNDcisTzRp3zEq9e4awRmJrEVU1j5vFRTKpRNYPqYrMg",
- "d1fab7ab7385ad26872237f1eb9789aa25cc986bacc695e07ac571d6cdac8bc0",
+ "932PLCLA19yPNqV67qwHBSGjxi82LVzWBF7josL9ab4Q1kxgPGF",
+ "bd8677e076eb39770bf7e9f9e8d3f2cf257effab9b4c220fd3439ccfc208c984",
{
+ "chain": "signet",
"isCompressed": false,
- "isPrivkey": true,
- "chain": "main"
+ "isPrivkey": true
}
],
[
- "L39Fy7AC2Hhj95gh3Yb2AU5YHh1mQSAHgpNixvm27poizcJyLtUi",
- "b0bbede33ef254e8376aceb1510253fc3550efd0fcf84dcd0c9998b288f166b3",
+ "cViUpEy8URSsLjUvxwL7cEuNgCVqM7oKBzd1ZPbA4khcQsQJuj1j",
+ "f2b36ade8393e29dc71e52cb75ba1109ba210203cd7d0a5ae881ad6846516203",
{
+ "chain": "signet",
"isCompressed": true,
- "isPrivkey": true,
- "chain": "main"
+ "isPrivkey": true
}
],
[
- "91cTVUcgydqyZLgaANpf1fvL55FH53QMm4BsnCADVNYuWuqdVys",
- "037f4192c630f399d9271e26c575269b1d15be553ea1a7217f0cb8513cef41cb",
+ "92jddDjJCVDmJtgvBHQ9i58PMash8kwsYhRdNo22ea2MYPXdCBE",
+ "977bf8686f1bcad28f86c4c14afbd33215746bd19203647bf7ff9c6fddc9cc87",
{
+ "chain": "regtest",
"isCompressed": false,
- "isPrivkey": true,
- "chain": "test"
+ "isPrivkey": true
}
],
[
- "cQspfSzsgLeiJGB2u8vrAiWpCU4MxUT6JseWo2SjXy4Qbzn2fwDw",
- "6251e205e8ad508bab5596bee086ef16cd4b239e0cc0c5d7c4e6035441e7d5de",
+ "cVwAuMoUqRo399X7vXzuzQyPEvZJMXM8c82zHzRkFCxPCSGx8A6y",
+ "f93acbbce02b8cb9ddca3fad495441e324cc01eb640b0a7b4c9f0e31644c822a",
{
+ "chain": "regtest",
"isCompressed": true,
- "isPrivkey": true,
- "chain": "test"
+ "isPrivkey": true
}
],
[
- "19dcawoKcZdQz365WpXWMhX6QCUpR9SY4r",
- "76a9145eadaf9bb7121f0f192561a5a62f5e5f5421029288ac",
+ "bc1qz377zwe5awr68dnggengqx9vrjt05k98q3sw2n",
+ "0014147de13b34eb87a3b66846668018ac1c96fa58a7",
{
+ "chain": "main",
"isPrivkey": false,
- "chain": "main"
+ "tryCaseFlip": true
}
],
[
- "37Sp6Rv3y4kVd1nQ1JV5pfqXccHNyZm1x3",
- "a9143f210e7277c899c3a155cc1c90f4106cbddeec6e87",
+ "bc1qkmhskpdzg8kdkfywhu09kswwn9qan9vnkrf6mk40jvnr06s6sz5ssf82ya",
+ "0020b6ef0b05a241ecdb248ebf1e5b41ce9941d99593b0d3addaaf932637ea1a80a9",
{
+ "chain": "main",
"isPrivkey": false,
- "chain": "main"
+ "tryCaseFlip": true
}
],
[
- "myoqcgYiehufrsnnkqdqbp69dddVDMopJu",
- "76a914c8a3c2a09a298592c3e180f02487cd91ba3400b588ac",
+ "bc1ps8cndas60cntk8x79sg9f5e5jz7x050z8agyugln2ukkks23rryqpejzkc",
+ "512081f136f61a7e26bb1cde2c1054d33490bc67d1e23f504e23f3572d6b415118c8",
{
+ "chain": "main",
"isPrivkey": false,
- "chain": "test"
+ "tryCaseFlip": true
}
],
[
- "2N7FuwuUuoTBrDFdrAZ9KxBmtqMLxce9i1C",
- "a91499b31df7c9068d1481b596578ddbb4d3bd90baeb87",
+ "bc1zn4tsczge9l",
+ "52029d57",
{
+ "chain": "main",
"isPrivkey": false,
- "chain": "test"
+ "tryCaseFlip": true
}
],
[
- "5KL6zEaMtPRXZKo1bbMq7JDjjo1bJuQcsgL33je3oY8uSJCR5b4",
- "c7666842503db6dc6ea061f092cfb9c388448629a6fe868d068c42a488b478ae",
+ "tb1q6xw0wwd9n9d7ge87dryz4vm5vtahzhvz6yett3",
+ "0014d19cf739a5995be464fe68c82ab37462fb715d82",
{
- "isCompressed": false,
- "isPrivkey": true,
- "chain": "main"
+ "chain": "test",
+ "isPrivkey": false,
+ "tryCaseFlip": true
}
],
[
- "KwV9KAfwbwt51veZWNscRTeZs9CKpojyu1MsPnaKTF5kz69H1UN2",
- "07f0803fc5399e773555ab1e8939907e9badacc17ca129e67a2f5f2ff84351dd",
+ "tb1qwn9zq9fu5uk35ykpgsc7rz4uawy4yh0r5m5er26768h5ur50su3qj6evun",
+ "002074ca20153ca72d1a12c14431e18abceb89525de3a6e991ab5ed1ef4e0e8f8722",
{
- "isCompressed": true,
- "isPrivkey": true,
- "chain": "main"
+ "chain": "test",
+ "isPrivkey": false,
+ "tryCaseFlip": true
}
],
[
- "93N87D6uxSBzwXvpokpzg8FFmfQPmvX4xHoWQe3pLdYpbiwT5YV",
- "ea577acfb5d1d14d3b7b195c321566f12f87d2b77ea3a53f68df7ebf8604a801",
+ "tb1pmcdc5d8gr92rtemfsnhpeqanvs0nr82upn5dktxluz9n0qcv34lqxke0wq",
+ "5120de1b8a34e8195435e76984ee1c83b3641f319d5c0ce8db2cdfe08b37830c8d7e",
{
- "isCompressed": false,
- "isPrivkey": true,
- "chain": "test"
+ "chain": "test",
+ "isPrivkey": false,
+ "tryCaseFlip": true
}
],
[
- "cMxXusSihaX58wpJ3tNuuUcZEQGt6DKJ1wEpxys88FFaQCYjku9h",
- "0b3b34f0958d8a268193a9814da92c3e8b58b4a4378a542863e34ac289cd830c",
+ "tb1rgxjvtfzp0xczz6dlzqv8d5cmuykk4qkk",
+ "531041a4c5a44179b02169bf101876d31be1",
{
- "isCompressed": true,
- "isPrivkey": true,
- "chain": "test"
+ "chain": "test",
+ "isPrivkey": false,
+ "tryCaseFlip": true
}
],
[
- "13p1ijLwsnrcuyqcTvJXkq2ASdXqcnEBLE",
- "76a9141ed467017f043e91ed4c44b4e8dd674db211c4e688ac",
+ "tb1qa9dlyt6fydestul4y4wh72yshh044w32np8etk",
+ "0014e95bf22f49237305f3f5255d7f2890bddf5aba2a",
{
+ "chain": "signet",
"isPrivkey": false,
- "chain": "main"
+ "tryCaseFlip": true
}
],
[
- "3ALJH9Y951VCGcVZYAdpA3KchoP9McEj1G",
- "a9145ece0cadddc415b1980f001785947120acdb36fc87",
+ "tb1qu4p26n0033720xm0rjgkds5ehdwf039k2fgv75um5krrvfhrrj7qckl9r2",
+ "0020e542ad4def8c7ca79b6f1c9166c299bb5c97c4b65250cf539ba5863626e31cbc",
{
+ "chain": "signet",
"isPrivkey": false,
- "chain": "main"
+ "tryCaseFlip": true
}
],
[
- "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4",
- "0014751e76e8199196d454941c45d1b3a323f1433bd6",
+ "tb1pjyukm4n4flwd0ey3lrl06c9kalr60ggmlkcxq2rhhxmy4lvkmkpqexdzqy",
+ "512091396dd6754fdcd7e491f8fefd60b6efc7a7a11bfdb0602877b9b64afd96dd82",
{
+ "chain": "signet",
"isPrivkey": false,
- "chain": "main",
"tryCaseFlip": true
}
],
[
- "bcrt1qw508d6qejxtdg4y5r3zarvary0c5xw7kygt080",
- "0014751e76e8199196d454941c45d1b3a323f1433bd6",
+ "tb1r4k75s5syvewsvxufdc3xfhf4tw4u30alw39xny3dnxrl6hau7systymfdv",
+ "5320adbd485204665d061b896e2264dd355babc8bfbf744a69922d9987fd5fbcf409",
{
+ "chain": "signet",
"isPrivkey": false,
- "chain": "regtest",
"tryCaseFlip": true
}
],
[
- "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7",
- "00201863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329604903262",
+ "bcrt1qnk3tdwwj47ppc4pqmxkjdusegedn9ru5gvccwa",
+ "00149da2b6b9d2af821c5420d9ad26f219465b328f94",
{
+ "chain": "regtest",
"isPrivkey": false,
- "chain": "test",
"tryCaseFlip": true
}
],
[
- "bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7k7grplx",
- "5128751e76e8199196d454941c45d1b3a323f1433bd6751e76e8199196d454941c45d1b3a323f1433bd6",
+ "bcrt1qz7prfshfkwsxuk72pt6mzr6uumq4qllxe4vmwqt89tat48d362yqlykk6a",
+ "0020178234c2e9b3a06e5bca0af5b10f5ce6c1507fe6cd59b701672afaba9db1d288",
{
+ "chain": "regtest",
"isPrivkey": false,
- "chain": "main",
"tryCaseFlip": true
}
],
[
- "bc1sw50qa3jx3s",
- "6002751e",
+ "bcrt1pumee3wj80xvyr7wjmj7zsk26x5pn095aegy862yhx6f2j9sgc9hq6cj4cm",
+ "5120e6f398ba47799841f9d2dcbc28595a350337969dca087d28973692a91608c16e",
{
+ "chain": "regtest",
"isPrivkey": false,
- "chain": "main",
"tryCaseFlip": true
}
],
[
- "bc1zw508d6qejxtdg4y5r3zarvaryvg6kdaj",
- "5210751e76e8199196d454941c45d1b3a323",
+ "bcrt1szqz8hj64d2hhc6nt65v09jxal66pgff2xpcp9kj648qkk8kjzxelsts4dktd799g47uase",
+ "602810047bcb556aaf7c6a6bd518f2c8ddfeb414252a307012da5aa9c16b1ed211b3f82e156d96df14a8",
{
+ "chain": "regtest",
"isPrivkey": false,
- "chain": "main",
"tryCaseFlip": true
}
],
[
- "tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy",
- "0020000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433",
+ "12agZTajtRE3STSchwWNWnrm467zzTQ916",
+ "76a9141156e00f70061e5faba8b71593a8c7554b47090c88ac",
+ {
+ "chain": "main",
+ "isPrivkey": false
+ }
+ ],
+ [
+ "3NXqB6iZiPYbKruNT3d9xNBTmtb73xMvvf",
+ "a914e49decc9e5d97e0547d3642f3a4795b13ae62bca87",
+ {
+ "chain": "main",
+ "isPrivkey": false
+ }
+ ],
+ [
+ "mjgt4BoCYxjzWvJFoh68x7cj5GeaKDYhyx",
+ "76a9142dc11fc7b8072f733f690ffb0591c00f4062295c88ac",
{
- "isPrivkey": false,
"chain": "test",
- "tryCaseFlip": true
+ "isPrivkey": false
}
],
[
- "bcrt1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvseswlauz7",
- "0020000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433",
+ "2NCT6FdQ5MxorHgnFxLeHyGwTGRdkHcrJDH",
+ "a914d2a8ec992b0894a0d9391ca5d9c45c388c41be7e87",
{
- "isPrivkey": false,
- "chain": "regtest",
- "tryCaseFlip": true
+ "chain": "test",
+ "isPrivkey": false
+ }
+ ],
+ [
+ "mpomiA7wqDnMcxaNLC23eBuXAb4U6H4ZqW",
+ "76a91465e75e340415ed297c58d6a14d3c17ceeaa17bbd88ac",
+ {
+ "chain": "signet",
+ "isPrivkey": false
+ }
+ ],
+ [
+ "2N1pGAA5uatbU2PKvMA9BnJmHcK6yHfMiZa",
+ "a9145e008b6cc232164570befc23d216060bf4ea793b87",
+ {
+ "chain": "signet",
+ "isPrivkey": false
}
]
]
diff --git a/src/test/descriptor_tests.cpp b/src/test/descriptor_tests.cpp
index acbd6a01ee..aecf955fee 100644
--- a/src/test/descriptor_tests.cpp
+++ b/src/test/descriptor_tests.cpp
@@ -10,6 +10,7 @@
#include <boost/test/unit_test.hpp>
+#include <optional>
#include <string>
#include <vector>
@@ -65,7 +66,7 @@ std::string UseHInsteadOfApostrophe(const std::string& desc)
const std::set<std::vector<uint32_t>> ONLY_EMPTY{{}};
-void DoCheck(const std::string& prv, const std::string& pub, const std::string& norm_prv, const std::string& norm_pub, int flags, const std::vector<std::vector<std::string>>& scripts, const Optional<OutputType>& type, const std::set<std::vector<uint32_t>>& paths = ONLY_EMPTY,
+void DoCheck(const std::string& prv, const std::string& pub, const std::string& norm_prv, const std::string& norm_pub, int flags, const std::vector<std::vector<std::string>>& scripts, const std::optional<OutputType>& type, const std::set<std::vector<uint32_t>>& paths = ONLY_EMPTY,
bool replace_apostrophe_with_h_in_prv=false, bool replace_apostrophe_with_h_in_pub=false)
{
FlatSigningProvider keys_priv, keys_pub;
@@ -262,7 +263,7 @@ void DoCheck(const std::string& prv, const std::string& pub, const std::string&
BOOST_CHECK_MESSAGE(left_paths.empty(), "Not all expected key paths found: " + prv);
}
-void Check(const std::string& prv, const std::string& pub, const std::string& norm_prv, const std::string& norm_pub, int flags, const std::vector<std::vector<std::string>>& scripts, const Optional<OutputType>& type, const std::set<std::vector<uint32_t>>& paths = ONLY_EMPTY)
+void Check(const std::string& prv, const std::string& pub, const std::string& norm_prv, const std::string& norm_pub, int flags, const std::vector<std::vector<std::string>>& scripts, const std::optional<OutputType>& type, const std::set<std::vector<uint32_t>>& paths = ONLY_EMPTY)
{
bool found_apostrophes_in_prv = false;
bool found_apostrophes_in_pub = false;
@@ -295,8 +296,8 @@ BOOST_FIXTURE_TEST_SUITE(descriptor_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(descriptor_test)
{
// Basic single-key compressed
- Check("combo(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "combo(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "combo(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "combo(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", SIGNABLE, {{"2103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bdac","76a9149a1c78a507689f6f54b847ad1cef1e614ee23f1e88ac","00149a1c78a507689f6f54b847ad1cef1e614ee23f1e","a91484ab21b1b2fd065d4504ff693d832434b6108d7b87"}}, nullopt);
- Check("pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", SIGNABLE, {{"2103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bdac"}}, nullopt);
+ Check("combo(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "combo(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "combo(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "combo(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", SIGNABLE, {{"2103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bdac","76a9149a1c78a507689f6f54b847ad1cef1e614ee23f1e88ac","00149a1c78a507689f6f54b847ad1cef1e614ee23f1e","a91484ab21b1b2fd065d4504ff693d832434b6108d7b87"}}, std::nullopt);
+ Check("pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", SIGNABLE, {{"2103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bdac"}}, std::nullopt);
Check("pkh([deadbeef/1/2'/3/4']L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "pkh([deadbeef/1/2'/3/4']03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "pkh([deadbeef/1/2'/3/4']L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "pkh([deadbeef/1/2'/3/4']03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", SIGNABLE, {{"76a9149a1c78a507689f6f54b847ad1cef1e614ee23f1e88ac"}}, OutputType::LEGACY, {{1,0x80000002UL,3,0x80000004UL}});
Check("wpkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "wpkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "wpkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "wpkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", SIGNABLE, {{"00149a1c78a507689f6f54b847ad1cef1e614ee23f1e"}}, OutputType::BECH32);
Check("sh(wpkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))", "sh(wpkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", "sh(wpkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))", "sh(wpkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", SIGNABLE, {{"a91484ab21b1b2fd065d4504ff693d832434b6108d7b87"}}, OutputType::P2SH_SEGWIT);
@@ -305,8 +306,8 @@ BOOST_AUTO_TEST_CASE(descriptor_test)
CheckUnparsable("pkh([deadbeef]/1/2'/3/4']L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "pkh([deadbeef]/1/2'/3/4']03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "Multiple ']' characters found for a single pubkey"); // Multiple end brackets in key origin
// Basic single-key uncompressed
- Check("combo(5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "combo(04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", "combo(5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "combo(04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)",SIGNABLE, {{"4104a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235ac","76a914b5bd079c4d57cc7fc28ecf8213a6b791625b818388ac"}}, nullopt);
- Check("pk(5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "pk(04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", "pk(5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "pk(04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", SIGNABLE, {{"4104a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235ac"}}, nullopt);
+ Check("combo(5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "combo(04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", "combo(5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "combo(04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)",SIGNABLE, {{"4104a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235ac","76a914b5bd079c4d57cc7fc28ecf8213a6b791625b818388ac"}}, std::nullopt);
+ Check("pk(5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "pk(04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", "pk(5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "pk(04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", SIGNABLE, {{"4104a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235ac"}}, std::nullopt);
Check("pkh(5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "pkh(04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", "pkh(5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "pkh(04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", SIGNABLE, {{"76a914b5bd079c4d57cc7fc28ecf8213a6b791625b818388ac"}}, OutputType::LEGACY);
CheckUnparsable("wpkh(5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "wpkh(04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", "Uncompressed keys are not allowed"); // No uncompressed keys in witness
CheckUnparsable("wsh(pk(5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss))", "wsh(pk(04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235))", "Uncompressed keys are not allowed"); // No uncompressed keys in witness
@@ -321,23 +322,23 @@ BOOST_AUTO_TEST_CASE(descriptor_test)
Check("sh(wsh(pkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)))", "sh(wsh(pkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)))", "sh(wsh(pkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)))", "sh(wsh(pkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)))", SIGNABLE, {{"a914b61b92e2ca21bac1e72a3ab859a742982bea960a87"}}, OutputType::P2SH_SEGWIT);
// Versions with BIP32 derivations
- Check("combo([01234567]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc)", "combo([01234567]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL)", "combo([01234567]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc)", "combo([01234567]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL)", SIGNABLE, {{"2102d2b36900396c9282fa14628566582f206a5dd0bcc8d5e892611806cafb0301f0ac","76a91431a507b815593dfc51ffc7245ae7e5aee304246e88ac","001431a507b815593dfc51ffc7245ae7e5aee304246e","a9142aafb926eb247cb18240a7f4c07983ad1f37922687"}}, nullopt);
- Check("pk(xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0)", "pk(xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0)", "pk(xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0)", "pk(xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0)", DEFAULT, {{"210379e45b3cf75f9c5f9befd8e9506fb962f6a9d185ac87001ec44a8d3df8d4a9e3ac"}}, nullopt, {{0}});
+ Check("combo([01234567]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc)", "combo([01234567]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL)", "combo([01234567]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc)", "combo([01234567]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL)", SIGNABLE, {{"2102d2b36900396c9282fa14628566582f206a5dd0bcc8d5e892611806cafb0301f0ac","76a91431a507b815593dfc51ffc7245ae7e5aee304246e88ac","001431a507b815593dfc51ffc7245ae7e5aee304246e","a9142aafb926eb247cb18240a7f4c07983ad1f37922687"}}, std::nullopt);
+ Check("pk(xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0)", "pk(xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0)", "pk(xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0)", "pk(xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0)", DEFAULT, {{"210379e45b3cf75f9c5f9befd8e9506fb962f6a9d185ac87001ec44a8d3df8d4a9e3ac"}}, std::nullopt, {{0}});
Check("pkh(xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483647'/0)", "pkh(xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/2147483647'/0)", "pkh([bd16bee5/2147483647']xprv9vHkqa6XAPwKqSKSEJMcAB3yoCZhaSVsGZbSkFY5L3Lfjjk8sjZucbsbvEw5o3QrSA69nPfZDCgFnNnLhQ2ohpZuwummndnPasDw2Qr6dC2/0)", "pkh([bd16bee5/2147483647']xpub69H7F5dQzmVd3vPuLKtcXJziMEQByuDidnX3YdwgtNsecY5HRGtAAQC5mXTt4dsv9RzyjgDjAQs9VGVV6ydYCHnprc9vvaA5YtqWyL6hyds/0)", HARDENED, {{"76a914ebdc90806a9c4356c1c88e42216611e1cb4c1c1788ac"}}, OutputType::LEGACY, {{0xFFFFFFFFUL,0}});
Check("wpkh([ffffffff/13']xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/1/2/*)", "wpkh([ffffffff/13']xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*)", "wpkh([ffffffff/13']xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/1/2/*)", "wpkh([ffffffff/13']xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*)", RANGE, {{"0014326b2249e3a25d5dc60935f044ee835d090ba859"},{"0014af0bd98abc2f2cae66e36896a39ffe2d32984fb7"},{"00141fa798efd1cbf95cebf912c031b8a4a6e9fb9f27"}}, OutputType::BECH32, {{0x8000000DUL, 1, 2, 0}, {0x8000000DUL, 1, 2, 1}, {0x8000000DUL, 1, 2, 2}});
Check("sh(wpkh(xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/10/20/30/40/*'))", "sh(wpkh(xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*'))", "sh(wpkh(xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/10/20/30/40/*'))", "sh(wpkh(xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*'))", RANGE | HARDENED | DERIVE_HARDENED, {{"a9149a4d9901d6af519b2a23d4a2f51650fcba87ce7b87"},{"a914bed59fc0024fae941d6e20a3b44a109ae740129287"},{"a9148483aa1116eb9c05c482a72bada4b1db24af654387"}}, OutputType::P2SH_SEGWIT, {{10, 20, 30, 40, 0x80000000UL}, {10, 20, 30, 40, 0x80000001UL}, {10, 20, 30, 40, 0x80000002UL}});
- Check("combo(xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334/*)", "combo(xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV/*)", "combo(xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334/*)", "combo(xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV/*)", RANGE, {{"2102df12b7035bdac8e3bab862a3a83d06ea6b17b6753d52edecba9be46f5d09e076ac","76a914f90e3178ca25f2c808dc76624032d352fdbdfaf288ac","0014f90e3178ca25f2c808dc76624032d352fdbdfaf2","a91408f3ea8c68d4a7585bf9e8bda226723f70e445f087"},{"21032869a233c9adff9a994e4966e5b821fd5bac066da6c3112488dc52383b4a98ecac","76a914a8409d1b6dfb1ed2a3e8aa5e0ef2ff26b15b75b788ac","0014a8409d1b6dfb1ed2a3e8aa5e0ef2ff26b15b75b7","a91473e39884cb71ae4e5ac9739e9225026c99763e6687"}}, nullopt, {{0}, {1}});
+ Check("combo(xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334/*)", "combo(xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV/*)", "combo(xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334/*)", "combo(xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV/*)", RANGE, {{"2102df12b7035bdac8e3bab862a3a83d06ea6b17b6753d52edecba9be46f5d09e076ac","76a914f90e3178ca25f2c808dc76624032d352fdbdfaf288ac","0014f90e3178ca25f2c808dc76624032d352fdbdfaf2","a91408f3ea8c68d4a7585bf9e8bda226723f70e445f087"},{"21032869a233c9adff9a994e4966e5b821fd5bac066da6c3112488dc52383b4a98ecac","76a914a8409d1b6dfb1ed2a3e8aa5e0ef2ff26b15b75b788ac","0014a8409d1b6dfb1ed2a3e8aa5e0ef2ff26b15b75b7","a91473e39884cb71ae4e5ac9739e9225026c99763e6687"}}, std::nullopt, {{0}, {1}});
CheckUnparsable("combo([012345678]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc)", "combo([012345678]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL)", "Fingerprint is not 4 bytes (9 characters instead of 8 characters)"); // Too long key fingerprint
CheckUnparsable("pkh(xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483648)", "pkh(xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/2147483648)", "Key path value 2147483648 is out of range"); // BIP 32 path element overflow
CheckUnparsable("pkh(xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/1aa)", "pkh(xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/1aa)", "Key path value '1aa' is not a valid uint32"); // Path is not valid uint
Check("pkh([01234567/10/20]xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483647'/0)", "pkh([01234567/10/20]xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/2147483647'/0)", "pkh([01234567/10/20/2147483647']xprv9vHkqa6XAPwKqSKSEJMcAB3yoCZhaSVsGZbSkFY5L3Lfjjk8sjZucbsbvEw5o3QrSA69nPfZDCgFnNnLhQ2ohpZuwummndnPasDw2Qr6dC2/0)", "pkh([01234567/10/20/2147483647']xpub69H7F5dQzmVd3vPuLKtcXJziMEQByuDidnX3YdwgtNsecY5HRGtAAQC5mXTt4dsv9RzyjgDjAQs9VGVV6ydYCHnprc9vvaA5YtqWyL6hyds/0)", HARDENED, {{"76a914ebdc90806a9c4356c1c88e42216611e1cb4c1c1788ac"}}, OutputType::LEGACY, {{10, 20, 0xFFFFFFFFUL, 0}});
// Multisig constructions
- Check("multi(1,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1,5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "multi(1,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", "multi(1,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1,5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "multi(1,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", SIGNABLE, {{"512103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd4104a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea23552ae"}}, nullopt);
- Check("sortedmulti(1,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1,5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "sortedmulti(1,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", "sortedmulti(1,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1,5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "sortedmulti(1,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", SIGNABLE, {{"512103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd4104a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea23552ae"}}, nullopt);
- Check("sortedmulti(1,5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "sortedmulti(1,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "sortedmulti(1,5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "sortedmulti(1,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", SIGNABLE, {{"512103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd4104a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea23552ae"}}, nullopt);
+ Check("multi(1,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1,5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "multi(1,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", "multi(1,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1,5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "multi(1,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", SIGNABLE, {{"512103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd4104a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea23552ae"}}, std::nullopt);
+ Check("sortedmulti(1,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1,5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "sortedmulti(1,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", "sortedmulti(1,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1,5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "sortedmulti(1,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", SIGNABLE, {{"512103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd4104a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea23552ae"}}, std::nullopt);
+ Check("sortedmulti(1,5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "sortedmulti(1,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "sortedmulti(1,5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "sortedmulti(1,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", SIGNABLE, {{"512103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd4104a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea23552ae"}}, std::nullopt);
Check("sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))", "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))", "sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))", "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))", DEFAULT, {{"a91445a9a622a8b0a1269944be477640eedc447bbd8487"}}, OutputType::LEGACY, {{0x8000006FUL,222},{0}});
- Check("sortedmulti(2,xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/*,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0/0/*)", "sortedmulti(2,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/*,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0/0/*)", "sortedmulti(2,xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/*,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0/0/*)", "sortedmulti(2,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/*,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0/0/*)", RANGE, {{"5221025d5fc65ebb8d44a5274b53bac21ff8307fec2334a32df05553459f8b1f7fe1b62102fbd47cc8034098f0e6a94c6aeee8528abf0a2153a5d8e46d325b7284c046784652ae"}, {"52210264fd4d1f5dea8ded94c61e9641309349b62f27fbffe807291f664e286bfbe6472103f4ece6dfccfa37b211eb3d0af4d0c61dba9ef698622dc17eecdf764beeb005a652ae"}, {"5221022ccabda84c30bad578b13c89eb3b9544ce149787e5b538175b1d1ba259cbb83321024d902e1a2fc7a8755ab5b694c575fce742c48d9ff192e63df5193e4c7afe1f9c52ae"}}, nullopt, {{0}, {1}, {2}, {0, 0, 0}, {0, 0, 1}, {0, 0, 2}});
+ Check("sortedmulti(2,xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/*,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0/0/*)", "sortedmulti(2,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/*,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0/0/*)", "sortedmulti(2,xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/*,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0/0/*)", "sortedmulti(2,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/*,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0/0/*)", RANGE, {{"5221025d5fc65ebb8d44a5274b53bac21ff8307fec2334a32df05553459f8b1f7fe1b62102fbd47cc8034098f0e6a94c6aeee8528abf0a2153a5d8e46d325b7284c046784652ae"}, {"52210264fd4d1f5dea8ded94c61e9641309349b62f27fbffe807291f664e286bfbe6472103f4ece6dfccfa37b211eb3d0af4d0c61dba9ef698622dc17eecdf764beeb005a652ae"}, {"5221022ccabda84c30bad578b13c89eb3b9544ce149787e5b538175b1d1ba259cbb83321024d902e1a2fc7a8755ab5b694c575fce742c48d9ff192e63df5193e4c7afe1f9c52ae"}}, std::nullopt, {{0}, {1}, {2}, {0, 0, 0}, {0, 0, 1}, {0, 0, 2}});
Check("wsh(multi(2,xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483647'/0,xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/1/2/*,xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/10/20/30/40/*'))", "wsh(multi(2,xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/2147483647'/0,xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*,xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*'))", "wsh(multi(2,[bd16bee5/2147483647']xprv9vHkqa6XAPwKqSKSEJMcAB3yoCZhaSVsGZbSkFY5L3Lfjjk8sjZucbsbvEw5o3QrSA69nPfZDCgFnNnLhQ2ohpZuwummndnPasDw2Qr6dC2/0,xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/1/2/*,xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/10/20/30/40/*'))", "wsh(multi(2,[bd16bee5/2147483647']xpub69H7F5dQzmVd3vPuLKtcXJziMEQByuDidnX3YdwgtNsecY5HRGtAAQC5mXTt4dsv9RzyjgDjAQs9VGVV6ydYCHnprc9vvaA5YtqWyL6hyds/0,xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*,xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*'))", HARDENED | RANGE | DERIVE_HARDENED, {{"0020b92623201f3bb7c3771d45b2ad1d0351ea8fbf8cfe0a0e570264e1075fa1948f"},{"002036a08bbe4923af41cf4316817c93b8d37e2f635dd25cfff06bd50df6ae7ea203"},{"0020a96e7ab4607ca6b261bfe3245ffda9c746b28d3f59e83d34820ec0e2b36c139c"}}, OutputType::BECH32, {{0xFFFFFFFFUL,0}, {1,2,0}, {1,2,1}, {1,2,2}, {10, 20, 30, 40, 0x80000000UL}, {10, 20, 30, 40, 0x80000001UL}, {10, 20, 30, 40, 0x80000002UL}});
Check("sh(wsh(multi(16,KzoAz5CanayRKex3fSLQ2BwJpN7U52gZvxMyk78nDMHuqrUxuSJy,KwGNz6YCCQtYvFzMtrC6D3tKTKdBBboMrLTsjr2NYVBwapCkn7Mr,KxogYhiNfwxuswvXV66eFyKcCpm7dZ7TqHVqujHAVUjJxyivxQ9X,L2BUNduTSyZwZjwNHynQTF14mv2uz2NRq5n5sYWTb4FkkmqgEE9f,L1okJGHGn1kFjdXHKxXjwVVtmCMR2JA5QsbKCSpSb7ReQjezKeoD,KxDCNSST75HFPaW5QKpzHtAyaCQC7p9Vo3FYfi2u4dXD1vgMiboK,L5edQjFtnkcf5UWURn6UuuoFrabgDQUHdheKCziwN42aLwS3KizU,KzF8UWFcEC7BYTq8Go1xVimMkDmyNYVmXV5PV7RuDicvAocoPB8i,L3nHUboKG2w4VSJ5jYZ5CBM97oeK6YuKvfZxrefdShECcjEYKMWZ,KyjHo36dWkYhimKmVVmQTq3gERv3pnqA4xFCpvUgbGDJad7eS8WE,KwsfyHKRUTZPQtysN7M3tZ4GXTnuov5XRgjdF2XCG8faAPmFruRF,KzCUbGhN9LJhdeFfL9zQgTJMjqxdBKEekRGZX24hXdgCNCijkkap,KzgpMBwwsDLwkaC5UrmBgCYaBD2WgZ7PBoGYXR8KT7gCA9UTN5a3,KyBXTPy4T7YG4q9tcAM3LkvfRpD1ybHMvcJ2ehaWXaSqeGUxEdkP,KzJDe9iwJRPtKP2F2AoN6zBgzS7uiuAwhWCfGdNeYJ3PC1HNJ8M8,L1xbHrxynrqLKkoYc4qtoQPx6uy5qYXR5ZDYVYBSRmCV5piU3JG9)))","sh(wsh(multi(16,03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600,0362a74e399c39ed5593852a30147f2959b56bb827dfa3e60e464b02ccf87dc5e8,0261345b53de74a4d721ef877c255429961b7e43714171ac06168d7e08c542a8b8,02da72e8b46901a65d4374fe6315538d8f368557dda3a1dcf9ea903f3afe7314c8,0318c82dd0b53fd3a932d16e0ba9e278fcc937c582d5781be626ff16e201f72286,0297ccef1ef99f9d73dec9ad37476ddb232f1238aff877af19e72ba04493361009,02e502cfd5c3f972fe9a3e2a18827820638f96b6f347e54d63deb839011fd5765d,03e687710f0e3ebe81c1037074da939d409c0025f17eb86adb9427d28f0f7ae0e9,02c04d3a5274952acdbc76987f3184b346a483d43be40874624b29e3692c1df5af,02ed06e0f418b5b43a7ec01d1d7d27290fa15f75771cb69b642a51471c29c84acd,036d46073cbb9ffee90473f3da429abc8de7f8751199da44485682a989a4bebb24,02f5d1ff7c9029a80a4e36b9a5497027ef7f3e73384a4a94fbfe7c4e9164eec8bc,02e41deffd1b7cce11cde209a781adcffdabd1b91c0ba0375857a2bfd9302419f3,02d76625f7956a7fc505ab02556c23ee72d832f1bac391bcd2d3abce5710a13d06,0399eb0a5487515802dc14544cf10b3666623762fbed2ec38a3975716e2c29c232)))", "sh(wsh(multi(16,KzoAz5CanayRKex3fSLQ2BwJpN7U52gZvxMyk78nDMHuqrUxuSJy,KwGNz6YCCQtYvFzMtrC6D3tKTKdBBboMrLTsjr2NYVBwapCkn7Mr,KxogYhiNfwxuswvXV66eFyKcCpm7dZ7TqHVqujHAVUjJxyivxQ9X,L2BUNduTSyZwZjwNHynQTF14mv2uz2NRq5n5sYWTb4FkkmqgEE9f,L1okJGHGn1kFjdXHKxXjwVVtmCMR2JA5QsbKCSpSb7ReQjezKeoD,KxDCNSST75HFPaW5QKpzHtAyaCQC7p9Vo3FYfi2u4dXD1vgMiboK,L5edQjFtnkcf5UWURn6UuuoFrabgDQUHdheKCziwN42aLwS3KizU,KzF8UWFcEC7BYTq8Go1xVimMkDmyNYVmXV5PV7RuDicvAocoPB8i,L3nHUboKG2w4VSJ5jYZ5CBM97oeK6YuKvfZxrefdShECcjEYKMWZ,KyjHo36dWkYhimKmVVmQTq3gERv3pnqA4xFCpvUgbGDJad7eS8WE,KwsfyHKRUTZPQtysN7M3tZ4GXTnuov5XRgjdF2XCG8faAPmFruRF,KzCUbGhN9LJhdeFfL9zQgTJMjqxdBKEekRGZX24hXdgCNCijkkap,KzgpMBwwsDLwkaC5UrmBgCYaBD2WgZ7PBoGYXR8KT7gCA9UTN5a3,KyBXTPy4T7YG4q9tcAM3LkvfRpD1ybHMvcJ2ehaWXaSqeGUxEdkP,KzJDe9iwJRPtKP2F2AoN6zBgzS7uiuAwhWCfGdNeYJ3PC1HNJ8M8,L1xbHrxynrqLKkoYc4qtoQPx6uy5qYXR5ZDYVYBSRmCV5piU3JG9)))","sh(wsh(multi(16,03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600,0362a74e399c39ed5593852a30147f2959b56bb827dfa3e60e464b02ccf87dc5e8,0261345b53de74a4d721ef877c255429961b7e43714171ac06168d7e08c542a8b8,02da72e8b46901a65d4374fe6315538d8f368557dda3a1dcf9ea903f3afe7314c8,0318c82dd0b53fd3a932d16e0ba9e278fcc937c582d5781be626ff16e201f72286,0297ccef1ef99f9d73dec9ad37476ddb232f1238aff877af19e72ba04493361009,02e502cfd5c3f972fe9a3e2a18827820638f96b6f347e54d63deb839011fd5765d,03e687710f0e3ebe81c1037074da939d409c0025f17eb86adb9427d28f0f7ae0e9,02c04d3a5274952acdbc76987f3184b346a483d43be40874624b29e3692c1df5af,02ed06e0f418b5b43a7ec01d1d7d27290fa15f75771cb69b642a51471c29c84acd,036d46073cbb9ffee90473f3da429abc8de7f8751199da44485682a989a4bebb24,02f5d1ff7c9029a80a4e36b9a5497027ef7f3e73384a4a94fbfe7c4e9164eec8bc,02e41deffd1b7cce11cde209a781adcffdabd1b91c0ba0375857a2bfd9302419f3,02d76625f7956a7fc505ab02556c23ee72d832f1bac391bcd2d3abce5710a13d06,0399eb0a5487515802dc14544cf10b3666623762fbed2ec38a3975716e2c29c232)))", SIGNABLE, {{"a9147fc63e13dc25e8a95a3cee3d9a714ac3afd96f1e87"}}, OutputType::P2SH_SEGWIT);
CheckUnparsable("sh(multi(16,KzoAz5CanayRKex3fSLQ2BwJpN7U52gZvxMyk78nDMHuqrUxuSJy,KwGNz6YCCQtYvFzMtrC6D3tKTKdBBboMrLTsjr2NYVBwapCkn7Mr,KxogYhiNfwxuswvXV66eFyKcCpm7dZ7TqHVqujHAVUjJxyivxQ9X,L2BUNduTSyZwZjwNHynQTF14mv2uz2NRq5n5sYWTb4FkkmqgEE9f,L1okJGHGn1kFjdXHKxXjwVVtmCMR2JA5QsbKCSpSb7ReQjezKeoD,KxDCNSST75HFPaW5QKpzHtAyaCQC7p9Vo3FYfi2u4dXD1vgMiboK,L5edQjFtnkcf5UWURn6UuuoFrabgDQUHdheKCziwN42aLwS3KizU,KzF8UWFcEC7BYTq8Go1xVimMkDmyNYVmXV5PV7RuDicvAocoPB8i,L3nHUboKG2w4VSJ5jYZ5CBM97oeK6YuKvfZxrefdShECcjEYKMWZ,KyjHo36dWkYhimKmVVmQTq3gERv3pnqA4xFCpvUgbGDJad7eS8WE,KwsfyHKRUTZPQtysN7M3tZ4GXTnuov5XRgjdF2XCG8faAPmFruRF,KzCUbGhN9LJhdeFfL9zQgTJMjqxdBKEekRGZX24hXdgCNCijkkap,KzgpMBwwsDLwkaC5UrmBgCYaBD2WgZ7PBoGYXR8KT7gCA9UTN5a3,KyBXTPy4T7YG4q9tcAM3LkvfRpD1ybHMvcJ2ehaWXaSqeGUxEdkP,KzJDe9iwJRPtKP2F2AoN6zBgzS7uiuAwhWCfGdNeYJ3PC1HNJ8M8,L1xbHrxynrqLKkoYc4qtoQPx6uy5qYXR5ZDYVYBSRmCV5piU3JG9))","sh(multi(16,03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600,0362a74e399c39ed5593852a30147f2959b56bb827dfa3e60e464b02ccf87dc5e8,0261345b53de74a4d721ef877c255429961b7e43714171ac06168d7e08c542a8b8,02da72e8b46901a65d4374fe6315538d8f368557dda3a1dcf9ea903f3afe7314c8,0318c82dd0b53fd3a932d16e0ba9e278fcc937c582d5781be626ff16e201f72286,0297ccef1ef99f9d73dec9ad37476ddb232f1238aff877af19e72ba04493361009,02e502cfd5c3f972fe9a3e2a18827820638f96b6f347e54d63deb839011fd5765d,03e687710f0e3ebe81c1037074da939d409c0025f17eb86adb9427d28f0f7ae0e9,02c04d3a5274952acdbc76987f3184b346a483d43be40874624b29e3692c1df5af,02ed06e0f418b5b43a7ec01d1d7d27290fa15f75771cb69b642a51471c29c84acd,036d46073cbb9ffee90473f3da429abc8de7f8751199da44485682a989a4bebb24,02f5d1ff7c9029a80a4e36b9a5497027ef7f3e73384a4a94fbfe7c4e9164eec8bc,02e41deffd1b7cce11cde209a781adcffdabd1b91c0ba0375857a2bfd9302419f3,02d76625f7956a7fc505ab02556c23ee72d832f1bac391bcd2d3abce5710a13d06,0399eb0a5487515802dc14544cf10b3666623762fbed2ec38a3975716e2c29c232))", "P2SH script is too large, 547 bytes is larger than 520 bytes"); // P2SH does not fit 16 compressed pubkeys in a redeemscript
diff --git a/src/test/fuzz/addrman.cpp b/src/test/fuzz/addrman.cpp
index b55f1c72b1..0baf30aef6 100644
--- a/src/test/fuzz/addrman.cpp
+++ b/src/test/fuzz/addrman.cpp
@@ -104,7 +104,7 @@ FUZZ_TARGET_INIT(addrman, initialize_addrman)
[&] {
const std::optional<CService> opt_service = ConsumeDeserializable<CService>(fuzzed_data_provider);
if (opt_service) {
- addr_man.SetServices(*opt_service, ServiceFlags{fuzzed_data_provider.ConsumeIntegral<uint64_t>()});
+ addr_man.SetServices(*opt_service, ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS));
}
},
[&] {
diff --git a/src/test/fuzz/asmap_direct.cpp b/src/test/fuzz/asmap_direct.cpp
index 8b7822dc16..8ca4de3919 100644
--- a/src/test/fuzz/asmap_direct.cpp
+++ b/src/test/fuzz/asmap_direct.cpp
@@ -2,8 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <test/fuzz/fuzz.h>
+#include <netaddress.h>
#include <util/asmap.h>
+#include <test/fuzz/fuzz.h>
#include <cstdint>
#include <optional>
diff --git a/src/test/fuzz/autofile.cpp b/src/test/fuzz/autofile.cpp
index dbc0b5ab81..479342e4be 100644
--- a/src/test/fuzz/autofile.cpp
+++ b/src/test/fuzz/autofile.cpp
@@ -2,7 +2,6 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <optional.h>
#include <streams.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
diff --git a/src/test/fuzz/bech32.cpp b/src/test/fuzz/bech32.cpp
index 95cd4b413f..ad3bf73af4 100644
--- a/src/test/fuzz/bech32.cpp
+++ b/src/test/fuzz/bech32.cpp
@@ -16,28 +16,28 @@
FUZZ_TARGET(bech32)
{
const std::string random_string(buffer.begin(), buffer.end());
- const std::pair<std::string, std::vector<uint8_t>> r1 = bech32::Decode(random_string);
- if (r1.first.empty()) {
- assert(r1.second.empty());
+ const auto r1 = bech32::Decode(random_string);
+ if (r1.hrp.empty()) {
+ assert(r1.encoding == bech32::Encoding::INVALID);
+ assert(r1.data.empty());
} else {
- const std::string& hrp = r1.first;
- const std::vector<uint8_t>& data = r1.second;
- const std::string reencoded = bech32::Encode(hrp, data);
+ assert(r1.encoding != bech32::Encoding::INVALID);
+ const std::string reencoded = bech32::Encode(r1.encoding, r1.hrp, r1.data);
assert(CaseInsensitiveEqual(random_string, reencoded));
}
std::vector<unsigned char> input;
ConvertBits<8, 5, true>([&](unsigned char c) { input.push_back(c); }, buffer.begin(), buffer.end());
- const std::string encoded = bech32::Encode("bc", input);
- assert(!encoded.empty());
- const std::pair<std::string, std::vector<uint8_t>> r2 = bech32::Decode(encoded);
- if (r2.first.empty()) {
- assert(r2.second.empty());
- } else {
- const std::string& hrp = r2.first;
- const std::vector<uint8_t>& data = r2.second;
- assert(hrp == "bc");
- assert(data == input);
+ if (input.size() + 3 + 6 <= 90) {
+ // If it's possible to encode input in Bech32(m) without exceeding the 90-character limit:
+ for (auto encoding : {bech32::Encoding::BECH32, bech32::Encoding::BECH32M}) {
+ const std::string encoded = bech32::Encode(encoding, "bc", input);
+ assert(!encoded.empty());
+ const auto r2 = bech32::Decode(encoded);
+ assert(r2.encoding == encoding);
+ assert(r2.hrp == "bc");
+ assert(r2.data == input);
+ }
}
}
diff --git a/src/test/fuzz/buffered_file.cpp b/src/test/fuzz/buffered_file.cpp
index ffe38f10fc..ed72260d10 100644
--- a/src/test/fuzz/buffered_file.cpp
+++ b/src/test/fuzz/buffered_file.cpp
@@ -2,7 +2,6 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <optional.h>
#include <streams.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
diff --git a/src/test/fuzz/cuckoocache.cpp b/src/test/fuzz/cuckoocache.cpp
index dc20dc3f62..a522c837ef 100644
--- a/src/test/fuzz/cuckoocache.cpp
+++ b/src/test/fuzz/cuckoocache.cpp
@@ -30,7 +30,7 @@ FUZZ_TARGET(cuckoocache)
{
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
fuzzed_data_provider_ptr = &fuzzed_data_provider;
- CuckooCache::cache<bool, RandomHasher> cuckoo_cache{};
+ CuckooCache::cache<int, RandomHasher> cuckoo_cache{};
if (fuzzed_data_provider.ConsumeBool()) {
const size_t megabytes = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 16);
cuckoo_cache.setup_bytes(megabytes << 20);
diff --git a/src/test/fuzz/deserialize.cpp b/src/test/fuzz/deserialize.cpp
index 64c6e49615..1290c78712 100644
--- a/src/test/fuzz/deserialize.cpp
+++ b/src/test/fuzz/deserialize.cpp
@@ -15,7 +15,6 @@
#include <net.h>
#include <netbase.h>
#include <node/utxo_snapshot.h>
-#include <optional.h>
#include <primitives/block.h>
#include <protocol.h>
#include <psbt.h>
@@ -26,6 +25,7 @@
#include <version.h>
#include <exception>
+#include <optional>
#include <stdexcept>
#include <stdint.h>
#include <unistd.h>
@@ -69,7 +69,7 @@ T Deserialize(CDataStream ds)
}
template <typename T>
-void DeserializeFromFuzzingInput(FuzzBufferType buffer, T& obj, const Optional<int> protocol_version = nullopt)
+void DeserializeFromFuzzingInput(FuzzBufferType buffer, T& obj, const std::optional<int> protocol_version = std::nullopt)
{
CDataStream ds(buffer, SER_NETWORK, INIT_PROTO_VERSION);
if (protocol_version) {
diff --git a/src/test/fuzz/net.cpp b/src/test/fuzz/net.cpp
index b056f46f2e..272f6415a9 100644
--- a/src/test/fuzz/net.cpp
+++ b/src/test/fuzz/net.cpp
@@ -7,7 +7,6 @@
#include <net.h>
#include <net_permissions.h>
#include <netaddress.h>
-#include <optional.h>
#include <protocol.h>
#include <random.h>
#include <test/fuzz/FuzzedDataProvider.h>
@@ -17,6 +16,7 @@
#include <test/util/setup_common.h>
#include <cstdint>
+#include <optional>
#include <string>
#include <vector>
diff --git a/src/test/fuzz/netbase_dns_lookup.cpp b/src/test/fuzz/netbase_dns_lookup.cpp
index 786440c8a4..cf2fa33744 100644
--- a/src/test/fuzz/netbase_dns_lookup.cpp
+++ b/src/test/fuzz/netbase_dns_lookup.cpp
@@ -12,27 +12,22 @@
#include <string>
#include <vector>
-namespace {
-FuzzedDataProvider* fuzzed_data_provider_ptr = nullptr;
-
-std::vector<CNetAddr> fuzzed_dns_lookup_function(const std::string& name, bool allow_lookup)
-{
- std::vector<CNetAddr> resolved_addresses;
- while (fuzzed_data_provider_ptr->ConsumeBool()) {
- resolved_addresses.push_back(ConsumeNetAddr(*fuzzed_data_provider_ptr));
- }
- return resolved_addresses;
-}
-} // namespace
-
FUZZ_TARGET(netbase_dns_lookup)
{
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
- fuzzed_data_provider_ptr = &fuzzed_data_provider;
const std::string name = fuzzed_data_provider.ConsumeRandomLengthString(512);
const unsigned int max_results = fuzzed_data_provider.ConsumeIntegral<unsigned int>();
const bool allow_lookup = fuzzed_data_provider.ConsumeBool();
- const int default_port = fuzzed_data_provider.ConsumeIntegral<int>();
+ const uint16_t default_port = fuzzed_data_provider.ConsumeIntegral<uint16_t>();
+
+ auto fuzzed_dns_lookup_function = [&](const std::string&, bool) {
+ std::vector<CNetAddr> resolved_addresses;
+ while (fuzzed_data_provider.ConsumeBool()) {
+ resolved_addresses.push_back(ConsumeNetAddr(fuzzed_data_provider));
+ }
+ return resolved_addresses;
+ };
+
{
std::vector<CNetAddr> resolved_addresses;
if (LookupHost(name, resolved_addresses, max_results, allow_lookup, fuzzed_dns_lookup_function)) {
@@ -73,5 +68,4 @@ FUZZ_TARGET(netbase_dns_lookup)
assert(resolved_subnet.IsValid());
}
}
- fuzzed_data_provider_ptr = nullptr;
}
diff --git a/src/test/fuzz/node_eviction.cpp b/src/test/fuzz/node_eviction.cpp
index 606ebfc151..603d520cf5 100644
--- a/src/test/fuzz/node_eviction.cpp
+++ b/src/test/fuzz/node_eviction.cpp
@@ -3,7 +3,6 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <net.h>
-#include <optional.h>
#include <protocol.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
@@ -37,7 +36,7 @@ FUZZ_TARGET(node_eviction)
// Make a copy since eviction_candidates may be in some valid but otherwise
// indeterminate state after the SelectNodeToEvict(&&) call.
const std::vector<NodeEvictionCandidate> eviction_candidates_copy = eviction_candidates;
- const Optional<NodeId> node_to_evict = SelectNodeToEvict(std::move(eviction_candidates));
+ const std::optional<NodeId> node_to_evict = SelectNodeToEvict(std::move(eviction_candidates));
if (node_to_evict) {
assert(std::any_of(eviction_candidates_copy.begin(), eviction_candidates_copy.end(), [&node_to_evict](const NodeEvictionCandidate& eviction_candidate) { return *node_to_evict == eviction_candidate.id; }));
}
diff --git a/src/test/fuzz/p2p_transport_deserializer.cpp b/src/test/fuzz/p2p_transport_deserializer.cpp
index 163f1b839e..3a1fdaad8f 100644
--- a/src/test/fuzz/p2p_transport_deserializer.cpp
+++ b/src/test/fuzz/p2p_transport_deserializer.cpp
@@ -10,6 +10,7 @@
#include <cassert>
#include <cstdint>
#include <limits>
+#include <optional>
#include <vector>
void initialize_p2p_transport_deserializer()
@@ -30,7 +31,7 @@ FUZZ_TARGET_INIT(p2p_transport_deserializer, initialize_p2p_transport_deserializ
if (deserializer.Complete()) {
const std::chrono::microseconds m_time{std::numeric_limits<int64_t>::max()};
uint32_t out_err_raw_size{0};
- Optional<CNetMessage> result{deserializer.GetMessage(m_time, out_err_raw_size)};
+ std::optional<CNetMessage> result{deserializer.GetMessage(m_time, out_err_raw_size)};
if (result) {
assert(result->m_command.size() <= CMessageHeader::COMMAND_SIZE);
assert(result->m_raw_message_size <= buffer.size());
diff --git a/src/test/fuzz/parse_numbers.cpp b/src/test/fuzz/parse_numbers.cpp
index ddd2bcfba3..2c546e9b4a 100644
--- a/src/test/fuzz/parse_numbers.cpp
+++ b/src/test/fuzz/parse_numbers.cpp
@@ -18,6 +18,12 @@ FUZZ_TARGET(parse_numbers)
double d;
(void)ParseDouble(random_string, &d);
+ uint8_t u8;
+ (void)ParseUInt8(random_string, &u8);
+
+ uint16_t u16;
+ (void)ParseUInt16(random_string, &u16);
+
int32_t i32;
(void)ParseInt32(random_string, &i32);
(void)atoi(random_string);
diff --git a/src/test/fuzz/psbt.cpp b/src/test/fuzz/psbt.cpp
index eb2754054a..d1cc6f9c7e 100644
--- a/src/test/fuzz/psbt.cpp
+++ b/src/test/fuzz/psbt.cpp
@@ -5,7 +5,6 @@
#include <test/fuzz/fuzz.h>
#include <node/psbt.h>
-#include <optional.h>
#include <psbt.h>
#include <pubkey.h>
#include <script/script.h>
@@ -13,6 +12,7 @@
#include <version.h>
#include <cstdint>
+#include <optional>
#include <string>
#include <vector>
@@ -39,7 +39,7 @@ FUZZ_TARGET_INIT(psbt, initialize_psbt)
(void)psbt.IsNull();
- Optional<CMutableTransaction> tx = psbt.tx;
+ std::optional<CMutableTransaction> tx = psbt.tx;
if (tx) {
const CMutableTransaction& mtx = *tx;
const PartiallySignedTransaction psbt_from_tx{mtx};
diff --git a/src/test/fuzz/script_descriptor_cache.cpp b/src/test/fuzz/script_descriptor_cache.cpp
index 1c62c018e7..6ce13d5679 100644
--- a/src/test/fuzz/script_descriptor_cache.cpp
+++ b/src/test/fuzz/script_descriptor_cache.cpp
@@ -2,7 +2,6 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <optional.h>
#include <pubkey.h>
#include <script/descriptor.h>
#include <test/fuzz/FuzzedDataProvider.h>
@@ -10,6 +9,7 @@
#include <test/fuzz/util.h>
#include <cstdint>
+#include <optional>
#include <string>
#include <vector>
diff --git a/src/test/fuzz/socks5.cpp b/src/test/fuzz/socks5.cpp
index e5cc4cabe5..c3a6eed089 100644
--- a/src/test/fuzz/socks5.cpp
+++ b/src/test/fuzz/socks5.cpp
@@ -2,6 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <netaddress.h>
#include <netbase.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
@@ -38,7 +39,7 @@ FUZZ_TARGET_INIT(socks5, initialize_socks5)
// This Socks5(...) fuzzing harness would have caught CVE-2017-18350 within
// a few seconds of fuzzing.
(void)Socks5(fuzzed_data_provider.ConsumeRandomLengthString(512),
- fuzzed_data_provider.ConsumeIntegral<int>(),
+ fuzzed_data_provider.ConsumeIntegral<uint16_t>(),
fuzzed_data_provider.ConsumeBool() ? &proxy_credentials : nullptr,
fuzzed_sock);
}
diff --git a/src/test/fuzz/string.cpp b/src/test/fuzz/string.cpp
index 93b4948a2f..286375f7ae 100644
--- a/src/test/fuzz/string.cpp
+++ b/src/test/fuzz/string.cpp
@@ -5,6 +5,7 @@
#include <blockfilter.h>
#include <clientversion.h>
#include <logging.h>
+#include <netaddress.h>
#include <netbase.h>
#include <outputtype.h>
#include <rpc/client.h>
@@ -82,7 +83,7 @@ FUZZ_TARGET(string)
#ifndef WIN32
(void)ShellEscape(random_string_1);
#endif // WIN32
- int port_out;
+ uint16_t port_out;
std::string host_out;
SplitHostPort(random_string_1, port_out, host_out);
(void)TimingResistantEqual(random_string_1, random_string_2);
diff --git a/src/test/fuzz/system.cpp b/src/test/fuzz/system.cpp
index d9571209fa..b25dcfcd3b 100644
--- a/src/test/fuzz/system.cpp
+++ b/src/test/fuzz/system.cpp
@@ -51,7 +51,7 @@ FUZZ_TARGET(system)
// Avoid hitting:
// util/system.cpp:425: void ArgsManager::AddArg(const std::string &, const std::string &, unsigned int, const OptionsCategory &): Assertion `ret.second' failed.
const std::string argument_name = GetArgumentName(fuzzed_data_provider.ConsumeRandomLengthString(16));
- if (args_manager.GetArgFlags(argument_name) != nullopt) {
+ if (args_manager.GetArgFlags(argument_name) != std::nullopt) {
return;
}
args_manager.AddArg(argument_name, fuzzed_data_provider.ConsumeRandomLengthString(16), fuzzed_data_provider.ConsumeIntegral<unsigned int>() & ~ArgsManager::COMMAND, options_category);
@@ -63,7 +63,7 @@ FUZZ_TARGET(system)
std::vector<std::string> hidden_arguments;
for (const std::string& name : names) {
const std::string hidden_argument = GetArgumentName(name);
- if (args_manager.GetArgFlags(hidden_argument) != nullopt) {
+ if (args_manager.GetArgFlags(hidden_argument) != std::nullopt) {
continue;
}
if (std::find(hidden_arguments.begin(), hidden_arguments.end(), hidden_argument) != hidden_arguments.end()) {
diff --git a/src/test/fuzz/tx_pool.cpp b/src/test/fuzz/tx_pool.cpp
new file mode 100644
index 0000000000..2a9363a7c3
--- /dev/null
+++ b/src/test/fuzz/tx_pool.cpp
@@ -0,0 +1,284 @@
+// Copyright (c) 2021 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 <consensus/validation.h>
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+#include <test/util/mining.h>
+#include <test/util/script.h>
+#include <test/util/setup_common.h>
+#include <util/rbf.h>
+#include <validation.h>
+#include <validationinterface.h>
+
+namespace {
+
+const TestingSetup* g_setup;
+std::vector<COutPoint> g_outpoints_coinbase_init;
+
+struct MockedTxPool : public CTxMemPool {
+ void RollingFeeUpdate()
+ {
+ lastRollingFeeUpdate = GetTime();
+ blockSinceLastRollingFeeBump = true;
+ }
+};
+
+void initialize_tx_pool()
+{
+ static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>();
+ g_setup = testing_setup.get();
+
+ for (int i = 0; i < 2 * COINBASE_MATURITY; ++i) {
+ CTxIn in = MineBlock(g_setup->m_node, P2WSH_OP_TRUE);
+ // Remember the txids to avoid expensive disk acess later on
+ g_outpoints_coinbase_init.push_back(in.prevout);
+ }
+ SyncWithValidationInterfaceQueue();
+}
+
+struct TransactionsDelta final : public CValidationInterface {
+ std::set<CTransactionRef>& m_removed;
+ std::set<CTransactionRef>& m_added;
+
+ explicit TransactionsDelta(std::set<CTransactionRef>& r, std::set<CTransactionRef>& a)
+ : m_removed{r}, m_added{a} {}
+
+ void TransactionAddedToMempool(const CTransactionRef& tx, uint64_t /* mempool_sequence */) override
+ {
+ Assert(m_added.insert(tx).second);
+ }
+
+ void TransactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason, uint64_t /* mempool_sequence */) override
+ {
+ Assert(m_removed.insert(tx).second);
+ }
+};
+
+void SetMempoolConstraints(ArgsManager& args, FuzzedDataProvider& fuzzed_data_provider)
+{
+ args.ForceSetArg("-limitancestorcount",
+ ToString(fuzzed_data_provider.ConsumeIntegralInRange<unsigned>(0, 50)));
+ args.ForceSetArg("-limitancestorsize",
+ ToString(fuzzed_data_provider.ConsumeIntegralInRange<unsigned>(0, 202)));
+ args.ForceSetArg("-limitdescendantcount",
+ ToString(fuzzed_data_provider.ConsumeIntegralInRange<unsigned>(0, 50)));
+ args.ForceSetArg("-limitdescendantsize",
+ ToString(fuzzed_data_provider.ConsumeIntegralInRange<unsigned>(0, 202)));
+ args.ForceSetArg("-maxmempool",
+ ToString(fuzzed_data_provider.ConsumeIntegralInRange<unsigned>(0, 200)));
+ args.ForceSetArg("-mempoolexpiry",
+ ToString(fuzzed_data_provider.ConsumeIntegralInRange<unsigned>(0, 999)));
+}
+
+FUZZ_TARGET_INIT(tx_pool_standard, initialize_tx_pool)
+{
+ FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
+ const auto& node = g_setup->m_node;
+ auto& chainstate = node.chainman->ActiveChainstate();
+
+ SetMockTime(ConsumeTime(fuzzed_data_provider));
+ SetMempoolConstraints(*node.args, fuzzed_data_provider);
+
+ // All RBF-spendable outpoints
+ std::set<COutPoint> outpoints_rbf;
+ // All outpoints counting toward the total supply (subset of outpoints_rbf)
+ std::set<COutPoint> outpoints_supply;
+ for (const auto& outpoint : g_outpoints_coinbase_init) {
+ Assert(outpoints_supply.insert(outpoint).second);
+ if (outpoints_supply.size() >= COINBASE_MATURITY) break;
+ }
+ outpoints_rbf = outpoints_supply;
+
+ // The sum of the values of all spendable outpoints
+ constexpr CAmount SUPPLY_TOTAL{COINBASE_MATURITY * 50 * COIN};
+
+ CTxMemPool tx_pool_{/* estimator */ nullptr, /* check_ratio */ 1};
+ MockedTxPool& tx_pool = *(MockedTxPool*)&tx_pool_;
+
+ // Helper to query an amount
+ const CCoinsViewMemPool amount_view{WITH_LOCK(::cs_main, return &chainstate.CoinsTip()), tx_pool};
+ const auto GetAmount = [&](const COutPoint& outpoint) {
+ Coin c;
+ amount_view.GetCoin(outpoint, c);
+ Assert(!c.IsSpent());
+ return c.out.nValue;
+ };
+
+ while (fuzzed_data_provider.ConsumeBool()) {
+ {
+ // Total supply is the mempool fee + all outpoints
+ CAmount supply_now{WITH_LOCK(tx_pool.cs, return tx_pool.GetTotalFee())};
+ for (const auto& op : outpoints_supply) {
+ supply_now += GetAmount(op);
+ }
+ Assert(supply_now == SUPPLY_TOTAL);
+ }
+ Assert(!outpoints_supply.empty());
+
+ // Create transaction to add to the mempool
+ const CTransactionRef tx = [&] {
+ CMutableTransaction tx_mut;
+ tx_mut.nVersion = CTransaction::CURRENT_VERSION;
+ tx_mut.nLockTime = fuzzed_data_provider.ConsumeBool() ? 0 : fuzzed_data_provider.ConsumeIntegral<uint32_t>();
+ const auto num_in = fuzzed_data_provider.ConsumeIntegralInRange<int>(1, outpoints_rbf.size());
+ const auto num_out = fuzzed_data_provider.ConsumeIntegralInRange<int>(1, outpoints_rbf.size() * 2);
+
+ CAmount amount_in{0};
+ for (int i = 0; i < num_in; ++i) {
+ // Pop random outpoint
+ auto pop = outpoints_rbf.begin();
+ std::advance(pop, fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, outpoints_rbf.size() - 1));
+ const auto outpoint = *pop;
+ outpoints_rbf.erase(pop);
+ amount_in += GetAmount(outpoint);
+
+ // Create input
+ const auto sequence = ConsumeSequence(fuzzed_data_provider);
+ const auto script_sig = CScript{};
+ const auto script_wit_stack = std::vector<std::vector<uint8_t>>{WITNESS_STACK_ELEM_OP_TRUE};
+ CTxIn in;
+ in.prevout = outpoint;
+ in.nSequence = sequence;
+ in.scriptSig = script_sig;
+ in.scriptWitness.stack = script_wit_stack;
+
+ tx_mut.vin.push_back(in);
+ }
+ const auto amount_fee = fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(-1000, amount_in);
+ const auto amount_out = (amount_in - amount_fee) / num_out;
+ for (int i = 0; i < num_out; ++i) {
+ tx_mut.vout.emplace_back(amount_out, P2WSH_OP_TRUE);
+ }
+ const auto tx = MakeTransactionRef(tx_mut);
+ // Restore previously removed outpoints
+ for (const auto& in : tx->vin) {
+ Assert(outpoints_rbf.insert(in.prevout).second);
+ }
+ return tx;
+ }();
+
+ if (fuzzed_data_provider.ConsumeBool()) {
+ SetMockTime(ConsumeTime(fuzzed_data_provider));
+ }
+ if (fuzzed_data_provider.ConsumeBool()) {
+ SetMempoolConstraints(*node.args, fuzzed_data_provider);
+ }
+ if (fuzzed_data_provider.ConsumeBool()) {
+ tx_pool.RollingFeeUpdate();
+ }
+ if (fuzzed_data_provider.ConsumeBool()) {
+ const auto& txid = fuzzed_data_provider.ConsumeBool() ?
+ tx->GetHash() :
+ PickValue(fuzzed_data_provider, outpoints_rbf).hash;
+ const auto delta = fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(-50 * COIN, +50 * COIN);
+ tx_pool.PrioritiseTransaction(txid, delta);
+ }
+
+ // Remember all removed and added transactions
+ std::set<CTransactionRef> removed;
+ std::set<CTransactionRef> added;
+ auto txr = std::make_shared<TransactionsDelta>(removed, added);
+ RegisterSharedValidationInterface(txr);
+ const bool bypass_limits = fuzzed_data_provider.ConsumeBool();
+ ::fRequireStandard = fuzzed_data_provider.ConsumeBool();
+ const auto res = WITH_LOCK(::cs_main, return AcceptToMemoryPool(chainstate, tx_pool, tx, bypass_limits));
+ const bool accepted = res.m_result_type == MempoolAcceptResult::ResultType::VALID;
+ SyncWithValidationInterfaceQueue();
+ UnregisterSharedValidationInterface(txr);
+
+ Assert(accepted != added.empty());
+ Assert(accepted == res.m_state.IsValid());
+ Assert(accepted != res.m_state.IsInvalid());
+ if (accepted) {
+ Assert(added.size() == 1); // For now, no package acceptance
+ Assert(tx == *added.begin());
+ } else {
+ // Do not consider rejected transaction removed
+ removed.erase(tx);
+ }
+
+ // Helper to insert spent and created outpoints of a tx into collections
+ using Sets = std::vector<std::reference_wrapper<std::set<COutPoint>>>;
+ const auto insert_tx = [](Sets created_by_tx, Sets consumed_by_tx, const auto& tx) {
+ for (size_t i{0}; i < tx.vout.size(); ++i) {
+ for (auto& set : created_by_tx) {
+ Assert(set.get().emplace(tx.GetHash(), i).second);
+ }
+ }
+ for (const auto& in : tx.vin) {
+ for (auto& set : consumed_by_tx) {
+ Assert(set.get().insert(in.prevout).second);
+ }
+ }
+ };
+ // Add created outpoints, remove spent outpoints
+ {
+ // Outpoints that no longer exist at all
+ std::set<COutPoint> consumed_erased;
+ // Outpoints that no longer count toward the total supply
+ std::set<COutPoint> consumed_supply;
+ for (const auto& removed_tx : removed) {
+ insert_tx(/* created_by_tx */ {consumed_erased}, /* consumed_by_tx */ {outpoints_supply}, /* tx */ *removed_tx);
+ }
+ for (const auto& added_tx : added) {
+ insert_tx(/* created_by_tx */ {outpoints_supply, outpoints_rbf}, /* consumed_by_tx */ {consumed_supply}, /* tx */ *added_tx);
+ }
+ for (const auto& p : consumed_erased) {
+ Assert(outpoints_supply.erase(p) == 1);
+ Assert(outpoints_rbf.erase(p) == 1);
+ }
+ for (const auto& p : consumed_supply) {
+ Assert(outpoints_supply.erase(p) == 1);
+ }
+ }
+ }
+ WITH_LOCK(::cs_main, tx_pool.check(chainstate));
+ const auto info_all = tx_pool.infoAll();
+ if (!info_all.empty()) {
+ const auto& tx_to_remove = *PickValue(fuzzed_data_provider, info_all).tx;
+ WITH_LOCK(tx_pool.cs, tx_pool.removeRecursive(tx_to_remove, /* dummy */ MemPoolRemovalReason::BLOCK));
+ std::vector<uint256> all_txids;
+ tx_pool.queryHashes(all_txids);
+ assert(all_txids.size() < info_all.size());
+ WITH_LOCK(::cs_main, tx_pool.check(chainstate));
+ }
+ SyncWithValidationInterfaceQueue();
+}
+
+FUZZ_TARGET_INIT(tx_pool, initialize_tx_pool)
+{
+ FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
+ const auto& node = g_setup->m_node;
+
+ std::vector<uint256> txids;
+ for (const auto& outpoint : g_outpoints_coinbase_init) {
+ txids.push_back(outpoint.hash);
+ if (txids.size() >= COINBASE_MATURITY) break;
+ }
+ for (int i{0}; i <= 3; ++i) {
+ // Add some immature and non-existent outpoints
+ txids.push_back(g_outpoints_coinbase_init.at(i).hash);
+ txids.push_back(ConsumeUInt256(fuzzed_data_provider));
+ }
+
+ CTxMemPool tx_pool{/* estimator */ nullptr, /* check_ratio */ 1};
+
+ while (fuzzed_data_provider.ConsumeBool()) {
+ const auto mut_tx = ConsumeTransaction(fuzzed_data_provider, txids);
+
+ const auto tx = MakeTransactionRef(mut_tx);
+ const bool bypass_limits = fuzzed_data_provider.ConsumeBool();
+ ::fRequireStandard = fuzzed_data_provider.ConsumeBool();
+ const auto res = WITH_LOCK(::cs_main, return AcceptToMemoryPool(node.chainman->ActiveChainstate(), tx_pool, tx, bypass_limits));
+ const bool accepted = res.m_result_type == MempoolAcceptResult::ResultType::VALID;
+ if (accepted) {
+ txids.push_back(tx->GetHash());
+ }
+
+ SyncWithValidationInterfaceQueue();
+ }
+}
+} // namespace
diff --git a/src/test/fuzz/util.cpp b/src/test/fuzz/util.cpp
index 0a541e4186..93418ab1ff 100644
--- a/src/test/fuzz/util.cpp
+++ b/src/test/fuzz/util.cpp
@@ -3,8 +3,11 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <test/fuzz/util.h>
+#include <test/util/script.h>
+#include <util/rbf.h>
#include <version.h>
+
void FillNode(FuzzedDataProvider& fuzzed_data_provider, CNode& node, bool init_version) noexcept
{
const ServiceFlags remote_services = ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS);
@@ -23,3 +26,78 @@ void FillNode(FuzzedDataProvider& fuzzed_data_provider, CNode& node, bool init_v
node.m_tx_relay->fRelayTxes = filter_txs;
}
}
+
+CMutableTransaction ConsumeTransaction(FuzzedDataProvider& fuzzed_data_provider, const std::optional<std::vector<uint256>>& prevout_txids, const int max_num_in, const int max_num_out) noexcept
+{
+ CMutableTransaction tx_mut;
+ const auto p2wsh_op_true = fuzzed_data_provider.ConsumeBool();
+ tx_mut.nVersion = fuzzed_data_provider.ConsumeBool() ?
+ CTransaction::CURRENT_VERSION :
+ fuzzed_data_provider.ConsumeIntegral<int32_t>();
+ tx_mut.nLockTime = fuzzed_data_provider.ConsumeIntegral<uint32_t>();
+ const auto num_in = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, max_num_in);
+ const auto num_out = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, max_num_out);
+ for (int i = 0; i < num_in; ++i) {
+ const auto& txid_prev = prevout_txids ?
+ PickValue(fuzzed_data_provider, *prevout_txids) :
+ ConsumeUInt256(fuzzed_data_provider);
+ const auto index_out = fuzzed_data_provider.ConsumeIntegralInRange<uint32_t>(0, max_num_out);
+ const auto sequence = ConsumeSequence(fuzzed_data_provider);
+ const auto script_sig = p2wsh_op_true ? CScript{} : ConsumeScript(fuzzed_data_provider);
+ CScriptWitness script_wit;
+ if (p2wsh_op_true) {
+ script_wit.stack = std::vector<std::vector<uint8_t>>{WITNESS_STACK_ELEM_OP_TRUE};
+ } else {
+ script_wit = ConsumeScriptWitness(fuzzed_data_provider);
+ }
+ CTxIn in;
+ in.prevout = COutPoint{txid_prev, index_out};
+ in.nSequence = sequence;
+ in.scriptSig = script_sig;
+ in.scriptWitness = script_wit;
+
+ tx_mut.vin.push_back(in);
+ }
+ for (int i = 0; i < num_out; ++i) {
+ const auto amount = fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(-10, 50 * COIN + 10);
+ const auto script_pk = p2wsh_op_true ?
+ P2WSH_OP_TRUE :
+ ConsumeScript(fuzzed_data_provider, /* max_length */ 128, /* maybe_p2wsh */ true);
+ tx_mut.vout.emplace_back(amount, script_pk);
+ }
+ return tx_mut;
+}
+
+CScriptWitness ConsumeScriptWitness(FuzzedDataProvider& fuzzed_data_provider, const size_t max_stack_elem_size) noexcept
+{
+ CScriptWitness ret;
+ const auto n_elements = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, max_stack_elem_size);
+ for (size_t i = 0; i < n_elements; ++i) {
+ ret.stack.push_back(ConsumeRandomLengthByteVector(fuzzed_data_provider));
+ }
+ return ret;
+}
+
+CScript ConsumeScript(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length, const bool maybe_p2wsh) noexcept
+{
+ const std::vector<uint8_t> b = ConsumeRandomLengthByteVector(fuzzed_data_provider);
+ CScript r_script{b.begin(), b.end()};
+ if (maybe_p2wsh && fuzzed_data_provider.ConsumeBool()) {
+ uint256 script_hash;
+ CSHA256().Write(&r_script[0], r_script.size()).Finalize(script_hash.begin());
+ r_script.clear();
+ r_script << OP_0 << ToByteVector(script_hash);
+ }
+ return r_script;
+}
+
+uint32_t ConsumeSequence(FuzzedDataProvider& fuzzed_data_provider) noexcept
+{
+ return fuzzed_data_provider.ConsumeBool() ?
+ fuzzed_data_provider.PickValueInArray({
+ CTxIn::SEQUENCE_FINAL,
+ CTxIn::SEQUENCE_FINAL - 1,
+ MAX_BIP125_RBF_SEQUENCE,
+ }) :
+ fuzzed_data_provider.ConsumeIntegral<uint32_t>();
+}
diff --git a/src/test/fuzz/util.h b/src/test/fuzz/util.h
index d8c536e8b1..df459fe60d 100644
--- a/src/test/fuzz/util.h
+++ b/src/test/fuzz/util.h
@@ -48,6 +48,16 @@ void CallOneOf(FuzzedDataProvider& fuzzed_data_provider, Callables... callables)
return ((i++ == call_index ? callables() : void()), ...);
}
+template <typename Collection>
+const auto& PickValue(FuzzedDataProvider& fuzzed_data_provider, const Collection& col)
+{
+ const auto sz = col.size();
+ assert(sz >= 1);
+ auto it = col.begin();
+ std::advance(it, fuzzed_data_provider.ConsumeIntegralInRange<decltype(sz)>(0, sz - 1));
+ return *it;
+}
+
[[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);
@@ -125,11 +135,13 @@ template <typename WeakEnumType, size_t size>
return fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(time_min, time_max);
}
-[[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]] CMutableTransaction ConsumeTransaction(FuzzedDataProvider& fuzzed_data_provider, const std::optional<std::vector<uint256>>& prevout_txids, const int max_num_in = 10, const int max_num_out = 10) noexcept;
+
+[[nodiscard]] CScriptWitness ConsumeScriptWitness(FuzzedDataProvider& fuzzed_data_provider, const size_t max_stack_elem_size = 32) noexcept;
+
+[[nodiscard]] CScript ConsumeScript(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length = 4096, const bool maybe_p2wsh = false) noexcept;
+
+[[nodiscard]] uint32_t ConsumeSequence(FuzzedDataProvider& fuzzed_data_provider) noexcept;
[[nodiscard]] inline CScriptNum ConsumeScriptNum(FuzzedDataProvider& fuzzed_data_provider) noexcept
{
@@ -259,6 +271,16 @@ void SetFuzzedErrNo(FuzzedDataProvider& fuzzed_data_provider, const std::array<T
errno = fuzzed_data_provider.PickValueInArray(errnos);
}
+/*
+ * Sets a fuzzed errno in the range [0, 133 (EHWPOISON)]. Can be used from functions emulating
+ * standard library functions that set errno, or in other contexts where the value of errno
+ * might be relevant for the execution path that will be taken.
+ */
+inline void SetFuzzedErrNo(FuzzedDataProvider& fuzzed_data_provider) noexcept
+{
+ errno = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 133);
+}
+
/**
* 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.
@@ -345,6 +367,7 @@ public:
FILE* open()
{
+ SetFuzzedErrNo(m_fuzzed_data_provider);
if (m_fuzzed_data_provider.ConsumeBool()) {
return nullptr;
}
@@ -386,6 +409,7 @@ public:
static ssize_t read(void* cookie, char* buf, size_t size)
{
FuzzedFileProvider* fuzzed_file = (FuzzedFileProvider*)cookie;
+ SetFuzzedErrNo(fuzzed_file->m_fuzzed_data_provider);
if (buf == nullptr || size == 0 || fuzzed_file->m_fuzzed_data_provider.ConsumeBool()) {
return fuzzed_file->m_fuzzed_data_provider.ConsumeBool() ? 0 : -1;
}
@@ -404,6 +428,7 @@ public:
static ssize_t write(void* cookie, const char* buf, size_t size)
{
FuzzedFileProvider* fuzzed_file = (FuzzedFileProvider*)cookie;
+ SetFuzzedErrNo(fuzzed_file->m_fuzzed_data_provider);
const ssize_t n = fuzzed_file->m_fuzzed_data_provider.ConsumeIntegralInRange<ssize_t>(0, size);
if (AdditionOverflow(fuzzed_file->m_offset, (int64_t)n)) {
return fuzzed_file->m_fuzzed_data_provider.ConsumeBool() ? 0 : -1;
@@ -414,8 +439,9 @@ public:
static int seek(void* cookie, int64_t* offset, int whence)
{
- assert(whence == SEEK_SET || whence == SEEK_CUR); // SEEK_END not implemented yet.
+ assert(whence == SEEK_SET || whence == SEEK_CUR || whence == SEEK_END);
FuzzedFileProvider* fuzzed_file = (FuzzedFileProvider*)cookie;
+ SetFuzzedErrNo(fuzzed_file->m_fuzzed_data_provider);
int64_t new_offset = 0;
if (whence == SEEK_SET) {
new_offset = *offset;
@@ -424,6 +450,12 @@ public:
return -1;
}
new_offset = fuzzed_file->m_offset + *offset;
+ } else if (whence == SEEK_END) {
+ const int64_t n = fuzzed_file->m_fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(0, 4096);
+ if (AdditionOverflow(n, *offset)) {
+ return -1;
+ }
+ new_offset = n + *offset;
}
if (new_offset < 0) {
return -1;
@@ -436,6 +468,7 @@ public:
static int close(void* cookie)
{
FuzzedFileProvider* fuzzed_file = (FuzzedFileProvider*)cookie;
+ SetFuzzedErrNo(fuzzed_file->m_fuzzed_data_provider);
return fuzzed_file->m_fuzzed_data_provider.ConsumeIntegralInRange<int>(-1, 0);
}
};
diff --git a/src/test/fuzz/validation_load_mempool.cpp b/src/test/fuzz/validation_load_mempool.cpp
new file mode 100644
index 0000000000..e1a21b6c53
--- /dev/null
+++ b/src/test/fuzz/validation_load_mempool.cpp
@@ -0,0 +1,34 @@
+// Copyright (c) 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 <chainparamsbase.h>
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+#include <test/util/setup_common.h>
+#include <txmempool.h>
+#include <util/time.h>
+#include <validation.h>
+
+#include <cstdint>
+#include <vector>
+
+void initialize_validation_load_mempool()
+{
+ static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>();
+}
+
+FUZZ_TARGET_INIT(validation_load_mempool, initialize_validation_load_mempool)
+{
+ FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
+ SetMockTime(ConsumeTime(fuzzed_data_provider));
+ FuzzedFileProvider fuzzed_file_provider = ConsumeFile(fuzzed_data_provider);
+
+ CTxMemPool pool{};
+ auto fuzzed_fopen = [&](const fs::path&, const char*) {
+ return fuzzed_file_provider.open();
+ };
+ (void)LoadMempool(pool, ::ChainstateActive(), fuzzed_fopen);
+ (void)DumpMempool(pool, fuzzed_fopen, true);
+}
diff --git a/src/test/fuzz/versionbits.cpp b/src/test/fuzz/versionbits.cpp
new file mode 100644
index 0000000000..a898e2782d
--- /dev/null
+++ b/src/test/fuzz/versionbits.cpp
@@ -0,0 +1,345 @@
+// Copyright (c) 2020-2021 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 <chain.h>
+#include <chainparams.h>
+#include <consensus/params.h>
+#include <primitives/block.h>
+#include <versionbits.h>
+
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+
+#include <cstdint>
+#include <limits>
+#include <memory>
+#include <vector>
+
+namespace {
+class TestConditionChecker : public AbstractThresholdConditionChecker
+{
+private:
+ mutable ThresholdConditionCache m_cache;
+ const Consensus::Params dummy_params{};
+
+public:
+ const int64_t m_begin = 0;
+ const int64_t m_end = 0;
+ const int m_period = 0;
+ const int m_threshold = 0;
+ const int m_bit = 0;
+
+ TestConditionChecker(int64_t begin, int64_t end, int period, int threshold, int bit)
+ : m_begin{begin}, m_end{end}, m_period{period}, m_threshold{threshold}, m_bit{bit}
+ {
+ assert(m_period > 0);
+ assert(0 <= m_threshold && m_threshold <= m_period);
+ assert(0 <= m_bit && m_bit <= 32 && m_bit < VERSIONBITS_NUM_BITS);
+ }
+
+ bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const override { return Condition(pindex->nVersion); }
+ int64_t BeginTime(const Consensus::Params& params) const override { return m_begin; }
+ int64_t EndTime(const Consensus::Params& params) const override { return m_end; }
+ int Period(const Consensus::Params& params) const override { return m_period; }
+ int Threshold(const Consensus::Params& params) const override { return m_threshold; }
+
+ ThresholdState GetStateFor(const CBlockIndex* pindexPrev) const { return AbstractThresholdConditionChecker::GetStateFor(pindexPrev, dummy_params, m_cache); }
+ int GetStateSinceHeightFor(const CBlockIndex* pindexPrev) const { return AbstractThresholdConditionChecker::GetStateSinceHeightFor(pindexPrev, dummy_params, m_cache); }
+ BIP9Stats GetStateStatisticsFor(const CBlockIndex* pindexPrev) const { return AbstractThresholdConditionChecker::GetStateStatisticsFor(pindexPrev, dummy_params); }
+
+ bool Condition(int64_t version) const
+ {
+ return ((version >> m_bit) & 1) != 0 && (version & VERSIONBITS_TOP_MASK) == VERSIONBITS_TOP_BITS;
+ }
+
+ bool Condition(const CBlockIndex* pindex) const { return Condition(pindex->nVersion); }
+};
+
+/** Track blocks mined for test */
+class Blocks
+{
+private:
+ std::vector<std::unique_ptr<CBlockIndex>> m_blocks;
+ const uint32_t m_start_time;
+ const uint32_t m_interval;
+ const int32_t m_signal;
+ const int32_t m_no_signal;
+
+public:
+ Blocks(uint32_t start_time, uint32_t interval, int32_t signal, int32_t no_signal)
+ : m_start_time{start_time}, m_interval{interval}, m_signal{signal}, m_no_signal{no_signal} {}
+
+ size_t size() const { return m_blocks.size(); }
+
+ CBlockIndex* tip() const
+ {
+ return m_blocks.empty() ? nullptr : m_blocks.back().get();
+ }
+
+ CBlockIndex* mine_block(bool signal)
+ {
+ CBlockHeader header;
+ header.nVersion = signal ? m_signal : m_no_signal;
+ header.nTime = m_start_time + m_blocks.size() * m_interval;
+ header.nBits = 0x1d00ffff;
+
+ auto current_block = std::make_unique<CBlockIndex>(header);
+ current_block->pprev = tip();
+ current_block->nHeight = m_blocks.size();
+ current_block->BuildSkip();
+
+ return m_blocks.emplace_back(std::move(current_block)).get();
+ }
+};
+
+void initialize()
+{
+ SelectParams(CBaseChainParams::MAIN);
+}
+} // namespace
+
+constexpr uint32_t MAX_TIME = 4102444800; // 2100-01-01
+
+FUZZ_TARGET_INIT(versionbits, initialize)
+{
+ const CChainParams& params = Params();
+
+ const int64_t interval = params.GetConsensus().nPowTargetSpacing;
+ assert(interval > 1); // need to be able to halve it
+ assert(interval < std::numeric_limits<int32_t>::max());
+
+ FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
+
+ // making period/max_periods larger slows these tests down significantly
+ const int period = 32;
+ const size_t max_periods = 16;
+ const size_t max_blocks = 2 * period * max_periods;
+
+ const int threshold = fuzzed_data_provider.ConsumeIntegralInRange(1, period);
+ assert(0 < threshold && threshold <= period); // must be able to both pass and fail threshold!
+
+ // too many blocks at 10min each might cause uint32_t time to overflow if
+ // block_start_time is at the end of the range above
+ assert(std::numeric_limits<uint32_t>::max() - MAX_TIME > interval * max_blocks);
+
+ const int64_t block_start_time = fuzzed_data_provider.ConsumeIntegralInRange<uint32_t>(params.GenesisBlock().nTime, MAX_TIME);
+
+ // what values for version will we use to signal / not signal?
+ const int32_t ver_signal = fuzzed_data_provider.ConsumeIntegral<int32_t>();
+ const int32_t ver_nosignal = fuzzed_data_provider.ConsumeIntegral<int32_t>();
+
+ // select deployment parameters: bit, start time, timeout
+ const int bit = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, VERSIONBITS_NUM_BITS - 1);
+
+ bool always_active_test = false;
+ bool never_active_test = false;
+ int64_t start_time;
+ int64_t timeout;
+ if (fuzzed_data_provider.ConsumeBool()) {
+ // pick the timestamp to switch based on a block
+ // note states will change *after* these blocks because mediantime lags
+ int start_block = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, period * (max_periods - 3));
+ int end_block = fuzzed_data_provider.ConsumeIntegralInRange<int>(start_block, period * (max_periods - 3));
+
+ start_time = block_start_time + start_block * interval;
+ timeout = block_start_time + end_block * interval;
+
+ assert(start_time <= timeout);
+
+ // allow for times to not exactly match a block
+ if (fuzzed_data_provider.ConsumeBool()) start_time += interval / 2;
+ if (fuzzed_data_provider.ConsumeBool()) timeout += interval / 2;
+
+ // this may make timeout too early; if so, don't run the test
+ if (start_time > timeout) return;
+ } else {
+ if (fuzzed_data_provider.ConsumeBool()) {
+ start_time = Consensus::BIP9Deployment::ALWAYS_ACTIVE;
+ timeout = Consensus::BIP9Deployment::NO_TIMEOUT;
+ always_active_test = true;
+ } else {
+ start_time = 1199145601; // January 1, 2008
+ timeout = 1230767999; // December 31, 2008
+ never_active_test = true;
+ }
+ }
+
+ TestConditionChecker checker(start_time, timeout, period, threshold, bit);
+
+ // Early exit if the versions don't signal sensibly for the deployment
+ if (!checker.Condition(ver_signal)) return;
+ if (checker.Condition(ver_nosignal)) return;
+ if (ver_nosignal < 0) return;
+
+ // TOP_BITS should ensure version will be positive
+ assert(ver_signal > 0);
+
+ // Now that we have chosen time and versions, setup to mine blocks
+ Blocks blocks(block_start_time, interval, ver_signal, ver_nosignal);
+
+ /* Strategy:
+ * * we will mine a final period worth of blocks, with
+ * randomised signalling according to a mask
+ * * but before we mine those blocks, we will mine some
+ * randomised number of prior periods; with either all
+ * or no blocks in the period signalling
+ *
+ * We establish the mask first, then consume "bools" until
+ * we run out of fuzz data to work out how many prior periods
+ * there are and which ones will signal.
+ */
+
+ // establish the mask
+ const uint32_t signalling_mask = fuzzed_data_provider.ConsumeIntegral<uint32_t>();
+
+ // mine prior periods
+ while (fuzzed_data_provider.remaining_bytes() > 0) {
+ // all blocks in these periods either do or don't signal
+ bool signal = fuzzed_data_provider.ConsumeBool();
+ for (int b = 0; b < period; ++b) {
+ blocks.mine_block(signal);
+ }
+
+ // don't risk exceeding max_blocks or times may wrap around
+ if (blocks.size() + period*2 > max_blocks) break;
+ }
+ // NOTE: fuzzed_data_provider may be fully consumed at this point and should not be used further
+
+ // now we mine the final period and check that everything looks sane
+
+ // count the number of signalling blocks
+ int blocks_sig = 0;
+
+ // get the info for the first block of the period
+ CBlockIndex* prev = blocks.tip();
+ const int exp_since = checker.GetStateSinceHeightFor(prev);
+ const ThresholdState exp_state = checker.GetStateFor(prev);
+ BIP9Stats last_stats = checker.GetStateStatisticsFor(prev);
+
+ int prev_next_height = (prev == nullptr ? 0 : prev->nHeight + 1);
+ assert(exp_since <= prev_next_height);
+
+ // mine (period-1) blocks and check state
+ for (int b = 1; b < period; ++b) {
+ const bool signal = (signalling_mask >> (b % 32)) & 1;
+ if (signal) ++blocks_sig;
+
+ CBlockIndex* current_block = blocks.mine_block(signal);
+
+ // verify that signalling attempt was interpreted correctly
+ assert(checker.Condition(current_block) == signal);
+
+ // state and since don't change within the period
+ const ThresholdState state = checker.GetStateFor(current_block);
+ const int since = checker.GetStateSinceHeightFor(current_block);
+ assert(state == exp_state);
+ assert(since == exp_since);
+
+ // GetStateStatistics may crash when state is not STARTED
+ if (state != ThresholdState::STARTED) continue;
+
+ // check that after mining this block stats change as expected
+ const BIP9Stats stats = checker.GetStateStatisticsFor(current_block);
+ assert(stats.period == period);
+ assert(stats.threshold == threshold);
+ assert(stats.elapsed == b);
+ assert(stats.count == last_stats.count + (signal ? 1 : 0));
+ assert(stats.possible == (stats.count + period >= stats.elapsed + threshold));
+ last_stats = stats;
+ }
+
+ if (exp_state == ThresholdState::STARTED) {
+ // double check that stats.possible is sane
+ if (blocks_sig >= threshold - 1) assert(last_stats.possible);
+ }
+
+ // mine the final block
+ bool signal = (signalling_mask >> (period % 32)) & 1;
+ if (signal) ++blocks_sig;
+ CBlockIndex* current_block = blocks.mine_block(signal);
+ assert(checker.Condition(current_block) == signal);
+
+ // GetStateStatistics is safe on a period boundary
+ // and has progressed to a new period
+ const BIP9Stats stats = checker.GetStateStatisticsFor(current_block);
+ assert(stats.period == period);
+ assert(stats.threshold == threshold);
+ assert(stats.elapsed == 0);
+ assert(stats.count == 0);
+ assert(stats.possible == true);
+
+ // More interesting is whether the state changed.
+ const ThresholdState state = checker.GetStateFor(current_block);
+ const int since = checker.GetStateSinceHeightFor(current_block);
+
+ // since is straightforward:
+ assert(since % period == 0);
+ assert(0 <= since && since <= current_block->nHeight + 1);
+ if (state == exp_state) {
+ assert(since == exp_since);
+ } else {
+ assert(since == current_block->nHeight + 1);
+ }
+
+ // state is where everything interesting is
+ switch (state) {
+ case ThresholdState::DEFINED:
+ assert(since == 0);
+ assert(exp_state == ThresholdState::DEFINED);
+ assert(current_block->GetMedianTimePast() < checker.m_begin);
+ assert(current_block->GetMedianTimePast() < checker.m_end);
+ break;
+ case ThresholdState::STARTED:
+ assert(current_block->GetMedianTimePast() >= checker.m_begin);
+ assert(current_block->GetMedianTimePast() < checker.m_end);
+ if (exp_state == ThresholdState::STARTED) {
+ assert(blocks_sig < threshold);
+ } else {
+ assert(exp_state == ThresholdState::DEFINED);
+ }
+ break;
+ case ThresholdState::LOCKED_IN:
+ assert(exp_state == ThresholdState::STARTED);
+ assert(current_block->GetMedianTimePast() < checker.m_end);
+ assert(blocks_sig >= threshold);
+ break;
+ case ThresholdState::ACTIVE:
+ assert(exp_state == ThresholdState::ACTIVE || exp_state == ThresholdState::LOCKED_IN);
+ break;
+ case ThresholdState::FAILED:
+ assert(current_block->GetMedianTimePast() >= checker.m_end);
+ assert(exp_state != ThresholdState::LOCKED_IN && exp_state != ThresholdState::ACTIVE);
+ break;
+ default:
+ assert(false);
+ }
+
+ if (blocks.size() >= max_periods * period) {
+ // we chose the timeout (and block times) so that by the time we have this many blocks it's all over
+ assert(state == ThresholdState::ACTIVE || state == ThresholdState::FAILED);
+ }
+
+ // "always active" has additional restrictions
+ if (always_active_test) {
+ assert(state == ThresholdState::ACTIVE);
+ assert(exp_state == ThresholdState::ACTIVE);
+ assert(since == 0);
+ } else {
+ // except for always active, the initial state is always DEFINED
+ assert(since > 0 || state == ThresholdState::DEFINED);
+ assert(exp_since > 0 || exp_state == ThresholdState::DEFINED);
+ }
+
+ // "never active" does too
+ if (never_active_test) {
+ assert(state == ThresholdState::FAILED);
+ assert(since == period);
+ if (exp_since == 0) {
+ assert(exp_state == ThresholdState::DEFINED);
+ } else {
+ assert(exp_state == ThresholdState::FAILED);
+ }
+ }
+}
diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp
index 167242a971..c336705d50 100644
--- a/src/test/net_tests.cpp
+++ b/src/test/net_tests.cpp
@@ -8,8 +8,8 @@
#include <clientversion.h>
#include <cstdint>
#include <net.h>
+#include <netaddress.h>
#include <netbase.h>
-#include <optional.h>
#include <serialize.h>
#include <span.h>
#include <streams.h>
@@ -24,6 +24,7 @@
#include <algorithm>
#include <ios>
#include <memory>
+#include <optional>
#include <string>
using namespace std::literals;
@@ -91,7 +92,7 @@ BOOST_FIXTURE_TEST_SUITE(net_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(cnode_listen_port)
{
// test default
- uint16_t port = GetListenPort();
+ uint16_t port{GetListenPort()};
BOOST_CHECK(port == Params().GetDefaultPort());
// test set port
uint16_t altPort = 12345;
@@ -827,7 +828,7 @@ std::vector<NodeEvictionCandidate> GetRandomNodeEvictionCandidates(const int n_c
bool IsEvicted(std::vector<NodeEvictionCandidate> candidates, const std::vector<NodeId>& node_ids, FastRandomContext& random_context)
{
Shuffle(candidates.begin(), candidates.end(), random_context);
- const Optional<NodeId> evicted_node_id = SelectNodeToEvict(std::move(candidates));
+ const std::optional<NodeId> evicted_node_id = SelectNodeToEvict(std::move(candidates));
if (!evicted_node_id) {
return false;
}
diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp
index 66ad7bb5ea..33b56624a8 100644
--- a/src/test/netbase_tests.cpp
+++ b/src/test/netbase_tests.cpp
@@ -3,6 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <net_permissions.h>
+#include <netaddress.h>
#include <netbase.h>
#include <protocol.h>
#include <serialize.h>
@@ -83,31 +84,31 @@ BOOST_AUTO_TEST_CASE(netbase_properties)
}
-bool static TestSplitHost(std::string test, std::string host, int port)
+bool static TestSplitHost(const std::string& test, const std::string& host, uint16_t port)
{
std::string hostOut;
- int portOut = -1;
+ uint16_t portOut{0};
SplitHostPort(test, portOut, hostOut);
return hostOut == host && port == portOut;
}
BOOST_AUTO_TEST_CASE(netbase_splithost)
{
- BOOST_CHECK(TestSplitHost("www.bitcoincore.org", "www.bitcoincore.org", -1));
- BOOST_CHECK(TestSplitHost("[www.bitcoincore.org]", "www.bitcoincore.org", -1));
+ BOOST_CHECK(TestSplitHost("www.bitcoincore.org", "www.bitcoincore.org", 0));
+ BOOST_CHECK(TestSplitHost("[www.bitcoincore.org]", "www.bitcoincore.org", 0));
BOOST_CHECK(TestSplitHost("www.bitcoincore.org:80", "www.bitcoincore.org", 80));
BOOST_CHECK(TestSplitHost("[www.bitcoincore.org]:80", "www.bitcoincore.org", 80));
- BOOST_CHECK(TestSplitHost("127.0.0.1", "127.0.0.1", -1));
+ BOOST_CHECK(TestSplitHost("127.0.0.1", "127.0.0.1", 0));
BOOST_CHECK(TestSplitHost("127.0.0.1:8333", "127.0.0.1", 8333));
- BOOST_CHECK(TestSplitHost("[127.0.0.1]", "127.0.0.1", -1));
+ BOOST_CHECK(TestSplitHost("[127.0.0.1]", "127.0.0.1", 0));
BOOST_CHECK(TestSplitHost("[127.0.0.1]:8333", "127.0.0.1", 8333));
- BOOST_CHECK(TestSplitHost("::ffff:127.0.0.1", "::ffff:127.0.0.1", -1));
+ BOOST_CHECK(TestSplitHost("::ffff:127.0.0.1", "::ffff:127.0.0.1", 0));
BOOST_CHECK(TestSplitHost("[::ffff:127.0.0.1]:8333", "::ffff:127.0.0.1", 8333));
BOOST_CHECK(TestSplitHost("[::]:8333", "::", 8333));
- BOOST_CHECK(TestSplitHost("::8333", "::8333", -1));
+ BOOST_CHECK(TestSplitHost("::8333", "::8333", 0));
BOOST_CHECK(TestSplitHost(":8333", "", 8333));
BOOST_CHECK(TestSplitHost("[]:8333", "", 8333));
- BOOST_CHECK(TestSplitHost("", "", -1));
+ BOOST_CHECK(TestSplitHost("", "", 0));
}
bool static TestParse(std::string src, std::string canon)
diff --git a/src/test/sanity_tests.cpp b/src/test/sanity_tests.cpp
index 3e4b963fe3..496292875d 100644
--- a/src/test/sanity_tests.cpp
+++ b/src/test/sanity_tests.cpp
@@ -13,7 +13,6 @@ BOOST_FIXTURE_TEST_SUITE(sanity_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(basic_sanity)
{
- BOOST_CHECK_MESSAGE(glibc_sanity_test() == true, "libc sanity test");
BOOST_CHECK_MESSAGE(glibcxx_sanity_test() == true, "stdlib sanity test");
BOOST_CHECK_MESSAGE(ECC_InitSanityCheck() == true, "secp256k1 sanity test");
BOOST_CHECK_MESSAGE(ChronoSanityCheck() == true, "chrono epoch test");
diff --git a/src/test/sock_tests.cpp b/src/test/sock_tests.cpp
index ed9780dfb5..400de875b7 100644
--- a/src/test/sock_tests.cpp
+++ b/src/test/sock_tests.cpp
@@ -4,11 +4,13 @@
#include <compat.h>
#include <test/util/setup_common.h>
+#include <threadinterrupt.h>
#include <util/sock.h>
#include <util/system.h>
#include <boost/test/unit_test.hpp>
+#include <cassert>
#include <thread>
using namespace std::chrono_literals;
@@ -144,6 +146,35 @@ BOOST_AUTO_TEST_CASE(wait)
waiter.join();
}
+BOOST_AUTO_TEST_CASE(recv_until_terminator_limit)
+{
+ constexpr auto timeout = 1min; // High enough so that it is never hit.
+ CThreadInterrupt interrupt;
+ int s[2];
+ CreateSocketPair(s);
+
+ Sock sock_send(s[0]);
+ Sock sock_recv(s[1]);
+
+ std::thread receiver([&sock_recv, &timeout, &interrupt]() {
+ constexpr size_t max_data{10};
+ bool threw_as_expected{false};
+ // BOOST_CHECK_EXCEPTION() writes to some variables shared with the main thread which
+ // creates a data race. So mimic it manually.
+ try {
+ sock_recv.RecvUntilTerminator('\n', timeout, interrupt, max_data);
+ } catch (const std::runtime_error& e) {
+ threw_as_expected = HasReason("too many bytes without a terminator")(e);
+ }
+ assert(threw_as_expected);
+ });
+
+ BOOST_REQUIRE_NO_THROW(sock_send.SendComplete("1234567", timeout, interrupt));
+ BOOST_REQUIRE_NO_THROW(sock_send.SendComplete("89a\n", timeout, interrupt));
+
+ receiver.join();
+}
+
#endif /* WIN32 */
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index b742fcaf0b..5ac09b05db 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -7,7 +7,6 @@
#include <clientversion.h>
#include <hash.h> // For Hash()
#include <key.h> // For CKey
-#include <optional.h>
#include <sync.h>
#include <test/util/logging.h>
#include <test/util/setup_common.h>
@@ -23,6 +22,7 @@
#include <util/vector.h>
#include <array>
+#include <optional>
#include <stdint.h>
#include <string.h>
#include <thread>
@@ -38,6 +38,7 @@
#include <boost/test/unit_test.hpp>
using namespace std::literals;
+static const std::string STRING_WITH_EMBEDDED_NULL_CHAR{"1"s "\0" "1"s};
/* defined in logging.cpp */
namespace BCLog {
@@ -76,6 +77,9 @@ BOOST_AUTO_TEST_CASE(util_check)
const int two = *Assert(p_two);
Assert(two == 2);
Assert(true);
+ // Check that Assume can be used as unary expression
+ const bool result{Assume(two == 2)};
+ Assert(result);
}
BOOST_AUTO_TEST_CASE(util_criticalsection)
@@ -227,9 +231,9 @@ public:
bool default_int = false;
bool default_bool = false;
const char* string_value = nullptr;
- Optional<int64_t> int_value;
- Optional<bool> bool_value;
- Optional<std::vector<std::string>> list_value;
+ std::optional<int64_t> int_value;
+ std::optional<bool> bool_value;
+ std::optional<std::vector<std::string>> list_value;
const char* error = nullptr;
explicit Expect(util::SettingsValue s) : setting(std::move(s)) {}
@@ -1272,7 +1276,7 @@ BOOST_AUTO_TEST_CASE(util_ParseMoney)
// Parsing strings with embedded NUL characters should fail
BOOST_CHECK(!ParseMoney("\0-1"s, ret));
- BOOST_CHECK(!ParseMoney("\0" "1"s, ret));
+ BOOST_CHECK(!ParseMoney(STRING_WITH_EMBEDDED_NULL_CHAR, ret));
BOOST_CHECK(!ParseMoney("1\0"s, ret));
}
@@ -1449,10 +1453,7 @@ BOOST_AUTO_TEST_CASE(test_ParseInt32)
BOOST_CHECK(!ParseInt32("1a", &n));
BOOST_CHECK(!ParseInt32("aap", &n));
BOOST_CHECK(!ParseInt32("0x1", &n)); // no hex
- BOOST_CHECK(!ParseInt32("0x1", &n)); // no hex
- const char test_bytes[] = {'1', 0, '1'};
- std::string teststr(test_bytes, sizeof(test_bytes));
- BOOST_CHECK(!ParseInt32(teststr, &n)); // no embedded NULs
+ BOOST_CHECK(!ParseInt32(STRING_WITH_EMBEDDED_NULL_CHAR, &n));
// Overflow and underflow
BOOST_CHECK(!ParseInt32("-2147483649", nullptr));
BOOST_CHECK(!ParseInt32("2147483648", nullptr));
@@ -1480,9 +1481,7 @@ BOOST_AUTO_TEST_CASE(test_ParseInt64)
BOOST_CHECK(!ParseInt64("1a", &n));
BOOST_CHECK(!ParseInt64("aap", &n));
BOOST_CHECK(!ParseInt64("0x1", &n)); // no hex
- const char test_bytes[] = {'1', 0, '1'};
- std::string teststr(test_bytes, sizeof(test_bytes));
- BOOST_CHECK(!ParseInt64(teststr, &n)); // no embedded NULs
+ BOOST_CHECK(!ParseInt64(STRING_WITH_EMBEDDED_NULL_CHAR, &n));
// Overflow and underflow
BOOST_CHECK(!ParseInt64("-9223372036854775809", nullptr));
BOOST_CHECK(!ParseInt64("9223372036854775808", nullptr));
@@ -1490,6 +1489,76 @@ BOOST_AUTO_TEST_CASE(test_ParseInt64)
BOOST_CHECK(!ParseInt64("32482348723847471234", nullptr));
}
+BOOST_AUTO_TEST_CASE(test_ParseUInt8)
+{
+ uint8_t n;
+ // Valid values
+ BOOST_CHECK(ParseUInt8("255", nullptr));
+ BOOST_CHECK(ParseUInt8("0", &n) && n == 0);
+ BOOST_CHECK(ParseUInt8("255", &n) && n == 255);
+ BOOST_CHECK(ParseUInt8("0255", &n) && n == 255); // no octal
+ BOOST_CHECK(ParseUInt8("255", &n) && n == static_cast<uint8_t>(255));
+ BOOST_CHECK(ParseUInt8("+255", &n) && n == 255);
+ BOOST_CHECK(ParseUInt8("00000000000000000012", &n) && n == 12);
+ BOOST_CHECK(ParseUInt8("00000000000000000000", &n) && n == 0);
+ // Invalid values
+ BOOST_CHECK(!ParseUInt8("-00000000000000000000", &n));
+ BOOST_CHECK(!ParseUInt8("", &n));
+ BOOST_CHECK(!ParseUInt8(" 1", &n)); // no padding inside
+ BOOST_CHECK(!ParseUInt8(" -1", &n));
+ BOOST_CHECK(!ParseUInt8("++1", &n));
+ BOOST_CHECK(!ParseUInt8("+-1", &n));
+ BOOST_CHECK(!ParseUInt8("-+1", &n));
+ BOOST_CHECK(!ParseUInt8("--1", &n));
+ BOOST_CHECK(!ParseUInt8("-1", &n));
+ BOOST_CHECK(!ParseUInt8("1 ", &n));
+ BOOST_CHECK(!ParseUInt8("1a", &n));
+ BOOST_CHECK(!ParseUInt8("aap", &n));
+ BOOST_CHECK(!ParseUInt8("0x1", &n)); // no hex
+ BOOST_CHECK(!ParseUInt8(STRING_WITH_EMBEDDED_NULL_CHAR, &n));
+ // Overflow and underflow
+ BOOST_CHECK(!ParseUInt8("-255", &n));
+ BOOST_CHECK(!ParseUInt8("256", &n));
+ BOOST_CHECK(!ParseUInt8("-123", &n));
+ BOOST_CHECK(!ParseUInt8("-123", nullptr));
+ BOOST_CHECK(!ParseUInt8("256", nullptr));
+}
+
+BOOST_AUTO_TEST_CASE(test_ParseUInt16)
+{
+ uint16_t n;
+ // Valid values
+ BOOST_CHECK(ParseUInt16("1234", nullptr));
+ BOOST_CHECK(ParseUInt16("0", &n) && n == 0);
+ BOOST_CHECK(ParseUInt16("1234", &n) && n == 1234);
+ BOOST_CHECK(ParseUInt16("01234", &n) && n == 1234); // no octal
+ BOOST_CHECK(ParseUInt16("65535", &n) && n == static_cast<uint16_t>(65535));
+ BOOST_CHECK(ParseUInt16("+65535", &n) && n == 65535);
+ BOOST_CHECK(ParseUInt16("00000000000000000012", &n) && n == 12);
+ BOOST_CHECK(ParseUInt16("00000000000000000000", &n) && n == 0);
+ // Invalid values
+ BOOST_CHECK(!ParseUInt16("-00000000000000000000", &n));
+ BOOST_CHECK(!ParseUInt16("", &n));
+ BOOST_CHECK(!ParseUInt16(" 1", &n)); // no padding inside
+ BOOST_CHECK(!ParseUInt16(" -1", &n));
+ BOOST_CHECK(!ParseUInt16("++1", &n));
+ BOOST_CHECK(!ParseUInt16("+-1", &n));
+ BOOST_CHECK(!ParseUInt16("-+1", &n));
+ BOOST_CHECK(!ParseUInt16("--1", &n));
+ BOOST_CHECK(!ParseUInt16("-1", &n));
+ BOOST_CHECK(!ParseUInt16("1 ", &n));
+ BOOST_CHECK(!ParseUInt16("1a", &n));
+ BOOST_CHECK(!ParseUInt16("aap", &n));
+ BOOST_CHECK(!ParseUInt16("0x1", &n)); // no hex
+ BOOST_CHECK(!ParseUInt16(STRING_WITH_EMBEDDED_NULL_CHAR, &n));
+ // Overflow and underflow
+ BOOST_CHECK(!ParseUInt16("-65535", &n));
+ BOOST_CHECK(!ParseUInt16("65536", &n));
+ BOOST_CHECK(!ParseUInt16("-123", &n));
+ BOOST_CHECK(!ParseUInt16("-123", nullptr));
+ BOOST_CHECK(!ParseUInt16("65536", nullptr));
+}
+
BOOST_AUTO_TEST_CASE(test_ParseUInt32)
{
uint32_t n;
@@ -1518,10 +1587,7 @@ BOOST_AUTO_TEST_CASE(test_ParseUInt32)
BOOST_CHECK(!ParseUInt32("1a", &n));
BOOST_CHECK(!ParseUInt32("aap", &n));
BOOST_CHECK(!ParseUInt32("0x1", &n)); // no hex
- BOOST_CHECK(!ParseUInt32("0x1", &n)); // no hex
- const char test_bytes[] = {'1', 0, '1'};
- std::string teststr(test_bytes, sizeof(test_bytes));
- BOOST_CHECK(!ParseUInt32(teststr, &n)); // no embedded NULs
+ BOOST_CHECK(!ParseUInt32(STRING_WITH_EMBEDDED_NULL_CHAR, &n));
// Overflow and underflow
BOOST_CHECK(!ParseUInt32("-2147483648", &n));
BOOST_CHECK(!ParseUInt32("4294967296", &n));
@@ -1550,9 +1616,7 @@ BOOST_AUTO_TEST_CASE(test_ParseUInt64)
BOOST_CHECK(!ParseUInt64("1a", &n));
BOOST_CHECK(!ParseUInt64("aap", &n));
BOOST_CHECK(!ParseUInt64("0x1", &n)); // no hex
- const char test_bytes[] = {'1', 0, '1'};
- std::string teststr(test_bytes, sizeof(test_bytes));
- BOOST_CHECK(!ParseUInt64(teststr, &n)); // no embedded NULs
+ BOOST_CHECK(!ParseUInt64(STRING_WITH_EMBEDDED_NULL_CHAR, &n));
// Overflow and underflow
BOOST_CHECK(!ParseUInt64("-9223372036854775809", nullptr));
BOOST_CHECK(!ParseUInt64("18446744073709551616", nullptr));
@@ -1582,9 +1646,7 @@ BOOST_AUTO_TEST_CASE(test_ParseDouble)
BOOST_CHECK(!ParseDouble("1a", &n));
BOOST_CHECK(!ParseDouble("aap", &n));
BOOST_CHECK(!ParseDouble("0x1", &n)); // no hex
- const char test_bytes[] = {'1', 0, '1'};
- std::string teststr(test_bytes, sizeof(test_bytes));
- BOOST_CHECK(!ParseDouble(teststr, &n)); // no embedded NULs
+ BOOST_CHECK(!ParseDouble(STRING_WITH_EMBEDDED_NULL_CHAR, &n));
// Overflow and underflow
BOOST_CHECK(!ParseDouble("-1e10000", nullptr));
BOOST_CHECK(!ParseDouble("1e10000", nullptr));
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index f10b4ad740..67549fc13d 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -8,7 +8,6 @@
#include <consensus/consensus.h>
#include <consensus/tx_verify.h>
#include <consensus/validation.h>
-#include <optional.h>
#include <policy/fees.h>
#include <policy/policy.h>
#include <policy/settings.h>
@@ -19,6 +18,8 @@
#include <validation.h>
#include <validationinterface.h>
+#include <optional>
+
CTxMemPoolEntry::CTxMemPoolEntry(const CTransactionRef& _tx, const CAmount& _nFee,
int64_t _nTime, unsigned int _entryHeight,
bool _spendsCoinbase, int64_t _sigOpsCost, LockPoints lp)
@@ -159,7 +160,7 @@ bool CTxMemPool::CalculateMemPoolAncestors(const CTxMemPoolEntry &entry, setEntr
// GetMemPoolParents() is only valid for entries in the mempool, so we
// iterate mapTx to find parents.
for (unsigned int i = 0; i < tx.vin.size(); i++) {
- Optional<txiter> piter = GetIter(tx.vin[i].prevout.hash);
+ std::optional<txiter> piter = GetIter(tx.vin[i].prevout.hash);
if (piter) {
staged_ancestors.insert(**piter);
if (staged_ancestors.size() + 1 > limitAncestorCount) {
@@ -890,11 +891,11 @@ const CTransaction* CTxMemPool::GetConflictTx(const COutPoint& prevout) const
return it == mapNextTx.end() ? nullptr : it->second;
}
-Optional<CTxMemPool::txiter> CTxMemPool::GetIter(const uint256& txid) const
+std::optional<CTxMemPool::txiter> CTxMemPool::GetIter(const uint256& txid) const
{
auto it = mapTx.find(txid);
if (it != mapTx.end()) return it;
- return Optional<txiter>{};
+ return std::nullopt;
}
CTxMemPool::setEntries CTxMemPool::GetIterSet(const std::set<uint256>& hashes) const
diff --git a/src/txmempool.h b/src/txmempool.h
index 8a96294192..c3a9bd851d 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -8,6 +8,7 @@
#include <atomic>
#include <map>
+#include <optional>
#include <set>
#include <string>
#include <utility>
@@ -16,7 +17,6 @@
#include <amount.h>
#include <coins.h>
#include <indirectmap.h>
-#include <optional.h>
#include <policy/feerate.h>
#include <primitives/transaction.h>
#include <random.h>
@@ -476,7 +476,7 @@ enum class MemPoolRemovalReason {
*/
class CTxMemPool
{
-private:
+protected:
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;
@@ -644,7 +644,7 @@ public:
const CTransaction* GetConflictTx(const COutPoint& prevout) const EXCLUSIVE_LOCKS_REQUIRED(cs);
/** Returns an iterator to the given hash, if found */
- Optional<txiter> GetIter(const uint256& txid) const EXCLUSIVE_LOCKS_REQUIRED(cs);
+ std::optional<txiter> GetIter(const uint256& txid) const EXCLUSIVE_LOCKS_REQUIRED(cs);
/** Translate a set of hashes into a set of pool iterators to avoid repeated lookups */
setEntries GetIterSet(const std::set<uint256>& hashes) const EXCLUSIVE_LOCKS_REQUIRED(cs);
@@ -841,7 +841,7 @@ public:
return m_epoch.visited(it->m_epoch_marker);
}
- bool visited(Optional<txiter> it) const EXCLUSIVE_LOCKS_REQUIRED(cs, m_epoch)
+ bool visited(std::optional<txiter> it) const EXCLUSIVE_LOCKS_REQUIRED(cs, m_epoch)
{
assert(m_epoch.guarded()); // verify guard even when it==nullopt
return !it || visited(*it);
diff --git a/src/util/check.h b/src/util/check.h
index bc62da3440..e60088a2c6 100644
--- a/src/util/check.h
+++ b/src/util/check.h
@@ -69,7 +69,7 @@ T get_pure_r_value(T&& val)
#ifdef ABORT_ON_FAILED_ASSUME
#define Assume(val) Assert(val)
#else
-#define Assume(val) ((void)(val))
+#define Assume(val) ([&]() -> decltype(get_pure_r_value(val)) { auto&& check = (val); return std::forward<decltype(get_pure_r_value(val))>(check); }())
#endif
#endif // BITCOIN_UTIL_CHECK_H
diff --git a/src/util/sock.cpp b/src/util/sock.cpp
index e13c52a16a..f9ecfef5d4 100644
--- a/src/util/sock.cpp
+++ b/src/util/sock.cpp
@@ -175,7 +175,8 @@ void Sock::SendComplete(const std::string& data,
std::string Sock::RecvUntilTerminator(uint8_t terminator,
std::chrono::milliseconds timeout,
- CThreadInterrupt& interrupt) const
+ CThreadInterrupt& interrupt,
+ size_t max_data) const
{
const auto deadline = GetTime<std::chrono::milliseconds>() + timeout;
std::string data;
@@ -190,9 +191,14 @@ std::string Sock::RecvUntilTerminator(uint8_t terminator,
// at a time is about 50 times slower.
for (;;) {
+ if (data.size() >= max_data) {
+ throw std::runtime_error(
+ strprintf("Received too many bytes without a terminator (%u)", data.size()));
+ }
+
char buf[512];
- const ssize_t peek_ret{Recv(buf, sizeof(buf), MSG_PEEK)};
+ const ssize_t peek_ret{Recv(buf, std::min(sizeof(buf), max_data - data.size()), MSG_PEEK)};
switch (peek_ret) {
case -1: {
diff --git a/src/util/sock.h b/src/util/sock.h
index ecebb84205..4b0618dcff 100644
--- a/src/util/sock.h
+++ b/src/util/sock.h
@@ -135,13 +135,16 @@ public:
* @param[in] terminator Character up to which to read from the socket.
* @param[in] timeout Timeout for the entire operation.
* @param[in] interrupt If this is signaled then the operation is canceled.
+ * @param[in] max_data The maximum amount of data (in bytes) to receive. If this many bytes
+ * are received and there is still no terminator, then this method will throw an exception.
* @return The data that has been read, without the terminating character.
* @throws std::runtime_error if the operation cannot be completed. In this case some bytes may
* have been consumed from the socket.
*/
virtual std::string RecvUntilTerminator(uint8_t terminator,
std::chrono::milliseconds timeout,
- CThreadInterrupt& interrupt) const;
+ CThreadInterrupt& interrupt,
+ size_t max_data) const;
/**
* Check if still connected.
diff --git a/src/util/strencodings.cpp b/src/util/strencodings.cpp
index f3d54a2ac9..4734de3e0b 100644
--- a/src/util/strencodings.cpp
+++ b/src/util/strencodings.cpp
@@ -107,23 +107,25 @@ std::vector<unsigned char> ParseHex(const std::string& str)
return ParseHex(str.c_str());
}
-void SplitHostPort(std::string in, int &portOut, std::string &hostOut) {
+void SplitHostPort(std::string in, uint16_t& portOut, std::string& hostOut)
+{
size_t colon = in.find_last_of(':');
// if a : is found, and it either follows a [...], or no other : is in the string, treat it as port separator
bool fHaveColon = colon != in.npos;
- bool fBracketed = fHaveColon && (in[0]=='[' && in[colon-1]==']'); // if there is a colon, and in[0]=='[', colon is not 0, so in[colon-1] is safe
- bool fMultiColon = fHaveColon && (in.find_last_of(':',colon-1) != in.npos);
- if (fHaveColon && (colon==0 || fBracketed || !fMultiColon)) {
- int32_t n;
- if (ParseInt32(in.substr(colon + 1), &n) && n > 0 && n < 0x10000) {
+ bool fBracketed = fHaveColon && (in[0] == '[' && in[colon - 1] == ']'); // if there is a colon, and in[0]=='[', colon is not 0, so in[colon-1] is safe
+ bool fMultiColon = fHaveColon && (in.find_last_of(':', colon - 1) != in.npos);
+ if (fHaveColon && (colon == 0 || fBracketed || !fMultiColon)) {
+ uint16_t n;
+ if (ParseUInt16(in.substr(colon + 1), &n)) {
in = in.substr(0, colon);
portOut = n;
}
}
- if (in.size()>0 && in[0] == '[' && in[in.size()-1] == ']')
- hostOut = in.substr(1, in.size()-2);
- else
+ if (in.size() > 0 && in[0] == '[' && in[in.size() - 1] == ']') {
+ hostOut = in.substr(1, in.size() - 2);
+ } else {
hostOut = in;
+ }
}
std::string EncodeBase64(Span<const unsigned char> input)
@@ -334,6 +336,18 @@ bool ParseUInt8(const std::string& str, uint8_t *out)
return true;
}
+bool ParseUInt16(const std::string& str, uint16_t* out)
+{
+ uint32_t u32;
+ if (!ParseUInt32(str, &u32) || u32 > std::numeric_limits<uint16_t>::max()) {
+ return false;
+ }
+ if (out != nullptr) {
+ *out = static_cast<uint16_t>(u32);
+ }
+ return true;
+}
+
bool ParseUInt32(const std::string& str, uint32_t *out)
{
if (!ParsePrechecks(str))
diff --git a/src/util/strencodings.h b/src/util/strencodings.h
index 98379e9138..26dc0a0ce3 100644
--- a/src/util/strencodings.h
+++ b/src/util/strencodings.h
@@ -65,7 +65,7 @@ std::string EncodeBase32(Span<const unsigned char> input, bool pad = true);
*/
std::string EncodeBase32(const std::string& str, bool pad = true);
-void SplitHostPort(std::string in, int& portOut, std::string& hostOut);
+void SplitHostPort(std::string in, uint16_t& portOut, std::string& hostOut);
int64_t atoi64(const std::string& str);
int atoi(const std::string& str);
@@ -116,6 +116,13 @@ constexpr inline bool IsSpace(char c) noexcept {
[[nodiscard]] bool ParseUInt8(const std::string& str, uint8_t *out);
/**
+ * Convert decimal string to unsigned 16-bit integer with strict parse error feedback.
+ * @returns true if the entire string could be parsed as valid integer,
+ * false if the entire string could not be parsed or if overflow or underflow occurred.
+ */
+[[nodiscard]] bool ParseUInt16(const std::string& str, uint16_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.
diff --git a/src/util/system.cpp b/src/util/system.cpp
index 63b3c52ee5..0b83a76504 100644
--- a/src/util/system.cpp
+++ b/src/util/system.cpp
@@ -315,7 +315,7 @@ bool ArgsManager::ParseParameters(int argc, const char* const argv[], std::strin
if (key[0] != '-') {
if (!m_accept_any_command && m_command.empty()) {
// The first non-dash arg is a registered command
- Optional<unsigned int> flags = GetArgFlags(key);
+ std::optional<unsigned int> flags = GetArgFlags(key);
if (!flags || !(*flags & ArgsManager::COMMAND)) {
error = strprintf("Invalid command '%s'", argv[i]);
return false;
@@ -337,7 +337,7 @@ bool ArgsManager::ParseParameters(int argc, const char* const argv[], std::strin
key.erase(0, 1);
std::string section;
util::SettingsValue value = InterpretOption(section, key, val);
- Optional<unsigned int> flags = GetArgFlags('-' + key);
+ std::optional<unsigned int> flags = GetArgFlags('-' + key);
// Unknown command line options and command line options with dot
// characters (which are returned from InterpretOption with nonempty
@@ -363,7 +363,7 @@ bool ArgsManager::ParseParameters(int argc, const char* const argv[], std::strin
return success;
}
-Optional<unsigned int> ArgsManager::GetArgFlags(const std::string& name) const
+std::optional<unsigned int> ArgsManager::GetArgFlags(const std::string& name) const
{
LOCK(cs_args);
for (const auto& arg_map : m_available_args) {
@@ -372,7 +372,7 @@ Optional<unsigned int> ArgsManager::GetArgFlags(const std::string& name) const
return search->second.m_flags;
}
}
- return nullopt;
+ return std::nullopt;
}
std::optional<const ArgsManager::Command> ArgsManager::GetCommand() const
@@ -874,7 +874,7 @@ bool ArgsManager::ReadConfigStream(std::istream& stream, const std::string& file
std::string section;
std::string key = option.first;
util::SettingsValue value = InterpretOption(section, key, option.second);
- Optional<unsigned int> flags = GetArgFlags('-' + key);
+ std::optional<unsigned int> flags = GetArgFlags('-' + key);
if (flags) {
if (!CheckValid(key, value, *flags, error)) {
return false;
@@ -1034,7 +1034,7 @@ void ArgsManager::logArgsPrefix(
std::string section_str = section.empty() ? "" : "[" + section + "] ";
for (const auto& arg : args) {
for (const auto& value : arg.second) {
- Optional<unsigned int> flags = GetArgFlags('-' + arg.first);
+ std::optional<unsigned int> flags = GetArgFlags('-' + arg.first);
if (flags) {
std::string value_str = (*flags & SENSITIVE) ? "****" : value.write();
LogPrintf("%s %s%s=%s\n", prefix, section_str, arg.first, value_str);
diff --git a/src/util/system.h b/src/util/system.h
index 30b8cb1c68..291f3f5541 100644
--- a/src/util/system.h
+++ b/src/util/system.h
@@ -19,7 +19,6 @@
#include <compat/assumptions.h>
#include <fs.h>
#include <logging.h>
-#include <optional.h>
#include <sync.h>
#include <tinyformat.h>
#include <util/settings.h>
@@ -28,6 +27,7 @@
#include <exception>
#include <map>
+#include <optional>
#include <set>
#include <stdint.h>
#include <string>
@@ -375,7 +375,7 @@ public:
* Return Flags for known arg.
* Return nullopt for unknown arg.
*/
- Optional<unsigned int> GetArgFlags(const std::string& name) const;
+ std::optional<unsigned int> GetArgFlags(const std::string& name) const;
/**
* Read and update settings file with saved settings. This needs to be
diff --git a/src/util/tokenpipe.cpp b/src/util/tokenpipe.cpp
index 79465dd430..4c091cd2e6 100644
--- a/src/util/tokenpipe.cpp
+++ b/src/util/tokenpipe.cpp
@@ -9,6 +9,7 @@
#include <errno.h>
#include <fcntl.h>
+#include <optional>
#include <unistd.h>
TokenPipeEnd TokenPipe::TakeReadEnd()
diff --git a/src/validation.cpp b/src/validation.cpp
index be0be904e9..d1b9efe7ba 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -23,7 +23,6 @@
#include <logging/timer.h>
#include <node/coinstats.h>
#include <node/ui_interface.h>
-#include <optional.h>
#include <policy/policy.h>
#include <policy/settings.h>
#include <pow.h>
@@ -50,6 +49,7 @@
#include <validationinterface.h>
#include <warnings.h>
+#include <optional>
#include <string>
#include <boost/algorithm/string/replace.hpp>
@@ -2974,6 +2974,10 @@ bool CChainState::PreciousBlock(BlockValidationState& state, const CChainParams&
bool CChainState::InvalidateBlock(BlockValidationState& state, const CChainParams& chainparams, CBlockIndex *pindex)
{
+ // Genesis block can't be invalidated
+ assert(pindex);
+ if (pindex->nHeight == 0) return false;
+
CBlockIndex* to_mark_failed = pindex;
bool pindex_was_in_chain = false;
int disconnected = 0;
@@ -5010,11 +5014,11 @@ CBlockFileInfo* GetBlockFileInfo(size_t n)
static const uint64_t MEMPOOL_DUMP_VERSION = 1;
-bool LoadMempool(CTxMemPool& pool, CChainState& active_chainstate)
+bool LoadMempool(CTxMemPool& pool, CChainState& active_chainstate, FopenFn mockable_fopen_function)
{
const CChainParams& chainparams = Params();
int64_t nExpiryTimeout = gArgs.GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60;
- FILE* filestr = fsbridge::fopen(GetDataDir() / "mempool.dat", "rb");
+ FILE* filestr{mockable_fopen_function(GetDataDir() / "mempool.dat", "rb")};
CAutoFile file(filestr, SER_DISK, CLIENT_VERSION);
if (file.IsNull()) {
LogPrintf("Failed to open mempool file from disk. Continuing anyway.\n");
@@ -5095,7 +5099,7 @@ bool LoadMempool(CTxMemPool& pool, CChainState& active_chainstate)
return true;
}
-bool DumpMempool(const CTxMemPool& pool)
+bool DumpMempool(const CTxMemPool& pool, FopenFn mockable_fopen_function, bool skip_file_commit)
{
int64_t start = GetTimeMicros();
@@ -5118,7 +5122,7 @@ bool DumpMempool(const CTxMemPool& pool)
int64_t mid = GetTimeMicros();
try {
- FILE* filestr = fsbridge::fopen(GetDataDir() / "mempool.dat.new", "wb");
+ FILE* filestr{mockable_fopen_function(GetDataDir() / "mempool.dat.new", "wb")};
if (!filestr) {
return false;
}
@@ -5141,7 +5145,7 @@ bool DumpMempool(const CTxMemPool& pool)
LogPrintf("Writing %d unbroadcast transactions to disk.\n", unbroadcast_txids.size());
file << unbroadcast_txids;
- if (!FileCommit(file.Get()))
+ if (!skip_file_commit && !FileCommit(file.Get()))
throw std::runtime_error("FileCommit failed");
file.fclose();
if (!RenameOver(GetDataDir() / "mempool.dat.new", GetDataDir() / "mempool.dat")) {
@@ -5175,14 +5179,14 @@ double GuessVerificationProgress(const ChainTxData& data, const CBlockIndex *pin
return std::min<double>(pindex->nChainTx / fTxTotal, 1.0);
}
-Optional<uint256> ChainstateManager::SnapshotBlockhash() const {
+std::optional<uint256> ChainstateManager::SnapshotBlockhash() const {
LOCK(::cs_main);
if (m_active_chainstate != nullptr &&
!m_active_chainstate->m_from_snapshot_blockhash.IsNull()) {
// If a snapshot chainstate exists, it will always be our active.
return m_active_chainstate->m_from_snapshot_blockhash;
}
- return {};
+ return std::nullopt;
}
std::vector<CChainState*> ChainstateManager::GetAll()
diff --git a/src/validation.h b/src/validation.h
index 512b306219..2ff5f4ac87 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -17,7 +17,6 @@
#include <crypto/common.h> // for ReadLE64
#include <fs.h>
#include <node/utxo_snapshot.h>
-#include <optional.h>
#include <policy/feerate.h>
#include <protocol.h> // For CMessageHeader::MessageStartChars
#include <script/script_error.h>
@@ -32,6 +31,7 @@
#include <atomic>
#include <map>
#include <memory>
+#include <optional>
#include <set>
#include <stdint.h>
#include <string>
@@ -205,8 +205,7 @@ struct MempoolAcceptResult {
/** Constructor for failure case */
explicit MempoolAcceptResult(TxValidationState state)
- : m_result_type(ResultType::INVALID),
- m_state(state), m_replaced_transactions(nullopt), m_base_fees(nullopt) {
+ : m_result_type(ResultType::INVALID), m_state(state) {
Assume(!state.IsValid()); // Can be invalid or error
}
@@ -924,7 +923,7 @@ public:
bool IsSnapshotActive() const;
- Optional<uint256> SnapshotBlockhash() const;
+ std::optional<uint256> SnapshotBlockhash() const;
//! Is there a snapshot in use and has it been fully validated?
bool IsSnapshotValidated() const { return m_snapshot_validated; }
@@ -1013,11 +1012,13 @@ int32_t ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Para
/** Get block file info entry for one block file */
CBlockFileInfo* GetBlockFileInfo(size_t n);
+using FopenFn = std::function<FILE*(const fs::path&, const char*)>;
+
/** Dump the mempool to disk. */
-bool DumpMempool(const CTxMemPool& pool);
+bool DumpMempool(const CTxMemPool& pool, FopenFn mockable_fopen_function = fsbridge::fopen, bool skip_file_commit = false);
/** Load the mempool from disk. */
-bool LoadMempool(CTxMemPool& pool, CChainState& active_chainstate);
+bool LoadMempool(CTxMemPool& pool, CChainState& active_chainstate, FopenFn mockable_fopen_function = fsbridge::fopen);
//! Check whether the block associated with this index entry is pruned or not.
inline bool IsBlockPruned(const CBlockIndex* pblockindex)
diff --git a/src/wallet/coincontrol.h b/src/wallet/coincontrol.h
index c499b0ff25..d25a3fb3fa 100644
--- a/src/wallet/coincontrol.h
+++ b/src/wallet/coincontrol.h
@@ -5,13 +5,14 @@
#ifndef BITCOIN_WALLET_COINCONTROL_H
#define BITCOIN_WALLET_COINCONTROL_H
-#include <optional.h>
#include <outputtype.h>
#include <policy/feerate.h>
#include <policy/fees.h>
#include <primitives/transaction.h>
#include <script/standard.h>
+#include <optional>
+
const int DEFAULT_MIN_DEPTH = 0;
const int DEFAULT_MAX_DEPTH = 9999999;
@@ -25,7 +26,7 @@ public:
//! Custom change destination, if not set an address is generated
CTxDestination destChange;
//! Override the default change type if set, ignored if destChange is set
- Optional<OutputType> m_change_type;
+ std::optional<OutputType> m_change_type;
//! If false, only selected inputs are used
bool m_add_inputs;
//! If false, allows unselected inputs, but requires all selected inputs be used
@@ -35,11 +36,11 @@ public:
//! Override automatic min/max checks on fee, m_feerate must be set if true
bool fOverrideFeeRate;
//! Override the wallet's m_pay_tx_fee if set
- Optional<CFeeRate> m_feerate;
+ std::optional<CFeeRate> m_feerate;
//! Override the default confirmation target if set
- Optional<unsigned int> m_confirm_target;
+ std::optional<unsigned int> m_confirm_target;
//! Override the wallet's m_signal_rbf if set
- Optional<bool> m_signal_bip125_rbf;
+ std::optional<bool> m_signal_bip125_rbf;
//! Avoid partial use of funds sent to a given address
bool m_avoid_partial_spends;
//! Forbids inclusion of dirty (previously used) addresses
diff --git a/src/wallet/coinselection.cpp b/src/wallet/coinselection.cpp
index 10f89e3a6f..5a18308a73 100644
--- a/src/wallet/coinselection.cpp
+++ b/src/wallet/coinselection.cpp
@@ -4,11 +4,12 @@
#include <wallet/coinselection.h>
-#include <optional.h>
#include <policy/feerate.h>
#include <util/system.h>
#include <util/moneystr.h>
+#include <optional>
+
// Descending order comparator
struct {
bool operator()(const OutputGroup& a, const OutputGroup& b) const
@@ -222,7 +223,7 @@ bool KnapsackSolver(const CAmount& nTargetValue, std::vector<OutputGroup>& group
nValueRet = 0;
// List of values less than target
- Optional<OutputGroup> lowest_larger;
+ std::optional<OutputGroup> lowest_larger;
std::vector<OutputGroup> applicable_groups;
CAmount nTotalLower = 0;
diff --git a/src/wallet/db.h b/src/wallet/db.h
index b64e9fa533..7a0d3d2e07 100644
--- a/src/wallet/db.h
+++ b/src/wallet/db.h
@@ -8,12 +8,12 @@
#include <clientversion.h>
#include <fs.h>
-#include <optional.h>
#include <streams.h>
#include <support/allocators/secure.h>
#include <atomic>
#include <memory>
+#include <optional>
#include <string>
struct bilingual_str;
@@ -203,7 +203,7 @@ enum class DatabaseFormat {
struct DatabaseOptions {
bool require_existing = false;
bool require_create = false;
- Optional<DatabaseFormat> require_format;
+ std::optional<DatabaseFormat> require_format;
uint64_t create_flags = 0;
SecureString create_passphrase;
bool verify = true;
diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp
index f3e24384df..fdeead1fa5 100644
--- a/src/wallet/init.cpp
+++ b/src/wallet/init.cpp
@@ -70,7 +70,7 @@ void WalletInit::AddWalletOptions(ArgsManager& argsman) const
argsman.AddArg("-walletbroadcast", strprintf("Make the wallet broadcast transactions (default: %u)", DEFAULT_WALLETBROADCAST), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
argsman.AddArg("-walletdir=<dir>", "Specify directory to hold wallets (default: <datadir>/wallets if it exists, otherwise <datadir>)", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::WALLET);
#if HAVE_SYSTEM
- argsman.AddArg("-walletnotify=<cmd>", "Execute command when a wallet transaction changes. %s in cmd is replaced by TxID and %w is replaced by wallet name. %w is not currently implemented on windows. On systems where %w is supported, it should NOT be quoted because this would break shell escaping used to invoke the command.", ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
+ argsman.AddArg("-walletnotify=<cmd>", "Execute command when a wallet transaction changes. %s in cmd is replaced by TxID, %w is replaced by wallet name, %b is replaced by the hash of the block including the transaction (set to 'unconfirmed' if the transaction is not included) and %h is replaced by the block height (-1 if not included). %w is not currently implemented on windows. On systems where %w is supported, it should NOT be quoted because this would break shell escaping used to invoke the command.", ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
#endif
argsman.AddArg("-walletrbf", strprintf("Send transactions with full-RBF opt-in enabled (RPC only, default: %u)", DEFAULT_WALLET_RBF), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
diff --git a/src/wallet/load.cpp b/src/wallet/load.cpp
index 30832f983b..4543f6fb4c 100644
--- a/src/wallet/load.cpp
+++ b/src/wallet/load.cpp
@@ -154,7 +154,7 @@ void UnloadWallets()
auto wallet = wallets.back();
wallets.pop_back();
std::vector<bilingual_str> warnings;
- RemoveWallet(wallet, nullopt, warnings);
+ RemoveWallet(wallet, std::nullopt, warnings);
UnloadWallet(std::move(wallet));
}
}
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index 50423c3e32..0737e68cf3 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -1788,7 +1788,7 @@ RPCHelpMan listdescriptors()
const bool active = active_spk_mans.count(desc_spk_man) != 0;
spk.pushKV("active", active);
const auto& type = wallet_descriptor.descriptor->GetOutputType();
- if (active && type != nullopt) {
+ if (active && type) {
spk.pushKV("internal", wallet->GetScriptPubKeyMan(*type, true) == desc_spk_man);
}
if (wallet_descriptor.descriptor->IsRange()) {
diff --git a/src/wallet/rpcsigner.cpp b/src/wallet/rpcsigner.cpp
index 607b778c68..696c74d665 100644
--- a/src/wallet/rpcsigner.cpp
+++ b/src/wallet/rpcsigner.cpp
@@ -32,9 +32,6 @@ static RPCHelpMan enumeratesigners()
},
RPCExamples{""},
[](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue {
- std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
- if (!wallet) return NullUniValue;
-
const std::string command = gArgs.GetArg("-signer", "");
if (command == "") throw JSONRPCError(RPC_WALLET_ERROR, "Error: restart bitcoind with -signer=<cmd>");
std::string chain = gArgs.GetChainName();
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 1b9071a712..6dc8d1de42 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -8,7 +8,6 @@
#include <interfaces/chain.h>
#include <key_io.h>
#include <node/context.h>
-#include <optional.h>
#include <outputtype.h>
#include <policy/feerate.h>
#include <policy/fees.h>
@@ -38,6 +37,7 @@
#include <wallet/walletdb.h>
#include <wallet/walletutil.h>
+#include <optional>
#include <stdint.h>
#include <univalue.h>
@@ -219,7 +219,7 @@ static void SetFeeEstimateMode(const CWallet& wallet, CCoinControl& cc, const Un
cc.m_feerate = CFeeRate(AmountFromValue(fee_rate), COIN);
if (override_min_fee) cc.fOverrideFeeRate = true;
// Default RBF to true for explicit fee_rate, if unset.
- if (cc.m_signal_bip125_rbf == nullopt) cc.m_signal_bip125_rbf = true;
+ if (!cc.m_signal_bip125_rbf) cc.m_signal_bip125_rbf = true;
return;
}
if (!estimate_mode.isNull() && !FeeModeFromString(estimate_mode.get_str(), cc.m_fee_mode)) {
@@ -1564,8 +1564,8 @@ static RPCHelpMan listsinceblock()
LOCK(wallet.cs_wallet);
- Optional<int> height; // Height of the specified block or the common ancestor, if the block provided was in a deactivated chain.
- Optional<int> altheight; // Height of the specified block, even if it's in a deactivated chain.
+ std::optional<int> height; // Height of the specified block or the common ancestor, if the block provided was in a deactivated chain.
+ std::optional<int> altheight; // Height of the specified block, even if it's in a deactivated chain.
int target_confirms = 1;
isminefilter filter = ISMINE_SPENDABLE;
@@ -2590,7 +2590,7 @@ static RPCHelpMan loadwallet()
options.require_existing = true;
bilingual_str error;
std::vector<bilingual_str> warnings;
- Optional<bool> load_on_start = request.params[1].isNull() ? nullopt : Optional<bool>(request.params[1].get_bool());
+ std::optional<bool> load_on_start = request.params[1].isNull() ? std::nullopt : std::optional<bool>(request.params[1].get_bool());
std::shared_ptr<CWallet> const wallet = LoadWallet(*context.chain, name, load_on_start, options, status, error, warnings);
if (!wallet) {
// Map bad format to not found, since bad format is returned when the
@@ -2764,7 +2764,7 @@ static RPCHelpMan createwallet()
options.create_flags = flags;
options.create_passphrase = passphrase;
bilingual_str error;
- Optional<bool> load_on_start = request.params[6].isNull() ? nullopt : Optional<bool>(request.params[6].get_bool());
+ std::optional<bool> load_on_start = request.params[6].isNull() ? std::nullopt : std::optional<bool>(request.params[6].get_bool());
std::shared_ptr<CWallet> wallet = CreateWallet(*context.chain, request.params[0].get_str(), load_on_start, options, status, error, warnings);
if (!wallet) {
RPCErrorCode code = status == DatabaseStatus::FAILED_ENCRYPT ? RPC_WALLET_ENCRYPTION_FAILED : RPC_WALLET_ERROR;
@@ -2816,7 +2816,7 @@ static RPCHelpMan unloadwallet()
// Note that any attempt to load the same wallet would fail until the wallet
// is destroyed (see CheckUniqueFileid).
std::vector<bilingual_str> warnings;
- Optional<bool> load_on_start = request.params[1].isNull() ? nullopt : Optional<bool>(request.params[1].get_bool());
+ std::optional<bool> load_on_start = request.params[1].isNull() ? std::nullopt : std::optional<bool>(request.params[1].get_bool());
if (!RemoveWallet(wallet, load_on_start, warnings)) {
throw JSONRPCError(RPC_MISC_ERROR, "Requested wallet already unloaded");
}
@@ -3587,7 +3587,7 @@ static RPCHelpMan rescanblockchain()
}
int start_height = 0;
- Optional<int> stop_height;
+ std::optional<int> stop_height;
uint256 start_block;
{
LOCK(pwallet->cs_wallet);
diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp
index a8200981d8..54319ca662 100644
--- a/src/wallet/scriptpubkeyman.cpp
+++ b/src/wallet/scriptpubkeyman.cpp
@@ -16,6 +16,8 @@
#include <wallet/external_signer.h>
#include <wallet/scriptpubkeyman.h>
+#include <optional>
+
//! Value for the first BIP 32 hardened derivation. Can be used as a bit mask and as a value. See BIP 32 for more details.
const uint32_t BIP32_HARDENED_KEY_LIMIT = 0x80000000;
@@ -1607,7 +1609,7 @@ bool DescriptorScriptPubKeyMan::GetNewDestination(const OutputType type, CTxDest
{
LOCK(cs_desc_man);
assert(m_wallet_descriptor.descriptor->IsSingleType()); // This is a combo descriptor which should not be an active descriptor
- Optional<OutputType> desc_addr_type = m_wallet_descriptor.descriptor->GetOutputType();
+ std::optional<OutputType> desc_addr_type = m_wallet_descriptor.descriptor->GetOutputType();
assert(desc_addr_type);
if (type != *desc_addr_type) {
throw std::runtime_error(std::string(__func__) + ": Types are inconsistent");
@@ -1629,7 +1631,7 @@ bool DescriptorScriptPubKeyMan::GetNewDestination(const OutputType type, CTxDest
return false;
}
- Optional<OutputType> out_script_type = m_wallet_descriptor.descriptor->GetOutputType();
+ std::optional<OutputType> out_script_type = m_wallet_descriptor.descriptor->GetOutputType();
if (out_script_type && out_script_type == type) {
ExtractDestination(scripts_temp[0], dest);
} else {
diff --git a/src/wallet/test/coinselector_tests.cpp b/src/wallet/test/coinselector_tests.cpp
index 0e9f3819eb..7eff6e592d 100644
--- a/src/wallet/test/coinselector_tests.cpp
+++ b/src/wallet/test/coinselector_tests.cpp
@@ -35,7 +35,10 @@ static CAmount balance = 0;
CoinEligibilityFilter filter_standard(1, 6, 0);
CoinEligibilityFilter filter_confirmed(1, 1, 0);
CoinEligibilityFilter filter_standard_extra(6, 6, 0);
-CoinSelectionParams coin_selection_params(false, 0, 0, CFeeRate(0), 0, false);
+CoinSelectionParams coin_selection_params(/* use_bnb= */ false, /* change_output_size= */ 0,
+ /* change_spend_size= */ 0, /* effective_feerate= */ CFeeRate(0),
+ /* long_term_feerate= */ CFeeRate(0), /* discard_feerate= */ CFeeRate(0),
+ /* tx_no_inputs_size= */ 0, /* avoid_partial= */ false);
static void add_coin(const CAmount& nValue, int nInput, std::vector<CInputCoin>& set)
{
@@ -269,7 +272,10 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
}
// Make sure that effective value is working in SelectCoinsMinConf when BnB is used
- CoinSelectionParams coin_selection_params_bnb(true, 0, 0, CFeeRate(3000), 0, false);
+ CoinSelectionParams coin_selection_params_bnb(/* use_bnb= */ true, /* change_output_size= */ 0,
+ /* change_spend_size= */ 0, /* effective_feerate= */ CFeeRate(3000),
+ /* long_term_feerate= */ CFeeRate(1000), /* discard_feerate= */ CFeeRate(1000),
+ /* tx_no_inputs_size= */ 0, /* avoid_partial= */ false);
CoinSet setCoinsRet;
CAmount nValueRet;
bool bnb_used;
@@ -301,7 +307,7 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
CCoinControl coin_control;
coin_control.fAllowOtherInputs = true;
coin_control.Select(COutPoint(vCoins.at(0).tx->GetHash(), vCoins.at(0).i));
- coin_selection_params_bnb.effective_fee = CFeeRate(0);
+ coin_selection_params_bnb.m_effective_feerate = CFeeRate(0);
BOOST_CHECK(wallet->SelectCoins(vCoins, 10 * CENT, setCoinsRet, nValueRet, coin_control, coin_selection_params_bnb, bnb_used));
BOOST_CHECK(bnb_used);
BOOST_CHECK(coin_selection_params_bnb.use_bnb);
@@ -639,8 +645,14 @@ BOOST_AUTO_TEST_CASE(SelectCoins_test)
CAmount target = rand.randrange(balance - 1000) + 1000;
// Perform selection
- CoinSelectionParams coin_selection_params_knapsack(false, 34, 148, CFeeRate(0), 0, false);
- CoinSelectionParams coin_selection_params_bnb(true, 34, 148, CFeeRate(0), 0, false);
+ CoinSelectionParams coin_selection_params_knapsack(/* use_bnb= */ false, /* change_output_size= */ 34,
+ /* change_spend_size= */ 148, /* effective_feerate= */ CFeeRate(0),
+ /* long_term_feerate= */ CFeeRate(0), /* discard_feerate= */ CFeeRate(0),
+ /* tx_no_inputs_size= */ 0, /* avoid_partial= */ false);
+ CoinSelectionParams coin_selection_params_bnb(/* use_bnb= */ true, /* change_output_size= */ 34,
+ /* change_spend_size= */ 148, /* effective_feerate= */ CFeeRate(0),
+ /* long_term_feerate= */ CFeeRate(0), /* discard_feerate= */ CFeeRate(0),
+ /* tx_no_inputs_size= */ 0, /* avoid_partial= */ false);
CoinSet out_set;
CAmount out_value = 0;
bool bnb_used = false;
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index 4598999b3c..30cc452065 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -228,7 +228,7 @@ BOOST_FIXTURE_TEST_CASE(importmulti_rescan, TestChain100Setup)
"downloading and rescanning the relevant blocks (see -reindex and -rescan "
"options).\"}},{\"success\":true}]",
0, oldTip->GetBlockTimeMax(), TIMESTAMP_WINDOW));
- RemoveWallet(wallet, nullopt);
+ RemoveWallet(wallet, std::nullopt);
}
}
@@ -271,7 +271,7 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
request.params.push_back(backup_file);
::dumpwallet().HandleRequest(request);
- RemoveWallet(wallet, nullopt);
+ RemoveWallet(wallet, std::nullopt);
}
// Call importwallet RPC and verify all blocks with timestamps >= BLOCK_TIME
@@ -288,7 +288,7 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
AddWallet(wallet);
wallet->SetLastBlockProcessed(::ChainActive().Height(), ::ChainActive().Tip()->GetBlockHash());
::importwallet().HandleRequest(request);
- RemoveWallet(wallet, nullopt);
+ RemoveWallet(wallet, std::nullopt);
BOOST_CHECK_EQUAL(wallet->mapWallet.size(), 3U);
BOOST_CHECK_EQUAL(m_coinbase_txns.size(), 103U);
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 58ab124061..b00fa851fd 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -13,7 +13,6 @@
#include <interfaces/wallet.h>
#include <key.h>
#include <key_io.h>
-#include <optional.h>
#include <outputtype.h>
#include <policy/fees.h>
#include <policy/policy.h>
@@ -40,6 +39,7 @@
#include <algorithm>
#include <assert.h>
+#include <optional>
#include <boost/algorithm/string/replace.hpp>
@@ -84,10 +84,10 @@ bool RemoveWalletSetting(interfaces::Chain& chain, const std::string& wallet_nam
static void UpdateWalletSetting(interfaces::Chain& chain,
const std::string& wallet_name,
- Optional<bool> load_on_startup,
+ std::optional<bool> load_on_startup,
std::vector<bilingual_str>& warnings)
{
- if (load_on_startup == nullopt) return;
+ if (!load_on_startup) return;
if (load_on_startup.value() && !AddWalletSetting(chain, wallet_name)) {
warnings.emplace_back(Untranslated("Wallet load on startup setting could not be updated, so wallet may not be loaded next node startup."));
} else if (!load_on_startup.value() && !RemoveWalletSetting(chain, wallet_name)) {
@@ -107,7 +107,7 @@ bool AddWallet(const std::shared_ptr<CWallet>& wallet)
return true;
}
-bool RemoveWallet(const std::shared_ptr<CWallet>& wallet, Optional<bool> load_on_start, std::vector<bilingual_str>& warnings)
+bool RemoveWallet(const std::shared_ptr<CWallet>& wallet, std::optional<bool> load_on_start, std::vector<bilingual_str>& warnings)
{
assert(wallet);
@@ -127,7 +127,7 @@ bool RemoveWallet(const std::shared_ptr<CWallet>& wallet, Optional<bool> load_on
return true;
}
-bool RemoveWallet(const std::shared_ptr<CWallet>& wallet, Optional<bool> load_on_start)
+bool RemoveWallet(const std::shared_ptr<CWallet>& wallet, std::optional<bool> load_on_start)
{
std::vector<bilingual_str> warnings;
return RemoveWallet(wallet, load_on_start, warnings);
@@ -204,7 +204,7 @@ void UnloadWallet(std::shared_ptr<CWallet>&& wallet)
}
namespace {
-std::shared_ptr<CWallet> LoadWalletInternal(interfaces::Chain& chain, const std::string& name, Optional<bool> load_on_start, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings)
+std::shared_ptr<CWallet> LoadWalletInternal(interfaces::Chain& chain, const std::string& name, std::optional<bool> load_on_start, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings)
{
try {
std::unique_ptr<WalletDatabase> database = MakeWalletDatabase(name, options, status, error);
@@ -234,11 +234,11 @@ std::shared_ptr<CWallet> LoadWalletInternal(interfaces::Chain& chain, const std:
}
} // namespace
-std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const std::string& name, Optional<bool> load_on_start, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings)
+std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const std::string& name, std::optional<bool> load_on_start, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings)
{
auto result = WITH_LOCK(g_loading_wallet_mutex, return g_loading_wallet_set.insert(name));
if (!result.second) {
- error = Untranslated("Wallet already being loading.");
+ error = Untranslated("Wallet already loading.");
status = DatabaseStatus::FAILED_LOAD;
return nullptr;
}
@@ -247,7 +247,7 @@ std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const std::string&
return wallet;
}
-std::shared_ptr<CWallet> CreateWallet(interfaces::Chain& chain, const std::string& name, Optional<bool> load_on_start, DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings)
+std::shared_ptr<CWallet> CreateWallet(interfaces::Chain& chain, const std::string& name, std::optional<bool> load_on_start, DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings)
{
uint64_t wallet_creation_flags = options.create_flags;
const SecureString& passphrase = options.create_passphrase;
@@ -944,6 +944,14 @@ CWalletTx* CWallet::AddToWallet(CTransactionRef tx, const CWalletTx::Confirmatio
if (!strCmd.empty())
{
boost::replace_all(strCmd, "%s", hash.GetHex());
+ if (confirm.status == CWalletTx::Status::CONFIRMED)
+ {
+ boost::replace_all(strCmd, "%b", confirm.hashBlock.GetHex());
+ boost::replace_all(strCmd, "%h", ToString(confirm.block_height));
+ } else {
+ boost::replace_all(strCmd, "%b", "unconfirmed");
+ boost::replace_all(strCmd, "%h", "-1");
+ }
#ifndef WIN32
// Substituting the wallet name isn't currently supported on windows
// because windows shell escaping has not been implemented yet:
@@ -1763,7 +1771,7 @@ int64_t CWallet::RescanFromTime(int64_t startTime, const WalletRescanReserver& r
* the main chain after to the addition of any new keys you want to detect
* transactions for.
*/
-CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_block, int start_height, Optional<int> max_height, const WalletRescanReserver& reserver, bool fUpdate)
+CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_block, int start_height, std::optional<int> max_height, const WalletRescanReserver& reserver, bool fUpdate)
{
int64_t nNow = GetTime();
int64_t start_time = GetTimeMillis();
@@ -2391,26 +2399,20 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const CoinEligibil
nValueRet = 0;
if (coin_selection_params.use_bnb) {
- // Get long term estimate
- FeeCalculation feeCalc;
- CCoinControl temp;
- temp.m_confirm_target = 1008;
- CFeeRate long_term_feerate = GetMinimumFeeRate(*this, temp, &feeCalc);
-
// Get the feerate for effective value.
// When subtracting the fee from the outputs, we want the effective feerate to be 0
CFeeRate effective_feerate{0};
if (!coin_selection_params.m_subtract_fee_outputs) {
- effective_feerate = coin_selection_params.effective_fee;
+ effective_feerate = coin_selection_params.m_effective_feerate;
}
- std::vector<OutputGroup> groups = GroupOutputs(coins, !coin_selection_params.m_avoid_partial_spends, effective_feerate, long_term_feerate, eligibility_filter, true /* positive_only */);
+ std::vector<OutputGroup> groups = GroupOutputs(coins, !coin_selection_params.m_avoid_partial_spends, effective_feerate, coin_selection_params.m_long_term_feerate, eligibility_filter, true /* positive_only */);
// Calculate cost of change
- CAmount cost_of_change = GetDiscardRate(*this).GetFee(coin_selection_params.change_spend_size) + coin_selection_params.effective_fee.GetFee(coin_selection_params.change_output_size);
+ CAmount cost_of_change = coin_selection_params.m_discard_feerate.GetFee(coin_selection_params.change_spend_size) + coin_selection_params.m_effective_feerate.GetFee(coin_selection_params.change_output_size);
// Calculate the fees for things that aren't inputs
- CAmount not_input_fees = coin_selection_params.effective_fee.GetFee(coin_selection_params.tx_noinputs_size);
+ CAmount not_input_fees = coin_selection_params.m_effective_feerate.GetFee(coin_selection_params.tx_noinputs_size);
bnb_used = true;
return SelectCoinsBnB(groups, nTargetValue, cost_of_change, setCoinsRet, nValueRet, not_input_fees);
} else {
@@ -2464,7 +2466,7 @@ bool CWallet::SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAm
if (coin.m_input_bytes <= 0) {
return false; // Not solvable, can't estimate size for fee
}
- coin.effective_value = coin.txout.nValue - coin_selection_params.effective_fee.GetFee(coin.m_input_bytes);
+ coin.effective_value = coin.txout.nValue - coin_selection_params.m_effective_feerate.GetFee(coin.m_input_bytes);
if (coin_selection_params.use_bnb) {
value_to_select -= coin.effective_value;
} else {
@@ -2725,7 +2727,7 @@ static uint32_t GetLocktimeForNewTransaction(interfaces::Chain& chain, const uin
return locktime;
}
-OutputType CWallet::TransactionChangeType(const Optional<OutputType>& change_type, const std::vector<CRecipient>& vecSend) const
+OutputType CWallet::TransactionChangeType(const std::optional<OutputType>& change_type, const std::vector<CRecipient>& vecSend) const
{
// If -changetype is specified, always use that change type.
if (change_type) {
@@ -2832,17 +2834,28 @@ bool CWallet::CreateTransactionInternal(
CTxOut change_prototype_txout(0, scriptChange);
coin_selection_params.change_output_size = GetSerializeSize(change_prototype_txout);
- CFeeRate discard_rate = GetDiscardRate(*this);
+ // Set discard feerate
+ coin_selection_params.m_discard_feerate = GetDiscardRate(*this);
// Get the fee rate to use effective values in coin selection
- CFeeRate nFeeRateNeeded = GetMinimumFeeRate(*this, coin_control, &feeCalc);
+ coin_selection_params.m_effective_feerate = GetMinimumFeeRate(*this, coin_control, &feeCalc);
// Do not, ever, assume that it's fine to change the fee rate if the user has explicitly
// provided one
- if (coin_control.m_feerate && nFeeRateNeeded > *coin_control.m_feerate) {
- error = strprintf(_("Fee rate (%s) is lower than the minimum fee rate setting (%s)"), coin_control.m_feerate->ToString(FeeEstimateMode::SAT_VB), nFeeRateNeeded.ToString(FeeEstimateMode::SAT_VB));
+ if (coin_control.m_feerate && coin_selection_params.m_effective_feerate > *coin_control.m_feerate) {
+ error = strprintf(_("Fee rate (%s) is lower than the minimum fee rate setting (%s)"), coin_control.m_feerate->ToString(FeeEstimateMode::SAT_VB), coin_selection_params.m_effective_feerate.ToString(FeeEstimateMode::SAT_VB));
+ return false;
+ }
+ if (feeCalc.reason == FeeReason::FALLBACK && !m_allow_fallback_fee) {
+ // eventually allow a fallback fee
+ error = _("Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.");
return false;
}
+ // Get long term estimate
+ CCoinControl cc_temp;
+ cc_temp.m_confirm_target = chain().estimateMaxBlocks();
+ coin_selection_params.m_long_term_feerate = GetMinimumFeeRate(*this, cc_temp, nullptr);
+
nFeeRet = 0;
bool pick_new_inputs = true;
CAmount nValueIn = 0;
@@ -2916,7 +2929,6 @@ bool CWallet::CreateTransactionInternal(
} else {
coin_selection_params.change_spend_size = (size_t)change_spend_size;
}
- coin_selection_params.effective_fee = nFeeRateNeeded;
if (!SelectCoins(vAvailableCoins, nValueToSelect, setCoins, nValueIn, coin_control, coin_selection_params, bnb_used))
{
// If BnB was used, it was the first pass. No longer the first pass and continue loop with knapsack.
@@ -2942,7 +2954,7 @@ bool CWallet::CreateTransactionInternal(
// Never create dust outputs; if we would, just
// add the dust to the fee.
// The nChange when BnB is used is always going to go to fees.
- if (IsDust(newTxOut, discard_rate) || bnb_used)
+ if (IsDust(newTxOut, coin_selection_params.m_discard_feerate) || bnb_used)
{
nChangePosInOut = -1;
nFeeRet += nChange;
@@ -2980,13 +2992,7 @@ bool CWallet::CreateTransactionInternal(
return false;
}
- nFeeNeeded = GetMinimumFee(*this, nBytes, coin_control, &feeCalc);
- if (feeCalc.reason == FeeReason::FALLBACK && !m_allow_fallback_fee) {
- // eventually allow a fallback fee
- error = _("Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.");
- return false;
- }
-
+ nFeeNeeded = coin_selection_params.m_effective_feerate.GetFee(nBytes);
if (nFeeRet >= nFeeNeeded) {
// Reduce fee to only the needed amount if possible. This
// prevents potential overpayment in fees if the coins
@@ -3000,8 +3006,8 @@ bool CWallet::CreateTransactionInternal(
// change output. Only try this once.
if (nChangePosInOut == -1 && nSubtractFeeFromAmount == 0 && pick_new_inputs) {
unsigned int tx_size_with_change = nBytes + coin_selection_params.change_output_size + 2; // Add 2 as a buffer in case increasing # of outputs changes compact size
- CAmount fee_needed_with_change = GetMinimumFee(*this, tx_size_with_change, coin_control, nullptr);
- CAmount minimum_value_for_change = GetDustThreshold(change_prototype_txout, discard_rate);
+ CAmount fee_needed_with_change = coin_selection_params.m_effective_feerate.GetFee(tx_size_with_change);
+ CAmount minimum_value_for_change = GetDustThreshold(change_prototype_txout, coin_selection_params.m_discard_feerate);
if (nFeeRet >= fee_needed_with_change + minimum_value_for_change) {
pick_new_inputs = false;
nFeeRet = fee_needed_with_change;
@@ -4067,13 +4073,13 @@ std::shared_ptr<CWallet> CWallet::Create(interfaces::Chain& chain, const std::st
WalletBatch batch(walletInstance->GetDatabase());
CBlockLocator locator;
if (batch.ReadBestBlock(locator)) {
- if (const Optional<int> fork_height = chain.findLocatorFork(locator)) {
+ if (const std::optional<int> fork_height = chain.findLocatorFork(locator)) {
rescan_height = *fork_height;
}
}
}
- const Optional<int> tip_height = chain.getHeight();
+ const std::optional<int> tip_height = chain.getHeight();
if (tip_height) {
walletInstance->m_last_block_processed = chain.getBlockHash(*tip_height);
walletInstance->m_last_block_processed_height = *tip_height;
@@ -4107,7 +4113,7 @@ std::shared_ptr<CWallet> CWallet::Create(interfaces::Chain& chain, const std::st
// No need to read and scan block if block was created before
// our wallet birthday (as adjusted for block time variability)
- Optional<int64_t> time_first_key;
+ std::optional<int64_t> time_first_key;
for (auto spk_man : walletInstance->GetAllScriptPubKeyMans()) {
int64_t time = spk_man->GetTimeFirstKey();
if (!time_first_key || time < *time_first_key) time_first_key = time;
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 3a76163dd2..6031d36b97 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -30,6 +30,7 @@
#include <atomic>
#include <map>
#include <memory>
+#include <optional>
#include <set>
#include <stdexcept>
#include <stdint.h>
@@ -51,12 +52,12 @@ struct bilingual_str;
void UnloadWallet(std::shared_ptr<CWallet>&& wallet);
bool AddWallet(const std::shared_ptr<CWallet>& wallet);
-bool RemoveWallet(const std::shared_ptr<CWallet>& wallet, Optional<bool> load_on_start, std::vector<bilingual_str>& warnings);
-bool RemoveWallet(const std::shared_ptr<CWallet>& wallet, Optional<bool> load_on_start);
+bool RemoveWallet(const std::shared_ptr<CWallet>& wallet, std::optional<bool> load_on_start, std::vector<bilingual_str>& warnings);
+bool RemoveWallet(const std::shared_ptr<CWallet>& wallet, std::optional<bool> load_on_start);
std::vector<std::shared_ptr<CWallet>> GetWallets();
std::shared_ptr<CWallet> GetWallet(const std::string& name);
-std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const std::string& name, Optional<bool> load_on_start, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings);
-std::shared_ptr<CWallet> CreateWallet(interfaces::Chain& chain, const std::string& name, Optional<bool> load_on_start, DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings);
+std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const std::string& name, std::optional<bool> load_on_start, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings);
+std::shared_ptr<CWallet> CreateWallet(interfaces::Chain& chain, const std::string& name, std::optional<bool> load_on_start, DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings);
std::unique_ptr<interfaces::Handler> HandleLoadWallet(LoadWalletFn load_wallet);
std::unique_ptr<WalletDatabase> MakeWalletDatabase(const std::string& name, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error);
@@ -608,17 +609,22 @@ struct CoinSelectionParams
bool use_bnb = true;
size_t change_output_size = 0;
size_t change_spend_size = 0;
- CFeeRate effective_fee = CFeeRate(0);
+ CFeeRate m_effective_feerate;
+ CFeeRate m_long_term_feerate;
+ CFeeRate m_discard_feerate;
size_t tx_noinputs_size = 0;
//! Indicate that we are subtracting the fee from outputs
bool m_subtract_fee_outputs = false;
bool m_avoid_partial_spends = false;
- CoinSelectionParams(bool use_bnb, size_t change_output_size, size_t change_spend_size, CFeeRate effective_fee, size_t tx_noinputs_size, bool avoid_partial) :
+ CoinSelectionParams(bool use_bnb, size_t change_output_size, size_t change_spend_size, CFeeRate effective_feerate,
+ CFeeRate long_term_feerate, CFeeRate discard_feerate, size_t tx_noinputs_size, bool avoid_partial) :
use_bnb(use_bnb),
change_output_size(change_output_size),
change_spend_size(change_spend_size),
- effective_fee(effective_fee),
+ m_effective_feerate(effective_feerate),
+ m_long_term_feerate(long_term_feerate),
+ m_discard_feerate(discard_feerate),
tx_noinputs_size(tx_noinputs_size),
m_avoid_partial_spends(avoid_partial)
{}
@@ -923,7 +929,7 @@ public:
//! Unset if no blocks were scanned due to read errors or the chain
//! being empty.
uint256 last_scanned_block;
- Optional<int> last_scanned_height;
+ std::optional<int> last_scanned_height;
//! Height of the most recent block that could not be scanned due to
//! read errors or pruning. Will be set if status is FAILURE, unset if
@@ -931,7 +937,7 @@ public:
//! USER_ABORT.
uint256 last_failed_block;
};
- ScanResult ScanForWalletTransactions(const uint256& start_block, int start_height, Optional<int> max_height, const WalletRescanReserver& reserver, bool fUpdate);
+ ScanResult ScanForWalletTransactions(const uint256& start_block, int start_height, std::optional<int> max_height, const WalletRescanReserver& reserver, bool fUpdate);
void transactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason, uint64_t mempool_sequence) override;
void ReacceptWalletTransactions() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
void ResendWalletTransactions();
@@ -946,7 +952,7 @@ public:
Balance GetBalance(int min_depth = 0, bool avoid_reuse = true) const;
CAmount GetAvailableBalance(const CCoinControl* coinControl = nullptr) const;
- OutputType TransactionChangeType(const Optional<OutputType>& change_type, const std::vector<CRecipient>& vecSend) const;
+ OutputType TransactionChangeType(const std::optional<OutputType>& change_type, const std::vector<CRecipient>& vecSend) const;
/**
* Insert additional inputs into the transaction by
@@ -1031,7 +1037,7 @@ public:
* (see -changetype option documentation and implementation in
* CWallet::TransactionChangeType for details).
*/
- Optional<OutputType> m_default_change_type{};
+ std::optional<OutputType> m_default_change_type{};
/** Absolute maximum transaction fee (in satoshis) used by default for the wallet */
CAmount m_default_max_tx_fee{DEFAULT_TRANSACTION_MAXFEE};
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index a5a454f9a8..3d9248009f 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -23,6 +23,7 @@
#include <wallet/wallet.h>
#include <atomic>
+#include <optional>
#include <string>
namespace DBKeys {
@@ -1015,7 +1016,7 @@ std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const Databas
return nullptr;
}
- Optional<DatabaseFormat> format;
+ std::optional<DatabaseFormat> format;
if (exists) {
if (IsBDBFile(BDBDataFile(path))) {
format = DatabaseFormat::BERKELEY;