kernel: Add notification interface

This commit is part of the libbitcoinkernel project and seeks to remove
the ChainstateManager's and, more generally, the kernel library's
dependency on interface_ui with options methods in this and the following
few commits. By removing interface_ui from the kernel library, its
dependency on boost is reduced to just boost::multi_index.

Define a new kernel notification class with virtual methods for
notifying about internal kernel events. Create a new file in the node
library for defining a function creating the default set of notification
methods such that these do not need to be re-defined all over the
codebase. As a first step, add a `blockTip` method, wrapping
`uiInterface.NotifyBlockTip`.
This commit is contained in:
TheCharlatan 2023-05-10 22:29:17 +02:00
parent 0f8c95dccd
commit 447761c822
No known key found for this signature in database
GPG Key ID: 9B79B45691DB4173
13 changed files with 103 additions and 2 deletions

View File

@ -186,6 +186,7 @@ BITCOIN_CORE_H = \
kernel/mempool_limits.h \
kernel/mempool_options.h \
kernel/mempool_persist.h \
kernel/notifications_interface.h \
kernel/validation_cache_sizes.h \
key.h \
key_io.h \
@ -214,6 +215,7 @@ BITCOIN_CORE_H = \
node/database_args.h \
node/eviction.h \
node/interface_ui.h \
node/kernel_notifications.h \
node/mempool_args.h \
node/mempool_persist_args.h \
node/miner.h \
@ -408,6 +410,7 @@ libbitcoin_node_a_SOURCES = \
node/eviction.cpp \
node/interface_ui.cpp \
node/interfaces.cpp \
node/kernel_notifications.cpp \
node/mempool_args.cpp \
node/mempool_persist_args.cpp \
node/miner.cpp \

View File

@ -12,6 +12,7 @@
// It is part of the libbitcoinkernel project.
#include <kernel/chainparams.h>
#include <kernel/chainstatemanager_opts.h>
#include <kernel/checks.h>
#include <kernel/context.h>
#include <kernel/validation_cache_sizes.h>
@ -34,6 +35,7 @@
#include <filesystem>
#include <functional>
#include <iosfwd>
#include <memory>
int main(int argc, char* argv[])
{
@ -80,12 +82,22 @@ int main(int argc, char* argv[])
GetMainSignals().RegisterBackgroundSignalScheduler(scheduler);
class KernelNotifications : public kernel::Notifications
{
public:
void blockTip(SynchronizationState, CBlockIndex&) override
{
std::cout << "Block tip changed" << std::endl;
}
};
auto notifications = std::make_unique<KernelNotifications>();
// SETUP: Chainstate
const ChainstateManager::Options chainman_opts{
.chainparams = *chainparams,
.datadir = gArgs.GetDataDirNet(),
.adjusted_time_callback = NodeClock::now,
.notifications = *notifications,
};
const node::BlockManager::Options blockman_opts{
.chainparams = chainman_opts.chainparams,

View File

@ -45,6 +45,7 @@
#include <node/chainstatemanager_args.h>
#include <node/context.h>
#include <node/interface_ui.h>
#include <node/kernel_notifications.h>
#include <node/mempool_args.h>
#include <node/mempool_persist_args.h>
#include <node/miner.h>
@ -124,6 +125,7 @@ using node::DEFAULT_PERSIST_MEMPOOL;
using node::DEFAULT_PRINTPRIORITY;
using node::fReindex;
using node::g_indexes_ready_to_sync;
using node::KernelNotifications;
using node::LoadChainstate;
using node::MempoolPath;
using node::NodeContext;
@ -1019,9 +1021,11 @@ bool AppInitParameterInteraction(const ArgsManager& args, bool use_syscall_sandb
// Also report errors from parsing before daemonization
{
KernelNotifications notifications{};
ChainstateManager::Options chainman_opts_dummy{
.chainparams = chainparams,
.datadir = args.GetDataDirNet(),
.notifications = notifications,
};
if (const auto error{ApplyArgsManOptions(args, chainman_opts_dummy)}) {
return InitError(*error);
@ -1427,12 +1431,14 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
// ********************************************************* Step 7: load block chain
node.notifications = std::make_unique<KernelNotifications>();
fReindex = args.GetBoolArg("-reindex", false);
bool fReindexChainState = args.GetBoolArg("-reindex-chainstate", false);
ChainstateManager::Options chainman_opts{
.chainparams = chainparams,
.datadir = args.GetDataDirNet(),
.adjusted_time_callback = GetAdjustedTime,
.notifications = *node.notifications,
};
Assert(!ApplyArgsManOptions(args, chainman_opts)); // no error can happen, already checked in AppInitParameterInteraction

View File

@ -5,6 +5,8 @@
#ifndef BITCOIN_KERNEL_CHAINSTATEMANAGER_OPTS_H
#define BITCOIN_KERNEL_CHAINSTATEMANAGER_OPTS_H
#include <kernel/notifications_interface.h>
#include <arith_uint256.h>
#include <dbwrapper.h>
#include <txdb.h>
@ -42,6 +44,7 @@ struct ChainstateManagerOpts {
DBOptions block_tree_db{};
DBOptions coins_db{};
CoinsViewOptions coins_view{};
Notifications& notifications;
};
} // namespace kernel

View File

@ -0,0 +1,26 @@
// Copyright (c) 2023 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_KERNEL_NOTIFICATIONS_INTERFACE_H
#define BITCOIN_KERNEL_NOTIFICATIONS_INTERFACE_H
class CBlockIndex;
enum class SynchronizationState;
namespace kernel {
/**
* A base class defining functions for notifying about certain kernel
* events.
*/
class Notifications
{
public:
virtual ~Notifications(){};
virtual void blockTip(SynchronizationState state, CBlockIndex& index) {}
};
} // namespace kernel
#endif // BITCOIN_KERNEL_NOTIFICATIONS_INTERFACE_H

View File

@ -11,6 +11,7 @@
#include <net.h>
#include <net_processing.h>
#include <netgroup.h>
#include <node/kernel_notifications.h>
#include <policy/fees.h>
#include <scheduler.h>
#include <txmempool.h>

View File

@ -30,6 +30,8 @@ class WalletLoader;
} // namespace interfaces
namespace node {
class KernelNotifications;
//! NodeContext struct containing references to chain state and connection
//! state.
//!
@ -62,6 +64,7 @@ struct NodeContext {
interfaces::WalletLoader* wallet_loader{nullptr};
std::unique_ptr<CScheduler> scheduler;
std::function<void()> rpc_interruption_point = [] {};
std::unique_ptr<KernelNotifications> notifications;
//! Declare default constructor and destructor that are not inline, so code
//! instantiating the NodeContext struct doesn't need to #include class

View File

@ -0,0 +1,16 @@
// Copyright (c) 2023 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <node/kernel_notifications.h>
#include <node/interface_ui.h>
namespace node {
void KernelNotifications::blockTip(SynchronizationState state, CBlockIndex& index)
{
uiInterface.NotifyBlockTip(state, &index);
}
} // namespace node

View File

@ -0,0 +1,21 @@
// Copyright (c) 2023 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_NODE_KERNEL_NOTIFICATIONS_H
#define BITCOIN_NODE_KERNEL_NOTIFICATIONS_H
#include <kernel/notifications_interface.h>
class CBlockIndex;
enum class SynchronizationState;
namespace node {
class KernelNotifications : public kernel::Notifications
{
public:
void blockTip(SynchronizationState state, CBlockIndex& index) override;
};
} // namespace node
#endif // BITCOIN_NODE_KERNEL_NOTIFICATIONS_H

View File

@ -23,6 +23,7 @@
#include <node/blockstorage.h>
#include <node/chainstate.h>
#include <node/context.h>
#include <node/kernel_notifications.h>
#include <node/mempool_args.h>
#include <node/miner.h>
#include <node/validation_cache_args.h>
@ -64,6 +65,7 @@ using node::ApplyArgsManOptions;
using node::BlockAssembler;
using node::BlockManager;
using node::CalculateCacheSizes;
using node::KernelNotifications;
using node::LoadChainstate;
using node::RegenerateCommitments;
using node::VerifyLoadedChainstate;
@ -182,11 +184,14 @@ ChainTestingSetup::ChainTestingSetup(const ChainType chainType, const std::vecto
m_cache_sizes = CalculateCacheSizes(m_args);
m_node.notifications = std::make_unique<KernelNotifications>();
const ChainstateManager::Options chainman_opts{
.chainparams = chainparams,
.datadir = m_args.GetDataDirNet(),
.adjusted_time_callback = GetAdjustedTime,
.check_block_index = true,
.notifications = *m_node.notifications,
};
const BlockManager::Options blockman_opts{
.chainparams = chainman_opts.chainparams,

View File

@ -4,6 +4,7 @@
//
#include <chainparams.h>
#include <consensus/validation.h>
#include <node/kernel_notifications.h>
#include <node/utxo_snapshot.h>
#include <random.h>
#include <rpc/blockchain.h>
@ -23,6 +24,7 @@
#include <boost/test/unit_test.hpp>
using node::BlockManager;
using node::KernelNotifications;
using node::SnapshotMetadata;
BOOST_FIXTURE_TEST_SUITE(validation_chainstatemanager_tests, ChainTestingSetup)
@ -377,10 +379,12 @@ struct SnapshotTestSetup : TestChain100Setup {
LOCK(::cs_main);
chainman.ResetChainstates();
BOOST_CHECK_EQUAL(chainman.GetAll().size(), 0);
m_node.notifications = std::make_unique<KernelNotifications>();
const ChainstateManager::Options chainman_opts{
.chainparams = ::Params(),
.datadir = m_args.GetDataDirNet(),
.adjusted_time_callback = GetAdjustedTime,
.notifications = *m_node.notifications,
};
const BlockManager::Options blockman_opts{
.chainparams = chainman_opts.chainparams,

View File

@ -3206,7 +3206,7 @@ bool Chainstate::ActivateBestChain(BlockValidationState& state, std::shared_ptr<
GetMainSignals().UpdatedBlockTip(pindexNewTip, pindexFork, fInitialDownload);
// Always notify the UI if a new block tip was connected
uiInterface.NotifyBlockTip(GetSynchronizationState(fInitialDownload), pindexNewTip);
m_chainman.GetNotifications().blockTip(GetSynchronizationState(fInitialDownload), *pindexNewTip);
}
}
// When we reach this point, we switched to a new tip (stored in pindexNewTip).
@ -3403,7 +3403,7 @@ bool Chainstate::InvalidateBlock(BlockValidationState& state, CBlockIndex* pinde
// Only notify about a new block tip if the active chain was modified.
if (pindex_was_in_chain) {
uiInterface.NotifyBlockTip(GetSynchronizationState(IsInitialBlockDownload()), to_mark_failed->pprev);
m_chainman.GetNotifications().blockTip(GetSynchronizationState(IsInitialBlockDownload()), *to_mark_failed->pprev);
}
return true;
}

View File

@ -955,6 +955,7 @@ public:
bool ShouldCheckBlockIndex() const { return *Assert(m_options.check_block_index); }
const arith_uint256& MinimumChainWork() const { return *Assert(m_options.minimum_chain_work); }
const uint256& AssumedValidBlock() const { return *Assert(m_options.assumed_valid_block); }
kernel::Notifications& GetNotifications() const { return m_options.notifications; };
/**
* Alias for ::cs_main.