aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/descriptors.md2
-rw-r--r--src/addrman.h16
-rw-r--r--src/core_read.cpp25
-rw-r--r--src/init.cpp2
-rw-r--r--src/net.cpp37
-rw-r--r--src/net.h30
-rw-r--r--src/net_processing.cpp11
-rw-r--r--src/qt/bitcoin.cpp2
-rw-r--r--src/qt/bitcoingui.cpp2
-rw-r--r--src/qt/bitcoingui.h1
-rw-r--r--src/qt/forms/optionsdialog.ui2
-rw-r--r--src/qt/guiutil.cpp31
-rw-r--r--src/qt/guiutil.h40
-rw-r--r--src/qt/optionsmodel.cpp2
-rw-r--r--src/qt/overviewpage.cpp1
-rw-r--r--src/qt/paymentserver.cpp1
-rw-r--r--src/qt/qrimagewidget.cpp13
-rw-r--r--src/qt/rpcconsole.cpp40
-rw-r--r--src/qt/rpcconsole.h7
-rw-r--r--src/qt/sendcoinsdialog.cpp7
-rw-r--r--src/qt/splashscreen.cpp4
-rw-r--r--src/qt/splashscreen.h2
-rw-r--r--src/qt/transactionview.cpp18
-rw-r--r--src/test/base32_tests.cpp19
-rw-r--r--src/test/base58_tests.cpp24
-rw-r--r--src/test/base64_tests.cpp19
-rw-r--r--src/test/fuzz/net.cpp2
-rw-r--r--src/test/fuzz/p2p_transport_deserializer.cpp9
-rw-r--r--src/test/net_tests.cpp6
-rw-r--r--src/test/netbase_tests.cpp26
-rw-r--r--src/test/util/net.cpp8
-rw-r--r--src/test/util/net.h2
-rw-r--r--src/test/util_tests.cpp9
-rw-r--r--src/validation.cpp16
-rwxr-xr-xtest/functional/feature_taproot.py14
-rwxr-xr-xtest/functional/mempool_spend_coinbase.py28
-rwxr-xr-xtest/functional/p2p_fingerprint.py44
-rw-r--r--test/functional/test_framework/wallet.py17
-rw-r--r--test/util/data/bitcoin-util-test.json2
39 files changed, 310 insertions, 231 deletions
diff --git a/doc/descriptors.md b/doc/descriptors.md
index 181ff77e50..63acb9167f 100644
--- a/doc/descriptors.md
+++ b/doc/descriptors.md
@@ -50,7 +50,7 @@ Output descriptors currently support:
- `wsh(multi(2,03a0434d9e47f3c86235477c7b1ae6ae5d3442d49b1943c2b752a68e2a47e247c7,03774ae7f858a9411e5ef4246b70c65aac5649980be5c17891bbec17895da008cb,03d01115d548e7561b15c38f004d734633687cf4419620095bc5b0f47070afe85a))` describes a P2WSH *2-of-3* multisig output with keys in the specified order.
- `sh(wsh(multi(1,03f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8,03499fdf9e895e719cfd64e67f07d38e3226aa7b63678949e6e49b241a60e823e4,02d7924d4f7d43ea965a465ae3095ff41131e5946f3c85f79e44adbcf8e27e080e)))` describes a P2SH-P2WSH *1-of-3* multisig output with keys in the specified order.
- `pk(xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8)` describes a P2PK output with the public key of the specified xpub.
-- `pkh(xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw/1'/2)` describes a P2PKH output with child key *1'/2* of the specified xpub.
+- `pkh(xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw/1/2)` describes a P2PKH output with child key *1/2* of the specified xpub.
- `pkh([d34db33f/44'/0'/0']xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/1/*)` describes a set of P2PKH outputs, but additionally specifies that the specified xpub is a child of a master with fingerprint `d34db33f`, and derived using path `44'/0'/0'`.
- `wsh(multi(1,xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/1/0/*,xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/0/0/*))` describes a set of *1-of-2* P2WSH multisig outputs where the first multisig key is the *1/0/`i`* child of the first specified xpub and the second multisig key is the *0/0/`i`* child of the second specified xpub, and `i` is any number in a configurable range (`0-1000` by default).
- `wsh(sortedmulti(1,xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/1/0/*,xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/0/0/*))` describes a set of *1-of-2* P2WSH multisig outputs where one multisig key is the *1/0/`i`* child of the first specified xpub and the other multisig key is the *0/0/`i`* child of the second specified xpub, and `i` is any number in a configurable range (`0-1000` by default). The order of public keys in the resulting witnessScripts is determined by the lexicographic order of the public keys at that index.
diff --git a/src/addrman.h b/src/addrman.h
index 04dd30b375..9ac67b7af6 100644
--- a/src/addrman.h
+++ b/src/addrman.h
@@ -281,8 +281,18 @@ protected:
//! Select several addresses at once.
void GetAddr_(std::vector<CAddress> &vAddr, size_t max_addresses, size_t max_pct) EXCLUSIVE_LOCKS_REQUIRED(cs);
- //! Mark an entry as currently-connected-to.
- void Connected_(const CService &addr, int64_t nTime) EXCLUSIVE_LOCKS_REQUIRED(cs);
+ /** We have successfully connected to this peer. Calling this function
+ * updates the CAddress's nTime, which is used in our IsTerrible()
+ * decisions and gossiped to peers. Callers should be careful that updating
+ * this information doesn't leak topology information to network spies.
+ *
+ * net_processing calls this function when it *disconnects* from a peer to
+ * not leak information about currently connected peers.
+ *
+ * @param[in] addr The address of the peer we were connected to
+ * @param[in] nTime The time that we were last connected to this peer
+ */
+ void Connected_(const CService& addr, int64_t nTime) EXCLUSIVE_LOCKS_REQUIRED(cs);
//! Update an entry's service bits.
void SetServices_(const CService &addr, ServiceFlags nServices) EXCLUSIVE_LOCKS_REQUIRED(cs);
@@ -704,7 +714,7 @@ public:
return vAddr;
}
- //! Mark an entry as currently-connected-to.
+ //! Outer function for Connected_()
void Connected(const CService &addr, int64_t nTime = GetAdjustedTime())
{
LOCK(cs);
diff --git a/src/core_read.cpp b/src/core_read.cpp
index c6416e6f07..a2eebbd528 100644
--- a/src/core_read.cpp
+++ b/src/core_read.cpp
@@ -20,10 +20,10 @@
#include <algorithm>
#include <string>
-CScript ParseScript(const std::string& s)
-{
- CScript result;
+namespace {
+opcodetype ParseOpCode(const std::string& s)
+{
static std::map<std::string, opcodetype> mapOpNames;
if (mapOpNames.empty())
@@ -45,6 +45,17 @@ CScript ParseScript(const std::string& s)
}
}
+ auto it = mapOpNames.find(s);
+ if (it == mapOpNames.end()) throw std::runtime_error("script parse error: unknown opcode");
+ return it->second;
+}
+
+} // namespace
+
+CScript ParseScript(const std::string& s)
+{
+ CScript result;
+
std::vector<std::string> words;
boost::algorithm::split(words, s, boost::algorithm::is_any_of(" \t\n"), boost::algorithm::token_compress_on);
@@ -82,14 +93,10 @@ CScript ParseScript(const std::string& s)
std::vector<unsigned char> value(w->begin()+1, w->end()-1);
result << value;
}
- else if (mapOpNames.count(*w))
- {
- // opcode, e.g. OP_ADD or ADD:
- result << mapOpNames[*w];
- }
else
{
- throw std::runtime_error("script parse error");
+ // opcode, e.g. OP_ADD or ADD:
+ result << ParseOpCode(*w);
}
}
diff --git a/src/init.cpp b/src/init.cpp
index 495d96f938..1e41616e94 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -1039,7 +1039,7 @@ bool AppInitParameterInteraction(const ArgsManager& args)
// Trim requested connection counts, to fit into system limitations
// <int> in std::min<int>(...) to work around FreeBSD compilation issue described in #2695
- nFD = RaiseFileDescriptorLimit(nMaxConnections + MIN_CORE_FILEDESCRIPTORS + MAX_ADDNODE_CONNECTIONS);
+ nFD = RaiseFileDescriptorLimit(nMaxConnections + MIN_CORE_FILEDESCRIPTORS + MAX_ADDNODE_CONNECTIONS + nBind);
#ifdef USE_POLL
int fd_max = nFD;
#else
diff --git a/src/net.cpp b/src/net.cpp
index 20c1763ea6..e8f5bc2116 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -629,34 +629,21 @@ void CNode::copyStats(CNodeStats &stats, const std::vector<bool> &m_asmap)
}
#undef X
-/**
- * Receive bytes from the buffer and deserialize them into messages.
- *
- * @param[in] pch A pointer to the raw data
- * @param[in] nBytes Size of the data
- * @param[out] complete Set True if at least one message has been
- * deserialized and is ready to be processed
- * @return True if the peer should stay connected,
- * False if the peer should be disconnected from.
- */
-bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes, bool& complete)
+bool CNode::ReceiveMsgBytes(Span<const char> msg_bytes, bool& complete)
{
complete = false;
const auto time = GetTime<std::chrono::microseconds>();
LOCK(cs_vRecv);
nLastRecv = std::chrono::duration_cast<std::chrono::seconds>(time).count();
- nRecvBytes += nBytes;
- while (nBytes > 0) {
+ nRecvBytes += msg_bytes.size();
+ while (msg_bytes.size() > 0) {
// absorb network data
- int handled = m_deserializer->Read(pch, nBytes);
+ int handled = m_deserializer->Read(msg_bytes);
if (handled < 0) {
// Serious header problem, disconnect from the peer.
return false;
}
- pch += handled;
- nBytes -= handled;
-
if (m_deserializer->Complete()) {
// decompose a transport agnostic CNetMessage from the deserializer
uint32_t out_err_raw_size{0};
@@ -686,13 +673,13 @@ bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes, bool& complete
return true;
}
-int V1TransportDeserializer::readHeader(const char *pch, unsigned int nBytes)
+int V1TransportDeserializer::readHeader(Span<const char> msg_bytes)
{
// copy data to temporary parsing buffer
unsigned int nRemaining = CMessageHeader::HEADER_SIZE - nHdrPos;
- unsigned int nCopy = std::min(nRemaining, nBytes);
+ unsigned int nCopy = std::min<unsigned int>(nRemaining, msg_bytes.size());
- memcpy(&hdrbuf[nHdrPos], pch, nCopy);
+ memcpy(&hdrbuf[nHdrPos], msg_bytes.data(), nCopy);
nHdrPos += nCopy;
// if header incomplete, exit
@@ -726,18 +713,18 @@ int V1TransportDeserializer::readHeader(const char *pch, unsigned int nBytes)
return nCopy;
}
-int V1TransportDeserializer::readData(const char *pch, unsigned int nBytes)
+int V1TransportDeserializer::readData(Span<const char> msg_bytes)
{
unsigned int nRemaining = hdr.nMessageSize - nDataPos;
- unsigned int nCopy = std::min(nRemaining, nBytes);
+ unsigned int nCopy = std::min<unsigned int>(nRemaining, msg_bytes.size());
if (vRecv.size() < nDataPos + nCopy) {
// Allocate up to 256 KiB ahead, but never more than the total message size.
vRecv.resize(std::min(hdr.nMessageSize, nDataPos + nCopy + 256 * 1024));
}
- hasher.Write({(const unsigned char*)pch, nCopy});
- memcpy(&vRecv[nDataPos], pch, nCopy);
+ hasher.Write(MakeUCharSpan(msg_bytes.first(nCopy)));
+ memcpy(&vRecv[nDataPos], msg_bytes.data(), nCopy);
nDataPos += nCopy;
return nCopy;
@@ -1487,7 +1474,7 @@ void CConnman::SocketHandler()
if (nBytes > 0)
{
bool notify = false;
- if (!pnode->ReceiveMsgBytes(pchBuf, nBytes, notify))
+ if (!pnode->ReceiveMsgBytes(Span<const char>(pchBuf, nBytes), notify))
pnode->CloseSocketDisconnect();
RecordBytesRecv(nBytes);
if (notify) {
diff --git a/src/net.h b/src/net.h
index a6dcf7f610..b14c860f7d 100644
--- a/src/net.h
+++ b/src/net.h
@@ -757,8 +757,8 @@ public:
virtual bool Complete() const = 0;
// set the serialization context version
virtual void SetVersion(int version) = 0;
- // read and deserialize data
- virtual int Read(const char *data, unsigned int bytes) = 0;
+ /** read and deserialize data, advances msg_bytes data pointer */
+ virtual int Read(Span<const char>& msg_bytes) = 0;
// decomposes a message from the context
virtual Optional<CNetMessage> GetMessage(std::chrono::microseconds time, uint32_t& out_err) = 0;
virtual ~TransportDeserializer() {}
@@ -779,8 +779,8 @@ private:
unsigned int nDataPos;
const uint256& GetMessageHash() const;
- int readHeader(const char *pch, unsigned int nBytes);
- int readData(const char *pch, unsigned int nBytes);
+ int readHeader(Span<const char> msg_bytes);
+ int readData(Span<const char> msg_bytes);
void Reset() {
vRecv.clear();
@@ -814,9 +814,14 @@ public:
hdrbuf.SetVersion(nVersionIn);
vRecv.SetVersion(nVersionIn);
}
- int Read(const char *pch, unsigned int nBytes) override {
- int ret = in_data ? readData(pch, nBytes) : readHeader(pch, nBytes);
- if (ret < 0) Reset();
+ int Read(Span<const char>& msg_bytes) override
+ {
+ int ret = in_data ? readData(msg_bytes) : readHeader(msg_bytes);
+ if (ret < 0) {
+ Reset();
+ } else {
+ msg_bytes = msg_bytes.subspan(ret);
+ }
return ret;
}
Optional<CNetMessage> GetMessage(std::chrono::microseconds time, uint32_t& out_err_raw_size) override;
@@ -1118,7 +1123,16 @@ public:
return nRefCount;
}
- bool ReceiveMsgBytes(const char *pch, unsigned int nBytes, bool& complete);
+ /**
+ * Receive bytes from the buffer and deserialize them into messages.
+ *
+ * @param[in] msg_bytes The raw data
+ * @param[out] complete Set True if at least one message has been
+ * deserialized and is ready to be processed
+ * @return True if the peer should stay connected,
+ * False if the peer should be disconnected from.
+ */
+ bool ReceiveMsgBytes(Span<const char> msg_bytes, bool& complete);
void SetCommonVersion(int greatest_common_version)
{
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index c649cf7757..e9915a3091 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -290,8 +290,6 @@ namespace {
struct CNodeState {
//! The peer's address
const CService address;
- //! Whether we have a fully established connection.
- bool fCurrentlyConnected;
//! The best known block we know this peer has announced.
const CBlockIndex *pindexBestKnownBlock;
//! The hash of the last unknown block this peer has announced.
@@ -390,7 +388,6 @@ struct CNodeState {
CNodeState(CAddress addrIn, bool is_inbound, bool is_manual)
: address(addrIn), m_is_inbound(is_inbound), m_is_manual_connection(is_manual)
{
- fCurrentlyConnected = false;
pindexBestKnownBlock = nullptr;
hashLastUnknownBlock.SetNull();
pindexLastCommonBlock = nullptr;
@@ -857,8 +854,9 @@ void PeerManager::FinalizeNode(const CNode& node, bool& fUpdateConnectionTime) {
if (state->fSyncStarted)
nSyncStarted--;
- if (misbehavior == 0 && state->fCurrentlyConnected && !node.IsBlockOnlyConn()) {
- // Note: we avoid changing visible addrman state for block-relay-only peers
+ if (node.fSuccessfullyConnected && misbehavior == 0 &&
+ !node.IsBlockOnlyConn() && !node.IsInboundConn()) {
+ // Only change visible addrman state for outbound, full-relay peers
fUpdateConnectionTime = true;
}
@@ -2488,9 +2486,6 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat
if (pfrom.fSuccessfullyConnected) return;
if (!pfrom.IsInboundConn()) {
- // Mark this node as currently connected, so we update its timestamp later.
- LOCK(cs_main);
- State(pfrom.GetId())->fCurrentlyConnected = true;
LogPrintf("New outbound peer connected: version: %d, blocks=%d, peer=%d%s (%s)\n",
pfrom.nVersion.load(), pfrom.nStartingHeight,
pfrom.GetId(), (fLogIPs ? strprintf(", peeraddr=%s", pfrom.addr.ToString()) : ""),
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index 63b4107f7e..4e1b239bc7 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -263,7 +263,7 @@ void BitcoinApplication::createWindow(const NetworkStyle *networkStyle)
void BitcoinApplication::createSplashScreen(const NetworkStyle *networkStyle)
{
assert(!m_splash);
- m_splash = new SplashScreen(nullptr, networkStyle);
+ m_splash = new SplashScreen(networkStyle);
// We don't hold a direct pointer to the splash screen after creation, but the splash
// screen will take care of deleting itself when finish() happens.
m_splash->show();
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index 23370e6ad3..20120285d8 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -1311,7 +1311,7 @@ void BitcoinGUI::updateProxyIcon()
bool proxy_enabled = clientModel->getProxyInfo(ip_port);
if (proxy_enabled) {
- if (labelProxyIcon->pixmap() == nullptr) {
+ if (!GUIUtil::HasPixmap(labelProxyIcon)) {
QString ip_port_q = QString::fromStdString(ip_port);
labelProxyIcon->setPixmap(platformStyle->SingleColorIcon(":/icons/proxy").pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE));
labelProxyIcon->setToolTip(tr("Proxy is <b>enabled</b>: %1").arg(ip_port_q));
diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index 912297a74e..17458c5777 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -49,6 +49,7 @@ struct BlockAndHeaderTipInfo;
QT_BEGIN_NAMESPACE
class QAction;
class QComboBox;
+class QDateTime;
class QMenu;
class QProgressBar;
class QProgressDialog;
diff --git a/src/qt/forms/optionsdialog.ui b/src/qt/forms/optionsdialog.ui
index 0016fb9739..045c2d3539 100644
--- a/src/qt/forms/optionsdialog.ui
+++ b/src/qt/forms/optionsdialog.ui
@@ -55,7 +55,7 @@
<item>
<widget class="QCheckBox" name="prune">
<property name="toolTip">
- <string>Disables some advanced features but all blocks will still be fully validated. Reverting this setting requires re-downloading the entire blockchain. Actual disk usage may be somewhat higher.</string>
+ <string>Enabling pruning significantly reduces the disk space required to store transactions. All blocks are still fully validated. Reverting this setting requires re-downloading the entire blockchain.</string>
</property>
<property name="text">
<string>Prune &amp;block storage to</string>
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index bab17562a6..70e76f765b 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -920,4 +920,35 @@ void PopupMenu(QMenu* menu, const QPoint& point, QAction* at_action)
menu->popup(point, at_action);
}
+QDateTime StartOfDay(const QDate& date)
+{
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
+ return date.startOfDay();
+#else
+ return QDateTime(date);
+#endif
+}
+
+bool HasPixmap(const QLabel* label)
+{
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
+ return !label->pixmap(Qt::ReturnByValue).isNull();
+#else
+ return label->pixmap() != nullptr;
+#endif
+}
+
+QImage GetImage(const QLabel* label)
+{
+ if (!HasPixmap(label)) {
+ return QImage();
+ }
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
+ return label->pixmap(Qt::ReturnByValue).toImage();
+#else
+ return label->pixmap()->toImage();
+#endif
+}
+
} // namespace GUIUtil
diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h
index 2bd94b5eb3..c976b4b4bb 100644
--- a/src/qt/guiutil.h
+++ b/src/qt/guiutil.h
@@ -289,7 +289,7 @@ namespace GUIUtil
/**
* Returns the distance in pixels appropriate for drawing a subsequent character after text.
*
- * In Qt 5.12 and before the QFontMetrics::width() is used and it is deprecated since Qt 13.0.
+ * In Qt 5.12 and before the QFontMetrics::width() is used and it is deprecated since Qt 5.13.
* In Qt 5.11 the QFontMetrics::horizontalAdvance() was introduced.
*/
int TextWidth(const QFontMetrics& fm, const QString& text);
@@ -303,6 +303,44 @@ namespace GUIUtil
* Call QMenu::popup() only on supported QT_QPA_PLATFORM.
*/
void PopupMenu(QMenu* menu, const QPoint& point, QAction* at_action = nullptr);
+
+ /**
+ * Returns the start-moment of the day in local time.
+ *
+ * QDateTime::QDateTime(const QDate& date) is deprecated since Qt 5.15.
+ * QDate::startOfDay() was introduced in Qt 5.14.
+ */
+ QDateTime StartOfDay(const QDate& date);
+
+ /**
+ * Returns true if pixmap has been set.
+ *
+ * QPixmap* QLabel::pixmap() is deprecated since Qt 5.15.
+ */
+ bool HasPixmap(const QLabel* label);
+ QImage GetImage(const QLabel* label);
+
+ /**
+ * Splits the string into substrings wherever separator occurs, and returns
+ * the list of those strings. Empty strings do not appear in the result.
+ *
+ * QString::split() signature differs in different Qt versions:
+ * - QString::SplitBehavior is deprecated since Qt 5.15
+ * - Qt::SplitBehavior was introduced in Qt 5.14
+ * If {QString|Qt}::SkipEmptyParts behavior is required, use this
+ * function instead of QString::split().
+ */
+ template <typename SeparatorType>
+ QStringList SplitSkipEmptyParts(const QString& string, const SeparatorType& separator)
+ {
+ #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
+ return string.split(separator, Qt::SkipEmptyParts);
+ #else
+ return string.split(separator, QString::SkipEmptyParts);
+ #endif
+ }
+
+
} // namespace GUIUtil
#endif // BITCOIN_QT_GUIUTIL_H
diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp
index 7e089b4f95..1603b12a73 100644
--- a/src/qt/optionsmodel.cpp
+++ b/src/qt/optionsmodel.cpp
@@ -219,7 +219,7 @@ static ProxySetting GetProxySetting(QSettings &settings, const QString &name)
return default_val;
}
// contains IP at index 0 and port at index 1
- QStringList ip_port = settings.value(name).toString().split(":", QString::SkipEmptyParts);
+ QStringList ip_port = GUIUtil::SplitSkipEmptyParts(settings.value(name).toString(), ":");
if (ip_port.size() == 2) {
return {true, ip_port.at(0), ip_port.at(1)};
} else { // Invalid: return default
diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp
index b536567c8b..1297eb8b75 100644
--- a/src/qt/overviewpage.cpp
+++ b/src/qt/overviewpage.cpp
@@ -17,6 +17,7 @@
#include <QAbstractItemDelegate>
#include <QApplication>
+#include <QDateTime>
#include <QPainter>
#include <QStatusTipEvent>
diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp
index 6c2db52f63..86d681aa6f 100644
--- a/src/qt/paymentserver.cpp
+++ b/src/qt/paymentserver.cpp
@@ -26,7 +26,6 @@
#include <QApplication>
#include <QByteArray>
#include <QDataStream>
-#include <QDateTime>
#include <QDebug>
#include <QFile>
#include <QFileOpenEvent>
diff --git a/src/qt/qrimagewidget.cpp b/src/qt/qrimagewidget.cpp
index 52f1e60957..141f4abb3b 100644
--- a/src/qt/qrimagewidget.cpp
+++ b/src/qt/qrimagewidget.cpp
@@ -98,15 +98,12 @@ bool QRImageWidget::setQR(const QString& data, const QString& text)
QImage QRImageWidget::exportImage()
{
- if(!pixmap())
- return QImage();
- return pixmap()->toImage();
+ return GUIUtil::GetImage(this);
}
void QRImageWidget::mousePressEvent(QMouseEvent *event)
{
- if(event->button() == Qt::LeftButton && pixmap())
- {
+ if (event->button() == Qt::LeftButton && GUIUtil::HasPixmap(this)) {
event->accept();
QMimeData *mimeData = new QMimeData;
mimeData->setImageData(exportImage());
@@ -121,7 +118,7 @@ void QRImageWidget::mousePressEvent(QMouseEvent *event)
void QRImageWidget::saveImage()
{
- if(!pixmap())
+ if (!GUIUtil::HasPixmap(this))
return;
QString fn = GUIUtil::getSaveFileName(this, tr("Save QR Code"), QString(), tr("PNG Image (*.png)"), nullptr);
if (!fn.isEmpty())
@@ -132,14 +129,14 @@ void QRImageWidget::saveImage()
void QRImageWidget::copyImage()
{
- if(!pixmap())
+ if (!GUIUtil::HasPixmap(this))
return;
QApplication::clipboard()->setImage(exportImage());
}
void QRImageWidget::contextMenuEvent(QContextMenuEvent *event)
{
- if(!pixmap())
+ if (!GUIUtil::HasPixmap(this))
return;
contextMenu->exec(event->globalPos());
}
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index 3d78703ff7..354a82b064 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -29,6 +29,7 @@
#include <wallet/wallet.h>
#endif
+#include <QDateTime>
#include <QFont>
#include <QKeyEvent>
#include <QMenu>
@@ -486,9 +487,7 @@ RPCConsole::RPCConsole(interfaces::Node& node, const PlatformStyle *_platformSty
m_node.rpcSetTimerInterfaceIfUnset(rpcTimerInterface);
setTrafficGraphRange(INITIAL_TRAFFIC_GRAPH_MINS);
-
- ui->detailWidget->hide();
- ui->peerHeading->setText(tr("Select a peer to view detailed information."));
+ updateDetailWidget();
consoleFontSize = settings.value(fontSizeSettingsKey, QFont().pointSize()).toInt();
clear();
@@ -619,7 +618,7 @@ void RPCConsole::setClientModel(ClientModel *model, int bestblock_height, int64_
connect(disconnectAction, &QAction::triggered, this, &RPCConsole::disconnectSelectedNode);
// peer table signal handling - update peer details when selecting new node
- connect(ui->peerWidget->selectionModel(), &QItemSelectionModel::selectionChanged, this, &RPCConsole::peerSelected);
+ connect(ui->peerWidget->selectionModel(), &QItemSelectionModel::selectionChanged, this, &RPCConsole::updateDetailWidget);
// peer table signal handling - update peer details when new nodes are added to the model
connect(model->getPeerTableModel(), &PeerTableModel::layoutChanged, this, &RPCConsole::peerLayoutChanged);
// peer table signal handling - cache selected node ids
@@ -1014,18 +1013,6 @@ void RPCConsole::updateTrafficStats(quint64 totalBytesIn, quint64 totalBytesOut)
ui->lblBytesOut->setText(GUIUtil::formatBytes(totalBytesOut));
}
-void RPCConsole::peerSelected(const QItemSelection &selected, const QItemSelection &deselected)
-{
- Q_UNUSED(deselected);
-
- if (!clientModel || !clientModel->getPeerTableModel() || selected.indexes().isEmpty())
- return;
-
- const CNodeCombinedStats *stats = clientModel->getPeerTableModel()->getNodeStats(selected.indexes().first().row());
- if (stats)
- updateNodeDetail(stats);
-}
-
void RPCConsole::peerLayoutAboutToChange()
{
QModelIndexList selected = ui->peerWidget->selectionModel()->selectedIndexes();
@@ -1042,7 +1029,6 @@ void RPCConsole::peerLayoutChanged()
if (!clientModel || !clientModel->getPeerTableModel())
return;
- const CNodeCombinedStats *stats = nullptr;
bool fUnselect = false;
bool fReselect = false;
@@ -1073,9 +1059,6 @@ void RPCConsole::peerLayoutChanged()
fUnselect = true;
fReselect = true;
}
-
- // get fresh stats on the detail node.
- stats = clientModel->getPeerTableModel()->getNodeStats(detailNodeRow);
}
if (fUnselect && selectedRow >= 0) {
@@ -1090,12 +1073,20 @@ void RPCConsole::peerLayoutChanged()
}
}
- if (stats)
- updateNodeDetail(stats);
+ updateDetailWidget();
}
-void RPCConsole::updateNodeDetail(const CNodeCombinedStats *stats)
+void RPCConsole::updateDetailWidget()
{
+ QModelIndexList selected_rows;
+ auto selection_model = ui->peerWidget->selectionModel();
+ if (selection_model) selected_rows = selection_model->selectedRows();
+ if (!clientModel || !clientModel->getPeerTableModel() || selected_rows.size() != 1) {
+ ui->detailWidget->hide();
+ ui->peerHeading->setText(tr("Select a peer to view detailed information."));
+ return;
+ }
+ const CNodeCombinedStats *stats = clientModel->getPeerTableModel()->getNodeStats(selected_rows.first().row());
// update the detail ui with latest node information
QString peerAddrDetails(QString::fromStdString(stats->nodeStats.addrName) + " ");
peerAddrDetails += tr("(node id: %1)").arg(QString::number(stats->nodeStats.nodeid));
@@ -1253,8 +1244,7 @@ void RPCConsole::clearSelectedNode()
{
ui->peerWidget->selectionModel()->clearSelection();
cachedNodeids.clear();
- ui->detailWidget->hide();
- ui->peerHeading->setText(tr("Select a peer to view detailed information."));
+ updateDetailWidget();
}
void RPCConsole::showOrHideBanTableIfRequired()
diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h
index 280c5bd71a..8fea08ab5c 100644
--- a/src/qt/rpcconsole.h
+++ b/src/qt/rpcconsole.h
@@ -28,6 +28,7 @@ namespace Ui {
}
QT_BEGIN_NAMESPACE
+class QDateTime;
class QMenu;
class QItemSelection;
QT_END_NAMESPACE
@@ -94,6 +95,8 @@ private Q_SLOTS:
void showOrHideBanTableIfRequired();
/** clear the selected node */
void clearSelectedNode();
+ /** show detailed information on ui about selected node */
+ void updateDetailWidget();
public Q_SLOTS:
void clear(bool clearHistory = true);
@@ -115,8 +118,6 @@ public Q_SLOTS:
void browseHistory(int offset);
/** Scroll console view to end */
void scrollToEnd();
- /** Handle selection of peer in peers list */
- void peerSelected(const QItemSelection &selected, const QItemSelection &deselected);
/** Handle selection caching before update */
void peerLayoutAboutToChange();
/** Handle updated peer information */
@@ -137,8 +138,6 @@ Q_SIGNALS:
private:
void startExecutor();
void setTrafficGraphRange(int mins);
- /** show detailed information on ui about selected node */
- void updateNodeDetail(const CNodeCombinedStats *stats);
enum ColumnWidths
{
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
index 50a1ea6936..8a62c64d79 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -173,8 +173,15 @@ void SendCoinsDialog::setModel(WalletModel *_model)
}
connect(ui->confTargetSelector, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &SendCoinsDialog::updateSmartFeeLabel);
connect(ui->confTargetSelector, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &SendCoinsDialog::coinControlUpdateLabels);
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
+ connect(ui->groupFee, &QButtonGroup::idClicked, this, &SendCoinsDialog::updateFeeSectionControls);
+ connect(ui->groupFee, &QButtonGroup::idClicked, this, &SendCoinsDialog::coinControlUpdateLabels);
+#else
connect(ui->groupFee, static_cast<void (QButtonGroup::*)(int)>(&QButtonGroup::buttonClicked), this, &SendCoinsDialog::updateFeeSectionControls);
connect(ui->groupFee, static_cast<void (QButtonGroup::*)(int)>(&QButtonGroup::buttonClicked), this, &SendCoinsDialog::coinControlUpdateLabels);
+#endif
+
connect(ui->customFee, &BitcoinAmountField::valueChanged, this, &SendCoinsDialog::coinControlUpdateLabels);
connect(ui->optInRBF, &QCheckBox::stateChanged, this, &SendCoinsDialog::updateSmartFeeLabel);
connect(ui->optInRBF, &QCheckBox::stateChanged, this, &SendCoinsDialog::coinControlUpdateLabels);
diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp
index f00f086d1e..5796a6ef56 100644
--- a/src/qt/splashscreen.cpp
+++ b/src/qt/splashscreen.cpp
@@ -25,8 +25,8 @@
#include <QScreen>
-SplashScreen::SplashScreen(Qt::WindowFlags f, const NetworkStyle *networkStyle) :
- QWidget(nullptr, f), curAlignment(0)
+SplashScreen::SplashScreen(const NetworkStyle* networkStyle)
+ : QWidget(), curAlignment(0)
{
// set reference point, paddings
int paddingRight = 50;
diff --git a/src/qt/splashscreen.h b/src/qt/splashscreen.h
index a0cd677d3d..d49fd87055 100644
--- a/src/qt/splashscreen.h
+++ b/src/qt/splashscreen.h
@@ -28,7 +28,7 @@ class SplashScreen : public QWidget
Q_OBJECT
public:
- explicit SplashScreen(Qt::WindowFlags f, const NetworkStyle *networkStyle);
+ explicit SplashScreen(const NetworkStyle *networkStyle);
~SplashScreen();
void setNode(interfaces::Node& node);
diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp
index 54ecfc38ec..e14e22e9de 100644
--- a/src/qt/transactionview.cpp
+++ b/src/qt/transactionview.cpp
@@ -237,7 +237,7 @@ void TransactionView::setModel(WalletModel *_model)
if (_model->getOptionsModel())
{
// Add third party transaction URLs to context menu
- QStringList listUrls = _model->getOptionsModel()->getThirdPartyTxUrls().split("|", QString::SkipEmptyParts);
+ QStringList listUrls = GUIUtil::SplitSkipEmptyParts(_model->getOptionsModel()->getThirdPartyTxUrls(), "|");
for (int i = 0; i < listUrls.size(); ++i)
{
QString url = listUrls[i].trimmed();
@@ -275,30 +275,30 @@ void TransactionView::chooseDate(int idx)
break;
case Today:
transactionProxyModel->setDateRange(
- QDateTime(current),
+ GUIUtil::StartOfDay(current),
TransactionFilterProxy::MAX_DATE);
break;
case ThisWeek: {
// Find last Monday
QDate startOfWeek = current.addDays(-(current.dayOfWeek()-1));
transactionProxyModel->setDateRange(
- QDateTime(startOfWeek),
+ GUIUtil::StartOfDay(startOfWeek),
TransactionFilterProxy::MAX_DATE);
} break;
case ThisMonth:
transactionProxyModel->setDateRange(
- QDateTime(QDate(current.year(), current.month(), 1)),
+ GUIUtil::StartOfDay(QDate(current.year(), current.month(), 1)),
TransactionFilterProxy::MAX_DATE);
break;
case LastMonth:
transactionProxyModel->setDateRange(
- QDateTime(QDate(current.year(), current.month(), 1).addMonths(-1)),
- QDateTime(QDate(current.year(), current.month(), 1)));
+ GUIUtil::StartOfDay(QDate(current.year(), current.month(), 1).addMonths(-1)),
+ GUIUtil::StartOfDay(QDate(current.year(), current.month(), 1)));
break;
case ThisYear:
transactionProxyModel->setDateRange(
- QDateTime(QDate(current.year(), 1, 1)),
+ GUIUtil::StartOfDay(QDate(current.year(), 1, 1)),
TransactionFilterProxy::MAX_DATE);
break;
case Range:
@@ -583,8 +583,8 @@ void TransactionView::dateRangeChanged()
if(!transactionProxyModel)
return;
transactionProxyModel->setDateRange(
- QDateTime(dateFrom->date()),
- QDateTime(dateTo->date()).addDays(1));
+ GUIUtil::StartOfDay(dateFrom->date()),
+ GUIUtil::StartOfDay(dateTo->date()).addDays(1));
}
void TransactionView::focusTransaction(const QModelIndex &idx)
diff --git a/src/test/base32_tests.cpp b/src/test/base32_tests.cpp
index d519eca859..3f7c5e99ee 100644
--- a/src/test/base32_tests.cpp
+++ b/src/test/base32_tests.cpp
@@ -6,6 +6,9 @@
#include <util/strencodings.h>
#include <boost/test/unit_test.hpp>
+#include <string>
+
+using namespace std::literals;
BOOST_FIXTURE_TEST_SUITE(base32_tests, BasicTestingSetup)
@@ -26,14 +29,14 @@ BOOST_AUTO_TEST_CASE(base32_testvectors)
// Decoding strings with embedded NUL characters should fail
bool failure;
- (void)DecodeBase32(std::string("invalid", 7), &failure);
- BOOST_CHECK_EQUAL(failure, true);
- (void)DecodeBase32(std::string("AWSX3VPP", 8), &failure);
- BOOST_CHECK_EQUAL(failure, false);
- (void)DecodeBase32(std::string("AWSX3VPP\0invalid", 16), &failure);
- BOOST_CHECK_EQUAL(failure, true);
- (void)DecodeBase32(std::string("AWSX3VPPinvalid", 15), &failure);
- BOOST_CHECK_EQUAL(failure, true);
+ (void)DecodeBase32("invalid\0"s, &failure); // correct size, invalid due to \0
+ BOOST_CHECK(failure);
+ (void)DecodeBase32("AWSX3VPP"s, &failure); // valid
+ BOOST_CHECK(!failure);
+ (void)DecodeBase32("AWSX3VPP\0invalid"s, &failure); // correct size, invalid due to \0
+ BOOST_CHECK(failure);
+ (void)DecodeBase32("AWSX3VPPinvalid"s, &failure); // invalid size
+ BOOST_CHECK(failure);
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/base58_tests.cpp b/src/test/base58_tests.cpp
index 6a636f2574..e55d6b3b19 100644
--- a/src/test/base58_tests.cpp
+++ b/src/test/base58_tests.cpp
@@ -12,7 +12,9 @@
#include <univalue.h>
#include <boost/test/unit_test.hpp>
+#include <string>
+using namespace std::literals;
extern UniValue read_json(const std::string& jsondata);
@@ -58,14 +60,14 @@ BOOST_AUTO_TEST_CASE(base58_DecodeBase58)
BOOST_CHECK_MESSAGE(result.size() == expected.size() && std::equal(result.begin(), result.end(), expected.begin()), strTest);
}
- BOOST_CHECK(!DecodeBase58("invalid", result, 100));
- BOOST_CHECK(!DecodeBase58(std::string("invalid"), result, 100));
- BOOST_CHECK(!DecodeBase58(std::string("\0invalid", 8), result, 100));
+ BOOST_CHECK(!DecodeBase58("invalid"s, result, 100));
+ BOOST_CHECK(!DecodeBase58("invalid\0"s, result, 100));
+ BOOST_CHECK(!DecodeBase58("\0invalid"s, result, 100));
- BOOST_CHECK(DecodeBase58(std::string("good", 4), result, 100));
- BOOST_CHECK(!DecodeBase58(std::string("bad0IOl", 7), result, 100));
- BOOST_CHECK(!DecodeBase58(std::string("goodbad0IOl", 11), result, 100));
- BOOST_CHECK(!DecodeBase58(std::string("good\0bad0IOl", 12), result, 100));
+ BOOST_CHECK(DecodeBase58("good"s, result, 100));
+ BOOST_CHECK(!DecodeBase58("bad0IOl"s, result, 100));
+ BOOST_CHECK(!DecodeBase58("goodbad0IOl"s, result, 100));
+ BOOST_CHECK(!DecodeBase58("good\0bad0IOl"s, result, 100));
// check that DecodeBase58 skips whitespace, but still fails with unexpected non-whitespace at the end.
BOOST_CHECK(!DecodeBase58(" \t\n\v\f\r skip \r\f\v\n\t a", result, 3));
@@ -73,10 +75,10 @@ BOOST_AUTO_TEST_CASE(base58_DecodeBase58)
std::vector<unsigned char> expected = ParseHex("971a55");
BOOST_CHECK_EQUAL_COLLECTIONS(result.begin(), result.end(), expected.begin(), expected.end());
- BOOST_CHECK(DecodeBase58Check(std::string("3vQB7B6MrGQZaxCuFg4oh", 21), result, 100));
- BOOST_CHECK(!DecodeBase58Check(std::string("3vQB7B6MrGQZaxCuFg4oi", 21), result, 100));
- BOOST_CHECK(!DecodeBase58Check(std::string("3vQB7B6MrGQZaxCuFg4oh0IOl", 25), result, 100));
- BOOST_CHECK(!DecodeBase58Check(std::string("3vQB7B6MrGQZaxCuFg4oh\00IOl", 26), result, 100));
+ BOOST_CHECK(DecodeBase58Check("3vQB7B6MrGQZaxCuFg4oh"s, result, 100));
+ BOOST_CHECK(!DecodeBase58Check("3vQB7B6MrGQZaxCuFg4oi"s, result, 100));
+ BOOST_CHECK(!DecodeBase58Check("3vQB7B6MrGQZaxCuFg4oh0IOl"s, result, 100));
+ BOOST_CHECK(!DecodeBase58Check("3vQB7B6MrGQZaxCuFg4oh\0" "0IOl"s, result, 100));
}
BOOST_AUTO_TEST_CASE(base58_random_encode_decode)
diff --git a/src/test/base64_tests.cpp b/src/test/base64_tests.cpp
index 5927eab6cf..bb8d102bd0 100644
--- a/src/test/base64_tests.cpp
+++ b/src/test/base64_tests.cpp
@@ -6,6 +6,9 @@
#include <util/strencodings.h>
#include <boost/test/unit_test.hpp>
+#include <string>
+
+using namespace std::literals;
BOOST_FIXTURE_TEST_SUITE(base64_tests, BasicTestingSetup)
@@ -23,14 +26,14 @@ BOOST_AUTO_TEST_CASE(base64_testvectors)
// Decoding strings with embedded NUL characters should fail
bool failure;
- (void)DecodeBase64(std::string("invalid", 7), &failure);
- BOOST_CHECK_EQUAL(failure, true);
- (void)DecodeBase64(std::string("nQB/pZw=", 8), &failure);
- BOOST_CHECK_EQUAL(failure, false);
- (void)DecodeBase64(std::string("nQB/pZw=\0invalid", 16), &failure);
- BOOST_CHECK_EQUAL(failure, true);
- (void)DecodeBase64(std::string("nQB/pZw=invalid", 15), &failure);
- BOOST_CHECK_EQUAL(failure, true);
+ (void)DecodeBase64("invalid\0"s, &failure);
+ BOOST_CHECK(failure);
+ (void)DecodeBase64("nQB/pZw="s, &failure);
+ BOOST_CHECK(!failure);
+ (void)DecodeBase64("nQB/pZw=\0invalid"s, &failure);
+ BOOST_CHECK(failure);
+ (void)DecodeBase64("nQB/pZw=invalid\0"s, &failure);
+ BOOST_CHECK(failure);
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/fuzz/net.cpp b/src/test/fuzz/net.cpp
index c61d406291..36afd4744d 100644
--- a/src/test/fuzz/net.cpp
+++ b/src/test/fuzz/net.cpp
@@ -128,7 +128,7 @@ void test_one_input(const std::vector<uint8_t>& buffer)
case 11: {
const std::vector<uint8_t> b = ConsumeRandomLengthByteVector(fuzzed_data_provider);
bool complete;
- node.ReceiveMsgBytes((const char*)b.data(), b.size(), complete);
+ node.ReceiveMsgBytes({(const char*)b.data(), b.size()}, complete);
break;
}
}
diff --git a/src/test/fuzz/p2p_transport_deserializer.cpp b/src/test/fuzz/p2p_transport_deserializer.cpp
index 7e216e16fe..3feabcc99a 100644
--- a/src/test/fuzz/p2p_transport_deserializer.cpp
+++ b/src/test/fuzz/p2p_transport_deserializer.cpp
@@ -21,15 +21,12 @@ void test_one_input(const std::vector<uint8_t>& buffer)
{
// Construct deserializer, with a dummy NodeId
V1TransportDeserializer deserializer{Params(), (NodeId)0, SER_NETWORK, INIT_PROTO_VERSION};
- const char* pch = (const char*)buffer.data();
- size_t n_bytes = buffer.size();
- while (n_bytes > 0) {
- const int handled = deserializer.Read(pch, n_bytes);
+ Span<const char> msg_bytes{(const char*)buffer.data(), buffer.size()};
+ while (msg_bytes.size() > 0) {
+ const int handled = deserializer.Read(msg_bytes);
if (handled < 0) {
break;
}
- pch += handled;
- n_bytes -= handled;
if (deserializer.Complete()) {
const std::chrono::microseconds m_time{std::numeric_limits<int64_t>::max()};
uint32_t out_err_raw_size{0};
diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp
index 37eca8b7ef..b23fec9b95 100644
--- a/src/test/net_tests.cpp
+++ b/src/test/net_tests.cpp
@@ -25,6 +25,8 @@
#include <memory>
#include <string>
+using namespace std::literals;
+
class CAddrManSerializationMock : public CAddrMan
{
public:
@@ -106,8 +108,8 @@ BOOST_AUTO_TEST_CASE(caddrdb_read)
BOOST_CHECK(Lookup("250.7.1.1", addr1, 8333, false));
BOOST_CHECK(Lookup("250.7.2.2", addr2, 9999, false));
BOOST_CHECK(Lookup("250.7.3.3", addr3, 9999, false));
- BOOST_CHECK(Lookup(std::string("250.7.3.3", 9), addr3, 9999, false));
- BOOST_CHECK(!Lookup(std::string("250.7.3.3\0example.com", 21), addr3, 9999, false));
+ BOOST_CHECK(Lookup("250.7.3.3"s, addr3, 9999, false));
+ BOOST_CHECK(!Lookup("250.7.3.3\0example.com"s, addr3, 9999, false));
// Add three addresses to new table.
CService source;
diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp
index f5d26fafef..ac4db3a5b6 100644
--- a/src/test/netbase_tests.cpp
+++ b/src/test/netbase_tests.cpp
@@ -16,6 +16,8 @@
#include <boost/test/unit_test.hpp>
+using namespace std::literals;
+
BOOST_FIXTURE_TEST_SUITE(netbase_tests, BasicTestingSetup)
static CNetAddr ResolveIP(const std::string& ip)
@@ -431,20 +433,20 @@ BOOST_AUTO_TEST_CASE(netpermissions_test)
BOOST_AUTO_TEST_CASE(netbase_dont_resolve_strings_with_embedded_nul_characters)
{
CNetAddr addr;
- BOOST_CHECK(LookupHost(std::string("127.0.0.1", 9), addr, false));
- BOOST_CHECK(!LookupHost(std::string("127.0.0.1\0", 10), addr, false));
- BOOST_CHECK(!LookupHost(std::string("127.0.0.1\0example.com", 21), addr, false));
- BOOST_CHECK(!LookupHost(std::string("127.0.0.1\0example.com\0", 22), addr, false));
+ BOOST_CHECK(LookupHost("127.0.0.1"s, addr, false));
+ BOOST_CHECK(!LookupHost("127.0.0.1\0"s, addr, false));
+ BOOST_CHECK(!LookupHost("127.0.0.1\0example.com"s, addr, false));
+ BOOST_CHECK(!LookupHost("127.0.0.1\0example.com\0"s, addr, false));
CSubNet ret;
- BOOST_CHECK(LookupSubNet(std::string("1.2.3.0/24", 10), ret));
- 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));
+ BOOST_CHECK(LookupSubNet("1.2.3.0/24"s, ret));
+ BOOST_CHECK(!LookupSubNet("1.2.3.0/24\0"s, ret));
+ BOOST_CHECK(!LookupSubNet("1.2.3.0/24\0example.com"s, ret));
+ BOOST_CHECK(!LookupSubNet("1.2.3.0/24\0example.com\0"s, 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\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));
+ BOOST_CHECK(!LookupSubNet("5wyqrzbvrdsumnok.onion"s, ret));
+ BOOST_CHECK(!LookupSubNet("5wyqrzbvrdsumnok.onion\0"s, ret));
+ BOOST_CHECK(!LookupSubNet("5wyqrzbvrdsumnok.onion\0example.com"s, ret));
+ BOOST_CHECK(!LookupSubNet("5wyqrzbvrdsumnok.onion\0example.com\0"s, ret));
}
// Since CNetAddr (un)ser is tested separately in net_tests.cpp here we only
diff --git a/src/test/util/net.cpp b/src/test/util/net.cpp
index 09f2f1807f..3b31ec4031 100644
--- a/src/test/util/net.cpp
+++ b/src/test/util/net.cpp
@@ -7,9 +7,9 @@
#include <chainparams.h>
#include <net.h>
-void ConnmanTestMsg::NodeReceiveMsgBytes(CNode& node, const char* pch, unsigned int nBytes, bool& complete) const
+void ConnmanTestMsg::NodeReceiveMsgBytes(CNode& node, Span<const char> msg_bytes, bool& complete) const
{
- assert(node.ReceiveMsgBytes(pch, nBytes, complete));
+ assert(node.ReceiveMsgBytes(msg_bytes, complete));
if (complete) {
size_t nSizeAdded = 0;
auto it(node.vRecvMsg.begin());
@@ -33,7 +33,7 @@ bool ConnmanTestMsg::ReceiveMsgFrom(CNode& node, CSerializedNetMsg& ser_msg) con
node.m_serializer->prepareForTransport(ser_msg, ser_msg_header);
bool complete;
- NodeReceiveMsgBytes(node, (const char*)ser_msg_header.data(), ser_msg_header.size(), complete);
- NodeReceiveMsgBytes(node, (const char*)ser_msg.data.data(), ser_msg.data.size(), complete);
+ NodeReceiveMsgBytes(node, {(const char*)ser_msg_header.data(), ser_msg_header.size()}, complete);
+ NodeReceiveMsgBytes(node, {(const char*)ser_msg.data.data(), ser_msg.data.size()}, complete);
return complete;
}
diff --git a/src/test/util/net.h b/src/test/util/net.h
index ca8cb7fad5..fe423e7e89 100644
--- a/src/test/util/net.h
+++ b/src/test/util/net.h
@@ -25,7 +25,7 @@ struct ConnmanTestMsg : public CConnman {
void ProcessMessagesOnce(CNode& node) { m_msgproc->ProcessMessages(&node, flagInterruptMsgProc); }
- void NodeReceiveMsgBytes(CNode& node, const char* pch, unsigned int nBytes, bool& complete) const;
+ void NodeReceiveMsgBytes(CNode& node, Span<const char> msg_bytes, bool& complete) const;
bool ReceiveMsgFrom(CNode& node, CSerializedNetMsg& ser_msg) const;
};
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index 010b6adf1f..8628dc9979 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -23,6 +23,7 @@
#include <array>
#include <stdint.h>
+#include <string.h>
#include <thread>
#include <univalue.h>
#include <utility>
@@ -35,6 +36,8 @@
#include <boost/test/unit_test.hpp>
+using namespace std::literals;
+
/* defined in logging.cpp */
namespace BCLog {
std::string LogEscapeMessage(const std::string& str);
@@ -1257,9 +1260,9 @@ BOOST_AUTO_TEST_CASE(util_ParseMoney)
BOOST_CHECK(!ParseMoney("-1", ret));
// Parsing strings with embedded NUL characters should fail
- BOOST_CHECK(!ParseMoney(std::string("\0-1", 3), ret));
- BOOST_CHECK(!ParseMoney(std::string("\01", 2), ret));
- BOOST_CHECK(!ParseMoney(std::string("1\0", 2), ret));
+ BOOST_CHECK(!ParseMoney("\0-1"s, ret));
+ BOOST_CHECK(!ParseMoney("\0" "1"s, ret));
+ BOOST_CHECK(!ParseMoney("1\0"s, ret));
}
BOOST_AUTO_TEST_CASE(util_IsHex)
diff --git a/src/validation.cpp b/src/validation.cpp
index 8c87c53ac7..71402ef263 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -2398,9 +2398,7 @@ static void UpdateTip(CTxMemPool& mempool, const CBlockIndex* pindexNew, const C
}
bilingual_str warning_messages;
- int num_unexpected_version = 0;
- if (!::ChainstateActive().IsInitialBlockDownload())
- {
+ if (!::ChainstateActive().IsInitialBlockDownload()) {
const CBlockIndex* pindex = pindexNew;
for (int bit = 0; bit < VERSIONBITS_NUM_BITS; bit++) {
WarningBitsConditionChecker checker(bit);
@@ -2414,14 +2412,6 @@ static void UpdateTip(CTxMemPool& mempool, const CBlockIndex* pindexNew, const C
}
}
}
- // Check the version of the last 100 blocks to see if we need to upgrade:
- for (int i = 0; i < 100 && pindex != nullptr; i++)
- {
- int32_t nExpectedVersion = ComputeBlockVersion(pindex->pprev, chainParams.GetConsensus());
- if (pindex->nVersion > VERSIONBITS_LAST_OLD_BLOCK_VERSION && (pindex->nVersion & ~nExpectedVersion) != 0)
- ++num_unexpected_version;
- pindex = pindex->pprev;
- }
}
LogPrintf("%s: new best=%s height=%d version=0x%08x log2_work=%f tx=%lu date='%s' progress=%f cache=%.1fMiB(%utxo)%s\n", __func__,
pindexNew->GetBlockHash().ToString(), pindexNew->nHeight, pindexNew->nVersion,
@@ -2429,10 +2419,6 @@ static void UpdateTip(CTxMemPool& mempool, const CBlockIndex* pindexNew, const C
FormatISO8601DateTime(pindexNew->GetBlockTime()),
GuessVerificationProgress(chainParams.TxData(), pindexNew), ::ChainstateActive().CoinsTip().DynamicMemoryUsage() * (1.0 / (1<<20)), ::ChainstateActive().CoinsTip().GetCacheSize(),
!warning_messages.empty() ? strprintf(" warning='%s'", warning_messages.original) : "");
-
- if (num_unexpected_version > 0) {
- LogPrint(BCLog::VALIDATION, "%d of last 100 blocks have unexpected version\n", num_unexpected_version);
- }
}
/** Disconnect m_chain's tip.
diff --git a/test/functional/feature_taproot.py b/test/functional/feature_taproot.py
index 6e28cfb265..0f0fe8a34a 100755
--- a/test/functional/feature_taproot.py
+++ b/test/functional/feature_taproot.py
@@ -1442,17 +1442,23 @@ class TaprootTest(BitcoinTestFramework):
self.nodes[1].generate(101)
self.test_spenders(self.nodes[1], spenders_taproot_active(), input_counts=[1, 2, 2, 2, 2, 3])
- # Transfer funds to pre-taproot node.
+ # Transfer value of the largest 500 coins to pre-taproot node.
addr = self.nodes[0].getnewaddress()
+
+ unsp = self.nodes[1].listunspent()
+ unsp = sorted(unsp, key=lambda i: i['amount'], reverse=True)
+ unsp = unsp[:500]
+
rawtx = self.nodes[1].createrawtransaction(
inputs=[{
'txid': i['txid'],
'vout': i['vout']
- } for i in self.nodes[1].listunspent()],
- outputs={addr: self.nodes[1].getbalance()},
+ } for i in unsp],
+ outputs={addr: sum(i['amount'] for i in unsp)}
)
rawtx = self.nodes[1].signrawtransactionwithwallet(rawtx)['hex']
- # Transaction is too large to fit into the mempool, so put it into a block
+
+ # Mine a block with the transaction
block = create_block(tmpl=self.nodes[1].getblocktemplate(NORMAL_GBT_REQUEST_PARAMS), txlist=[rawtx])
add_witness_commitment(block)
block.rehash()
diff --git a/test/functional/mempool_spend_coinbase.py b/test/functional/mempool_spend_coinbase.py
index 854d506f0d..86d382ff69 100755
--- a/test/functional/mempool_spend_coinbase.py
+++ b/test/functional/mempool_spend_coinbase.py
@@ -13,44 +13,48 @@ but less mature coinbase spends are NOT.
"""
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.blocktools import create_raw_transaction
from test_framework.util import assert_equal, assert_raises_rpc_error
+from test_framework.wallet import MiniWallet
class MempoolSpendCoinbaseTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
-
- def skip_test_if_missing_module(self):
- self.skip_if_no_wallet()
+ self.setup_clean_chain = True
def run_test(self):
+ wallet = MiniWallet(self.nodes[0])
+
+ wallet.generate(200)
chain_height = self.nodes[0].getblockcount()
assert_equal(chain_height, 200)
- node0_address = self.nodes[0].getnewaddress()
# Coinbase at height chain_height-100+1 ok in mempool, should
# get mined. Coinbase at height chain_height-100+2 is
- # is too immature to spend.
+ # too immature to spend.
b = [self.nodes[0].getblockhash(n) for n in range(101, 103)]
coinbase_txids = [self.nodes[0].getblock(h)['tx'][0] for h in b]
- spends_raw = [create_raw_transaction(self.nodes[0], txid, node0_address, amount=49.99) for txid in coinbase_txids]
+ utxo_101 = wallet.get_utxo(txid=coinbase_txids[0])
+ utxo_102 = wallet.get_utxo(txid=coinbase_txids[1])
- spend_101_id = self.nodes[0].sendrawtransaction(spends_raw[0])
+ spend_101_id = wallet.send_self_transfer(from_node=self.nodes[0], utxo_to_spend=utxo_101)["txid"]
# coinbase at height 102 should be too immature to spend
- assert_raises_rpc_error(-26,"bad-txns-premature-spend-of-coinbase", self.nodes[0].sendrawtransaction, spends_raw[1])
+ assert_raises_rpc_error(-26,
+ "bad-txns-premature-spend-of-coinbase",
+ lambda: wallet.send_self_transfer(from_node=self.nodes[0], utxo_to_spend=utxo_102))
# mempool should have just spend_101:
- assert_equal(self.nodes[0].getrawmempool(), [ spend_101_id ])
+ assert_equal(self.nodes[0].getrawmempool(), [spend_101_id])
# mine a block, spend_101 should get confirmed
self.nodes[0].generate(1)
assert_equal(set(self.nodes[0].getrawmempool()), set())
# ... and now height 102 can be spent:
- spend_102_id = self.nodes[0].sendrawtransaction(spends_raw[1])
- assert_equal(self.nodes[0].getrawmempool(), [ spend_102_id ])
+ spend_102_id = wallet.send_self_transfer(from_node=self.nodes[0], utxo_to_spend=utxo_102)["txid"]
+ assert_equal(self.nodes[0].getrawmempool(), [spend_102_id])
+
if __name__ == '__main__':
MempoolSpendCoinbaseTest().main()
diff --git a/test/functional/p2p_fingerprint.py b/test/functional/p2p_fingerprint.py
index aaf862e6c8..f60eba2dbf 100755
--- a/test/functional/p2p_fingerprint.py
+++ b/test/functional/p2p_fingerprint.py
@@ -18,6 +18,7 @@ from test_framework.p2p import (
msg_block,
msg_getdata,
msg_getheaders,
+ p2p_lock,
)
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
@@ -57,18 +58,6 @@ class P2PFingerprintTest(BitcoinTestFramework):
msg.hashstop = block_hash
node.send_message(msg)
- # Check whether last block received from node has a given hash
- def last_block_equals(self, expected_hash, node):
- block_msg = node.last_message.get("block")
- return block_msg and block_msg.block.rehash() == expected_hash
-
- # Check whether last block header received from node has a given hash
- def last_header_equals(self, expected_hash, node):
- headers_msg = node.last_message.get("headers")
- return (headers_msg and
- headers_msg.headers and
- headers_msg.headers[0].rehash() == expected_hash)
-
# Checks that stale blocks timestamped more than a month ago are not served
# by the node while recent stale blocks and old active chain blocks are.
# This does not currently test that stale blocks timestamped within the
@@ -101,34 +90,31 @@ class P2PFingerprintTest(BitcoinTestFramework):
# Check that getdata request for stale block succeeds
self.send_block_request(stale_hash, node0)
- test_function = lambda: self.last_block_equals(stale_hash, node0)
- self.wait_until(test_function, timeout=3)
+ node0.wait_for_block(stale_hash, timeout=3)
# Check that getheader request for stale block header succeeds
self.send_header_request(stale_hash, node0)
- test_function = lambda: self.last_header_equals(stale_hash, node0)
- self.wait_until(test_function, timeout=3)
+ node0.wait_for_header(hex(stale_hash), timeout=3)
# Longest chain is extended so stale is much older than chain tip
self.nodes[0].setmocktime(0)
- tip = self.nodes[0].generatetoaddress(1, self.nodes[0].get_deterministic_priv_key().address)[0]
+ self.nodes[0].generatetoaddress(1, self.nodes[0].get_deterministic_priv_key().address)
assert_equal(self.nodes[0].getblockcount(), 14)
-
- # Send getdata & getheaders to refresh last received getheader message
- block_hash = int(tip, 16)
- self.send_block_request(block_hash, node0)
- self.send_header_request(block_hash, node0)
node0.sync_with_ping()
# Request for very old stale block should now fail
+ with p2p_lock:
+ node0.last_message.pop("block", None)
self.send_block_request(stale_hash, node0)
- time.sleep(3)
- assert not self.last_block_equals(stale_hash, node0)
+ node0.sync_with_ping()
+ assert "block" not in node0.last_message
# Request for very old stale block header should now fail
+ with p2p_lock:
+ node0.last_message.pop("headers", None)
self.send_header_request(stale_hash, node0)
- time.sleep(3)
- assert not self.last_header_equals(stale_hash, node0)
+ node0.sync_with_ping()
+ assert "headers" not in node0.last_message
# Verify we can fetch very old blocks and headers on the active chain
block_hash = int(block_hashes[2], 16)
@@ -137,12 +123,10 @@ class P2PFingerprintTest(BitcoinTestFramework):
node0.sync_with_ping()
self.send_block_request(block_hash, node0)
- test_function = lambda: self.last_block_equals(block_hash, node0)
- self.wait_until(test_function, timeout=3)
+ node0.wait_for_block(block_hash, timeout=3)
self.send_header_request(block_hash, node0)
- test_function = lambda: self.last_header_equals(block_hash, node0)
- self.wait_until(test_function, timeout=3)
+ node0.wait_for_header(hex(block_hash), timeout=3)
if __name__ == '__main__':
P2PFingerprintTest().main()
diff --git a/test/functional/test_framework/wallet.py b/test/functional/test_framework/wallet.py
index 39b3bf2a5b..a71f2c69cb 100644
--- a/test/functional/test_framework/wallet.py
+++ b/test/functional/test_framework/wallet.py
@@ -40,9 +40,20 @@ class MiniWallet:
self._utxos.append({'txid': cb_tx['txid'], 'vout': 0, 'value': cb_tx['vout'][0]['value']})
return blocks
- def get_utxo(self):
- """Return the last utxo. Can be used to get the change output immediately after a send_self_transfer"""
- return self._utxos.pop()
+ def get_utxo(self, *, txid=''):
+ """
+ Returns a utxo and marks it as spent (pops it from the internal list)
+
+ Args:
+ txid (string), optional: get the first utxo we find from a specific transaction
+
+ Note: Can be used to get the change output immediately after a send_self_transfer
+ """
+ index = -1 # by default the last utxo
+ if txid:
+ utxo = next(filter(lambda utxo: txid == utxo['txid'], self._utxos))
+ index = self._utxos.index(utxo)
+ return self._utxos.pop(index)
def send_self_transfer(self, *, fee_rate=Decimal("0.003"), from_node, utxo_to_spend=None):
"""Create and send a tx with the specified fee_rate. Fee may be exact or at most one satoshi higher than needed."""
diff --git a/test/util/data/bitcoin-util-test.json b/test/util/data/bitcoin-util-test.json
index 99cd4ab695..0a9846b4be 100644
--- a/test/util/data/bitcoin-util-test.json
+++ b/test/util/data/bitcoin-util-test.json
@@ -221,7 +221,7 @@
{ "exec": "./bitcoin-tx",
"args": ["-create", "outscript=0:123badscript"],
"return_code": 1,
- "error_txt": "error: script parse error",
+ "error_txt": "error: script parse error: unknown opcode",
"description": "Create a new transaction with an invalid output script"
},
{ "exec": "./bitcoin-tx",