kernel: Add chainstate manager object to C header

This is the main driver class for anything validation related, so expose
it here.

Creating the chainstate manager options will currently also trigger the
creation of their respectively configured directories.

The chainstate manager and block manager options are consolidated into a
single object. The kernel might eventually introduce a separate block
manager object for the purposes of being a light-weight block store
reader.

The chainstate manager will associate with the context with which it was
created for the duration of its lifetime and it keeps it in memory with
a shared pointer.

The tests now also create dedicated temporary directories. This is
similar to the behaviour in the existing unit test framework.

Co-authored-by: stickies-v <stickies-v@protonmail.com>
This commit is contained in:
TheCharlatan
2024-05-28 20:58:48 +02:00
parent c62f657ba3
commit 65571c36a2
5 changed files with 249 additions and 0 deletions

View File

@@ -7,6 +7,7 @@
#include <kernel/bitcoinkernel.h>
#include <consensus/amount.h>
#include <kernel/caches.h>
#include <kernel/chainparams.h>
#include <kernel/checks.h>
#include <kernel/context.h>
@@ -14,6 +15,7 @@
#include <kernel/notifications_interface.h>
#include <kernel/warning.h>
#include <logging.h>
#include <node/blockstorage.h>
#include <primitives/transaction.h>
#include <script/interpreter.h>
#include <script/script.h>
@@ -21,6 +23,7 @@
#include <streams.h>
#include <sync.h>
#include <tinyformat.h>
#include <util/fs.h>
#include <util/result.h>
#include <util/signalinterrupt.h>
#include <util/translation.h>
@@ -354,6 +357,39 @@ public:
}
};
//! Helper struct to wrap the ChainstateManager-related Options
struct ChainstateManagerOptions {
mutable Mutex m_mutex;
ChainstateManager::Options m_chainman_options GUARDED_BY(m_mutex);
node::BlockManager::Options m_blockman_options GUARDED_BY(m_mutex);
std::shared_ptr<const Context> m_context;
ChainstateManagerOptions(const std::shared_ptr<const Context>& context, const fs::path& data_dir, const fs::path& blocks_dir)
: m_chainman_options{ChainstateManager::Options{
.chainparams = *context->m_chainparams,
.datadir = data_dir,
.notifications = *context->m_notifications}},
m_blockman_options{node::BlockManager::Options{
.chainparams = *context->m_chainparams,
.blocks_dir = blocks_dir,
.notifications = *context->m_notifications,
.block_tree_db_params = DBParams{
.path = data_dir / "blocks" / "index",
.cache_bytes = kernel::CacheSizes{DEFAULT_KERNEL_CACHE}.block_tree_db,
}}},
m_context{context}
{
}
};
struct ChainMan {
std::unique_ptr<ChainstateManager> m_chainman;
std::shared_ptr<const Context> m_context;
ChainMan(std::unique_ptr<ChainstateManager> chainman, std::shared_ptr<const Context> context)
: m_chainman(std::move(chainman)), m_context(std::move(context)) {}
};
} // namespace
struct btck_Transaction : Handle<btck_Transaction, std::shared_ptr<const CTransaction>> {};
@@ -363,6 +399,8 @@ struct btck_LoggingConnection : Handle<btck_LoggingConnection, LoggingConnection
struct btck_ContextOptions : Handle<btck_ContextOptions, ContextOptions> {};
struct btck_Context : Handle<btck_Context, std::shared_ptr<const Context>> {};
struct btck_ChainParameters : Handle<btck_ChainParameters, CChainParams> {};
struct btck_ChainstateManagerOptions : Handle<btck_ChainstateManagerOptions, ChainstateManagerOptions> {};
struct btck_ChainstateManager : Handle<btck_ChainstateManager, ChainMan> {};
btck_Transaction* btck_transaction_create(const void* raw_transaction, size_t raw_transaction_len)
{
@@ -636,3 +674,52 @@ void btck_context_destroy(btck_Context* context)
{
delete context;
}
btck_ChainstateManagerOptions* btck_chainstate_manager_options_create(const btck_Context* context, const char* data_dir, size_t data_dir_len, const char* blocks_dir, size_t blocks_dir_len)
{
try {
fs::path abs_data_dir{fs::absolute(fs::PathFromString({data_dir, data_dir_len}))};
fs::create_directories(abs_data_dir);
fs::path abs_blocks_dir{fs::absolute(fs::PathFromString({blocks_dir, blocks_dir_len}))};
fs::create_directories(abs_blocks_dir);
return btck_ChainstateManagerOptions::create(btck_Context::get(context), abs_data_dir, abs_blocks_dir);
} catch (const std::exception& e) {
LogError("Failed to create chainstate manager options: %s", e.what());
return nullptr;
}
}
void btck_chainstate_manager_options_destroy(btck_ChainstateManagerOptions* options)
{
delete options;
}
btck_ChainstateManager* btck_chainstate_manager_create(
const btck_ChainstateManagerOptions* chainman_opts)
{
try {
auto& opts{btck_ChainstateManagerOptions::get(chainman_opts)};
LOCK(opts.m_mutex);
auto& context{opts.m_context};
auto chainman{std::make_unique<ChainstateManager>(*context->m_interrupt, opts.m_chainman_options, opts.m_blockman_options)};
return btck_ChainstateManager::create(std::move(chainman), context);
} catch (const std::exception& e) {
LogError("Failed to create chainstate manager: %s", e.what());
return nullptr;
}
}
void btck_chainstate_manager_destroy(btck_ChainstateManager* chainman)
{
{
LOCK(btck_ChainstateManager::get(chainman).m_chainman->GetMutex());
for (Chainstate* chainstate : btck_ChainstateManager::get(chainman).m_chainman->GetAll()) {
if (chainstate->CanFlushToDisk()) {
chainstate->ForceFlushStateToDisk();
chainstate->ResetCoinsViews();
}
}
}
delete chainman;
}