aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.qt.include2
-rw-r--r--src/bech32.cpp52
-rw-r--r--src/bech32.h39
-rw-r--r--src/bench/bech32.cpp2
-rw-r--r--src/key_io.cpp22
-rw-r--r--src/net.cpp4
-rw-r--r--src/net_processing.cpp3
-rw-r--r--src/netaddress.cpp81
-rw-r--r--src/netaddress.h24
-rw-r--r--src/qt/bitcoin.cpp8
-rw-r--r--src/qt/bitcoingui.cpp2
-rw-r--r--src/qt/forms/createwalletdialog.ui253
-rw-r--r--src/qt/forms/overviewpage.ui15
-rw-r--r--src/qt/overviewpage.cpp39
-rw-r--r--src/qt/psbtoperationsdialog.cpp2
-rw-r--r--src/qt/sendcoinsdialog.cpp5
-rw-r--r--src/qt/sendcoinsdialog.h2
-rw-r--r--src/qt/transactionoverviewwidget.h41
-rw-r--r--src/qt/walletframe.cpp17
-rw-r--r--src/randomenv.cpp4
-rw-r--r--src/rpc/misc.cpp19
-rw-r--r--src/script/interpreter.h28
-rw-r--r--src/script/sign.cpp8
-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/fuzz/FuzzedDataProvider.h564
-rw-r--r--src/test/fuzz/bech32.cpp32
-rw-r--r--src/test/netbase_tests.cpp21
-rw-r--r--src/util/time.cpp5
-rw-r--r--src/wallet/rpcwallet.cpp8
31 files changed, 1295 insertions, 782 deletions
diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include
index f46310a603..eb17795b48 100644
--- a/src/Makefile.qt.include
+++ b/src/Makefile.qt.include
@@ -78,6 +78,7 @@ QT_MOC_CPP = \
qt/moc_transactiondesc.cpp \
qt/moc_transactiondescdialog.cpp \
qt/moc_transactionfilterproxy.cpp \
+ qt/moc_transactionoverviewwidget.cpp \
qt/moc_transactiontablemodel.cpp \
qt/moc_transactionview.cpp \
qt/moc_utilitydialog.cpp \
@@ -151,6 +152,7 @@ BITCOIN_QT_H = \
qt/transactiondesc.h \
qt/transactiondescdialog.h \
qt/transactionfilterproxy.h \
+ qt/transactionoverviewwidget.h \
qt/transactionrecord.h \
qt/transactiontablemodel.h \
qt/transactionview.h \
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/key_io.cpp b/src/key_io.cpp
index d2f5be93f5..0cb4d0bf7c 100644
--- a/src/key_io.cpp
+++ b/src/key_io.cpp
@@ -44,7 +44,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
@@ -52,7 +52,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
@@ -63,7 +63,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 {}; }
@@ -91,13 +91,19 @@ CTxDestination DecodeDestination(const std::string& str, const CChainParams& par
}
}
data.clear();
- auto bech = bech32::Decode(str);
- if (bech.second.size() > 0 && bech.first == params.Bech32HRP()) {
+ const auto dec = bech32::Decode(str);
+ if ((dec.encoding == bech32::Encoding::BECH32 || dec.encoding == bech32::Encoding::BECH32M) && dec.data.size() > 0 && dec.hrp == params.Bech32HRP()) {
// 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) {
+ return CNoDestination();
+ }
+ if (version != 0 && dec.encoding != bech32::Encoding::BECH32M) {
+ 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/net.cpp b/src/net.cpp
index 1fd913eb64..15e52de94d 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -28,6 +28,10 @@
#include <fcntl.h>
#endif
+#if HAVE_DECL_GETIFADDRS && HAVE_DECL_FREEIFADDRS
+#include <ifaddrs.h>
+#endif
+
#ifdef USE_POLL
#include <poll.h>
#endif
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 98e3d90c2d..f29be8d8a3 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -2305,6 +2305,9 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat
bool fRelay = true;
vRecv >> nVersion >> nServiceInt >> nTime >> addrMe;
+ if (nTime < 0) {
+ nTime = 0;
+ }
nServices = ServiceFlags(nServiceInt);
if (!pfrom.IsInboundConn())
{
diff --git a/src/netaddress.cpp b/src/netaddress.cpp
index 35e9161f58..e0d4638dd6 100644
--- a/src/netaddress.cpp
+++ b/src/netaddress.cpp
@@ -1063,15 +1063,24 @@ CSubNet::CSubNet(const CNetAddr& addr, const CNetAddr& mask) : CSubNet()
CSubNet::CSubNet(const CNetAddr& addr) : CSubNet()
{
- valid = addr.IsIPv4() || addr.IsIPv6();
- if (!valid) {
+ switch (addr.m_net) {
+ case NET_IPV4:
+ case NET_IPV6:
+ valid = true;
+ assert(addr.m_addr.size() <= sizeof(netmask));
+ memset(netmask, 0xFF, addr.m_addr.size());
+ break;
+ case NET_ONION:
+ case NET_I2P:
+ case NET_CJDNS:
+ valid = true;
+ break;
+ case NET_INTERNAL:
+ case NET_UNROUTABLE:
+ case NET_MAX:
return;
}
- assert(addr.m_addr.size() <= sizeof(netmask));
-
- memset(netmask, 0xFF, addr.m_addr.size());
-
network = addr;
}
@@ -1083,6 +1092,21 @@ bool CSubNet::Match(const CNetAddr &addr) const
{
if (!valid || !addr.IsValid() || network.m_net != addr.m_net)
return false;
+
+ switch (network.m_net) {
+ case NET_IPV4:
+ case NET_IPV6:
+ break;
+ case NET_ONION:
+ case NET_I2P:
+ case NET_CJDNS:
+ case NET_INTERNAL:
+ return addr == network;
+ case NET_UNROUTABLE:
+ case NET_MAX:
+ return false;
+ }
+
assert(network.m_addr.size() == addr.m_addr.size());
for (size_t x = 0; x < addr.m_addr.size(); ++x) {
if ((addr.m_addr[x] & netmask[x]) != network.m_addr[x]) {
@@ -1094,18 +1118,35 @@ bool CSubNet::Match(const CNetAddr &addr) const
std::string CSubNet::ToString() const
{
- assert(network.m_addr.size() <= sizeof(netmask));
+ std::string suffix;
- uint8_t cidr = 0;
+ switch (network.m_net) {
+ case NET_IPV4:
+ case NET_IPV6: {
+ assert(network.m_addr.size() <= sizeof(netmask));
- for (size_t i = 0; i < network.m_addr.size(); ++i) {
- if (netmask[i] == 0x00) {
- break;
+ uint8_t cidr = 0;
+
+ for (size_t i = 0; i < network.m_addr.size(); ++i) {
+ if (netmask[i] == 0x00) {
+ break;
+ }
+ cidr += NetmaskBits(netmask[i]);
}
- cidr += NetmaskBits(netmask[i]);
+
+ suffix = strprintf("/%u", cidr);
+ break;
+ }
+ case NET_ONION:
+ case NET_I2P:
+ case NET_CJDNS:
+ case NET_INTERNAL:
+ case NET_UNROUTABLE:
+ case NET_MAX:
+ break;
}
- return network.ToString() + strprintf("/%u", cidr);
+ return network.ToString() + suffix;
}
bool CSubNet::IsValid() const
@@ -1115,7 +1156,19 @@ bool CSubNet::IsValid() const
bool CSubNet::SanityCheck() const
{
- if (!(network.IsIPv4() || network.IsIPv6())) return false;
+ switch (network.m_net) {
+ case NET_IPV4:
+ case NET_IPV6:
+ break;
+ case NET_ONION:
+ case NET_I2P:
+ case NET_CJDNS:
+ return true;
+ case NET_INTERNAL:
+ case NET_UNROUTABLE:
+ case NET_MAX:
+ return false;
+ }
for (size_t x = 0; x < network.m_addr.size(); ++x) {
if (network.m_addr[x] & ~netmask[x]) return false;
diff --git a/src/netaddress.h b/src/netaddress.h
index 29b2eaafeb..b9beb1e358 100644
--- a/src/netaddress.h
+++ b/src/netaddress.h
@@ -462,11 +462,33 @@ class CSubNet
bool SanityCheck() const;
public:
+ /**
+ * Construct an invalid subnet (empty, `Match()` always returns false).
+ */
CSubNet();
+
+ /**
+ * Construct from a given network start and number of bits (CIDR mask).
+ * @param[in] addr Network start. Must be IPv4 or IPv6, otherwise an invalid subnet is
+ * created.
+ * @param[in] mask CIDR mask, must be in [0, 32] for IPv4 addresses and in [0, 128] for
+ * IPv6 addresses. Otherwise an invalid subnet is created.
+ */
CSubNet(const CNetAddr& addr, uint8_t mask);
+
+ /**
+ * Construct from a given network start and mask.
+ * @param[in] addr Network start. Must be IPv4 or IPv6, otherwise an invalid subnet is
+ * created.
+ * @param[in] mask Network mask, must be of the same type as `addr` and not contain 0-bits
+ * followed by 1-bits. Otherwise an invalid subnet is created.
+ */
CSubNet(const CNetAddr& addr, const CNetAddr& mask);
- //constructor for single ip subnet (<ipv4>/32 or <ipv6>/128)
+ /**
+ * Construct a single-host subnet.
+ * @param[in] addr The sole address to be contained in the subnet, can also be non-IPv[46].
+ */
explicit CSubNet(const CNetAddr& addr);
bool Match(const CNetAddr &addr) const;
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index 63b4107f7e..6737452aba 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -51,6 +51,7 @@
#include <QThread>
#include <QTimer>
#include <QTranslator>
+#include <QtGlobal>
#if defined(QT_STATICPLUGIN)
#include <QtPlugin>
@@ -466,6 +467,13 @@ int GuiMain(int argc, char* argv[])
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
+#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;
/// 2. Parse command-line options. We do this after qt in order to show an error if there are problems parsing these
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index 23370e6ad3..6a412b95f8 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -845,7 +845,7 @@ void BitcoinGUI::showDebugWindowActivateConsole()
void BitcoinGUI::showHelpMessageClicked()
{
- helpMessageDialog->show();
+ GUIUtil::bringToFront(helpMessageDialog);
}
#ifdef ENABLE_WALLET
diff --git a/src/qt/forms/createwalletdialog.ui b/src/qt/forms/createwalletdialog.ui
index 0b33c2cb8d..881869a46c 100644
--- a/src/qt/forms/createwalletdialog.ui
+++ b/src/qt/forms/createwalletdialog.ui
@@ -7,140 +7,135 @@
<x>0</x>
<y>0</y>
<width>364</width>
- <height>213</height>
+ <height>249</height>
</rect>
</property>
<property name="windowTitle">
<string>Create Wallet</string>
</property>
- <widget class="QDialogButtonBox" name="buttonBox">
- <property name="geometry">
- <rect>
- <x>10</x>
- <y>170</y>
- <width>341</width>
- <height>32</height>
- </rect>
- </property>
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="standardButtons">
- <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
- </property>
- </widget>
- <widget class="QLineEdit" name="wallet_name_line_edit">
- <property name="geometry">
- <rect>
- <x>120</x>
- <y>20</y>
- <width>231</width>
- <height>24</height>
- </rect>
- </property>
- <property name="placeholderText">
- <string>Wallet</string>
- </property>
- </widget>
- <widget class="QLabel" name="label">
- <property name="geometry">
- <rect>
- <x>20</x>
- <y>20</y>
- <width>101</width>
- <height>21</height>
- </rect>
- </property>
- <property name="text">
- <string>Wallet Name</string>
- </property>
- </widget>
- <widget class="QCheckBox" name="encrypt_wallet_checkbox">
- <property name="geometry">
- <rect>
- <x>20</x>
- <y>50</y>
- <width>220</width>
- <height>22</height>
- </rect>
- </property>
- <property name="toolTip">
- <string>Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</string>
- </property>
- <property name="text">
- <string>Encrypt Wallet</string>
- </property>
- <property name="checked">
- <bool>false</bool>
- </property>
- </widget>
- <widget class="QLabel" name="advanced_options_label">
- <property name="geometry">
- <rect>
- <x>20</x>
- <y>90</y>
- <width>220</width>
- <height>21</height>
- </rect>
- </property>
- <property name="styleSheet">
- <string notr="true">font-weight:bold;</string>
- </property>
- <property name="text">
- <string>Advanced options</string>
- </property>
- </widget>
- <widget class="QCheckBox" name="disable_privkeys_checkbox">
- <property name="enabled">
- <bool>true</bool>
- </property>
- <property name="geometry">
- <rect>
- <x>20</x>
- <y>115</y>
- <width>220</width>
- <height>22</height>
- </rect>
- </property>
- <property name="toolTip">
- <string>Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</string>
- </property>
- <property name="text">
- <string>Disable Private Keys</string>
- </property>
- </widget>
- <widget class="QCheckBox" name="blank_wallet_checkbox">
- <property name="geometry">
- <rect>
- <x>20</x>
- <y>135</y>
- <width>220</width>
- <height>22</height>
- </rect>
- </property>
- <property name="toolTip">
- <string>Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time.</string>
- </property>
- <property name="text">
- <string>Make Blank Wallet</string>
- </property>
- </widget>
- <widget class="QCheckBox" name="descriptor_checkbox">
- <property name="geometry">
- <rect>
- <x>20</x>
- <y>155</y>
- <width>220</width>
- <height>22</height>
- </rect>
- </property>
- <property name="toolTip">
- <string>Use descriptors for scriptPubKey management</string>
- </property>
- <property name="text">
- <string>Descriptor Wallet</string>
- </property>
- </widget>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QLabel" name="wallet_name_label">
+ <property name="text">
+ <string>Wallet Name</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="wallet_name_line_edit">
+ <property name="minimumSize">
+ <size>
+ <width>262</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="placeholderText">
+ <string>Wallet</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="encrypt_wallet_checkbox">
+ <property name="toolTip">
+ <string>Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</string>
+ </property>
+ <property name="text">
+ <string>Encrypt Wallet</string>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_1">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>8</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="title">
+ <string>Advanced Options</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_groupbox">
+ <item>
+ <widget class="QCheckBox" name="disable_privkeys_checkbox">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="toolTip">
+ <string>Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</string>
+ </property>
+ <property name="text">
+ <string>Disable Private Keys</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="blank_wallet_checkbox">
+ <property name="toolTip">
+ <string>Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time.</string>
+ </property>
+ <property name="text">
+ <string>Make Blank Wallet</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="descriptor_checkbox">
+ <property name="toolTip">
+ <string>Use descriptors for scriptPubKey management</string>
+ </property>
+ <property name="text">
+ <string>Descriptor Wallet</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
</widget>
<tabstops>
<tabstop>wallet_name_line_edit</tabstop>
diff --git a/src/qt/forms/overviewpage.ui b/src/qt/forms/overviewpage.ui
index 4d3f90c484..ee9d4a113c 100644
--- a/src/qt/forms/overviewpage.ui
+++ b/src/qt/forms/overviewpage.ui
@@ -504,7 +504,7 @@
</layout>
</item>
<item>
- <widget class="QListView" name="listTransactions">
+ <widget class="TransactionOverviewWidget" name="listTransactions">
<property name="styleSheet">
<string notr="true">QListView { background: transparent; }</string>
</property>
@@ -517,9 +517,15 @@
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
+ <property name="sizeAdjustPolicy">
+ <enum>QAbstractScrollArea::AdjustToContents</enum>
+ </property>
<property name="selectionMode">
<enum>QAbstractItemView::NoSelection</enum>
</property>
+ <property name="uniformItemSizes">
+ <bool>true</bool>
+ </property>
</widget>
</item>
</layout>
@@ -544,6 +550,13 @@
</item>
</layout>
</widget>
+ <customwidgets>
+ <customwidget>
+ <class>TransactionOverviewWidget</class>
+ <extends>QListView</extends>
+ <header>qt/transactionoverviewwidget.h</header>
+ </customwidget>
+ </customwidgets>
<resources/>
<connections/>
</ui>
diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp
index b536567c8b..6a66584544 100644
--- a/src/qt/overviewpage.cpp
+++ b/src/qt/overviewpage.cpp
@@ -12,6 +12,7 @@
#include <qt/optionsmodel.h>
#include <qt/platformstyle.h>
#include <qt/transactionfilterproxy.h>
+#include <qt/transactionoverviewwidget.h>
#include <qt/transactiontablemodel.h>
#include <qt/walletmodel.h>
@@ -20,6 +21,9 @@
#include <QPainter>
#include <QStatusTipEvent>
+#include <algorithm>
+#include <map>
+
#define DECORATION_SIZE 54
#define NUM_ITEMS 5
@@ -33,7 +37,7 @@ public:
QAbstractItemDelegate(parent), unit(BitcoinUnits::BTC),
platformStyle(_platformStyle)
{
-
+ connect(this, &TxViewDelegate::width_changed, this, &TxViewDelegate::sizeHintChanged);
}
inline void paint(QPainter *painter, const QStyleOptionViewItem &option,
@@ -66,13 +70,15 @@ public:
painter->setPen(foreground);
QRect boundingRect;
- painter->drawText(addressRect, Qt::AlignLeft|Qt::AlignVCenter, address, &boundingRect);
+ painter->drawText(addressRect, Qt::AlignLeft | Qt::AlignVCenter, address, &boundingRect);
+ int address_rect_min_width = boundingRect.width();
if (index.data(TransactionTableModel::WatchonlyRole).toBool())
{
QIcon iconWatchonly = qvariant_cast<QIcon>(index.data(TransactionTableModel::WatchonlyDecorationRole));
QRect watchonlyRect(boundingRect.right() + 5, mainRect.top()+ypad+halfheight, 16, halfheight);
iconWatchonly.paint(painter, watchonlyRect);
+ address_rect_min_width += 5 + watchonlyRect.width();
}
if(amount < 0)
@@ -93,23 +99,42 @@ public:
{
amountText = QString("[") + amountText + QString("]");
}
- painter->drawText(amountRect, Qt::AlignRight|Qt::AlignVCenter, amountText);
+
+ QRect amount_bounding_rect;
+ painter->drawText(amountRect, Qt::AlignRight | Qt::AlignVCenter, amountText, &amount_bounding_rect);
painter->setPen(option.palette.color(QPalette::Text));
- painter->drawText(amountRect, Qt::AlignLeft|Qt::AlignVCenter, GUIUtil::dateTimeStr(date));
+ QRect date_bounding_rect;
+ painter->drawText(amountRect, Qt::AlignLeft | Qt::AlignVCenter, GUIUtil::dateTimeStr(date), &date_bounding_rect);
+
+ const int minimum_width = std::max(address_rect_min_width, amount_bounding_rect.width() + date_bounding_rect.width());
+ const auto search = m_minimum_width.find(index.row());
+ if (search == m_minimum_width.end() || search->second != minimum_width) {
+ m_minimum_width[index.row()] = minimum_width;
+ Q_EMIT width_changed(index);
+ }
painter->restore();
}
inline QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override
{
- return QSize(DECORATION_SIZE, DECORATION_SIZE);
+ const auto search = m_minimum_width.find(index.row());
+ const int minimum_text_width = search == m_minimum_width.end() ? 0 : search->second;
+ return {DECORATION_SIZE + 8 + minimum_text_width, DECORATION_SIZE};
}
int unit;
- const PlatformStyle *platformStyle;
+Q_SIGNALS:
+ //! An intermediate signal for emitting from the `paint() const` member function.
+ void width_changed(const QModelIndex& index) const;
+
+private:
+ const PlatformStyle* platformStyle;
+ mutable std::map<int, int> m_minimum_width;
};
+
#include <qt/overviewpage.moc>
OverviewPage::OverviewPage(const PlatformStyle *platformStyle, QWidget *parent) :
@@ -135,7 +160,7 @@ OverviewPage::OverviewPage(const PlatformStyle *platformStyle, QWidget *parent)
ui->listTransactions->setMinimumHeight(NUM_ITEMS * (DECORATION_SIZE + 2));
ui->listTransactions->setAttribute(Qt::WA_MacShowFocusRect, false);
- connect(ui->listTransactions, &QListView::clicked, this, &OverviewPage::handleTransactionClicked);
+ connect(ui->listTransactions, &TransactionOverviewWidget::clicked, this, &OverviewPage::handleTransactionClicked);
// start with displaying the "out of sync" warnings
showOutOfSyncWarning(true);
diff --git a/src/qt/psbtoperationsdialog.cpp b/src/qt/psbtoperationsdialog.cpp
index 58167d4bb4..28103495da 100644
--- a/src/qt/psbtoperationsdialog.cpp
+++ b/src/qt/psbtoperationsdialog.cpp
@@ -145,7 +145,7 @@ void PSBTOperationsDialog::saveTransaction() {
if (filename.isEmpty()) {
return;
}
- std::ofstream out(filename.toLocal8Bit().data());
+ std::ofstream out(filename.toLocal8Bit().data(), std::ofstream::out | std::ofstream::binary);
out << ssTx.str();
out.close();
showStatus(tr("PSBT saved to disk."), StatusLevel::INFO);
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
index 50a1ea6936..62606ff0b0 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -427,7 +427,7 @@ void SendCoinsDialog::on_sendButton_clicked()
if (filename.isEmpty()) {
return;
}
- std::ofstream out(filename.toLocal8Bit().data());
+ std::ofstream out(filename.toLocal8Bit().data(), std::ofstream::out | std::ofstream::binary);
out << ssTx.str();
out.close();
Q_EMIT message(tr("PSBT saved"), "PSBT saved to disk", CClientUIInterface::MSG_INFORMATION);
@@ -966,6 +966,9 @@ SendConfirmationDialog::SendConfirmationDialog(const QString& title, const QStri
setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
setDefaultButton(QMessageBox::Cancel);
yesButton = button(QMessageBox::Yes);
+ if (confirmButtonText.isEmpty()) {
+ confirmButtonText = yesButton->text();
+ }
updateYesButton();
connect(&countDownTimer, &QTimer::timeout, this, &SendConfirmationDialog::countDown);
}
diff --git a/src/qt/sendcoinsdialog.h b/src/qt/sendcoinsdialog.h
index 8519f1f65b..8863d2e5c8 100644
--- a/src/qt/sendcoinsdialog.h
+++ b/src/qt/sendcoinsdialog.h
@@ -115,7 +115,7 @@ class SendConfirmationDialog : public QMessageBox
Q_OBJECT
public:
- SendConfirmationDialog(const QString& title, const QString& text, const QString& informative_text = "", const QString& detailed_text = "", int secDelay = SEND_CONFIRM_DELAY, const QString& confirmText = "Send", QWidget* parent = nullptr);
+ SendConfirmationDialog(const QString& title, const QString& text, const QString& informative_text = "", const QString& detailed_text = "", int secDelay = SEND_CONFIRM_DELAY, const QString& confirmText = "", QWidget* parent = nullptr);
int exec() override;
private Q_SLOTS:
diff --git a/src/qt/transactionoverviewwidget.h b/src/qt/transactionoverviewwidget.h
new file mode 100644
index 0000000000..2bdead7bc4
--- /dev/null
+++ b/src/qt/transactionoverviewwidget.h
@@ -0,0 +1,41 @@
+// 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.
+
+#ifndef BITCOIN_QT_TRANSACTIONOVERVIEWWIDGET_H
+#define BITCOIN_QT_TRANSACTIONOVERVIEWWIDGET_H
+
+#include <qt/transactiontablemodel.h>
+
+#include <QListView>
+#include <QSize>
+#include <QSizePolicy>
+
+QT_BEGIN_NAMESPACE
+class QShowEvent;
+class QWidget;
+QT_END_NAMESPACE
+
+class TransactionOverviewWidget : public QListView
+{
+ Q_OBJECT
+
+public:
+ explicit TransactionOverviewWidget(QWidget* parent = nullptr) : QListView(parent) {}
+
+ QSize sizeHint() const override
+ {
+ return {sizeHintForColumn(TransactionTableModel::ToAddress), QListView::sizeHint().height()};
+ }
+
+protected:
+ void showEvent(QShowEvent* event) override
+ {
+ Q_UNUSED(event);
+ QSizePolicy sp = sizePolicy();
+ sp.setHorizontalPolicy(QSizePolicy::Minimum);
+ setSizePolicy(sp);
+ }
+};
+
+#endif // BITCOIN_QT_TRANSACTIONOVERVIEWWIDGET_H
diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp
index 4a9b4a5c84..eaa18b03a3 100644
--- a/src/qt/walletframe.cpp
+++ b/src/qt/walletframe.cpp
@@ -106,9 +106,24 @@ void WalletFrame::setCurrentWallet(WalletModel* wallet_model)
{
if (mapWalletViews.count(wallet_model) == 0) return;
+ // Stop the effect of hidden widgets on the size hint of the shown one in QStackedWidget.
+ WalletView* view_about_to_hide = currentWalletView();
+ if (view_about_to_hide) {
+ QSizePolicy sp = view_about_to_hide->sizePolicy();
+ sp.setHorizontalPolicy(QSizePolicy::Ignored);
+ view_about_to_hide->setSizePolicy(sp);
+ }
+
WalletView *walletView = mapWalletViews.value(wallet_model);
- walletStack->setCurrentWidget(walletView);
assert(walletView);
+
+ // Set or restore the default QSizePolicy which could be set to QSizePolicy::Ignored previously.
+ QSizePolicy sp = walletView->sizePolicy();
+ sp.setHorizontalPolicy(QSizePolicy::Preferred);
+ walletView->setSizePolicy(sp);
+ walletView->updateGeometry();
+
+ walletStack->setCurrentWidget(walletView);
walletView->updateEncryptionStatus();
}
diff --git a/src/randomenv.cpp b/src/randomenv.cpp
index 07122b7f6d..79ab8daf6a 100644
--- a/src/randomenv.cpp
+++ b/src/randomenv.cpp
@@ -38,7 +38,7 @@
#include <sys/utsname.h>
#include <unistd.h>
#endif
-#if HAVE_DECL_GETIFADDRS
+#if HAVE_DECL_GETIFADDRS && HAVE_DECL_FREEIFADDRS
#include <ifaddrs.h>
#endif
#if HAVE_SYSCTL
@@ -361,7 +361,7 @@ void RandAddStaticEnv(CSHA512& hasher)
hasher.Write((const unsigned char*)hname, strnlen(hname, 256));
}
-#if HAVE_DECL_GETIFADDRS
+#if HAVE_DECL_GETIFADDRS && HAVE_DECL_FREEIFADDRS
// Network interfaces
struct ifaddrs *ifad = NULL;
getifaddrs(&ifad);
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp
index 0c982317f5..00f7445cfa 100644
--- a/src/rpc/misc.cpp
+++ b/src/rpc/misc.cpp
@@ -360,13 +360,13 @@ static RPCHelpMan signmessagewithprivkey()
static RPCHelpMan setmocktime()
{
return RPCHelpMan{"setmocktime",
- "\nSet the local time to given timestamp (-regtest only)\n",
- {
- {"timestamp", RPCArg::Type::NUM, RPCArg::Optional::NO, UNIX_EPOCH_TIME + "\n"
- " Pass 0 to go back to using the system time."},
- },
- RPCResult{RPCResult::Type::NONE, "", ""},
- RPCExamples{""},
+ "\nSet the local time to given timestamp (-regtest only)\n",
+ {
+ {"timestamp", RPCArg::Type::NUM, RPCArg::Optional::NO, UNIX_EPOCH_TIME + "\n"
+ "Pass 0 to go back to using the system time."},
+ },
+ RPCResult{RPCResult::Type::NONE, "", ""},
+ RPCExamples{""},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
if (!Params().IsMockableChain()) {
@@ -381,7 +381,10 @@ static RPCHelpMan setmocktime()
LOCK(cs_main);
RPCTypeCheck(request.params, {UniValue::VNUM});
- int64_t time = request.params[0].get_int64();
+ const int64_t time{request.params[0].get_int64()};
+ if (time < 0) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Mocktime can not be negative: %s.", time));
+ }
SetMockTime(time);
if (request.context.Has<NodeContext>()) {
for (const auto& chain_client : request.context.Get<NodeContext>().chain_clients) {
diff --git a/src/script/interpreter.h b/src/script/interpreter.h
index c0c2b012c6..70789869a0 100644
--- a/src/script/interpreter.h
+++ b/src/script/interpreter.h
@@ -272,6 +272,34 @@ public:
using TransactionSignatureChecker = GenericTransactionSignatureChecker<CTransaction>;
using MutableTransactionSignatureChecker = GenericTransactionSignatureChecker<CMutableTransaction>;
+class DeferringSignatureChecker : public BaseSignatureChecker
+{
+protected:
+ BaseSignatureChecker& m_checker;
+
+public:
+ DeferringSignatureChecker(BaseSignatureChecker& checker) : m_checker(checker) {}
+
+ bool CheckECDSASignature(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override
+ {
+ return m_checker.CheckECDSASignature(scriptSig, vchPubKey, scriptCode, sigversion);
+ }
+
+ bool CheckSchnorrSignature(Span<const unsigned char> sig, Span<const unsigned char> pubkey, SigVersion sigversion, const ScriptExecutionData& execdata, ScriptError* serror = nullptr) const override
+ {
+ return m_checker.CheckSchnorrSignature(sig, pubkey, sigversion, execdata, serror);
+ }
+
+ bool CheckLockTime(const CScriptNum& nLockTime) const override
+ {
+ return m_checker.CheckLockTime(nLockTime);
+ }
+ bool CheckSequence(const CScriptNum& nSequence) const override
+ {
+ return m_checker.CheckSequence(nSequence);
+ }
+};
+
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptExecutionData& execdata, ScriptError* error = nullptr);
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* error = nullptr);
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror = nullptr);
diff --git a/src/script/sign.cpp b/src/script/sign.cpp
index 0e6864d547..903c95a5c9 100644
--- a/src/script/sign.cpp
+++ b/src/script/sign.cpp
@@ -253,17 +253,17 @@ bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreato
}
namespace {
-class SignatureExtractorChecker final : public BaseSignatureChecker
+class SignatureExtractorChecker final : public DeferringSignatureChecker
{
private:
SignatureData& sigdata;
- BaseSignatureChecker& checker;
public:
- SignatureExtractorChecker(SignatureData& sigdata, BaseSignatureChecker& checker) : sigdata(sigdata), checker(checker) {}
+ SignatureExtractorChecker(SignatureData& sigdata, BaseSignatureChecker& checker) : DeferringSignatureChecker(checker), sigdata(sigdata) {}
+
bool CheckECDSASignature(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override
{
- if (checker.CheckECDSASignature(scriptSig, vchPubKey, scriptCode, sigversion)) {
+ if (m_checker.CheckECDSASignature(scriptSig, vchPubKey, scriptCode, sigversion)) {
CPubKey pubkey(vchPubKey);
sigdata.signatures.emplace(pubkey.GetID(), SigPair(pubkey, scriptSig));
return true;
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/fuzz/FuzzedDataProvider.h b/src/test/fuzz/FuzzedDataProvider.h
index 3e069eba69..6cbfc39bc2 100644
--- a/src/test/fuzz/FuzzedDataProvider.h
+++ b/src/test/fuzz/FuzzedDataProvider.h
@@ -14,11 +14,13 @@
#define LLVM_FUZZER_FUZZED_DATA_PROVIDER_H_
#include <algorithm>
+#include <array>
#include <climits>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <initializer_list>
+#include <limits>
#include <string>
#include <type_traits>
#include <utility>
@@ -34,272 +36,362 @@ class FuzzedDataProvider {
: data_ptr_(data), remaining_bytes_(size) {}
~FuzzedDataProvider() = default;
- // Returns a std::vector containing |num_bytes| of input data. If fewer than
- // |num_bytes| of data remain, returns a shorter std::vector containing all
- // of the data that's left. Can be used with any byte sized type, such as
- // char, unsigned char, uint8_t, etc.
- template <typename T> std::vector<T> ConsumeBytes(size_t num_bytes) {
- num_bytes = std::min(num_bytes, remaining_bytes_);
- return ConsumeBytes<T>(num_bytes, num_bytes);
- }
+ // See the implementation below (after the class definition) for more verbose
+ // comments for each of the methods.
- // Similar to |ConsumeBytes|, but also appends the terminator value at the end
- // of the resulting vector. Useful, when a mutable null-terminated C-string is
- // needed, for example. But that is a rare case. Better avoid it, if possible,
- // and prefer using |ConsumeBytes| or |ConsumeBytesAsString| methods.
+ // Methods returning std::vector of bytes. These are the most popular choice
+ // when splitting fuzzing input into pieces, as every piece is put into a
+ // separate buffer (i.e. ASan would catch any under-/overflow) and the memory
+ // will be released automatically.
+ template <typename T> std::vector<T> ConsumeBytes(size_t num_bytes);
template <typename T>
- std::vector<T> ConsumeBytesWithTerminator(size_t num_bytes,
- T terminator = 0) {
- num_bytes = std::min(num_bytes, remaining_bytes_);
- std::vector<T> result = ConsumeBytes<T>(num_bytes + 1, num_bytes);
- result.back() = terminator;
- return result;
- }
+ std::vector<T> ConsumeBytesWithTerminator(size_t num_bytes, T terminator = 0);
+ template <typename T> std::vector<T> ConsumeRemainingBytes();
- // Returns a std::string containing |num_bytes| of input data. Using this and
- // |.c_str()| on the resulting string is the best way to get an immutable
- // null-terminated C string. If fewer than |num_bytes| of data remain, returns
- // a shorter std::string containing all of the data that's left.
- std::string ConsumeBytesAsString(size_t num_bytes) {
- static_assert(sizeof(std::string::value_type) == sizeof(uint8_t),
- "ConsumeBytesAsString cannot convert the data to a string.");
-
- num_bytes = std::min(num_bytes, remaining_bytes_);
- std::string result(
- reinterpret_cast<const std::string::value_type *>(data_ptr_),
- num_bytes);
- Advance(num_bytes);
- return result;
- }
+ // Methods returning strings. Use only when you need a std::string or a null
+ // terminated C-string. Otherwise, prefer the methods returning std::vector.
+ std::string ConsumeBytesAsString(size_t num_bytes);
+ std::string ConsumeRandomLengthString(size_t max_length);
+ std::string ConsumeRandomLengthString();
+ std::string ConsumeRemainingBytesAsString();
- // Returns a number in the range [min, max] by consuming bytes from the
- // input data. The value might not be uniformly distributed in the given
- // range. If there's no input data left, always returns |min|. |min| must
- // be less than or equal to |max|.
- template <typename T> T ConsumeIntegralInRange(T min, T max) {
- static_assert(std::is_integral<T>::value, "An integral type is required.");
- static_assert(sizeof(T) <= sizeof(uint64_t), "Unsupported integral type.");
+ // Methods returning integer values.
+ template <typename T> T ConsumeIntegral();
+ template <typename T> T ConsumeIntegralInRange(T min, T max);
- if (min > max)
- abort();
+ // Methods returning floating point values.
+ template <typename T> T ConsumeFloatingPoint();
+ template <typename T> T ConsumeFloatingPointInRange(T min, T max);
- // Use the biggest type possible to hold the range and the result.
- uint64_t range = static_cast<uint64_t>(max) - min;
- uint64_t result = 0;
- size_t offset = 0;
-
- while (offset < sizeof(T) * CHAR_BIT && (range >> offset) > 0 &&
- remaining_bytes_ != 0) {
- // Pull bytes off the end of the seed data. Experimentally, this seems to
- // allow the fuzzer to more easily explore the input space. This makes
- // sense, since it works by modifying inputs that caused new code to run,
- // and this data is often used to encode length of data read by
- // |ConsumeBytes|. Separating out read lengths makes it easier modify the
- // contents of the data that is actually read.
- --remaining_bytes_;
- result = (result << CHAR_BIT) | data_ptr_[remaining_bytes_];
- offset += CHAR_BIT;
- }
+ // 0 <= return value <= 1.
+ template <typename T> T ConsumeProbability();
- // Avoid division by 0, in case |range + 1| results in overflow.
- if (range != std::numeric_limits<decltype(range)>::max())
- result = result % (range + 1);
+ bool ConsumeBool();
- return static_cast<T>(min + result);
- }
+ // Returns a value chosen from the given enum.
+ template <typename T> T ConsumeEnum();
- // Returns a std::string of length from 0 to |max_length|. When it runs out of
- // input data, returns what remains of the input. Designed to be more stable
- // with respect to a fuzzer inserting characters than just picking a random
- // length and then consuming that many bytes with |ConsumeBytes|.
- std::string ConsumeRandomLengthString(size_t max_length) {
- // Reads bytes from the start of |data_ptr_|. Maps "\\" to "\", and maps "\"
- // followed by anything else to the end of the string. As a result of this
- // logic, a fuzzer can insert characters into the string, and the string
- // will be lengthened to include those new characters, resulting in a more
- // stable fuzzer than picking the length of a string independently from
- // picking its contents.
- std::string result;
-
- // Reserve the anticipated capaticity to prevent several reallocations.
- result.reserve(std::min(max_length, remaining_bytes_));
- for (size_t i = 0; i < max_length && remaining_bytes_ != 0; ++i) {
- char next = ConvertUnsignedToSigned<char>(data_ptr_[0]);
- Advance(1);
- if (next == '\\' && remaining_bytes_ != 0) {
- next = ConvertUnsignedToSigned<char>(data_ptr_[0]);
- Advance(1);
- if (next != '\\')
- break;
- }
- result += next;
- }
-
- result.shrink_to_fit();
- return result;
- }
+ // Returns a value from the given array.
+ template <typename T, size_t size> T PickValueInArray(const T (&array)[size]);
+ template <typename T, size_t size>
+ T PickValueInArray(const std::array<T, size> &array);
+ template <typename T> T PickValueInArray(std::initializer_list<const T> list);
- // Returns a std::vector containing all remaining bytes of the input data.
- template <typename T> std::vector<T> ConsumeRemainingBytes() {
- return ConsumeBytes<T>(remaining_bytes_);
- }
+ // Writes data to the given destination and returns number of bytes written.
+ size_t ConsumeData(void *destination, size_t num_bytes);
- // Returns a std::string containing all remaining bytes of the input data.
- // Prefer using |ConsumeRemainingBytes| unless you actually need a std::string
- // object.
- std::string ConsumeRemainingBytesAsString() {
- return ConsumeBytesAsString(remaining_bytes_);
- }
+ // Reports the remaining bytes available for fuzzed input.
+ size_t remaining_bytes() { return remaining_bytes_; }
- // Returns a number in the range [Type's min, Type's max]. The value might
- // not be uniformly distributed in the given range. If there's no input data
- // left, always returns |min|.
- template <typename T> T ConsumeIntegral() {
- return ConsumeIntegralInRange(std::numeric_limits<T>::min(),
- std::numeric_limits<T>::max());
- }
+ private:
+ FuzzedDataProvider(const FuzzedDataProvider &) = delete;
+ FuzzedDataProvider &operator=(const FuzzedDataProvider &) = delete;
- // Reads one byte and returns a bool, or false when no data remains.
- bool ConsumeBool() { return 1 & ConsumeIntegral<uint8_t>(); }
+ void CopyAndAdvance(void *destination, size_t num_bytes);
- // Returns a copy of the value selected from the given fixed-size |array|.
- template <typename T, size_t size>
- T PickValueInArray(const T (&array)[size]) {
- static_assert(size > 0, "The array must be non empty.");
- return array[ConsumeIntegralInRange<size_t>(0, size - 1)];
- }
+ void Advance(size_t num_bytes);
template <typename T>
- T PickValueInArray(std::initializer_list<const T> list) {
- // TODO(Dor1s): switch to static_assert once C++14 is allowed.
- if (!list.size())
- abort();
-
- return *(list.begin() + ConsumeIntegralInRange<size_t>(0, list.size() - 1));
- }
-
- // Returns an enum value. The enum must start at 0 and be contiguous. It must
- // also contain |kMaxValue| aliased to its largest (inclusive) value. Such as:
- // enum class Foo { SomeValue, OtherValue, kMaxValue = OtherValue };
- template <typename T> T ConsumeEnum() {
- static_assert(std::is_enum<T>::value, "|T| must be an enum type.");
- return static_cast<T>(ConsumeIntegralInRange<uint32_t>(
- 0, static_cast<uint32_t>(T::kMaxValue)));
- }
+ std::vector<T> ConsumeBytes(size_t size, size_t num_bytes);
- // Returns a floating point number in the range [0.0, 1.0]. If there's no
- // input data left, always returns 0.
- template <typename T> T ConsumeProbability() {
- static_assert(std::is_floating_point<T>::value,
- "A floating point type is required.");
+ template <typename TS, typename TU> TS ConvertUnsignedToSigned(TU value);
- // Use different integral types for different floating point types in order
- // to provide better density of the resulting values.
- using IntegralType =
- typename std::conditional<(sizeof(T) <= sizeof(uint32_t)), uint32_t,
- uint64_t>::type;
+ const uint8_t *data_ptr_;
+ size_t remaining_bytes_;
+};
- T result = static_cast<T>(ConsumeIntegral<IntegralType>());
- result /= static_cast<T>(std::numeric_limits<IntegralType>::max());
- return result;
+// Returns a std::vector containing |num_bytes| of input data. If fewer than
+// |num_bytes| of data remain, returns a shorter std::vector containing all
+// of the data that's left. Can be used with any byte sized type, such as
+// char, unsigned char, uint8_t, etc.
+template <typename T>
+std::vector<T> FuzzedDataProvider::ConsumeBytes(size_t num_bytes) {
+ num_bytes = std::min(num_bytes, remaining_bytes_);
+ return ConsumeBytes<T>(num_bytes, num_bytes);
+}
+
+// Similar to |ConsumeBytes|, but also appends the terminator value at the end
+// of the resulting vector. Useful, when a mutable null-terminated C-string is
+// needed, for example. But that is a rare case. Better avoid it, if possible,
+// and prefer using |ConsumeBytes| or |ConsumeBytesAsString| methods.
+template <typename T>
+std::vector<T> FuzzedDataProvider::ConsumeBytesWithTerminator(size_t num_bytes,
+ T terminator) {
+ num_bytes = std::min(num_bytes, remaining_bytes_);
+ std::vector<T> result = ConsumeBytes<T>(num_bytes + 1, num_bytes);
+ result.back() = terminator;
+ return result;
+}
+
+// Returns a std::vector containing all remaining bytes of the input data.
+template <typename T>
+std::vector<T> FuzzedDataProvider::ConsumeRemainingBytes() {
+ return ConsumeBytes<T>(remaining_bytes_);
+}
+
+// Returns a std::string containing |num_bytes| of input data. Using this and
+// |.c_str()| on the resulting string is the best way to get an immutable
+// null-terminated C string. If fewer than |num_bytes| of data remain, returns
+// a shorter std::string containing all of the data that's left.
+inline std::string FuzzedDataProvider::ConsumeBytesAsString(size_t num_bytes) {
+ static_assert(sizeof(std::string::value_type) == sizeof(uint8_t),
+ "ConsumeBytesAsString cannot convert the data to a string.");
+
+ num_bytes = std::min(num_bytes, remaining_bytes_);
+ std::string result(
+ reinterpret_cast<const std::string::value_type *>(data_ptr_), num_bytes);
+ Advance(num_bytes);
+ return result;
+}
+
+// Returns a std::string of length from 0 to |max_length|. When it runs out of
+// input data, returns what remains of the input. Designed to be more stable
+// with respect to a fuzzer inserting characters than just picking a random
+// length and then consuming that many bytes with |ConsumeBytes|.
+inline std::string
+FuzzedDataProvider::ConsumeRandomLengthString(size_t max_length) {
+ // Reads bytes from the start of |data_ptr_|. Maps "\\" to "\", and maps "\"
+ // followed by anything else to the end of the string. As a result of this
+ // logic, a fuzzer can insert characters into the string, and the string
+ // will be lengthened to include those new characters, resulting in a more
+ // stable fuzzer than picking the length of a string independently from
+ // picking its contents.
+ std::string result;
+
+ // Reserve the anticipated capaticity to prevent several reallocations.
+ result.reserve(std::min(max_length, remaining_bytes_));
+ for (size_t i = 0; i < max_length && remaining_bytes_ != 0; ++i) {
+ char next = ConvertUnsignedToSigned<char>(data_ptr_[0]);
+ Advance(1);
+ if (next == '\\' && remaining_bytes_ != 0) {
+ next = ConvertUnsignedToSigned<char>(data_ptr_[0]);
+ Advance(1);
+ if (next != '\\')
+ break;
+ }
+ result += next;
}
- // Returns a floating point value in the range [Type's lowest, Type's max] by
- // consuming bytes from the input data. If there's no input data left, always
- // returns approximately 0.
- template <typename T> T ConsumeFloatingPoint() {
- return ConsumeFloatingPointInRange<T>(std::numeric_limits<T>::lowest(),
- std::numeric_limits<T>::max());
+ result.shrink_to_fit();
+ return result;
+}
+
+// Returns a std::string of length from 0 to |remaining_bytes_|.
+inline std::string FuzzedDataProvider::ConsumeRandomLengthString() {
+ return ConsumeRandomLengthString(remaining_bytes_);
+}
+
+// Returns a std::string containing all remaining bytes of the input data.
+// Prefer using |ConsumeRemainingBytes| unless you actually need a std::string
+// object.
+inline std::string FuzzedDataProvider::ConsumeRemainingBytesAsString() {
+ return ConsumeBytesAsString(remaining_bytes_);
+}
+
+// Returns a number in the range [Type's min, Type's max]. The value might
+// not be uniformly distributed in the given range. If there's no input data
+// left, always returns |min|.
+template <typename T> T FuzzedDataProvider::ConsumeIntegral() {
+ return ConsumeIntegralInRange(std::numeric_limits<T>::min(),
+ std::numeric_limits<T>::max());
+}
+
+// Returns a number in the range [min, max] by consuming bytes from the
+// input data. The value might not be uniformly distributed in the given
+// range. If there's no input data left, always returns |min|. |min| must
+// be less than or equal to |max|.
+template <typename T>
+T FuzzedDataProvider::ConsumeIntegralInRange(T min, T max) {
+ static_assert(std::is_integral<T>::value, "An integral type is required.");
+ static_assert(sizeof(T) <= sizeof(uint64_t), "Unsupported integral type.");
+
+ if (min > max)
+ abort();
+
+ // Use the biggest type possible to hold the range and the result.
+ uint64_t range = static_cast<uint64_t>(max) - min;
+ uint64_t result = 0;
+ size_t offset = 0;
+
+ while (offset < sizeof(T) * CHAR_BIT && (range >> offset) > 0 &&
+ remaining_bytes_ != 0) {
+ // Pull bytes off the end of the seed data. Experimentally, this seems to
+ // allow the fuzzer to more easily explore the input space. This makes
+ // sense, since it works by modifying inputs that caused new code to run,
+ // and this data is often used to encode length of data read by
+ // |ConsumeBytes|. Separating out read lengths makes it easier modify the
+ // contents of the data that is actually read.
+ --remaining_bytes_;
+ result = (result << CHAR_BIT) | data_ptr_[remaining_bytes_];
+ offset += CHAR_BIT;
}
- // Returns a floating point value in the given range by consuming bytes from
- // the input data. If there's no input data left, returns |min|. Note that
- // |min| must be less than or equal to |max|.
- template <typename T> T ConsumeFloatingPointInRange(T min, T max) {
- if (min > max)
- abort();
-
- T range = .0;
- T result = min;
- constexpr T zero(.0);
- if (max > zero && min < zero && max > min + std::numeric_limits<T>::max()) {
- // The diff |max - min| would overflow the given floating point type. Use
- // the half of the diff as the range and consume a bool to decide whether
- // the result is in the first of the second part of the diff.
- range = (max / 2.0) - (min / 2.0);
- if (ConsumeBool()) {
- result += range;
- }
- } else {
- range = max - min;
+ // Avoid division by 0, in case |range + 1| results in overflow.
+ if (range != std::numeric_limits<decltype(range)>::max())
+ result = result % (range + 1);
+
+ return static_cast<T>(min + result);
+}
+
+// Returns a floating point value in the range [Type's lowest, Type's max] by
+// consuming bytes from the input data. If there's no input data left, always
+// returns approximately 0.
+template <typename T> T FuzzedDataProvider::ConsumeFloatingPoint() {
+ return ConsumeFloatingPointInRange<T>(std::numeric_limits<T>::lowest(),
+ std::numeric_limits<T>::max());
+}
+
+// Returns a floating point value in the given range by consuming bytes from
+// the input data. If there's no input data left, returns |min|. Note that
+// |min| must be less than or equal to |max|.
+template <typename T>
+T FuzzedDataProvider::ConsumeFloatingPointInRange(T min, T max) {
+ if (min > max)
+ abort();
+
+ T range = .0;
+ T result = min;
+ constexpr T zero(.0);
+ if (max > zero && min < zero && max > min + std::numeric_limits<T>::max()) {
+ // The diff |max - min| would overflow the given floating point type. Use
+ // the half of the diff as the range and consume a bool to decide whether
+ // the result is in the first of the second part of the diff.
+ range = (max / 2.0) - (min / 2.0);
+ if (ConsumeBool()) {
+ result += range;
}
-
- return result + range * ConsumeProbability<T>();
+ } else {
+ range = max - min;
}
- // Reports the remaining bytes available for fuzzed input.
- size_t remaining_bytes() { return remaining_bytes_; }
-
- private:
- FuzzedDataProvider(const FuzzedDataProvider &) = delete;
- FuzzedDataProvider &operator=(const FuzzedDataProvider &) = delete;
-
- void Advance(size_t num_bytes) {
- if (num_bytes > remaining_bytes_)
+ return result + range * ConsumeProbability<T>();
+}
+
+// Returns a floating point number in the range [0.0, 1.0]. If there's no
+// input data left, always returns 0.
+template <typename T> T FuzzedDataProvider::ConsumeProbability() {
+ static_assert(std::is_floating_point<T>::value,
+ "A floating point type is required.");
+
+ // Use different integral types for different floating point types in order
+ // to provide better density of the resulting values.
+ using IntegralType =
+ typename std::conditional<(sizeof(T) <= sizeof(uint32_t)), uint32_t,
+ uint64_t>::type;
+
+ T result = static_cast<T>(ConsumeIntegral<IntegralType>());
+ result /= static_cast<T>(std::numeric_limits<IntegralType>::max());
+ return result;
+}
+
+// Reads one byte and returns a bool, or false when no data remains.
+inline bool FuzzedDataProvider::ConsumeBool() {
+ return 1 & ConsumeIntegral<uint8_t>();
+}
+
+// Returns an enum value. The enum must start at 0 and be contiguous. It must
+// also contain |kMaxValue| aliased to its largest (inclusive) value. Such as:
+// enum class Foo { SomeValue, OtherValue, kMaxValue = OtherValue };
+template <typename T> T FuzzedDataProvider::ConsumeEnum() {
+ static_assert(std::is_enum<T>::value, "|T| must be an enum type.");
+ return static_cast<T>(
+ ConsumeIntegralInRange<uint32_t>(0, static_cast<uint32_t>(T::kMaxValue)));
+}
+
+// Returns a copy of the value selected from the given fixed-size |array|.
+template <typename T, size_t size>
+T FuzzedDataProvider::PickValueInArray(const T (&array)[size]) {
+ static_assert(size > 0, "The array must be non empty.");
+ return array[ConsumeIntegralInRange<size_t>(0, size - 1)];
+}
+
+template <typename T, size_t size>
+T FuzzedDataProvider::PickValueInArray(const std::array<T, size> &array) {
+ static_assert(size > 0, "The array must be non empty.");
+ return array[ConsumeIntegralInRange<size_t>(0, size - 1)];
+}
+
+template <typename T>
+T FuzzedDataProvider::PickValueInArray(std::initializer_list<const T> list) {
+ // TODO(Dor1s): switch to static_assert once C++14 is allowed.
+ if (!list.size())
+ abort();
+
+ return *(list.begin() + ConsumeIntegralInRange<size_t>(0, list.size() - 1));
+}
+
+// Writes |num_bytes| of input data to the given destination pointer. If there
+// is not enough data left, writes all remaining bytes. Return value is the
+// number of bytes written.
+// In general, it's better to avoid using this function, but it may be useful
+// in cases when it's necessary to fill a certain buffer or object with
+// fuzzing data.
+inline size_t FuzzedDataProvider::ConsumeData(void *destination,
+ size_t num_bytes) {
+ num_bytes = std::min(num_bytes, remaining_bytes_);
+ CopyAndAdvance(destination, num_bytes);
+ return num_bytes;
+}
+
+// Private methods.
+inline void FuzzedDataProvider::CopyAndAdvance(void *destination,
+ size_t num_bytes) {
+ std::memcpy(destination, data_ptr_, num_bytes);
+ Advance(num_bytes);
+}
+
+inline void FuzzedDataProvider::Advance(size_t num_bytes) {
+ if (num_bytes > remaining_bytes_)
+ abort();
+
+ data_ptr_ += num_bytes;
+ remaining_bytes_ -= num_bytes;
+}
+
+template <typename T>
+std::vector<T> FuzzedDataProvider::ConsumeBytes(size_t size, size_t num_bytes) {
+ static_assert(sizeof(T) == sizeof(uint8_t), "Incompatible data type.");
+
+ // The point of using the size-based constructor below is to increase the
+ // odds of having a vector object with capacity being equal to the length.
+ // That part is always implementation specific, but at least both libc++ and
+ // libstdc++ allocate the requested number of bytes in that constructor,
+ // which seems to be a natural choice for other implementations as well.
+ // To increase the odds even more, we also call |shrink_to_fit| below.
+ std::vector<T> result(size);
+ if (size == 0) {
+ if (num_bytes != 0)
abort();
-
- data_ptr_ += num_bytes;
- remaining_bytes_ -= num_bytes;
- }
-
- template <typename T>
- std::vector<T> ConsumeBytes(size_t size, size_t num_bytes_to_consume) {
- static_assert(sizeof(T) == sizeof(uint8_t), "Incompatible data type.");
-
- // The point of using the size-based constructor below is to increase the
- // odds of having a vector object with capacity being equal to the length.
- // That part is always implementation specific, but at least both libc++ and
- // libstdc++ allocate the requested number of bytes in that constructor,
- // which seems to be a natural choice for other implementations as well.
- // To increase the odds even more, we also call |shrink_to_fit| below.
- std::vector<T> result(size);
- if (size == 0) {
- if (num_bytes_to_consume != 0)
- abort();
- return result;
- }
-
- std::memcpy(result.data(), data_ptr_, num_bytes_to_consume);
- Advance(num_bytes_to_consume);
-
- // Even though |shrink_to_fit| is also implementation specific, we expect it
- // to provide an additional assurance in case vector's constructor allocated
- // a buffer which is larger than the actual amount of data we put inside it.
- result.shrink_to_fit();
return result;
}
- template <typename TS, typename TU> TS ConvertUnsignedToSigned(TU value) {
- static_assert(sizeof(TS) == sizeof(TU), "Incompatible data types.");
- static_assert(!std::numeric_limits<TU>::is_signed,
- "Source type must be unsigned.");
-
- // TODO(Dor1s): change to `if constexpr` once C++17 becomes mainstream.
- if (std::numeric_limits<TS>::is_modulo)
- return static_cast<TS>(value);
-
- // Avoid using implementation-defined unsigned to signer conversions.
- // To learn more, see https://stackoverflow.com/questions/13150449.
- if (value <= std::numeric_limits<TS>::max()) {
- return static_cast<TS>(value);
- } else {
- constexpr auto TS_min = std::numeric_limits<TS>::min();
- return TS_min + static_cast<char>(value - TS_min);
- }
+ CopyAndAdvance(result.data(), num_bytes);
+
+ // Even though |shrink_to_fit| is also implementation specific, we expect it
+ // to provide an additional assurance in case vector's constructor allocated
+ // a buffer which is larger than the actual amount of data we put inside it.
+ result.shrink_to_fit();
+ return result;
+}
+
+template <typename TS, typename TU>
+TS FuzzedDataProvider::ConvertUnsignedToSigned(TU value) {
+ static_assert(sizeof(TS) == sizeof(TU), "Incompatible data types.");
+ static_assert(!std::numeric_limits<TU>::is_signed,
+ "Source type must be unsigned.");
+
+ // TODO(Dor1s): change to `if constexpr` once C++17 becomes mainstream.
+ if (std::numeric_limits<TS>::is_modulo)
+ return static_cast<TS>(value);
+
+ // Avoid using implementation-defined unsigned to signed conversions.
+ // To learn more, see https://stackoverflow.com/questions/13150449.
+ if (value <= std::numeric_limits<TS>::max()) {
+ return static_cast<TS>(value);
+ } else {
+ constexpr auto TS_min = std::numeric_limits<TS>::min();
+ return TS_min + static_cast<char>(value - TS_min);
}
-
- const uint8_t *data_ptr_;
- size_t remaining_bytes_;
-};
+}
#endif // LLVM_FUZZER_FUZZED_DATA_PROVIDER_H_
diff --git a/src/test/fuzz/bech32.cpp b/src/test/fuzz/bech32.cpp
index 8b91f9bc96..0ac1f02263 100644
--- a/src/test/fuzz/bech32.cpp
+++ b/src/test/fuzz/bech32.cpp
@@ -16,28 +16,28 @@
void test_one_input(const std::vector<uint8_t>& buffer)
{
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/netbase_tests.cpp b/src/test/netbase_tests.cpp
index f5d26fafef..36f18fcf67 100644
--- a/src/test/netbase_tests.cpp
+++ b/src/test/netbase_tests.cpp
@@ -224,8 +224,22 @@ BOOST_AUTO_TEST_CASE(subnet_test)
// IPv4 address with IPv6 netmask or the other way around.
BOOST_CHECK(!CSubNet(ResolveIP("1.1.1.1"), ResolveIP("ffff::")).IsValid());
BOOST_CHECK(!CSubNet(ResolveIP("::1"), ResolveIP("255.0.0.0")).IsValid());
- // Can't subnet TOR (or any other non-IPv4 and non-IPv6 network).
- BOOST_CHECK(!CSubNet(ResolveIP("5wyqrzbvrdsumnok.onion"), ResolveIP("255.0.0.0")).IsValid());
+
+ // Create Non-IP subnets.
+
+ const CNetAddr tor_addr{
+ ResolveIP("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion")};
+
+ subnet = CSubNet(tor_addr);
+ BOOST_CHECK(subnet.IsValid());
+ BOOST_CHECK_EQUAL(subnet.ToString(), tor_addr.ToString());
+ BOOST_CHECK(subnet.Match(tor_addr));
+ BOOST_CHECK(
+ !subnet.Match(ResolveIP("kpgvmscirrdqpekbqjsvw5teanhatztpp2gl6eee4zkowvwfxwenqaid.onion")));
+ BOOST_CHECK(!subnet.Match(ResolveIP("1.2.3.4")));
+
+ BOOST_CHECK(!CSubNet(tor_addr, 200).IsValid());
+ BOOST_CHECK(!CSubNet(tor_addr, ResolveIP("255.0.0.0")).IsValid());
subnet = ResolveSubNet("1.2.3.4/255.255.255.255");
BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.4/32");
@@ -440,8 +454,7 @@ BOOST_AUTO_TEST_CASE(netbase_dont_resolve_strings_with_embedded_nul_characters)
BOOST_CHECK(!LookupSubNet(std::string("1.2.3.0/24\0", 11), ret));
BOOST_CHECK(!LookupSubNet(std::string("1.2.3.0/24\0example.com", 22), ret));
BOOST_CHECK(!LookupSubNet(std::string("1.2.3.0/24\0example.com\0", 23), ret));
- // We only do subnetting for IPv4 and IPv6
- BOOST_CHECK(!LookupSubNet(std::string("5wyqrzbvrdsumnok.onion", 22), ret));
+ BOOST_CHECK(LookupSubNet(std::string("5wyqrzbvrdsumnok.onion", 22), ret));
BOOST_CHECK(!LookupSubNet(std::string("5wyqrzbvrdsumnok.onion\0", 23), ret));
BOOST_CHECK(!LookupSubNet(std::string("5wyqrzbvrdsumnok.onion\0example.com", 34), ret));
BOOST_CHECK(!LookupSubNet(std::string("5wyqrzbvrdsumnok.onion\0example.com\0", 35), ret));
diff --git a/src/util/time.cpp b/src/util/time.cpp
index e96972fe12..d130e4e4d4 100644
--- a/src/util/time.cpp
+++ b/src/util/time.cpp
@@ -9,6 +9,8 @@
#include <util/time.h>
+#include <util/check.h>
+
#include <atomic>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <ctime>
@@ -18,7 +20,7 @@
void UninterruptibleSleep(const std::chrono::microseconds& n) { std::this_thread::sleep_for(n); }
-static std::atomic<int64_t> nMockTime(0); //!< For unit testing
+static std::atomic<int64_t> nMockTime(0); //!< For testing
int64_t GetTime()
{
@@ -46,6 +48,7 @@ template std::chrono::microseconds GetTime();
void SetMockTime(int64_t nMockTimeIn)
{
+ Assert(nMockTimeIn >= 0);
nMockTime.store(nMockTimeIn, std::memory_order_relaxed);
}
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index e8c3ae888d..37d672ace1 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -400,6 +400,12 @@ UniValue SendMoney(CWallet* const pwallet, const CCoinControl &coin_control, std
{
EnsureWalletIsUnlocked(pwallet);
+ // This function is only used by sendtoaddress and sendmany.
+ // This should always try to sign, if we don't have private keys, don't try to do anything here.
+ if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "Error: Private keys are disabled for this wallet");
+ }
+
// Shuffle recipient list
std::shuffle(recipients.begin(), recipients.end(), FastRandomContext());
@@ -409,7 +415,7 @@ UniValue SendMoney(CWallet* const pwallet, const CCoinControl &coin_control, std
bilingual_str error;
CTransactionRef tx;
FeeCalculation fee_calc_out;
- bool fCreated = pwallet->CreateTransaction(recipients, tx, nFeeRequired, nChangePosRet, error, coin_control, fee_calc_out, !pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS));
+ const bool fCreated = pwallet->CreateTransaction(recipients, tx, nFeeRequired, nChangePosRet, error, coin_control, fee_calc_out, true);
if (!fCreated) {
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, error.original);
}