Bitcoin Core 32.99.0
P2P Digital Currency
Loading...
Searching...
No Matches
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) {
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(const LogEntry& entry)
48 {
49 std::cout << "kernel: " << entry.Timestamp().time_since_epoch().count()
50 << " [" << Name(entry.Category()) << ":"
51 << Name(entry.Level()) << "] "
52 << entry.Message() << "\n";
53 }
54};
55
57{
58public:
60
61 std::optional<std::string> m_expected_valid_block = std::nullopt;
62
63 void BlockChecked(Block block, BlockValidationStateView state) override
64 {
65 auto mode{state.GetValidationMode()};
66 switch (mode) {
67 case ValidationMode::VALID: {
68 std::cout << "Valid block" << std::endl;
69 return;
70 }
71 case ValidationMode::INVALID: {
72 std::cout << "Invalid block: ";
73 auto result{state.GetBlockValidationResult()};
74 switch (result) {
75 case BlockValidationResult::UNSET:
76 std::cout << "initial value. Block has not yet been rejected" << std::endl;
77 break;
78 case BlockValidationResult::HEADER_LOW_WORK:
79 std::cout << "the block header may be on a too-little-work chain" << std::endl;
80 break;
81 case BlockValidationResult::CONSENSUS:
82 std::cout << "invalid by consensus rules" << std::endl;
83 break;
84 case BlockValidationResult::CACHED_INVALID:
85 std::cout << "this block was cached as being invalid and we didn't store the reason why" << std::endl;
86 break;
87 case BlockValidationResult::INVALID_HEADER:
88 std::cout << "invalid proof of work or time too old" << std::endl;
89 break;
90 case BlockValidationResult::MUTATED:
91 std::cout << "the block's data didn't match the data committed to by the PoW" << std::endl;
92 break;
93 case BlockValidationResult::MISSING_PREV:
94 std::cout << "We don't have the previous block the checked one is built on" << std::endl;
95 break;
96 case BlockValidationResult::INVALID_PREV:
97 std::cout << "A block this one builds on is invalid" << std::endl;
98 break;
99 case BlockValidationResult::TIME_FUTURE:
100 std::cout << "block timestamp was > 2 hours in the future (or our clock is bad)" << std::endl;
101 break;
102 }
103 return;
104 }
105 case ValidationMode::INTERNAL_ERROR: {
106 std::cout << "Internal error" << std::endl;
107 return;
108 }
109 }
110 }
111};
112
114{
115public:
117 {
118 std::cout << "Block tip changed" << std::endl;
119 }
120
121 void ProgressHandler(std::string_view title, int progress_percent, bool resume_possible) override
122 {
123 std::cout << "Made progress: " << title << " " << progress_percent << "%" << std::endl;
124 }
125
126 void WarningSetHandler(Warning warning, std::string_view message) override
127 {
128 std::cout << message << std::endl;
129 }
130
132 {
133 std::cout << "Warning unset: " << static_cast<std::underlying_type_t<Warning>>(warning) << std::endl;
134 }
135
136 void FlushErrorHandler(std::string_view error) override
137 {
138 std::cout << error << std::endl;
139 }
140
141 void FatalErrorHandler(std::string_view error) override
142 {
143 std::cout << error << std::endl;
144 }
145};
146
147int main(int argc, char* argv[])
148{
149 // SETUP: Argument parsing and handling
150 const bool has_regtest_flag{argc == 3 && std::string(argv[1]) == "-regtest"};
151 if (argc < 2 || argc > 3 || (argc == 3 && !has_regtest_flag)) {
152 std::cerr
153 << "Usage: " << argv[0] << " [-regtest] DATADIR" << std::endl
154 << "Display DATADIR information, and process hex-encoded blocks on standard input." << std::endl
155 << "Uses mainnet parameters by default, regtest with -regtest flag" << std::endl
156 << std::endl
157 << "IMPORTANT: THIS EXECUTABLE IS EXPERIMENTAL, FOR TESTING ONLY, AND EXPECTED TO" << std::endl
158 << " BREAK IN FUTURE VERSIONS. DO NOT USE ON YOUR ACTUAL DATADIR." << std::endl;
159 return 1;
160 }
161 std::filesystem::path abs_datadir{std::filesystem::absolute(argv[argc-1])};
162 std::filesystem::create_directories(abs_datadir);
163
164 Logger logger{std::make_unique<KernelLog>()};
165
166 ContextOptions options{};
167 ChainParams params{has_regtest_flag ? ChainType::REGTEST : ChainType::MAINNET};
168 options.SetChainParams(params);
169
170 options.SetNotifications(std::make_shared<TestKernelNotifications>());
171 options.SetValidationInterface(std::make_shared<TestValidationInterface>());
172
173 Context context{options};
174
175 ChainstateManagerOptions chainman_opts{context, abs_datadir.string(), (abs_datadir / "blocks").string()};
177
178 std::unique_ptr<ChainMan> chainman;
179 try {
180 chainman = std::make_unique<ChainMan>(context, chainman_opts);
181 } catch (std::exception&) {
182 std::cerr << "Failed to instantiate ChainMan, exiting" << std::endl;
183 return 1;
184 }
185
186 std::cout << "Enter the block you want to validate on the next line:" << std::endl;
187
188 for (std::string line; std::getline(std::cin, line);) {
189 if (line.empty()) {
190 std::cerr << "Empty line found, try again:" << std::endl;
191 continue;
192 }
193
195 std::unique_ptr<Block> block;
196 try {
197 block = std::make_unique<Block>(raw_block);
198 } catch (std::exception&) {
199 std::cerr << "Block decode failed, try again:" << std::endl;
200 continue;
201 }
202
203 bool new_block = false;
204 bool accepted = chainman->ProcessBlock(*block, &new_block);
205 if (accepted) {
206 std::cerr << "Block has not yet been rejected" << std::endl;
207 } else {
208 std::cerr << "Block was not accepted" << std::endl;
209 }
210 if (!new_block) {
211 std::cerr << "Block is a duplicate" << std::endl;
212 }
213 }
214}
std::vector< std::byte > hex_string_to_byte_vec(std::string_view hex)
void LogMessage(const LogEntry &entry)
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)
Non-owning view over a btck_LogEntry.
LogLevel Level() const
LogCategory Category() const
std::string_view Message() const
std::chrono::sys_time< std::chrono::nanoseconds > Timestamp() const
int main(void)
Definition bench.c:156
constexpr std::string_view Name(LogLevel level) noexcept
constexpr auto Ticks(Dur2 d)
Helper to count the seconds of a duration/time_point.
Definition time.h:82
WalletContext context