aboutsummaryrefslogtreecommitdiff
path: root/src/node
diff options
context:
space:
mode:
authorstickies-v <stickies-v@protonmail.com>2024-05-07 17:05:40 +0100
committerstickies-v <stickies-v@protonmail.com>2024-06-13 11:20:48 +0100
commitb071ad9770b7ae7fc718dcbfdc8f62dffbf6cfee (patch)
tree71f6d60e4546b6567a840d1e7733cfd73c60b5fa /src/node
parent20e616f86444d00712ac7eb840666e2b0378af4a (diff)
downloadbitcoin-b071ad9770b7ae7fc718dcbfdc8f62dffbf6cfee.tar.xz
introduce and use the generalized `node::Warnings` interface
Instead of having separate warning functions (and globals) for each different warning that can be raised, encapsulate this logic into a single class and allow to (un)set any number of warnings. Introduces behaviour change: - the `-alertnotify` command is executed for all `KernelNotifications::warningSet` calls, which now also covers the `LARGE_WORK_INVALID_CHAIN` warning. - previously, warnings were returned based on a predetermined order, e.g. with the "pre-release test build" warning always first. This is no longer the case, and Warnings::GetMessages() will return messages sorted by the id of the warning. Removes warnings.cpp from kernel.
Diffstat (limited to 'src/node')
-rw-r--r--src/node/abort.cpp3
-rw-r--r--src/node/interfaces.cpp2
-rw-r--r--src/node/kernel_notifications.cpp22
-rw-r--r--src/node/kernel_notifications.h8
-rw-r--r--src/node/timeoffsets.cpp4
-rw-r--r--src/node/warnings.cpp66
-rw-r--r--src/node/warnings.h82
7 files changed, 117 insertions, 70 deletions
diff --git a/src/node/abort.cpp b/src/node/abort.cpp
index 6f836824b2..68c09f0ef7 100644
--- a/src/node/abort.cpp
+++ b/src/node/abort.cpp
@@ -12,13 +12,12 @@
#include <atomic>
#include <cstdlib>
-#include <string>
namespace node {
void AbortNode(util::SignalInterrupt* shutdown, std::atomic<int>& exit_status, const bilingual_str& message)
{
- SetMiscWarning(message);
+ g_warnings.Set(Warning::FATAL_INTERNAL_ERROR, message);
InitError(_("A fatal internal error occurred, see debug.log for details: ") + message);
exit_status.store(EXIT_FAILURE);
if (shutdown && !(*shutdown)()) {
diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp
index 88af9dadbc..9ea3f63fdf 100644
--- a/src/node/interfaces.cpp
+++ b/src/node/interfaces.cpp
@@ -93,7 +93,7 @@ public:
explicit NodeImpl(NodeContext& context) { setContext(&context); }
void initLogging() override { InitLogging(args()); }
void initParameterInteraction() override { InitParameterInteraction(args()); }
- bilingual_str getWarnings() override { return Join(GetWarnings(), Untranslated("<hr />")); }
+ bilingual_str getWarnings() override { return Join(node::g_warnings.GetMessages(), Untranslated("<hr />")); }
int getExitStatus() override { return Assert(m_context)->exit_status.load(); }
uint32_t getLogCategories() override { return LogInstance().GetCategoryMask(); }
bool baseInitialize() override
diff --git a/src/node/kernel_notifications.cpp b/src/node/kernel_notifications.cpp
index 1900ac3117..e18919f503 100644
--- a/src/node/kernel_notifications.cpp
+++ b/src/node/kernel_notifications.cpp
@@ -10,6 +10,7 @@
#include <common/args.h>
#include <common/system.h>
#include <kernel/context.h>
+#include <kernel/warning.h>
#include <logging.h>
#include <node/abort.h>
#include <node/interface_ui.h>
@@ -46,16 +47,6 @@ static void AlertNotify(const std::string& strMessage)
#endif
}
-static void DoWarning(const bilingual_str& warning)
-{
- static bool fWarned = false;
- node::SetMiscWarning(warning);
- if (!fWarned) {
- AlertNotify(warning.original);
- fWarned = true;
- }
-}
-
namespace node {
kernel::InterruptResult KernelNotifications::blockTip(SynchronizationState state, CBlockIndex& index)
@@ -80,9 +71,16 @@ void KernelNotifications::progress(const bilingual_str& title, int progress_perc
uiInterface.ShowProgress(title.translated, progress_percent, resume_possible);
}
-void KernelNotifications::warning(const bilingual_str& warning)
+void KernelNotifications::warningSet(kernel::Warning id, const bilingual_str& message)
+{
+ if (node::g_warnings.Set(id, message)) {
+ AlertNotify(message.original);
+ }
+}
+
+void KernelNotifications::warningUnset(kernel::Warning id)
{
- DoWarning(warning);
+ g_warnings.Unset(id);
}
void KernelNotifications::flushError(const bilingual_str& message)
diff --git a/src/node/kernel_notifications.h b/src/node/kernel_notifications.h
index f4d97a0fff..96f09be453 100644
--- a/src/node/kernel_notifications.h
+++ b/src/node/kernel_notifications.h
@@ -15,6 +15,10 @@ class CBlockIndex;
enum class SynchronizationState;
struct bilingual_str;
+namespace kernel {
+enum class Warning;
+} // namespace kernel
+
namespace util {
class SignalInterrupt;
} // namespace util
@@ -34,7 +38,9 @@ public:
void progress(const bilingual_str& title, int progress_percent, bool resume_possible) override;
- void warning(const bilingual_str& warning) override;
+ void warningSet(kernel::Warning id, const bilingual_str& message) override;
+
+ void warningUnset(kernel::Warning id) override;
void flushError(const bilingual_str& message) override;
diff --git a/src/node/timeoffsets.cpp b/src/node/timeoffsets.cpp
index 17ee44a92c..b839b60565 100644
--- a/src/node/timeoffsets.cpp
+++ b/src/node/timeoffsets.cpp
@@ -49,7 +49,7 @@ bool TimeOffsets::WarnIfOutOfSync() const
// when median == std::numeric_limits<int64_t>::min(), calling std::chrono::abs is UB
auto median{std::max(Median(), std::chrono::seconds(std::numeric_limits<int64_t>::min() + 1))};
if (std::chrono::abs(median) <= WARN_THRESHOLD) {
- node::SetMedianTimeOffsetWarning(std::nullopt);
+ node::g_warnings.Unset(node::Warning::CLOCK_OUT_OF_SYNC);
uiInterface.NotifyAlertChanged();
return false;
}
@@ -63,7 +63,7 @@ bool TimeOffsets::WarnIfOutOfSync() const
"RPC methods to get more info."
), Ticks<std::chrono::minutes>(WARN_THRESHOLD))};
LogWarning("%s\n", msg.original);
- node::SetMedianTimeOffsetWarning(msg);
+ node::g_warnings.Set(node::Warning::CLOCK_OUT_OF_SYNC, msg);
uiInterface.NotifyAlertChanged();
return true;
}
diff --git a/src/node/warnings.cpp b/src/node/warnings.cpp
index 9d2239e64a..8a94eb0bd2 100644
--- a/src/node/warnings.cpp
+++ b/src/node/warnings.cpp
@@ -12,69 +12,53 @@
#include <univalue.h>
#include <util/translation.h>
-#include <optional>
+#include <utility>
#include <vector>
-static GlobalMutex g_warnings_mutex;
-static bilingual_str g_misc_warnings GUARDED_BY(g_warnings_mutex);
-static bool fLargeWorkInvalidChainFound GUARDED_BY(g_warnings_mutex) = false;
-static std::optional<bilingual_str> g_timeoffset_warning GUARDED_BY(g_warnings_mutex){};
-
namespace node {
-void SetMiscWarning(const bilingual_str& warning)
+Warnings g_warnings;
+
+Warnings::Warnings()
{
- LOCK(g_warnings_mutex);
- g_misc_warnings = warning;
+ // Pre-release build warning
+ if (!CLIENT_VERSION_IS_RELEASE) {
+ m_warnings.insert(
+ {Warning::PRE_RELEASE_TEST_BUILD,
+ _("This is a pre-release test build - use at your own risk - do not use for mining or merchant applications")});
+ }
}
-
-void SetfLargeWorkInvalidChainFound(bool flag)
+bool Warnings::Set(warning_type id, bilingual_str message)
{
- LOCK(g_warnings_mutex);
- fLargeWorkInvalidChainFound = flag;
+ LOCK(m_mutex);
+ const auto& [_, inserted]{m_warnings.insert({id, std::move(message)})};
+ return inserted;
}
-void SetMedianTimeOffsetWarning(std::optional<bilingual_str> warning)
+bool Warnings::Unset(warning_type id)
{
- LOCK(g_warnings_mutex);
- g_timeoffset_warning = warning;
+ return WITH_LOCK(m_mutex, return m_warnings.erase(id));
}
-std::vector<bilingual_str> GetWarnings()
+std::vector<bilingual_str> Warnings::GetMessages() const
{
- std::vector<bilingual_str> warnings;
-
- LOCK(g_warnings_mutex);
-
- // Pre-release build warning
- if (!CLIENT_VERSION_IS_RELEASE) {
- warnings.emplace_back(_("This is a pre-release test build - use at your own risk - do not use for mining or merchant applications"));
- }
-
- // Misc warnings like out of disk space and clock is wrong
- if (!g_misc_warnings.empty()) {
- warnings.emplace_back(g_misc_warnings);
- }
-
- if (fLargeWorkInvalidChainFound) {
- warnings.emplace_back(_("Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade."));
+ LOCK(m_mutex);
+ std::vector<bilingual_str> messages;
+ messages.reserve(m_warnings.size());
+ for (const auto& [id, msg] : m_warnings) {
+ messages.push_back(msg);
}
-
- if (g_timeoffset_warning) {
- warnings.emplace_back(g_timeoffset_warning.value());
- }
-
- return warnings;
+ return messages;
}
UniValue GetWarningsForRpc(bool use_deprecated)
{
if (use_deprecated) {
- const auto all_warnings{GetWarnings()};
+ const auto all_warnings{g_warnings.GetMessages()};
return all_warnings.empty() ? "" : all_warnings.back().original;
}
UniValue warnings{UniValue::VARR};
- for (auto&& warning : GetWarnings()) {
+ for (auto&& warning : g_warnings.GetMessages()) {
warnings.push_back(std::move(warning.original));
}
return warnings;
diff --git a/src/node/warnings.h b/src/node/warnings.h
index 7766f1dbc9..c85e8a16a9 100644
--- a/src/node/warnings.h
+++ b/src/node/warnings.h
@@ -6,26 +6,86 @@
#ifndef BITCOIN_NODE_WARNINGS_H
#define BITCOIN_NODE_WARNINGS_H
-#include <optional>
-#include <string>
+#include <sync.h>
+
+#include <map>
+#include <variant>
#include <vector>
class UniValue;
struct bilingual_str;
+namespace kernel {
+enum class Warning;
+} // namespace kernel
+
namespace node {
-void SetMiscWarning(const bilingual_str& warning);
-void SetfLargeWorkInvalidChainFound(bool flag);
-/** Pass std::nullopt to disable the warning */
-void SetMedianTimeOffsetWarning(std::optional<bilingual_str> warning);
-/** Return potential problems detected by the node. */
-std::vector<bilingual_str> GetWarnings();
+enum class Warning {
+ CLOCK_OUT_OF_SYNC,
+ PRE_RELEASE_TEST_BUILD,
+ FATAL_INTERNAL_ERROR,
+};
+
/**
- * RPC helper function that wraps GetWarnings. Returns a UniValue::VSTR
- * with the latest warning if use_deprecated is set to true, or a
- * UniValue::VARR with all warnings otherwise.
+ * @class Warnings
+ * @brief Manages warning messages within a node.
+ *
+ * The Warnings class provides mechanisms to set, unset, and retrieve
+ * warning messages.
+ *
+ * This class is designed to be non-copyable to ensure warnings
+ * are managed centrally.
+ */
+class Warnings
+{
+ typedef std::variant<kernel::Warning, node::Warning> warning_type;
+
+ mutable Mutex m_mutex;
+ std::map<warning_type, bilingual_str> m_warnings GUARDED_BY(m_mutex);
+
+public:
+ Warnings();
+ //! A warnings instance should always be passed by reference, never copied.
+ Warnings(const Warnings&) = delete;
+ Warnings& operator=(const Warnings&) = delete;
+ /**
+ * @brief Set a warning message. If a warning with the specified
+ * `id` is already active, false is returned and the new
+ * warning is ignored. If `id` does not yet exist, the
+ * warning is set, and true is returned.
+ *
+ * @param[in] id Unique identifier of the warning.
+ * @param[in] message Warning message to be shown.
+ *
+ * @returns true if the warning was indeed set (i.e. there is no
+ * active warning with this `id`), otherwise false.
+ */
+ bool Set(warning_type id, bilingual_str message) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);
+ /**
+ * @brief Unset a warning message. If a warning with the specified
+ * `id` is active, it is unset, and true is returned.
+ * Otherwise, no warning is unset and false is returned.
+ *
+ * @param[in] id Unique identifier of the warning.
+ *
+ * @returns true if the warning was indeed unset (i.e. there is an
+ * active warning with this `id`), otherwise false.
+ */
+ bool Unset(warning_type id) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);
+ /** Return potential problems detected by the node, sorted by the
+ * warning_type id */
+ std::vector<bilingual_str> GetMessages() const EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);
+};
+
+/**
+ * RPC helper function that wraps g_warnings.GetMessages().
+ *
+ * Returns a UniValue::VSTR with the latest warning if use_deprecated is
+ * set to true, or a UniValue::VARR with all warnings otherwise.
*/
UniValue GetWarningsForRpc(bool use_deprecated);
+
+extern Warnings g_warnings;
} // namespace node
#endif // BITCOIN_NODE_WARNINGS_H