mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-01-20 23:29:12 +01:00
kernel: Add notifications context option to C header
The notifications are used for notifying on connected blocks and on warning and fatal error conditions. The user of the C header may define callbacks that gets passed to the internal notification object in the `kernel_NotificationInterfaceCallbacks` struct. Each of the callbacks take a `user_data` argument that gets populated from the `user_data` value in the struct. It can be used to recreate the structure containing the callbacks on the user's side, or to give the callbacks additional contextual information.
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
#include <kernel/context.h>
|
||||
#include <kernel/cs_main.h>
|
||||
#include <kernel/notifications_interface.h>
|
||||
#include <kernel/warning.h>
|
||||
#include <logging.h>
|
||||
#include <primitives/transaction.h>
|
||||
#include <script/interpreter.h>
|
||||
@@ -23,6 +24,7 @@
|
||||
#include <util/result.h>
|
||||
#include <util/signalinterrupt.h>
|
||||
#include <util/translation.h>
|
||||
#include <validation.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
@@ -36,6 +38,8 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
class CBlockIndex;
|
||||
|
||||
// Define G_TRANSLATION_FUN symbol in libbitcoinkernel library so users of the
|
||||
// library aren't required to export this symbol
|
||||
extern const std::function<std::string(const char*)> G_TRANSLATION_FUN{nullptr};
|
||||
@@ -120,6 +124,12 @@ struct Handle {
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
struct btck_BlockTreeEntry: Handle<btck_BlockTreeEntry, CBlockIndex> {};
|
||||
|
||||
namespace {
|
||||
|
||||
BCLog::Level get_bclog_level(btck_LogLevel level)
|
||||
{
|
||||
switch (level) {
|
||||
@@ -176,6 +186,30 @@ BCLog::LogFlags get_bclog_flag(btck_LogCategory category)
|
||||
assert(false);
|
||||
}
|
||||
|
||||
btck_SynchronizationState cast_state(SynchronizationState state)
|
||||
{
|
||||
switch (state) {
|
||||
case SynchronizationState::INIT_REINDEX:
|
||||
return btck_SynchronizationState_INIT_REINDEX;
|
||||
case SynchronizationState::INIT_DOWNLOAD:
|
||||
return btck_SynchronizationState_INIT_DOWNLOAD;
|
||||
case SynchronizationState::POST_INIT:
|
||||
return btck_SynchronizationState_POST_INIT;
|
||||
} // no default case, so the compiler can warn about missing cases
|
||||
assert(false);
|
||||
}
|
||||
|
||||
btck_Warning cast_btck_warning(kernel::Warning warning)
|
||||
{
|
||||
switch (warning) {
|
||||
case kernel::Warning::UNKNOWN_NEW_RULES_ACTIVATED:
|
||||
return btck_Warning_UNKNOWN_NEW_RULES_ACTIVATED;
|
||||
case kernel::Warning::LARGE_WORK_INVALID_CHAIN:
|
||||
return btck_Warning_LARGE_WORK_INVALID_CHAIN;
|
||||
} // no default case, so the compiler can warn about missing cases
|
||||
assert(false);
|
||||
}
|
||||
|
||||
struct LoggingConnection {
|
||||
std::unique_ptr<std::list<std::function<void(const std::string&)>>::iterator> m_connection;
|
||||
void* m_user_data;
|
||||
@@ -224,9 +258,61 @@ struct LoggingConnection {
|
||||
}
|
||||
};
|
||||
|
||||
class KernelNotifications final : public kernel::Notifications
|
||||
{
|
||||
private:
|
||||
btck_NotificationInterfaceCallbacks m_cbs;
|
||||
|
||||
public:
|
||||
KernelNotifications(btck_NotificationInterfaceCallbacks cbs)
|
||||
: m_cbs{cbs}
|
||||
{
|
||||
}
|
||||
|
||||
~KernelNotifications()
|
||||
{
|
||||
if (m_cbs.user_data && m_cbs.user_data_destroy) {
|
||||
m_cbs.user_data_destroy(m_cbs.user_data);
|
||||
}
|
||||
m_cbs.user_data_destroy = nullptr;
|
||||
m_cbs.user_data = nullptr;
|
||||
}
|
||||
|
||||
kernel::InterruptResult blockTip(SynchronizationState state, const CBlockIndex& index, double verification_progress) override
|
||||
{
|
||||
if (m_cbs.block_tip) m_cbs.block_tip(m_cbs.user_data, cast_state(state), btck_BlockTreeEntry::ref(&index), verification_progress);
|
||||
return {};
|
||||
}
|
||||
void headerTip(SynchronizationState state, int64_t height, int64_t timestamp, bool presync) override
|
||||
{
|
||||
if (m_cbs.header_tip) m_cbs.header_tip(m_cbs.user_data, cast_state(state), height, timestamp, presync ? 1 : 0);
|
||||
}
|
||||
void progress(const bilingual_str& title, int progress_percent, bool resume_possible) override
|
||||
{
|
||||
if (m_cbs.progress) m_cbs.progress(m_cbs.user_data, title.original.c_str(), title.original.length(), progress_percent, resume_possible ? 1 : 0);
|
||||
}
|
||||
void warningSet(kernel::Warning id, const bilingual_str& message) override
|
||||
{
|
||||
if (m_cbs.warning_set) m_cbs.warning_set(m_cbs.user_data, cast_btck_warning(id), message.original.c_str(), message.original.length());
|
||||
}
|
||||
void warningUnset(kernel::Warning id) override
|
||||
{
|
||||
if (m_cbs.warning_unset) m_cbs.warning_unset(m_cbs.user_data, cast_btck_warning(id));
|
||||
}
|
||||
void flushError(const bilingual_str& message) override
|
||||
{
|
||||
if (m_cbs.flush_error) m_cbs.flush_error(m_cbs.user_data, message.original.c_str(), message.original.length());
|
||||
}
|
||||
void fatalError(const bilingual_str& message) override
|
||||
{
|
||||
if (m_cbs.fatal_error) m_cbs.fatal_error(m_cbs.user_data, message.original.c_str(), message.original.length());
|
||||
}
|
||||
};
|
||||
|
||||
struct ContextOptions {
|
||||
mutable Mutex m_mutex;
|
||||
std::unique_ptr<const CChainParams> m_chainparams GUARDED_BY(m_mutex);
|
||||
std::shared_ptr<KernelNotifications> m_notifications GUARDED_BY(m_mutex);
|
||||
};
|
||||
|
||||
class Context
|
||||
@@ -234,7 +320,7 @@ class Context
|
||||
public:
|
||||
std::unique_ptr<kernel::Context> m_context;
|
||||
|
||||
std::unique_ptr<kernel::Notifications> m_notifications;
|
||||
std::shared_ptr<KernelNotifications> m_notifications;
|
||||
|
||||
std::unique_ptr<util::SignalInterrupt> m_interrupt;
|
||||
|
||||
@@ -242,7 +328,6 @@ public:
|
||||
|
||||
Context(const ContextOptions* options, bool& sane)
|
||||
: m_context{std::make_unique<kernel::Context>()},
|
||||
m_notifications{std::make_unique<kernel::Notifications>()},
|
||||
m_interrupt{std::make_unique<util::SignalInterrupt>()}
|
||||
{
|
||||
if (options) {
|
||||
@@ -250,11 +335,18 @@ public:
|
||||
if (options->m_chainparams) {
|
||||
m_chainparams = std::make_unique<const CChainParams>(*options->m_chainparams);
|
||||
}
|
||||
if (options->m_notifications) {
|
||||
m_notifications = options->m_notifications;
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_chainparams) {
|
||||
m_chainparams = CChainParams::Main();
|
||||
}
|
||||
if (!m_notifications) {
|
||||
m_notifications = std::make_shared<KernelNotifications>(btck_NotificationInterfaceCallbacks{
|
||||
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr});
|
||||
}
|
||||
|
||||
if (!kernel::SanityChecks(*m_context)) {
|
||||
sane = false;
|
||||
@@ -511,6 +603,13 @@ void btck_context_options_set_chainparams(btck_ContextOptions* options, const bt
|
||||
btck_ContextOptions::get(options).m_chainparams = std::make_unique<const CChainParams>(btck_ChainParameters::get(chain_parameters));
|
||||
}
|
||||
|
||||
void btck_context_options_set_notifications(btck_ContextOptions* options, btck_NotificationInterfaceCallbacks notifications)
|
||||
{
|
||||
// The KernelNotifications are copy-initialized, so the caller can free them again.
|
||||
LOCK(btck_ContextOptions::get(options).m_mutex);
|
||||
btck_ContextOptions::get(options).m_notifications = std::make_shared<KernelNotifications>(notifications);
|
||||
}
|
||||
|
||||
void btck_context_options_destroy(btck_ContextOptions* options)
|
||||
{
|
||||
delete options;
|
||||
|
||||
Reference in New Issue
Block a user