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