Bitcoin Core 30.99.0
P2P Digital Currency
bitcoin-chainstate.cpp
Go to the documentation of this file.
1// Copyright (c) 2022-present The Bitcoin Core developers
2// Distributed under the MIT software license, see the accompanying
3// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4//
5// The bitcoin-chainstate executable serves to surface the dependencies required
6// by a program wishing to use Bitcoin Core's consensus engine as it is right
7// 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.
13
15
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>
24
25using namespace btck;
26
27std::vector<std::byte> hex_string_to_byte_vec(std::string_view hex)
28{
29 std::vector<std::byte> bytes;
30 bytes.reserve(hex.length() / 2);
31
32 for (size_t i{0}; i < hex.length(); i += 2) {
33 uint8_t byte_value;
34 auto [ptr, ec] = std::from_chars(hex.data() + i, hex.data() + i + 2, byte_value, 16);
35
36 if (ec != std::errc{} || ptr != hex.data() + i + 2) {
37 throw std::invalid_argument("Invalid hex character");
38 }
39 bytes.push_back(static_cast<std::byte>(byte_value));
40 }
41 return bytes;
42}
43
45{
46public:
47 void LogMessage(std::string_view message)
48 {
49 std::cout << "kernel: " << message;
50 }
51};
52
54{
55public:
57
58 std::optional<std::string> m_expected_valid_block = std::nullopt;
59
60 void BlockChecked(const Block block, const BlockValidationState state) override
61 {
62 auto mode{state.GetValidationMode()};
63 switch (mode) {
64 case ValidationMode::VALID: {
65 std::cout << "Valid block" << std::endl;
66 return;
67 }
69 std::cout << "Invalid block: ";
70 auto result{state.GetBlockValidationResult()};
71 switch (result) {
72 case BlockValidationResult::UNSET:
73 std::cout << "initial value. Block has not yet been rejected" << std::endl;
74 break;
75 case BlockValidationResult::HEADER_LOW_WORK:
76 std::cout << "the block header may be on a too-little-work chain" << std::endl;
77 break;
78 case BlockValidationResult::CONSENSUS:
79 std::cout << "invalid by consensus rules" << std::endl;
80 break;
81 case BlockValidationResult::CACHED_INVALID:
82 std::cout << "this block was cached as being invalid and we didn't store the reason why" << std::endl;
83 break;
84 case BlockValidationResult::INVALID_HEADER:
85 std::cout << "invalid proof of work or time too old" << std::endl;
86 break;
87 case BlockValidationResult::MUTATED:
88 std::cout << "the block's data didn't match the data committed to by the PoW" << std::endl;
89 break;
90 case BlockValidationResult::MISSING_PREV:
91 std::cout << "We don't have the previous block the checked one is built on" << std::endl;
92 break;
93 case BlockValidationResult::INVALID_PREV:
94 std::cout << "A block this one builds on is invalid" << std::endl;
95 break;
96 case BlockValidationResult::TIME_FUTURE:
97 std::cout << "block timestamp was > 2 hours in the future (or our clock is bad)" << std::endl;
98 break;
99 }
100 return;
101 }
102 case ValidationMode::INTERNAL_ERROR: {
103 std::cout << "Internal error" << std::endl;
104 return;
105 }
106 }
107 }
108};
109
111{
112public:
114 {
115 std::cout << "Block tip changed" << std::endl;
116 }
117
118 void ProgressHandler(std::string_view title, int progress_percent, bool resume_possible) override
119 {
120 std::cout << "Made progress: " << title << " " << progress_percent << "%" << std::endl;
121 }
122
123 void WarningSetHandler(Warning warning, std::string_view message) override
124 {
125 std::cout << message << std::endl;
126 }
127
128 void WarningUnsetHandler(Warning warning) override
129 {
130 std::cout << "Warning unset: " << static_cast<std::underlying_type_t<Warning>>(warning) << std::endl;
131 }
132
133 void FlushErrorHandler(std::string_view error) override
134 {
135 std::cout << error << std::endl;
136 }
137
138 void FatalErrorHandler(std::string_view error) override
139 {
140 std::cout << error << std::endl;
141 }
142};
143
144int main(int argc, char* argv[])
145{
146 // SETUP: Argument parsing and handling
147 if (argc != 2) {
148 std::cerr
149 << "Usage: " << argv[0] << " DATADIR" << std::endl
150 << "Display DATADIR information, and process hex-encoded blocks on standard input." << std::endl
151 << std::endl
152 << "IMPORTANT: THIS EXECUTABLE IS EXPERIMENTAL, FOR TESTING ONLY, AND EXPECTED TO" << std::endl
153 << " BREAK IN FUTURE VERSIONS. DO NOT USE ON YOUR ACTUAL DATADIR." << std::endl;
154 return 1;
155 }
156 std::filesystem::path abs_datadir{std::filesystem::absolute(argv[1])};
157 std::filesystem::create_directories(abs_datadir);
158
159 btck_LoggingOptions logging_options = {
160 .log_timestamps = true,
161 .log_time_micros = false,
162 .log_threadnames = false,
163 .log_sourcelocations = false,
164 .always_print_category_levels = true,
165 };
166
167 logging_set_options(logging_options);
168
169 Logger logger{std::make_unique<KernelLog>()};
170
171 ContextOptions options{};
172 ChainParams params{ChainType::MAINNET};
173 options.SetChainParams(params);
174
175 options.SetNotifications(std::make_shared<TestKernelNotifications>());
176 options.SetValidationInterface(std::make_shared<TestValidationInterface>());
177
178 Context context{options};
179
180 ChainstateManagerOptions chainman_opts{context, abs_datadir.string(), (abs_datadir / "blocks").string()};
181 chainman_opts.SetWorkerThreads(4);
182
183 std::unique_ptr<ChainMan> chainman;
184 try {
185 chainman = std::make_unique<ChainMan>(context, chainman_opts);
186 } catch (std::exception&) {
187 std::cerr << "Failed to instantiate ChainMan, exiting" << std::endl;
188 return 1;
189 }
190
191 std::cout << "Enter the block you want to validate on the next line:" << std::endl;
192
193 for (std::string line; std::getline(std::cin, line);) {
194 if (line.empty()) {
195 std::cerr << "Empty line found, try again:" << std::endl;
196 continue;
197 }
198
199 auto raw_block{hex_string_to_byte_vec(line)};
200 std::unique_ptr<Block> block;
201 try {
202 block = std::make_unique<Block>(raw_block);
203 } catch (std::exception&) {
204 std::cerr << "Block decode failed, try again:" << std::endl;
205 continue;
206 }
207
208 bool new_block = false;
209 bool accepted = chainman->ProcessBlock(*block, &new_block);
210 if (accepted) {
211 std::cerr << "Block has not yet been rejected" << std::endl;
212 } else {
213 std::cerr << "Block was not accepted" << std::endl;
214 }
215 if (!new_block) {
216 std::cerr << "Block is a duplicate" << std::endl;
217 }
218 }
219}
int main(int argc, char *argv[])
std::vector< std::byte > hex_string_to_byte_vec(std::string_view hex)
void LogMessage(std::string_view message)
void FlushErrorHandler(std::string_view error) override
void FatalErrorHandler(std::string_view error) override
void WarningUnsetHandler(Warning warning) override
void WarningSetHandler(Warning warning, std::string_view message) override
void ProgressHandler(std::string_view title, int progress_percent, bool resume_possible) override
void BlockTipHandler(SynchronizationState, const BlockTreeEntry, double) override
TestValidationInterface()=default
void BlockChecked(const Block block, const BlockValidationState state) override
std::optional< std::string > m_expected_valid_block
BlockValidationResult GetBlockValidationResult() const
ValidationMode GetValidationMode() const
void SetWorkerThreads(int worker_threads)
void logging_set_options(const btck_LoggingOptions &logging_options)
static const auto INVALID
A stack representing the lack of any (dis)satisfactions.
Definition: miniscript.h:356
Options controlling the format of log messages.
int log_timestamps
Prepend a timestamp to log messages.