mirror of https://github.com/bitcoin/bitcoin.git
Merge 4fce466d1a
into b510893d00
This commit is contained in:
commit
139299de0f
|
@ -42,6 +42,8 @@ def main():
|
||||||
"-DBUILD_BENCH=ON",
|
"-DBUILD_BENCH=ON",
|
||||||
"-DBUILD_FUZZ_BINARY=ON",
|
"-DBUILD_FUZZ_BINARY=ON",
|
||||||
"-DWITH_USDT=ON",
|
"-DWITH_USDT=ON",
|
||||||
|
"-DBUILD_KERNEL_LIB=ON",
|
||||||
|
"-DBUILD_KERNEL_TEST=ON",
|
||||||
"-DCMAKE_CXX_FLAGS=-Wno-error=unused-member-function",
|
"-DCMAKE_CXX_FLAGS=-Wno-error=unused-member-function",
|
||||||
])
|
])
|
||||||
run(["cmake", "--build", "build", "-j", str(num_procs)])
|
run(["cmake", "--build", "build", "-j", str(num_procs)])
|
||||||
|
|
|
@ -202,7 +202,7 @@ jobs:
|
||||||
job-type: [standard, fuzz]
|
job-type: [standard, fuzz]
|
||||||
include:
|
include:
|
||||||
- job-type: standard
|
- job-type: standard
|
||||||
generate-options: '-DBUILD_GUI=ON -DWITH_ZMQ=ON -DBUILD_BENCH=ON -DWERROR=ON'
|
generate-options: '-DBUILD_GUI=ON -DWITH_ZMQ=ON -DBUILD_BENCH=ON -DBUILD_KERNEL_LIB=ON -DBUILD_UTIL_CHAINSTATE=ON -DBUILD_KERNEL_TEST=OFF -DWERROR=ON'
|
||||||
job-name: 'Windows native, VS 2022'
|
job-name: 'Windows native, VS 2022'
|
||||||
- job-type: fuzz
|
- job-type: fuzz
|
||||||
generate-options: '-DVCPKG_MANIFEST_NO_DEFAULT_FEATURES=ON -DVCPKG_MANIFEST_FEATURES="wallet" -DBUILD_GUI=OFF -DBUILD_FOR_FUZZING=ON -DWERROR=ON'
|
generate-options: '-DVCPKG_MANIFEST_NO_DEFAULT_FEATURES=ON -DVCPKG_MANIFEST_FEATURES="wallet" -DBUILD_GUI=OFF -DBUILD_FOR_FUZZING=ON -DWERROR=ON'
|
||||||
|
@ -307,6 +307,7 @@ jobs:
|
||||||
BITCOINTX: '${{ github.workspace }}\build\bin\Release\bitcoin-tx.exe'
|
BITCOINTX: '${{ github.workspace }}\build\bin\Release\bitcoin-tx.exe'
|
||||||
BITCOINUTIL: '${{ github.workspace }}\build\bin\Release\bitcoin-util.exe'
|
BITCOINUTIL: '${{ github.workspace }}\build\bin\Release\bitcoin-util.exe'
|
||||||
BITCOINWALLET: '${{ github.workspace }}\build\bin\Release\bitcoin-wallet.exe'
|
BITCOINWALLET: '${{ github.workspace }}\build\bin\Release\bitcoin-wallet.exe'
|
||||||
|
BITCOINCHAINSTATE: '${{ github.workspace }}\build\bin\Release\bitcoin-chainstate.exe'
|
||||||
TEST_RUNNER_EXTRA: ${{ github.event_name != 'pull_request' && '--extended' || '' }}
|
TEST_RUNNER_EXTRA: ${{ github.event_name != 'pull_request' && '--extended' || '' }}
|
||||||
run: py -3 test/functional/test_runner.py --jobs $NUMBER_OF_PROCESSORS --ci --quiet --tmpdirprefix="${RUNNER_TEMP}" --combinedlogslen=99999999 --timeout-factor=${TEST_RUNNER_TIMEOUT_FACTOR} ${TEST_RUNNER_EXTRA}
|
run: py -3 test/functional/test_runner.py --jobs $NUMBER_OF_PROCESSORS --ci --quiet --tmpdirprefix="${RUNNER_TEMP}" --combinedlogslen=99999999 --timeout-factor=${TEST_RUNNER_TIMEOUT_FACTOR} ${TEST_RUNNER_EXTRA}
|
||||||
|
|
||||||
|
|
|
@ -105,6 +105,7 @@ option(BUILD_UTIL "Build bitcoin-util executable." ${BUILD_TESTS})
|
||||||
|
|
||||||
option(BUILD_UTIL_CHAINSTATE "Build experimental bitcoin-chainstate executable." OFF)
|
option(BUILD_UTIL_CHAINSTATE "Build experimental bitcoin-chainstate executable." OFF)
|
||||||
option(BUILD_KERNEL_LIB "Build experimental bitcoinkernel library." ${BUILD_UTIL_CHAINSTATE})
|
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(ENABLE_WALLET "Enable wallet." ON)
|
||||||
if(ENABLE_WALLET)
|
if(ENABLE_WALLET)
|
||||||
|
@ -210,6 +211,7 @@ if(BUILD_FOR_FUZZING)
|
||||||
set(BUILD_UTIL OFF)
|
set(BUILD_UTIL OFF)
|
||||||
set(BUILD_UTIL_CHAINSTATE OFF)
|
set(BUILD_UTIL_CHAINSTATE OFF)
|
||||||
set(BUILD_KERNEL_LIB OFF)
|
set(BUILD_KERNEL_LIB OFF)
|
||||||
|
set(BUILD_KERNEL_TEST OFF)
|
||||||
set(BUILD_WALLET_TOOL OFF)
|
set(BUILD_WALLET_TOOL OFF)
|
||||||
set(BUILD_GUI OFF)
|
set(BUILD_GUI OFF)
|
||||||
set(ENABLE_EXTERNAL_SIGNER OFF)
|
set(ENABLE_EXTERNAL_SIGNER OFF)
|
||||||
|
@ -668,6 +670,7 @@ message(" bitcoin-util ........................ ${BUILD_UTIL}")
|
||||||
message(" bitcoin-wallet ...................... ${BUILD_WALLET_TOOL}")
|
message(" bitcoin-wallet ...................... ${BUILD_WALLET_TOOL}")
|
||||||
message(" bitcoin-chainstate (experimental) ... ${BUILD_UTIL_CHAINSTATE}")
|
message(" bitcoin-chainstate (experimental) ... ${BUILD_UTIL_CHAINSTATE}")
|
||||||
message(" libbitcoinkernel (experimental) ..... ${BUILD_KERNEL_LIB}")
|
message(" libbitcoinkernel (experimental) ..... ${BUILD_KERNEL_LIB}")
|
||||||
|
message(" kernel-test (experimental) .......... ${BUILD_KERNEL_TEST}")
|
||||||
message("Optional features:")
|
message("Optional features:")
|
||||||
message(" wallet support ...................... ${ENABLE_WALLET}")
|
message(" wallet support ...................... ${ENABLE_WALLET}")
|
||||||
message(" external signer ..................... ${ENABLE_EXTERNAL_SIGNER}")
|
message(" external signer ..................... ${ENABLE_EXTERNAL_SIGNER}")
|
||||||
|
|
|
@ -12,7 +12,7 @@ export CONTAINER_NAME="ci_mac_native" # macos does not use a container, but the
|
||||||
export PIP_PACKAGES="--break-system-packages zmq"
|
export PIP_PACKAGES="--break-system-packages zmq"
|
||||||
export GOAL="install deploy"
|
export GOAL="install deploy"
|
||||||
export CMAKE_GENERATOR="Ninja"
|
export CMAKE_GENERATOR="Ninja"
|
||||||
export BITCOIN_CONFIG="-DBUILD_GUI=ON -DWITH_ZMQ=ON -DREDUCE_EXPORTS=ON -DCMAKE_EXE_LINKER_FLAGS='-Wl,-stack_size -Wl,0x80000'"
|
export BITCOIN_CONFIG="-DBUILD_GUI=ON -DWITH_ZMQ=ON -DBUILD_KERNEL_LIB=ON -DBUILD_KERNEL_TEST=ON -DREDUCE_EXPORTS=ON -DCMAKE_EXE_LINKER_FLAGS='-Wl,-stack_size -Wl,0x80000'"
|
||||||
export CI_OS_NAME="macos"
|
export CI_OS_NAME="macos"
|
||||||
export NO_DEPENDS=1
|
export NO_DEPENDS=1
|
||||||
export OSX_SDK=""
|
export OSX_SDK=""
|
||||||
|
|
|
@ -13,4 +13,4 @@ export PACKAGES="python3-zmq python3-pip clang-16 llvm-16 libc++abi-16-dev libc+
|
||||||
export PIP_PACKAGES="--break-system-packages pycapnp"
|
export PIP_PACKAGES="--break-system-packages pycapnp"
|
||||||
export DEP_OPTS="NO_WALLET=1 CC=clang-16 CXX='clang++-16 -stdlib=libc++'"
|
export DEP_OPTS="NO_WALLET=1 CC=clang-16 CXX='clang++-16 -stdlib=libc++'"
|
||||||
export GOAL="install"
|
export GOAL="install"
|
||||||
export BITCOIN_CONFIG="-DREDUCE_EXPORTS=ON -DBUILD_UTIL_CHAINSTATE=ON -DBUILD_KERNEL_LIB=ON -DBUILD_SHARED_LIBS=ON"
|
export BITCOIN_CONFIG="-DREDUCE_EXPORTS=ON -DBUILD_UTIL_CHAINSTATE=ON -DBUILD_KERNEL_LIB=ON -DBUILD_KERNEL_TEST=ON -DBUILD_SHARED_LIBS=ON"
|
||||||
|
|
|
@ -14,5 +14,5 @@ export PACKAGES="g++-mingw-w64-x86-64-posix nsis"
|
||||||
export RUN_UNIT_TESTS=false
|
export RUN_UNIT_TESTS=false
|
||||||
export RUN_FUNCTIONAL_TESTS=false
|
export RUN_FUNCTIONAL_TESTS=false
|
||||||
export GOAL="deploy"
|
export GOAL="deploy"
|
||||||
export BITCOIN_CONFIG="-DREDUCE_EXPORTS=ON -DBUILD_GUI_TESTS=OFF \
|
export BITCOIN_CONFIG="-DREDUCE_EXPORTS=ON -DBUILD_GUI_TESTS=OFF -DBUILD_KERNEL_LIB=ON -DBUILD_KERNEL_TEST=ON \
|
||||||
-DCMAKE_CXX_FLAGS='-Wno-error=maybe-uninitialized'"
|
-DCMAKE_CXX_FLAGS='-Wno-error=maybe-uninitialized'"
|
||||||
|
|
|
@ -404,6 +404,9 @@ endif()
|
||||||
|
|
||||||
if(BUILD_KERNEL_LIB)
|
if(BUILD_KERNEL_LIB)
|
||||||
add_subdirectory(kernel)
|
add_subdirectory(kernel)
|
||||||
|
if (BUILD_KERNEL_TEST)
|
||||||
|
add_subdirectory(test/kernel)
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(BUILD_UTIL_CHAINSTATE)
|
if(BUILD_UTIL_CHAINSTATE)
|
||||||
|
|
|
@ -1,53 +1,144 @@
|
||||||
// Copyright (c) 2022 The Bitcoin Core developers
|
#include <kernel/bitcoinkernel_wrapper.h>
|
||||||
// Distributed under the MIT software license, see the accompanying
|
|
||||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
||||||
//
|
|
||||||
// The bitcoin-chainstate executable serves to surface the dependencies required
|
|
||||||
// by a program wishing to use Bitcoin Core's consensus engine as it is right
|
|
||||||
// now.
|
|
||||||
//
|
|
||||||
// DEVELOPER NOTE: Since this is a "demo-only", experimental, etc. executable,
|
|
||||||
// it may diverge from Bitcoin Core's coding style.
|
|
||||||
//
|
|
||||||
// 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/warning.h>
|
|
||||||
|
|
||||||
#include <consensus/validation.h>
|
|
||||||
#include <core_io.h>
|
|
||||||
#include <kernel/caches.h>
|
|
||||||
#include <logging.h>
|
|
||||||
#include <node/blockstorage.h>
|
|
||||||
#include <node/chainstate.h>
|
|
||||||
#include <random.h>
|
|
||||||
#include <script/sigcache.h>
|
|
||||||
#include <util/chaintype.h>
|
|
||||||
#include <util/fs.h>
|
|
||||||
#include <util/signalinterrupt.h>
|
|
||||||
#include <util/task_runner.h>
|
|
||||||
#include <util/translation.h>
|
|
||||||
#include <validation.h>
|
|
||||||
#include <validationinterface.h>
|
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstdint>
|
#include <charconv>
|
||||||
#include <functional>
|
#include <filesystem>
|
||||||
#include <iosfwd>
|
#include <iostream>
|
||||||
#include <memory>
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
// clang-format off
|
||||||
|
#include <windows.h>
|
||||||
|
// clang-format on
|
||||||
|
#include <codecvt>
|
||||||
|
#include <locale>
|
||||||
|
#include <shellapi.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using namespace btck;
|
||||||
|
|
||||||
|
std::vector<std::byte> hex_string_to_byte_vec(std::string_view hex)
|
||||||
|
{
|
||||||
|
std::vector<std::byte> bytes;
|
||||||
|
bytes.reserve(hex.length() / 2);
|
||||||
|
|
||||||
|
for (size_t i{0}; i < hex.length(); i += 2) {
|
||||||
|
uint8_t byte_value;
|
||||||
|
auto [ptr, ec] = std::from_chars(hex.data() + i, hex.data() + i + 2, byte_value, 16);
|
||||||
|
|
||||||
|
if (ec != std::errc{} || ptr != hex.data() + i + 2) {
|
||||||
|
throw std::invalid_argument("Invalid hex character");
|
||||||
|
}
|
||||||
|
bytes.push_back(static_cast<std::byte>(byte_value));
|
||||||
|
}
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
class KernelLog
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void LogMessage(std::string_view message)
|
||||||
|
{
|
||||||
|
std::cout << "kernel: " << message;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class TestValidationInterface : public ValidationInterface<TestValidationInterface>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TestValidationInterface() = default;
|
||||||
|
|
||||||
|
std::optional<std::string> m_expected_valid_block = std::nullopt;
|
||||||
|
|
||||||
|
void BlockChecked(const Block block, const BlockValidationState state) override
|
||||||
|
{
|
||||||
|
auto mode{state.GetValidationMode()};
|
||||||
|
switch (mode) {
|
||||||
|
case ValidationMode::VALID: {
|
||||||
|
std::cout << "Valid block" << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case ValidationMode::INVALID: {
|
||||||
|
std::cout << "Invalid block: ";
|
||||||
|
auto result{state.GetBlockValidationResult()};
|
||||||
|
switch (result) {
|
||||||
|
case BlockValidationResult::UNSET:
|
||||||
|
std::cout << "initial value. Block has not yet been rejected" << std::endl;
|
||||||
|
break;
|
||||||
|
case BlockValidationResult::HEADER_LOW_WORK:
|
||||||
|
std::cout << "the block header may be on a too-little-work chain" << std::endl;
|
||||||
|
break;
|
||||||
|
case BlockValidationResult::CONSENSUS:
|
||||||
|
std::cout << "invalid by consensus rules (excluding any below reasons)" << std::endl;
|
||||||
|
break;
|
||||||
|
case BlockValidationResult::CACHED_INVALID:
|
||||||
|
std::cout << "this block was cached as being invalid and we didn't store the reason why" << std::endl;
|
||||||
|
break;
|
||||||
|
case BlockValidationResult::INVALID_HEADER:
|
||||||
|
std::cout << "invalid proof of work or time too old" << std::endl;
|
||||||
|
break;
|
||||||
|
case BlockValidationResult::MUTATED:
|
||||||
|
std::cout << "the block's data didn't match the data committed to by the PoW" << std::endl;
|
||||||
|
break;
|
||||||
|
case BlockValidationResult::MISSING_PREV:
|
||||||
|
std::cout << "We don't have the previous block the checked one is built on" << std::endl;
|
||||||
|
break;
|
||||||
|
case BlockValidationResult::INVALID_PREV:
|
||||||
|
std::cout << "A block this one builds on is invalid" << std::endl;
|
||||||
|
break;
|
||||||
|
case BlockValidationResult::TIME_FUTURE:
|
||||||
|
std::cout << "block timestamp was > 2 hours in the future (or our clock is bad)" << std::endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case ValidationMode::INTERNAL_ERROR: {
|
||||||
|
std::cout << "Internal error" << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class TestKernelNotifications : public KernelNotifications<TestKernelNotifications>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void BlockTipHandler(SynchronizationState, const BlockTreeEntry, double) override
|
||||||
|
{
|
||||||
|
std::cout << "Block tip changed" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProgressHandler(std::string_view title, int progress_percent, bool resume_possible) override
|
||||||
|
{
|
||||||
|
std::cout << "Made progress: " << title << " " << progress_percent << "%" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WarningSetHandler(Warning warning, std::string_view message) override
|
||||||
|
{
|
||||||
|
std::cout << message << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WarningUnsetHandler(Warning warning) override
|
||||||
|
{
|
||||||
|
std::cout << "Warning unset: " << static_cast<std::underlying_type_t<Warning>>(warning) << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlushErrorHandler(std::string_view error) override
|
||||||
|
{
|
||||||
|
std::cout << error << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FatalErrorHandler(std::string_view error) override
|
||||||
|
{
|
||||||
|
std::cout << error << std::endl;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
// We do not enable logging for this app, so explicitly disable it.
|
|
||||||
// To enable logging instead, replace with:
|
|
||||||
// LogInstance().m_print_to_console = true;
|
|
||||||
// LogInstance().StartLogging();
|
|
||||||
LogInstance().DisableLogging();
|
|
||||||
|
|
||||||
// SETUP: Argument parsing and handling
|
// SETUP: Argument parsing and handling
|
||||||
if (argc != 2) {
|
if (argc != 2) {
|
||||||
std::cerr
|
std::cerr
|
||||||
|
@ -58,213 +149,81 @@ int main(int argc, char* argv[])
|
||||||
<< " BREAK IN FUTURE VERSIONS. DO NOT USE ON YOUR ACTUAL DATADIR." << std::endl;
|
<< " BREAK IN FUTURE VERSIONS. DO NOT USE ON YOUR ACTUAL DATADIR." << std::endl;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
fs::path abs_datadir{fs::absolute(argv[1])};
|
|
||||||
fs::create_directories(abs_datadir);
|
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
int win_argc;
|
||||||
|
wchar_t** wargv = CommandLineToArgvW(GetCommandLineW(), &win_argc);
|
||||||
|
std::vector<std::string> utf8_args(win_argc);
|
||||||
|
std::vector<char*> win_argv(win_argc);
|
||||||
|
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t> utf8_cvt;
|
||||||
|
for (int i = 0; i < win_argc; i++) {
|
||||||
|
utf8_args[i] = utf8_cvt.to_bytes(wargv[i]);
|
||||||
|
win_argv[i] = &utf8_args[i][0];
|
||||||
|
}
|
||||||
|
LocalFree(wargv);
|
||||||
|
argc = win_argc;
|
||||||
|
argv = win_argv.data();
|
||||||
|
#endif
|
||||||
|
|
||||||
// SETUP: Context
|
std::filesystem::path abs_datadir{std::filesystem::absolute(argv[1])};
|
||||||
kernel::Context kernel_context{};
|
std::filesystem::create_directories(abs_datadir);
|
||||||
// We can't use a goto here, but we can use an assert since none of the
|
|
||||||
// things instantiated so far requires running the epilogue to be torn down
|
|
||||||
// properly
|
|
||||||
assert(kernel::SanityChecks(kernel_context));
|
|
||||||
|
|
||||||
ValidationSignals validation_signals{std::make_unique<util::ImmediateTaskRunner>()};
|
btck_LoggingOptions logging_options = {
|
||||||
|
.log_timestamps = true,
|
||||||
class KernelNotifications : public kernel::Notifications
|
.log_time_micros = false,
|
||||||
{
|
.log_threadnames = false,
|
||||||
public:
|
.log_sourcelocations = false,
|
||||||
kernel::InterruptResult blockTip(SynchronizationState, const CBlockIndex&, double) override
|
.always_print_category_levels = true,
|
||||||
{
|
|
||||||
std::cout << "Block tip changed" << std::endl;
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
void headerTip(SynchronizationState, int64_t height, int64_t timestamp, bool presync) override
|
|
||||||
{
|
|
||||||
std::cout << "Header tip changed: " << height << ", " << timestamp << ", " << presync << std::endl;
|
|
||||||
}
|
|
||||||
void progress(const bilingual_str& title, int progress_percent, bool resume_possible) override
|
|
||||||
{
|
|
||||||
std::cout << "Progress: " << title.original << ", " << progress_percent << ", " << resume_possible << std::endl;
|
|
||||||
}
|
|
||||||
void warningSet(kernel::Warning id, const bilingual_str& message) override
|
|
||||||
{
|
|
||||||
std::cout << "Warning " << static_cast<int>(id) << " set: " << message.original << std::endl;
|
|
||||||
}
|
|
||||||
void warningUnset(kernel::Warning id) override
|
|
||||||
{
|
|
||||||
std::cout << "Warning " << static_cast<int>(id) << " unset" << std::endl;
|
|
||||||
}
|
|
||||||
void flushError(const bilingual_str& message) override
|
|
||||||
{
|
|
||||||
std::cerr << "Error flushing block data to disk: " << message.original << std::endl;
|
|
||||||
}
|
|
||||||
void fatalError(const bilingual_str& message) override
|
|
||||||
{
|
|
||||||
std::cerr << "Error: " << message.original << std::endl;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
auto notifications = std::make_unique<KernelNotifications>();
|
|
||||||
|
|
||||||
kernel::CacheSizes cache_sizes{DEFAULT_KERNEL_CACHE};
|
Logger logger{std::make_unique<KernelLog>(KernelLog{}), logging_options};
|
||||||
|
|
||||||
// SETUP: Chainstate
|
ContextOptions options{};
|
||||||
auto chainparams = CChainParams::Main();
|
ChainParams params{ChainType::MAINNET};
|
||||||
const ChainstateManager::Options chainman_opts{
|
options.SetChainParams(params);
|
||||||
.chainparams = *chainparams,
|
|
||||||
.datadir = abs_datadir,
|
|
||||||
.notifications = *notifications,
|
|
||||||
.signals = &validation_signals,
|
|
||||||
};
|
|
||||||
const node::BlockManager::Options blockman_opts{
|
|
||||||
.chainparams = chainman_opts.chainparams,
|
|
||||||
.blocks_dir = abs_datadir / "blocks",
|
|
||||||
.notifications = chainman_opts.notifications,
|
|
||||||
.block_tree_db_params = DBParams{
|
|
||||||
.path = abs_datadir / "blocks" / "index",
|
|
||||||
.cache_bytes = cache_sizes.block_tree_db,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
util::SignalInterrupt interrupt;
|
|
||||||
ChainstateManager chainman{interrupt, chainman_opts, blockman_opts};
|
|
||||||
|
|
||||||
node::ChainstateLoadOptions options;
|
options.SetNotifications(std::make_shared<TestKernelNotifications>());
|
||||||
auto [status, error] = node::LoadChainstate(chainman, cache_sizes, options);
|
options.SetValidationInterface(std::make_shared<TestValidationInterface>());
|
||||||
if (status != node::ChainstateLoadStatus::SUCCESS) {
|
|
||||||
std::cerr << "Failed to load Chain state from your datadir." << std::endl;
|
Context context{options};
|
||||||
goto epilogue;
|
|
||||||
} else {
|
ChainstateManagerOptions chainman_opts{context, abs_datadir.string(), (abs_datadir / "blocks").string()};
|
||||||
std::tie(status, error) = node::VerifyLoadedChainstate(chainman, options);
|
chainman_opts.SetWorkerThreads(4);
|
||||||
if (status != node::ChainstateLoadStatus::SUCCESS) {
|
|
||||||
std::cerr << "Failed to verify loaded Chain state from your datadir." << std::endl;
|
std::unique_ptr<ChainMan> chainman;
|
||||||
goto epilogue;
|
try {
|
||||||
}
|
chainman = std::make_unique<ChainMan>(context, chainman_opts);
|
||||||
|
} catch (std::exception&) {
|
||||||
|
std::cerr << "Failed to instantiate ChainMan, exiting" << std::endl;
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Chainstate* chainstate : WITH_LOCK(::cs_main, return chainman.GetAll())) {
|
std::cout << "Enter the block you want to validate on the next line:" << std::endl;
|
||||||
BlockValidationState state;
|
|
||||||
if (!chainstate->ActivateBestChain(state, nullptr)) {
|
|
||||||
std::cerr << "Failed to connect best block (" << state.ToString() << ")" << std::endl;
|
|
||||||
goto epilogue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Main program logic starts here
|
|
||||||
std::cout
|
|
||||||
<< "Hello! I'm going to print out some information about your datadir." << std::endl
|
|
||||||
<< "\t"
|
|
||||||
<< "Path: " << abs_datadir << std::endl;
|
|
||||||
{
|
|
||||||
LOCK(chainman.GetMutex());
|
|
||||||
std::cout
|
|
||||||
<< "\t" << "Blockfiles Indexed: " << std::boolalpha << chainman.m_blockman.m_blockfiles_indexed.load() << std::noboolalpha << std::endl
|
|
||||||
<< "\t" << "Snapshot Active: " << std::boolalpha << chainman.IsSnapshotActive() << std::noboolalpha << std::endl
|
|
||||||
<< "\t" << "Active Height: " << chainman.ActiveHeight() << std::endl
|
|
||||||
<< "\t" << "Active IBD: " << std::boolalpha << chainman.IsInitialBlockDownload() << std::noboolalpha << std::endl;
|
|
||||||
CBlockIndex* tip = chainman.ActiveTip();
|
|
||||||
if (tip) {
|
|
||||||
std::cout << "\t" << tip->ToString() << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (std::string line; std::getline(std::cin, line);) {
|
for (std::string line; std::getline(std::cin, line);) {
|
||||||
if (line.empty()) {
|
if (line.empty()) {
|
||||||
std::cerr << "Empty line found" << std::endl;
|
std::cerr << "Empty line found, try again:" << std::endl;
|
||||||
break;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<CBlock> blockptr = std::make_shared<CBlock>();
|
auto raw_block{hex_string_to_byte_vec(line)};
|
||||||
CBlock& block = *blockptr;
|
std::unique_ptr<Block> block;
|
||||||
|
try {
|
||||||
if (!DecodeHexBlk(block, line)) {
|
block = std::make_unique<Block>(raw_block);
|
||||||
std::cerr << "Block decode failed" << std::endl;
|
} catch (std::exception&) {
|
||||||
break;
|
std::cerr << "Block decode failed, try again:" << std::endl;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
bool new_block = false;
|
||||||
LOCK(cs_main);
|
bool accepted = chainman->ProcessBlock(*block, &new_block);
|
||||||
const CBlockIndex* pindex = chainman.m_blockman.LookupBlockIndex(block.hashPrevBlock);
|
if (accepted) {
|
||||||
if (pindex) {
|
std::cerr << "Block has not yet been rejected" << std::endl;
|
||||||
chainman.UpdateUncommittedBlockStructures(block, pindex);
|
} else {
|
||||||
}
|
std::cerr << "Block was not accepted" << std::endl;
|
||||||
}
|
}
|
||||||
|
if (!new_block) {
|
||||||
// Adapted from rpc/mining.cpp
|
std::cerr << "Block is a duplicate" << std::endl;
|
||||||
class submitblock_StateCatcher final : public CValidationInterface
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
uint256 hash;
|
|
||||||
bool found;
|
|
||||||
BlockValidationState state;
|
|
||||||
|
|
||||||
explicit submitblock_StateCatcher(const uint256& hashIn) : hash(hashIn), found(false), state() {}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void BlockChecked(const std::shared_ptr<const CBlock>& block, const BlockValidationState& stateIn) override
|
|
||||||
{
|
|
||||||
if (block->GetHash() != hash)
|
|
||||||
return;
|
|
||||||
found = true;
|
|
||||||
state = stateIn;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
bool new_block;
|
|
||||||
auto sc = std::make_shared<submitblock_StateCatcher>(block.GetHash());
|
|
||||||
validation_signals.RegisterSharedValidationInterface(sc);
|
|
||||||
bool accepted = chainman.ProcessNewBlock(blockptr, /*force_processing=*/true, /*min_pow_checked=*/true, /*new_block=*/&new_block);
|
|
||||||
validation_signals.UnregisterSharedValidationInterface(sc);
|
|
||||||
if (!new_block && accepted) {
|
|
||||||
std::cerr << "duplicate" << std::endl;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!sc->found) {
|
|
||||||
std::cerr << "inconclusive" << std::endl;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
std::cout << sc->state.ToString() << std::endl;
|
|
||||||
switch (sc->state.GetResult()) {
|
|
||||||
case BlockValidationResult::BLOCK_RESULT_UNSET:
|
|
||||||
std::cerr << "initial value. Block has not yet been rejected" << std::endl;
|
|
||||||
break;
|
|
||||||
case BlockValidationResult::BLOCK_HEADER_LOW_WORK:
|
|
||||||
std::cerr << "the block header may be on a too-little-work chain" << std::endl;
|
|
||||||
break;
|
|
||||||
case BlockValidationResult::BLOCK_CONSENSUS:
|
|
||||||
std::cerr << "invalid by consensus rules (excluding any below reasons)" << std::endl;
|
|
||||||
break;
|
|
||||||
case BlockValidationResult::BLOCK_CACHED_INVALID:
|
|
||||||
std::cerr << "this block was cached as being invalid and we didn't store the reason why" << std::endl;
|
|
||||||
break;
|
|
||||||
case BlockValidationResult::BLOCK_INVALID_HEADER:
|
|
||||||
std::cerr << "invalid proof of work or time too old" << std::endl;
|
|
||||||
break;
|
|
||||||
case BlockValidationResult::BLOCK_MUTATED:
|
|
||||||
std::cerr << "the block's data didn't match the data committed to by the PoW" << std::endl;
|
|
||||||
break;
|
|
||||||
case BlockValidationResult::BLOCK_MISSING_PREV:
|
|
||||||
std::cerr << "We don't have the previous block the checked one is built on" << std::endl;
|
|
||||||
break;
|
|
||||||
case BlockValidationResult::BLOCK_INVALID_PREV:
|
|
||||||
std::cerr << "A block this one builds on is invalid" << std::endl;
|
|
||||||
break;
|
|
||||||
case BlockValidationResult::BLOCK_TIME_FUTURE:
|
|
||||||
std::cerr << "block timestamp was > 2 hours in the future (or our clock is bad)" << std::endl;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
epilogue:
|
|
||||||
// Without this precise shutdown sequence, there will be a lot of nullptr
|
|
||||||
// dereferencing and UB.
|
|
||||||
validation_signals.FlushBackgroundCallbacks();
|
|
||||||
{
|
|
||||||
LOCK(cs_main);
|
|
||||||
for (Chainstate* chainstate : chainman.GetAll()) {
|
|
||||||
if (chainstate->CanFlushToDisk()) {
|
|
||||||
chainstate->ForceFlushStateToDisk();
|
|
||||||
chainstate->ResetCoinsViews();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,20 +96,15 @@ target_link_libraries(bitcoinkernel
|
||||||
|
|
||||||
target_include_directories(bitcoinkernel PRIVATE $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/src/leveldb/include>)
|
target_include_directories(bitcoinkernel PRIVATE $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/src/leveldb/include>)
|
||||||
|
|
||||||
# libbitcoinkernel requires default symbol visibility, explicitly
|
|
||||||
# specify that here so that things still work even when user
|
|
||||||
# configures with -DREDUCE_EXPORTS=ON
|
|
||||||
#
|
|
||||||
# Note this is a quick hack that will be removed as we
|
|
||||||
# incrementally define what to export from the library.
|
|
||||||
set_target_properties(bitcoinkernel PROPERTIES
|
|
||||||
CXX_VISIBILITY_PRESET default
|
|
||||||
)
|
|
||||||
|
|
||||||
# Add a convenience libbitcoinkernel target as a synonym for bitcoinkernel.
|
# Add a convenience libbitcoinkernel target as a synonym for bitcoinkernel.
|
||||||
add_custom_target(libbitcoinkernel)
|
add_custom_target(libbitcoinkernel)
|
||||||
add_dependencies(libbitcoinkernel bitcoinkernel)
|
add_dependencies(libbitcoinkernel bitcoinkernel)
|
||||||
|
|
||||||
|
get_target_property(bitcoinkernel_type bitcoinkernel TYPE)
|
||||||
|
if(bitcoinkernel_type STREQUAL "STATIC_LIBRARY")
|
||||||
|
target_compile_definitions(bitcoinkernel PUBLIC BITCOINKERNEL_STATIC)
|
||||||
|
endif()
|
||||||
|
|
||||||
configure_file(${PROJECT_SOURCE_DIR}/libbitcoinkernel.pc.in ${PROJECT_BINARY_DIR}/libbitcoinkernel.pc @ONLY)
|
configure_file(${PROJECT_SOURCE_DIR}/libbitcoinkernel.pc.in ${PROJECT_BINARY_DIR}/libbitcoinkernel.pc @ONLY)
|
||||||
install(FILES ${PROJECT_BINARY_DIR}/libbitcoinkernel.pc DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig" COMPONENT libbitcoinkernel)
|
install(FILES ${PROJECT_BINARY_DIR}/libbitcoinkernel.pc DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig" COMPONENT libbitcoinkernel)
|
||||||
|
|
||||||
|
@ -124,3 +119,5 @@ install(TARGETS bitcoinkernel
|
||||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||||
COMPONENT libbitcoinkernel
|
COMPONENT libbitcoinkernel
|
||||||
)
|
)
|
||||||
|
|
||||||
|
install(FILES bitcoinkernel.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT libbitcoinkernel)
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -201,6 +201,7 @@ static const std::map<std::string, BCLog::LogFlags, std::less<>> LOG_CATEGORIES_
|
||||||
{"txreconciliation", BCLog::TXRECONCILIATION},
|
{"txreconciliation", BCLog::TXRECONCILIATION},
|
||||||
{"scan", BCLog::SCAN},
|
{"scan", BCLog::SCAN},
|
||||||
{"txpackages", BCLog::TXPACKAGES},
|
{"txpackages", BCLog::TXPACKAGES},
|
||||||
|
{"kernel", BCLog::KERNEL},
|
||||||
};
|
};
|
||||||
|
|
||||||
static const std::unordered_map<BCLog::LogFlags, std::string> LOG_CATEGORIES_BY_FLAG{
|
static const std::unordered_map<BCLog::LogFlags, std::string> LOG_CATEGORIES_BY_FLAG{
|
||||||
|
|
|
@ -94,6 +94,7 @@ namespace BCLog {
|
||||||
TXRECONCILIATION = (CategoryMask{1} << 26),
|
TXRECONCILIATION = (CategoryMask{1} << 26),
|
||||||
SCAN = (CategoryMask{1} << 27),
|
SCAN = (CategoryMask{1} << 27),
|
||||||
TXPACKAGES = (CategoryMask{1} << 28),
|
TXPACKAGES = (CategoryMask{1} << 28),
|
||||||
|
KERNEL = (CategoryMask{1} << 29),
|
||||||
ALL = ~NONE,
|
ALL = ~NONE,
|
||||||
};
|
};
|
||||||
enum class Level {
|
enum class Level {
|
||||||
|
@ -256,6 +257,12 @@ namespace BCLog {
|
||||||
m_print_callbacks.erase(it);
|
m_print_callbacks.erase(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t NumConnections()
|
||||||
|
{
|
||||||
|
StdLockGuard scoped_lock(m_cs);
|
||||||
|
return m_print_callbacks.size();
|
||||||
|
}
|
||||||
|
|
||||||
/** Start logging (and flush all buffered messages) */
|
/** Start logging (and flush all buffered messages) */
|
||||||
bool StartLogging() EXCLUSIVE_LOCKS_REQUIRED(!m_cs);
|
bool StartLogging() EXCLUSIVE_LOCKS_REQUIRED(!m_cs);
|
||||||
/** Only for testing */
|
/** Only for testing */
|
||||||
|
@ -287,6 +294,11 @@ namespace BCLog {
|
||||||
StdLockGuard scoped_lock(m_cs);
|
StdLockGuard scoped_lock(m_cs);
|
||||||
m_category_log_levels = levels;
|
m_category_log_levels = levels;
|
||||||
}
|
}
|
||||||
|
void AddCategoryLogLevel(LogFlags category, Level level)
|
||||||
|
{
|
||||||
|
StdLockGuard scoped_lock(m_cs);
|
||||||
|
m_category_log_levels[category] = level;
|
||||||
|
}
|
||||||
bool SetCategoryLogLevel(std::string_view category_str, std::string_view level_str) EXCLUSIVE_LOCKS_REQUIRED(!m_cs);
|
bool SetCategoryLogLevel(std::string_view category_str, std::string_view level_str) EXCLUSIVE_LOCKS_REQUIRED(!m_cs);
|
||||||
|
|
||||||
Level LogLevel() const { return m_log_level.load(); }
|
Level LogLevel() const { return m_log_level.load(); }
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
add_executable(test_kernel
|
||||||
|
test_kernel.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(test_kernel
|
||||||
|
PRIVATE
|
||||||
|
core_interface
|
||||||
|
bitcoinkernel
|
||||||
|
Boost::headers
|
||||||
|
)
|
||||||
|
|
||||||
|
set_target_properties(test_kernel PROPERTIES
|
||||||
|
SKIP_BUILD_RPATH OFF
|
||||||
|
)
|
||||||
|
|
||||||
|
add_test(NAME test_kernel COMMAND test_kernel)
|
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
|
@ -373,6 +373,8 @@ fn lint_std_filesystem() -> LintResult {
|
||||||
"./src/",
|
"./src/",
|
||||||
":(exclude)src/ipc/libmultiprocess/",
|
":(exclude)src/ipc/libmultiprocess/",
|
||||||
":(exclude)src/util/fs.h",
|
":(exclude)src/util/fs.h",
|
||||||
|
":(exclude)src/test/kernel/test_kernel.cpp",
|
||||||
|
":(exclude)src/bitcoin-chainstate.cpp",
|
||||||
])
|
])
|
||||||
.status()
|
.status()
|
||||||
.expect("command error")
|
.expect("command error")
|
||||||
|
|
Loading…
Reference in New Issue