What changed, and why it matters
This commit simply moves a header file called btcsignals.h from the top-level src/ directory into src/util/ and updates all the source files that include it. The code inside the file is unchanged. It is a routine code reorganization with no security relevance.
No security action needed. Treat as normal refactoring/reorganization.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The change is a pure file relocation: src/btcsignals.h is deleted and an identical copy is created at src/util/btcsignals.h. All include directives across the codebase are updated from
Changed components
src/util/btcsignals.hsrc/common/interfaces.cppsrc/init.cppsrc/node/interface_ui.cppsrc/node/interfaces.cppsrc/noui.cppsrc/qt/bitcoin.cppsrc/test/btcsignals_tests.cppsrc/wallet/scriptpubkeyman.hsrc/wallet/wallet.hInspect captured patch +271 / −272
diff --git a/src/btcsignals.h b/src/btcsignals.h
deleted file mode 100644
index b990fb9d..00000000
--- a/src/btcsignals.h
+++ /dev/null
@@ -1,261 +0,0 @@
-// Copyright (c) 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_BTCSIGNALS_H
-#define BITCOIN_BTCSIGNALS_H
-
-#include <sync.h>
-
-#include <algorithm>
-#include <atomic>
-#include <functional>
-#include <memory>
-#include <optional>
-#include <type_traits>
-#include <utility>
-#include <vector>
-
-/**
- * btcsignals is a simple mechanism for signaling events to multiple subscribers.
- * It is api-compatible with a minimal subset of boost::signals2.
- *
- * Rather than using a custom slot type, and the features/complexity that they
- * imply, std::function is used to store the callbacks. Lifetime management of
- * the callbacks is left up to the user.
- *
- * All usage is thread-safe except for interacting with a connection while
- * copying/moving it on another thread.
- */
-
-namespace btcsignals {
-
-/// The default combiner, which only returns void.
-class null_value
-{
-public:
- using result_type = void;
-};
-
-/// A combiner, which checks if at least one callback returned true.
-class any_of
-{
-public:
- // This is the only supported combiner with a non-void return type. As
- // such, its behavior is embedded into the signal functor.
- using result_type = bool;
-};
-
-template <typename Signature, typename Combiner = null_value>
-class signal;
-
-/*
- * State object representing the liveness of a registered callback.
- * signal::connect() returns an enabled connection which can be held and
- * disabled in the future.
- */
-class connection
-{
- template <typename Signature, typename Combiner>
- friend class signal;
- /**
- * Track liveness. Also serves as a tag for the constructor used by signal.
- */
- class liveness
- {
- friend class connection;
- std::atomic_bool m_connected{true};
-
- void disconnect() { m_connected.store(false); }
- public:
- bool connected() const { return m_connected.load(); }
- };
-
- /**
- * connections have shared_ptr-like copy and move semantics.
- */
- std::shared_ptr<liveness> m_state{};
-
- /**
- * Only a signal can create an enabled connection.
- */
- explicit connection(std::shared_ptr<liveness>&& state) : m_state{std::move(state)}{}
-
-public:
- /**
- * The default constructor creates a connection with no associated signal
- */
- constexpr connection() noexcept = default;
-
- /**
- * If a callback is associated with this connection, prevent it from being
- * called in the future.
- *
- * If a connection is disabled as part of a signal's callback function, it
- * will _not_ be executed in the current signal invocation.
- *
- * Note that disconnected callbacks are not removed from their owning
- * signals here. They are garbage collected in signal::connect().
- */
- void disconnect()
- {
- if (m_state) {
- m_state->disconnect();
- }
- }
-
- /**
- * Returns true if this connection was created by a signal and has not been
- * disabled.
- */
- bool connected() const
- {
- return m_state && m_state->connected();
- }
-};
-
-/*
- * RAII-style connection management
- */
-class scoped_connection
-{
- connection m_conn;
-
-public:
- explicit scoped_connection(connection rhs) noexcept : m_conn{std::move(rhs)} {}
-
- scoped_connection(scoped_connection&&) noexcept = default;
-
- /**
- * For simplicity, disable copy construction and copy/move assignment.
- */
- scoped_connection& operator=(scoped_connection&&) = delete;
- scoped_connection& operator=(const scoped_connection&) = delete;
- scoped_connection(const scoped_connection&) = delete;
-
- void disconnect()
- {
- m_conn.disconnect();
- }
-
- ~scoped_connection()
- {
- disconnect();
- }
-};
-
-/*
- * Functor for calling zero or more connected callbacks
- */
-template <typename Signature, typename Combiner>
-class signal
-{
- using function_type = std::function<Signature>;
-
- /*
- * Helper struct for maintaining a callback and its associated connection liveness
- */
- struct connection_holder : connection::liveness {
- template <typename Callable>
- connection_holder(Callable&& callback) : m_callback{std::forward<Callable>(callback)}
- {
- }
-
- const function_type m_callback;
- };
-
- mutable Mutex m_mutex;
-
- std::vector<std::shared_ptr<connection_holder>> m_connections GUARDED_BY(m_mutex){};
-
-public:
- using result_type = Combiner::result_type;
-
- constexpr signal() noexcept = default;
- ~signal() = default;
-
- /*
- * For simplicity, disable all moving/copying/assigning.
- */
- signal(const signal&) = delete;
- signal(signal&&) = delete;
- signal& operator=(const signal&) = delete;
- signal& operator=(signal&&) = delete;
-
- /*
- * Execute all enabled callbacks for the signal. Rather than allowing for
- * custom combiners, the behavior of any_of is hard-coded here.
- *
- * Callbacks which return void require special handling.
- *
- * In order to avoid locking during the callbacks, the list of callbacks is
- * cached before they are called. This allows a callback to call connect(),
- * but the newly connected callback will not be run during the current
- * signal invocation.
- *
- * Note that the parameters are accepted as universal references, though
- * they are not perfectly forwarded as that could cause a use-after-move if
- * more than one callback is enabled.
- */
- template <typename... Args>
- [[nodiscard]] result_type operator()(Args&&... args) const EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
- {
- std::vector<std::shared_ptr<connection_holder>> connections;
- {
- LOCK(m_mutex);
- connections = m_connections;
- }
- if constexpr (std::is_void_v<result_type>) {
- static_assert(std::is_same_v<result_type, typename function_type::result_type>,
- "Callback result type must be equal to the combiner result type (void).");
- for (const auto& connection : connections) {
- if (connection->connected()) {
- connection->m_callback(args...);
- }
- }
- } else {
- static_assert(std::is_same_v<Combiner, any_of>,
- "only the any_of combiner is supported and hard-coded into this functor.");
- static_assert(std::is_same_v<result_type, typename function_type::result_type>,
- "Callback result type must be equal to the combiner result type (bool).");
- result_type ret{false};
- for (const auto& connection : connections) {
- if (connection->connected()) {
- ret |= connection->m_callback(args...);
- }
- }
- return ret;
- }
- }
-
- /*
- * Connect a new callback to the signal. A forwarding callable accepts
- * anything that can be stored in a std::function.
- */
- template <typename Callable>
- connection connect(Callable&& func) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
- {
- LOCK(m_mutex);
-
- // Garbage-collect disconnected connections to prevent unbounded growth
- std::erase_if(m_connections, [](const auto& holder) { return !holder->connected(); });
-
- const auto& entry = m_connections.emplace_back(std::make_shared<connection_holder>(std::forward<Callable>(func)));
- return connection(entry);
- }
-
- /*
- * Returns true if there are no enabled callbacks
- */
- [[nodiscard]] bool empty() const EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
- {
- LOCK(m_mutex);
- return std::ranges::none_of(m_connections, [](const auto& holder) {
- return holder->connected();
- });
- }
-};
-
-} // namespace btcsignals
-
-#endif // BITCOIN_BTCSIGNALS_H
diff --git a/src/common/interfaces.cpp b/src/common/interfaces.cpp
index de028f9c..b501493d 100644
--- a/src/common/interfaces.cpp
+++ b/src/common/interfaces.cpp
@@ -2,9 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <btcsignals.h>
#include <interfaces/echo.h>
#include <interfaces/handler.h>
+#include <util/btcsignals.h>
#include <memory>
#include <utility>
diff --git a/src/init.cpp b/src/init.cpp
index da58efe7..a2277728 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -7,13 +7,10 @@
#include <init.h>
-#include <kernel/checks.h>
-
#include <addrdb.h>
#include <addrman.h>
#include <banman.h>
#include <blockfilter.h>
-#include <btcsignals.h>
#include <chain.h>
#include <chainparams.h>
#include <chainparamsbase.h>
@@ -42,6 +39,7 @@
#include <kernel/blockmanager_opts.h>
#include <kernel/caches.h>
#include <kernel/chainstatemanager_opts.h>
+#include <kernel/checks.h>
#include <kernel/context.h>
#include <kernel/notifications_interface.h>
#include <key.h>
@@ -87,6 +85,7 @@
#include <uint256.h>
#include <util/asmap.h>
#include <util/batchpriority.h>
+#include <util/btcsignals.h>
#include <util/chaintype.h>
#include <util/check.h>
#include <util/fs.h>
diff --git a/src/node/interface_ui.cpp b/src/node/interface_ui.cpp
index c80c2902..a9a3da2b 100644
--- a/src/node/interface_ui.cpp
+++ b/src/node/interface_ui.cpp
@@ -4,7 +4,7 @@
#include <node/interface_ui.h>
-#include <btcsignals.h>
+#include <util/btcsignals.h>
#include <util/string.h>
#include <util/translation.h>
diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp
index 2f68f414..ac64876c 100644
--- a/src/node/interfaces.cpp
+++ b/src/node/interfaces.cpp
@@ -6,7 +6,6 @@
#include <banman.h>
#include <blockfilter.h>
-#include <btcsignals.h>
#include <chain.h>
#include <chainparams.h>
#include <coins.h>
@@ -60,6 +59,7 @@
#include <txmempool.h>
#include <uint256.h>
#include <univalue.h>
+#include <util/btcsignals.h>
#include <util/check.h>
#include <util/result.h>
#include <util/signalinterrupt.h>
diff --git a/src/noui.cpp b/src/noui.cpp
index ee61a099..b9c9e78b 100644
--- a/src/noui.cpp
+++ b/src/noui.cpp
@@ -5,8 +5,8 @@
#include <noui.h>
-#include <btcsignals.h>
#include <node/interface_ui.h>
+#include <util/btcsignals.h>
#include <util/log.h>
#include <util/translation.h>
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index 47790eb3..40a60a26 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -6,7 +6,6 @@
#include <qt/bitcoin.h>
-#include <btcsignals.h>
#include <chainparams.h>
#include <common/args.h>
#include <common/init.h>
@@ -31,6 +30,7 @@
#include <qt/utilitydialog.h>
#include <qt/winshutdownmonitor.h>
#include <uint256.h>
+#include <util/btcsignals.h>
#include <util/exception.h>
#include <util/log.h>
#include <util/string.h>
diff --git a/src/test/btcsignals_tests.cpp b/src/test/btcsignals_tests.cpp
index dd7fcb9b..d6122896 100644
--- a/src/test/btcsignals_tests.cpp
+++ b/src/test/btcsignals_tests.cpp
@@ -2,8 +2,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <btcsignals.h>
#include <test/util/setup_common.h>
+#include <util/btcsignals.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/util/btcsignals.h b/src/util/btcsignals.h
new file mode 100644
index 00000000..1da40298
--- /dev/null
+++ b/src/util/btcsignals.h
@@ -0,0 +1,261 @@
+// Copyright (c) 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_UTIL_BTCSIGNALS_H
+#define BITCOIN_UTIL_BTCSIGNALS_H
+
+#include <sync.h>
+
+#include <algorithm>
+#include <atomic>
+#include <functional>
+#include <memory>
+#include <optional>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+/**
+ * btcsignals is a simple mechanism for signaling events to multiple subscribers.
+ * It is api-compatible with a minimal subset of boost::signals2.
+ *
+ * Rather than using a custom slot type, and the features/complexity that they
+ * imply, std::function is used to store the callbacks. Lifetime management of
+ * the callbacks is left up to the user.
+ *
+ * All usage is thread-safe except for interacting with a connection while
+ * copying/moving it on another thread.
+ */
+
+namespace btcsignals {
+
+/// The default combiner, which only returns void.
+class null_value
+{
+public:
+ using result_type = void;
+};
+
+/// A combiner, which checks if at least one callback returned true.
+class any_of
+{
+public:
+ // This is the only supported combiner with a non-void return type. As
+ // such, its behavior is embedded into the signal functor.
+ using result_type = bool;
+};
+
+template <typename Signature, typename Combiner = null_value>
+class signal;
+
+/*
+ * State object representing the liveness of a registered callback.
+ * signal::connect() returns an enabled connection which can be held and
+ * disabled in the future.
+ */
+class connection
+{
+ template <typename Signature, typename Combiner>
+ friend class signal;
+ /**
+ * Track liveness. Also serves as a tag for the constructor used by signal.
+ */
+ class liveness
+ {
+ friend class connection;
+ std::atomic_bool m_connected{true};
+
+ void disconnect() { m_connected.store(false); }
+ public:
+ bool connected() const { return m_connected.load(); }
+ };
+
+ /**
+ * connections have shared_ptr-like copy and move semantics.
+ */
+ std::shared_ptr<liveness> m_state{};
+
+ /**
+ * Only a signal can create an enabled connection.
+ */
+ explicit connection(std::shared_ptr<liveness>&& state) : m_state{std::move(state)}{}
+
+public:
+ /**
+ * The default constructor creates a connection with no associated signal
+ */
+ constexpr connection() noexcept = default;
+
+ /**
+ * If a callback is associated with this connection, prevent it from being
+ * called in the future.
+ *
+ * If a connection is disabled as part of a signal's callback function, it
+ * will _not_ be executed in the current signal invocation.
+ *
+ * Note that disconnected callbacks are not removed from their owning
+ * signals here. They are garbage collected in signal::connect().
+ */
+ void disconnect()
+ {
+ if (m_state) {
+ m_state->disconnect();
+ }
+ }
+
+ /**
+ * Returns true if this connection was created by a signal and has not been
+ * disabled.
+ */
+ bool connected() const
+ {
+ return m_state && m_state->connected();
+ }
+};
+
+/*
+ * RAII-style connection management
+ */
+class scoped_connection
+{
+ connection m_conn;
+
+public:
+ explicit scoped_connection(connection rhs) noexcept : m_conn{std::move(rhs)} {}
+
+ scoped_connection(scoped_connection&&) noexcept = default;
+
+ /**
+ * For simplicity, disable copy construction and copy/move assignment.
+ */
+ scoped_connection& operator=(scoped_connection&&) = delete;
+ scoped_connection& operator=(const scoped_connection&) = delete;
+ scoped_connection(const scoped_connection&) = delete;
+
+ void disconnect()
+ {
+ m_conn.disconnect();
+ }
+
+ ~scoped_connection()
+ {
+ disconnect();
+ }
+};
+
+/*
+ * Functor for calling zero or more connected callbacks
+ */
+template <typename Signature, typename Combiner>
+class signal
+{
+ using function_type = std::function<Signature>;
+
+ /*
+ * Helper struct for maintaining a callback and its associated connection liveness
+ */
+ struct connection_holder : connection::liveness {
+ template <typename Callable>
+ connection_holder(Callable&& callback) : m_callback{std::forward<Callable>(callback)}
+ {
+ }
+
+ const function_type m_callback;
+ };
+
+ mutable Mutex m_mutex;
+
+ std::vector<std::shared_ptr<connection_holder>> m_connections GUARDED_BY(m_mutex){};
+
+public:
+ using result_type = Combiner::result_type;
+
+ constexpr signal() noexcept = default;
+ ~signal() = default;
+
+ /*
+ * For simplicity, disable all moving/copying/assigning.
+ */
+ signal(const signal&) = delete;
+ signal(signal&&) = delete;
+ signal& operator=(const signal&) = delete;
+ signal& operator=(signal&&) = delete;
+
+ /*
+ * Execute all enabled callbacks for the signal. Rather than allowing for
+ * custom combiners, the behavior of any_of is hard-coded here.
+ *
+ * Callbacks which return void require special handling.
+ *
+ * In order to avoid locking during the callbacks, the list of callbacks is
+ * cached before they are called. This allows a callback to call connect(),
+ * but the newly connected callback will not be run during the current
+ * signal invocation.
+ *
+ * Note that the parameters are accepted as universal references, though
+ * they are not perfectly forwarded as that could cause a use-after-move if
+ * more than one callback is enabled.
+ */
+ template <typename... Args>
+ [[nodiscard]] result_type operator()(Args&&... args) const EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
+ {
+ std::vector<std::shared_ptr<connection_holder>> connections;
+ {
+ LOCK(m_mutex);
+ connections = m_connections;
+ }
+ if constexpr (std::is_void_v<result_type>) {
+ static_assert(std::is_same_v<result_type, typename function_type::result_type>,
+ "Callback result type must be equal to the combiner result type (void).");
+ for (const auto& connection : connections) {
+ if (connection->connected()) {
+ connection->m_callback(args...);
+ }
+ }
+ } else {
+ static_assert(std::is_same_v<Combiner, any_of>,
+ "only the any_of combiner is supported and hard-coded into this functor.");
+ static_assert(std::is_same_v<result_type, typename function_type::result_type>,
+ "Callback result type must be equal to the combiner result type (bool).");
+ result_type ret{false};
+ for (const auto& connection : connections) {
+ if (connection->connected()) {
+ ret |= connection->m_callback(args...);
+ }
+ }
+ return ret;
+ }
+ }
+
+ /*
+ * Connect a new callback to the signal. A forwarding callable accepts
+ * anything that can be stored in a std::function.
+ */
+ template <typename Callable>
+ connection connect(Callable&& func) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
+ {
+ LOCK(m_mutex);
+
+ // Garbage-collect disconnected connections to prevent unbounded growth
+ std::erase_if(m_connections, [](const auto& holder) { return !holder->connected(); });
+
+ const auto& entry = m_connections.emplace_back(std::make_shared<connection_holder>(std::forward<Callable>(func)));
+ return connection(entry);
+ }
+
+ /*
+ * Returns true if there are no enabled callbacks
+ */
+ [[nodiscard]] bool empty() const EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
+ {
+ LOCK(m_mutex);
+ return std::ranges::none_of(m_connections, [](const auto& holder) {
+ return holder->connected();
+ });
+ }
+};
+
+} // namespace btcsignals
+
+#endif // BITCOIN_UTIL_BTCSIGNALS_H
diff --git a/src/wallet/scriptpubkeyman.h b/src/wallet/scriptpubkeyman.h
index 9a5554d9..6cebae05 100644
--- a/src/wallet/scriptpubkeyman.h
+++ b/src/wallet/scriptpubkeyman.h
@@ -6,7 +6,6 @@
#define BITCOIN_WALLET_SCRIPTPUBKEYMAN_H
#include <addresstype.h>
-#include <btcsignals.h>
#include <common/messages.h>
#include <common/signmessage.h>
#include <common/types.h>
@@ -16,6 +15,7 @@
#include <script/descriptor.h>
#include <script/script.h>
#include <script/signingprovider.h>
+#include <util/btcsignals.h>
#include <util/hasher.h>
#include <util/log.h>
#include <util/result.h>
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 54bc60f5..8056b59e 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -7,7 +7,6 @@
#define BITCOIN_WALLET_WALLET_H
#include <addresstype.h>
-#include <btcsignals.h>
#include <consensus/amount.h>
#include <interfaces/chain.h>
#include <interfaces/handler.h>
@@ -23,6 +22,7 @@
#include <sync.h>
#include <tinyformat.h>
#include <uint256.h>
+#include <util/btcsignals.h>
#include <util/fs.h>
#include <util/hasher.h>
#include <util/log.h>
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.