Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1// Copyright (c) 2022-present The Bitcoin Core developers2// Distributed under the MIT software license, see the accompanying3// file COPYING or http://www.opensource.org/licenses/mit-license.php.4//5// The bitcoin-chainstate executable serves to surface the dependencies required6// by a program wishing to use Bitcoin Core's consensus engine as it is right7// now.8//9// DEVELOPER NOTE: Since this is a "demo-only", experimental, etc. executable,10// it may diverge from Bitcoin Core's coding style.11//12// It is part of the libbitcoinkernel project.14#include <kernel/bitcoinkernel_wrapper.h>16#include <cassert>17#include <charconv>18#include <filesystem>19#include <iostream>20#include <optional>21#include <string>22#include <string_view>23#include <vector>25using namespace btck;27std::vector<std::byte> hex_string_to_byte_vec(std::string_view hex)28{29std::vector<std::byte> bytes;30bytes.reserve(hex.length() / 2);32for (size_t i{0}; i < hex.length(); i += 2) {33uint8_t byte_value;34auto [ptr, ec] = std::from_chars(hex.data() + i, hex.data() + i + 2, byte_value, 16);36if (ec != std::errc{} || ptr != hex.data() + i + 2) {37throw std::invalid_argument("Invalid hex character");38}39bytes.push_back(static_cast<std::byte>(byte_value));40}41return bytes;42}44class KernelLog45{46public:47void LogMessage(std::string_view message)48{49std::cout << "kernel: " << message;50}51};53class TestValidationInterface : public ValidationInterface54{55public:56TestValidationInterface() = default;58std::optional<std::string> m_expected_valid_block = std::nullopt;60void BlockChecked(Block block, BlockValidationStateView state) override61{62auto mode{state.GetValidationMode()};63switch (mode) {64case ValidationMode::VALID: {65std::cout << "Valid block" << std::endl;66return;67}68case ValidationMode::INVALID: {69std::cout << "Invalid block: ";70auto result{state.GetBlockValidationResult()};71switch (result) {72case BlockValidationResult::UNSET:73std::cout << "initial value. Block has not yet been rejected" << std::endl;74break;75case BlockValidationResult::HEADER_LOW_WORK:76std::cout << "the block header may be on a too-little-work chain" << std::endl;77break;78case BlockValidationResult::CONSENSUS:79std::cout << "invalid by consensus rules" << std::endl;80break;81case BlockValidationResult::CACHED_INVALID:82std::cout << "this block was cached as being invalid and we didn't store the reason why" << std::endl;83break;84case BlockValidationResult::INVALID_HEADER:85std::cout << "invalid proof of work or time too old" << std::endl;86break;87case BlockValidationResult::MUTATED:88std::cout << "the block's data didn't match the data committed to by the PoW" << std::endl;89break;90case BlockValidationResult::MISSING_PREV:91std::cout << "We don't have the previous block the checked one is built on" << std::endl;92break;93case BlockValidationResult::INVALID_PREV:94std::cout << "A block this one builds on is invalid" << std::endl;95break;96case BlockValidationResult::TIME_FUTURE:97std::cout << "block timestamp was > 2 hours in the future (or our clock is bad)" << std::endl;98break;99}100return;101}102case ValidationMode::INTERNAL_ERROR: {103std::cout << "Internal error" << std::endl;104return;105}106}107}108};110class TestKernelNotifications : public KernelNotifications111{112public:113void BlockTipHandler(SynchronizationState, const BlockTreeEntry, double) override114{115std::cout << "Block tip changed" << std::endl;116}118void ProgressHandler(std::string_view title, int progress_percent, bool resume_possible) override119{120std::cout << "Made progress: " << title << " " << progress_percent << "%" << std::endl;121}123void WarningSetHandler(Warning warning, std::string_view message) override124{125std::cout << message << std::endl;126}128void WarningUnsetHandler(Warning warning) override129{130std::cout << "Warning unset: " << static_cast<std::underlying_type_t<Warning>>(warning) << std::endl;131}133void FlushErrorHandler(std::string_view error) override134{135std::cout << error << std::endl;136}138void FatalErrorHandler(std::string_view error) override139{140std::cout << error << std::endl;141}142};144int main(int argc, char* argv[])145{146// SETUP: Argument parsing and handling147const bool has_regtest_flag{argc == 3 && std::string(argv[1]) == "-regtest"};148if (argc < 2 || argc > 3 || (argc == 3 && !has_regtest_flag)) {149std::cerr150<< "Usage: " << argv[0] << " [-regtest] DATADIR" << std::endl151<< "Display DATADIR information, and process hex-encoded blocks on standard input." << std::endl152<< "Uses mainnet parameters by default, regtest with -regtest flag" << std::endl153<< std::endl154<< "IMPORTANT: THIS EXECUTABLE IS EXPERIMENTAL, FOR TESTING ONLY, AND EXPECTED TO" << std::endl155<< " BREAK IN FUTURE VERSIONS. DO NOT USE ON YOUR ACTUAL DATADIR." << std::endl;156return 1;157}158std::filesystem::path abs_datadir{std::filesystem::absolute(argv[argc-1])};159std::filesystem::create_directories(abs_datadir);161btck_LoggingOptions logging_options = {162.log_timestamps = true,163.log_time_micros = false,164.log_threadnames = false,165.log_sourcelocations = false,166.always_print_category_levels = true,167};169logging_set_options(logging_options);171Logger logger{std::make_unique<KernelLog>()};173ContextOptions options{};174ChainParams params{has_regtest_flag ? ChainType::REGTEST : ChainType::MAINNET};175options.SetChainParams(params);177options.SetNotifications(std::make_shared<TestKernelNotifications>());178options.SetValidationInterface(std::make_shared<TestValidationInterface>());180Context context{options};182ChainstateManagerOptions chainman_opts{context, abs_datadir.string(), (abs_datadir / "blocks").string()};183chainman_opts.SetWorkerThreads(4);185std::unique_ptr<ChainMan> chainman;186try {187chainman = std::make_unique<ChainMan>(context, chainman_opts);188} catch (std::exception&) {189std::cerr << "Failed to instantiate ChainMan, exiting" << std::endl;190return 1;191}193std::cout << "Enter the block you want to validate on the next line:" << std::endl;195for (std::string line; std::getline(std::cin, line);) {196if (line.empty()) {197std::cerr << "Empty line found, try again:" << std::endl;198continue;199}201auto raw_block{hex_string_to_byte_vec(line)};202std::unique_ptr<Block> block;203try {204block = std::make_unique<Block>(raw_block);205} catch (std::exception&) {206std::cerr << "Block decode failed, try again:" << std::endl;207continue;208}210bool new_block = false;211bool accepted = chainman->ProcessBlock(*block, &new_block);212if (accepted) {213std::cerr << "Block has not yet been rejected" << std::endl;214} else {215std::cerr << "Block was not accepted" << std::endl;216}217if (!new_block) {218std::cerr << "Block is a duplicate" << std::endl;219}220}221}
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.