diff options
author | stickies-v <stickies-v@protonmail.com> | 2024-05-07 17:05:40 +0100 |
---|---|---|
committer | stickies-v <stickies-v@protonmail.com> | 2024-06-13 11:20:48 +0100 |
commit | b071ad9770b7ae7fc718dcbfdc8f62dffbf6cfee (patch) | |
tree | 71f6d60e4546b6567a840d1e7733cfd73c60b5fa /src/node | |
parent | 20e616f86444d00712ac7eb840666e2b0378af4a (diff) | |
download | bitcoin-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.cpp | 3 | ||||
-rw-r--r-- | src/node/interfaces.cpp | 2 | ||||
-rw-r--r-- | src/node/kernel_notifications.cpp | 22 | ||||
-rw-r--r-- | src/node/kernel_notifications.h | 8 | ||||
-rw-r--r-- | src/node/timeoffsets.cpp | 4 | ||||
-rw-r--r-- | src/node/warnings.cpp | 66 | ||||
-rw-r--r-- | src/node/warnings.h | 82 |
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 |