Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
44c65c4
kernel: Introduce initial kernel C header API
sedited May 28, 2024
d114ccf
kernel: Add logging to kernel library C header
sedited May 29, 2024
bb482dc
kernel: Add kernel library context object
sedited Jun 3, 2024
62a8968
kerenl: Add chain params context option to C header
sedited Jun 3, 2024
ec137a0
kernel: Add notifications context option to C header
sedited Jun 3, 2024
583820c
kernel: Add chainstate manager object to C header
sedited May 28, 2024
ad7b880
Kernel: Add chainstate loading to kernel C header
sedited May 29, 2024
8254f20
kernel: Add block validation to C header
sedited Jun 17, 2024
ea92eb1
kernel: Add options for reindexing in C header
sedited Jun 17, 2024
2b803d5
kernel: Add chainstate load options for in-memory dbs in C header
sedited Jun 22, 2024
7e47ec7
kernel: Add import blocks function to C header
sedited May 30, 2024
cdce448
kernel: Add interrupt function to C header
sedited Jun 5, 2024
eb6e25a
kernel: Add validation interface to C header
sedited May 30, 2024
368fc93
kernel: Add functions for the block validation state to C header
sedited May 31, 2024
9324c8c
kernel: Add function for copying block data to C header
sedited Jun 1, 2024
845b824
kernel: Add functions to read block from disk to C header
sedited Jun 1, 2024
a6ab534
kernel: Add function to read block undo data from disk to C header
sedited Jun 1, 2024
bf80d2f
kernel: Add block index utility functions to C header
sedited Jun 5, 2024
bdc4e56
kernel: Add functions to get the block hash from a block
sedited Nov 17, 2024
26042c7
kernel: Add pure kernel bitcoin-chainstate
sedited Jun 14, 2024
d56eabe
kernel: Add utxo set iteration and value retrieval
sedited Aug 14, 2024
8e1f1d9
kernel: Add support for handling block headers
sedited Aug 28, 2024
e72cf71
kernel: Add check for when a block has been mutated.
sedited Aug 29, 2024
ba63fab
kernel: Add support for handling transactions
sedited Aug 29, 2024
c4bc927
kernel: Add optional mempool
sedited Aug 29, 2024
be9f140
kernel: Process transactions
sedited Aug 29, 2024
527e82d
kernel: Add check if the chainstate maanger is busy loading blocks
sedited Aug 30, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ option(BUILD_UTIL "Build bitcoin-util executable." ${BUILD_TESTS})

option(BUILD_UTIL_CHAINSTATE "Build experimental bitcoin-chainstate executable." OFF)
option(BUILD_KERNEL_LIB "Build experimental bitcoinkernel library." ${BUILD_UTIL_CHAINSTATE})
option(BUILD_KERNEL_TEST "Build tests for the experimental bitcoinkernel library." ${BUILD_KERNEL_LIB})

option(ENABLE_WALLET "Enable wallet." ON)
option(WITH_SQLITE "Enable SQLite wallet support." ${ENABLE_WALLET})
Expand Down Expand Up @@ -216,6 +217,7 @@ if(BUILD_FOR_FUZZING)
set(BUILD_UTIL OFF)
set(BUILD_UTIL_CHAINSTATE OFF)
set(BUILD_KERNEL_LIB OFF)
set(BUILD_KERNEL_TEST OFF)
set(BUILD_WALLET_TOOL OFF)
set(BUILD_GUI OFF)
set(ENABLE_EXTERNAL_SIGNER OFF)
Expand Down Expand Up @@ -598,6 +600,7 @@ message(" bitcoin-util ........................ ${BUILD_UTIL}")
message(" bitcoin-wallet ...................... ${BUILD_WALLET_TOOL}")
message(" bitcoin-chainstate (experimental) ... ${BUILD_UTIL_CHAINSTATE}")
message(" libbitcoinkernel (experimental) ..... ${BUILD_KERNEL_LIB}")
message(" kernel-test (experimental) .......... ${BUILD_KERNEL_TEST}")
message("Optional features:")
message(" wallet support ...................... ${ENABLE_WALLET}")
if(ENABLE_WALLET)
Expand Down
3 changes: 3 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,9 @@ if(BUILD_FUZZ_BINARY)
add_subdirectory(test/fuzz)
endif()

if (BUILD_KERNEL_TEST)
add_subdirectory(test/kernel)
endif()

install(TARGETS ${installable_targets}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
Expand Down
16 changes: 16 additions & 0 deletions src/kernel/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -142,3 +142,19 @@ install(TARGETS bitcoinkernel
DESTINATION ${CMAKE_INSTALL_LIBDIR}
COMPONENT Kernel
)

install(FILES bitcoinkernel.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT Kernel)

add_executable(kernel-bitcoin-chainstate
bitcoin-chainstate.cpp
)

target_link_libraries(kernel-bitcoin-chainstate
PRIVATE
core_interface
bitcoinkernel
)

set_target_properties(kernel-bitcoin-chainstate PROPERTIES
SKIP_BUILD_RPATH OFF
)
197 changes: 197 additions & 0 deletions src/kernel/bitcoin-chainstate.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
#include <kernel/bitcoinkernel_wrapper.h>

#include <cassert>
#include <filesystem>
#include <iostream>
#include <optional>
#include <sstream>

std::vector<unsigned char> hex_string_to_char_vec(const std::string& hex)
{
std::vector<unsigned char> bytes;

for (size_t i{0}; i < hex.length(); i += 2) {
std::string byteString{hex.substr(i, 2)};
unsigned char byte = (char)std::strtol(byteString.c_str(), nullptr, 16);
bytes.push_back(byte);
}

return bytes;
}

class KernelLog
{
public:
void LogMessage(const char* message)
{
std::cout << "kernel: " << message;
}
};

class TestValidationInterface : public ValidationInterface<TestValidationInterface>
{
public:
TestValidationInterface() : ValidationInterface() {}

std::optional<std::string> m_expected_valid_block = std::nullopt;

void BlockChecked(const UnownedBlock block, const BlockValidationState state) override
{
auto mode{state.ValidationMode()};
switch (mode) {
case kernel_ValidationMode::kernel_VALIDATION_STATE_VALID: {
std::cout << "Valid block" << std::endl;
return;
}
case kernel_ValidationMode::kernel_VALIDATION_STATE_INVALID: {
std::cout << "Invalid block: ";
auto result{state.BlockValidationResult()};
switch (result) {
case kernel_BlockValidationResult::kernel_BLOCK_RESULT_UNSET:
std::cout << "initial value. Block has not yet been rejected" << std::endl;
break;
case kernel_BlockValidationResult::kernel_BLOCK_HEADER_LOW_WORK:
std::cout << "the block header may be on a too-little-work chain" << std::endl;
break;
case kernel_BlockValidationResult::kernel_BLOCK_CONSENSUS:
std::cout << "invalid by consensus rules (excluding any below reasons)" << std::endl;
break;
case kernel_BlockValidationResult::kernel_BLOCK_CACHED_INVALID:
std::cout << "this block was cached as being invalid and we didn't store the reason why" << std::endl;
break;
case kernel_BlockValidationResult::kernel_BLOCK_INVALID_HEADER:
std::cout << "invalid proof of work or time too old" << std::endl;
break;
case kernel_BlockValidationResult::kernel_BLOCK_MUTATED:
std::cout << "the block's data didn't match the data committed to by the PoW" << std::endl;
break;
case kernel_BlockValidationResult::kernel_BLOCK_MISSING_PREV:
std::cout << "We don't have the previous block the checked one is built on" << std::endl;
break;
case kernel_BlockValidationResult::kernel_BLOCK_INVALID_PREV:
std::cout << "A block this one builds on is invalid" << std::endl;
break;
case kernel_BlockValidationResult::kernel_BLOCK_TIME_FUTURE:
std::cout << "block timestamp was > 2 hours in the future (or our clock is bad)" << std::endl;
break;
case kernel_BlockValidationResult::kernel_BLOCK_CHECKPOINT:
std::cout << "the block failed to meet one of our checkpoints" << std::endl;
break;
}
return;
}
case kernel_ValidationMode::kernel_VALIDATION_STATE_ERROR: {
std::cout << "Internal error" << std::endl;
return;
}
}
}
};

class TestKernelNotifications : public KernelNotifications<TestKernelNotifications>
{
public:
void BlockTipHandler(kernel_SynchronizationState state, kernel_BlockIndex* index) override
{
std::cout << "Block tip changed" << std::endl;
}

void ProgressHandler(const char* title, int progress_percent, bool resume_possible) override
{
std::cout << "Made progress: " << title << " " << progress_percent << "%" << std::endl;
}

void WarningSetHandler(kernel_Warning warning, const char* message) override
{
std::cout << message << std::endl;
}

void WarningUnsetHandler(kernel_Warning warning) override
{
std::cout << "Warning unset: " << warning << std::endl;
}

void FlushErrorHandler(const char* error) override
{
std::cout << error << std::endl;
}

void FatalErrorHandler(const char* error) override
{
std::cout << error << std::endl;
}
};

int main(int argc, char* argv[])
{
// SETUP: Argument parsing and handling
if (argc != 2) {
std::cerr
<< "Usage: " << argv[0] << " DATADIR" << std::endl
<< "Display DATADIR information, and process hex-encoded blocks on standard input." << std::endl
<< std::endl
<< "IMPORTANT: THIS EXECUTABLE IS EXPERIMENTAL, FOR TESTING ONLY, AND EXPECTED TO" << std::endl
<< " BREAK IN FUTURE VERSIONS. DO NOT USE ON YOUR ACTUAL DATADIR." << std::endl;
return 1;
}
std::filesystem::path abs_datadir{std::filesystem::absolute(argv[1])};
std::filesystem::create_directories(abs_datadir);

kernel_LoggingOptions logging_options = {
.log_timestamps = true,
.log_time_micros = false,
.log_threadnames = false,
.log_sourcelocations = false,
.always_print_category_levels = true,
};

Logger logger{std::make_unique<KernelLog>(KernelLog{}), logging_options};

ContextOptions options{};
ChainParams params{kernel_ChainType::kernel_CHAIN_TYPE_REGTEST};
options.SetChainParams(params);

TestKernelNotifications notifications{};
options.SetNotifications(notifications);

Context context{options};
assert(context);

ChainstateManagerOptions chainman_opts{context, abs_datadir};
assert(chainman_opts);
BlockManagerOptions blockman_opts{context, abs_datadir / "blocks"};
assert(blockman_opts);

auto chainman{std::make_unique<ChainMan>(context, chainman_opts, blockman_opts)};
assert(chainman);

ChainstateLoadOptions chainstate_load_opts{};
assert(chainman->LoadChainstate(chainstate_load_opts));

std::cout << "Enter the block you want to validate on the next line:" << std::endl;

for (std::string line; std::getline(std::cin, line);) {
if (line.empty()) {
std::cerr << "Empty line found, try again:" << std::endl;
continue;
}

auto raw_block{hex_string_to_char_vec(line)};
auto block = Block{raw_block};
if (!block) {
std::cout << "Failed to parse entered block, try again:" << std::endl;
continue;
}

bool new_block = false;
bool accepted = chainman->ProcessBlock(block, &new_block);
if (accepted) {
std::cout << "Validated block successfully." << std::endl;
} else {
std::cout << "Block was not accepted" << std::endl;
}
if (!new_block) {
std::cout << "Block is a duplicate" << std::endl;
}
}
}
Loading
Loading