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(Block block, BlockValidationStateView 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 const bool has_regtest_flag{argc == 3 && std::string(argv[1]) == "-regtest"};
148 if (argc < 2 || argc > 3 || (argc == 3 && !has_regtest_flag)) {
149 std::cerr
150 << "Usage: " << argv[0] << " [-regtest] DATADIR" << std::endl
151 << "Display DATADIR information, and process hex-encoded blocks on standard input." << std::endl
152 << "Uses mainnet parameters by default, regtest with -regtest flag" << std::endl
153 << std::endl
154 << "IMPORTANT: THIS EXECUTABLE IS EXPERIMENTAL, FOR TESTING ONLY, AND EXPECTED TO" << std::endl
155 << " BREAK IN FUTURE VERSIONS. DO NOT USE ON YOUR ACTUAL DATADIR." << std::endl;
156 return 1;
157 }
158 std::filesystem::path abs_datadir{std::filesystem::absolute(argv[argc-1])};
159 std::filesystem::create_directories(abs_datadir);
160
161 btck_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 };
168
169 logging_set_options(logging_options);
170
171 Logger logger{std::make_unique<KernelLog>()};
172
173 ContextOptions options{};
174 ChainParams params{has_regtest_flag ? ChainType::REGTEST : ChainType::MAINNET};
175 options.SetChainParams(params);
176
177 options.SetNotifications(std::make_shared<TestKernelNotifications>());
178 options.SetValidationInterface(std::make_shared<TestValidationInterface>());
179
180 Context context{options};
181
182 ChainstateManagerOptions chainman_opts{context, abs_datadir.string(), (abs_datadir / "blocks").string()};
183 chainman_opts.SetWorkerThreads(4);
184
185 std::unique_ptr<ChainMan> chainman;
186 try {
187 chainman = std::make_unique<ChainMan>(context, chainman_opts);
188 } catch (std::exception&) {
189 std::cerr << "Failed to instantiate ChainMan, exiting" << std::endl;
190 return 1;
191 }
192
193 std::cout << "Enter the block you want to validate on the next line:" << std::endl;
194
195 for (std::string line; std::getline(std::cin, line);) {
196 if (line.empty()) {
197 std::cerr << "Empty line found, try again:" << std::endl;
198 continue;
199 }
200
201 auto raw_block{hex_string_to_byte_vec(line)};
202 std::unique_ptr<Block> block;
203 try {
204 block = std::make_unique<Block>(raw_block);
205 } catch (std::exception&) {
206 std::cerr << "Block decode failed, try again:" << std::endl;
207 continue;
208 }
209
210 bool new_block = false;
211 bool accepted = chainman->ProcessBlock(*block, &new_block);
212 if (accepted) {
213 std::cerr << "Block has not yet been rejected" << std::endl;
214 } else {
215 std::cerr << "Block was not accepted" << std::endl;
216 }
217 if (!new_block) {
218 std::cerr << "Block is a duplicate" << std::endl;
219 }
220 }
221}
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
std::optional< std::string > m_expected_valid_block
void BlockChecked(Block block, BlockValidationStateView state) override
ValidationMode GetValidationMode() const
BlockValidationResult GetBlockValidationResult() 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.