Bitcoin Core 28.0.0
P2P Digital Currency
Loading...
Searching...
No Matches
bitcoin-chainstate.cpp
Go to the documentation of this file.
1// Copyright (c) 2022 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
14#include <kernel/chainparams.h>
16#include <kernel/checks.h>
17#include <kernel/context.h>
18#include <kernel/warning.h>
19
21#include <core_io.h>
22#include <logging.h>
23#include <node/blockstorage.h>
24#include <node/caches.h>
25#include <node/chainstate.h>
26#include <random.h>
27#include <script/sigcache.h>
28#include <util/chaintype.h>
29#include <util/fs.h>
31#include <util/task_runner.h>
32#include <util/translation.h>
33#include <validation.h>
34#include <validationinterface.h>
35
36#include <cassert>
37#include <cstdint>
38#include <functional>
39#include <iosfwd>
40#include <memory>
41#include <string>
42
43int main(int argc, char* argv[])
44{
45 // We do not enable logging for this app, so explicitly disable it.
46 // To enable logging instead, replace with:
47 // LogInstance().m_print_to_console = true;
48 // LogInstance().StartLogging();
50
51 // SETUP: Argument parsing and handling
52 if (argc != 2) {
53 std::cerr
54 << "Usage: " << argv[0] << " DATADIR" << std::endl
55 << "Display DATADIR information, and process hex-encoded blocks on standard input." << std::endl
56 << std::endl
57 << "IMPORTANT: THIS EXECUTABLE IS EXPERIMENTAL, FOR TESTING ONLY, AND EXPECTED TO" << std::endl
58 << " BREAK IN FUTURE VERSIONS. DO NOT USE ON YOUR ACTUAL DATADIR." << std::endl;
59 return 1;
60 }
61 fs::path abs_datadir{fs::absolute(argv[1])};
62 fs::create_directories(abs_datadir);
63
64
65 // SETUP: Context
66 kernel::Context kernel_context{};
67 // We can't use a goto here, but we can use an assert since none of the
68 // things instantiated so far requires running the epilogue to be torn down
69 // properly
70 assert(kernel::SanityChecks(kernel_context));
71
72 ValidationSignals validation_signals{std::make_unique<util::ImmediateTaskRunner>()};
73
74 class KernelNotifications : public kernel::Notifications
75 {
76 public:
78 {
79 std::cout << "Block tip changed" << std::endl;
80 return {};
81 }
82 void headerTip(SynchronizationState, int64_t height, int64_t timestamp, bool presync) override
83 {
84 std::cout << "Header tip changed: " << height << ", " << timestamp << ", " << presync << std::endl;
85 }
86 void progress(const bilingual_str& title, int progress_percent, bool resume_possible) override
87 {
88 std::cout << "Progress: " << title.original << ", " << progress_percent << ", " << resume_possible << std::endl;
89 }
90 void warningSet(kernel::Warning id, const bilingual_str& message) override
91 {
92 std::cout << "Warning " << static_cast<int>(id) << " set: " << message.original << std::endl;
93 }
94 void warningUnset(kernel::Warning id) override
95 {
96 std::cout << "Warning " << static_cast<int>(id) << " unset" << std::endl;
97 }
98 void flushError(const bilingual_str& message) override
99 {
100 std::cerr << "Error flushing block data to disk: " << message.original << std::endl;
101 }
102 void fatalError(const bilingual_str& message) override
103 {
104 std::cerr << "Error: " << message.original << std::endl;
105 }
106 };
107 auto notifications = std::make_unique<KernelNotifications>();
108
109
110 // SETUP: Chainstate
111 auto chainparams = CChainParams::Main();
112 const ChainstateManager::Options chainman_opts{
113 .chainparams = *chainparams,
114 .datadir = abs_datadir,
115 .notifications = *notifications,
116 .signals = &validation_signals,
117 };
118 const node::BlockManager::Options blockman_opts{
119 .chainparams = chainman_opts.chainparams,
120 .blocks_dir = abs_datadir / "blocks",
121 .notifications = chainman_opts.notifications,
122 };
123 util::SignalInterrupt interrupt;
124 ChainstateManager chainman{interrupt, chainman_opts, blockman_opts};
125
126 node::CacheSizes cache_sizes;
127 cache_sizes.block_tree_db = 2 << 20;
128 cache_sizes.coins_db = 2 << 22;
129 cache_sizes.coins = (450 << 20) - (2 << 20) - (2 << 22);
131 auto [status, error] = node::LoadChainstate(chainman, cache_sizes, options);
133 std::cerr << "Failed to load Chain state from your datadir." << std::endl;
134 goto epilogue;
135 } else {
136 std::tie(status, error) = node::VerifyLoadedChainstate(chainman, options);
138 std::cerr << "Failed to verify loaded Chain state from your datadir." << std::endl;
139 goto epilogue;
140 }
141 }
142
143 for (Chainstate* chainstate : WITH_LOCK(::cs_main, return chainman.GetAll())) {
145 if (!chainstate->ActivateBestChain(state, nullptr)) {
146 std::cerr << "Failed to connect best block (" << state.ToString() << ")" << std::endl;
147 goto epilogue;
148 }
149 }
150
151 // Main program logic starts here
152 std::cout
153 << "Hello! I'm going to print out some information about your datadir." << std::endl
154 << "\t"
155 << "Path: " << abs_datadir << std::endl;
156 {
157 LOCK(chainman.GetMutex());
158 std::cout
159 << "\t" << "Blockfiles Indexed: " << std::boolalpha << chainman.m_blockman.m_blockfiles_indexed.load() << std::noboolalpha << std::endl
160 << "\t" << "Snapshot Active: " << std::boolalpha << chainman.IsSnapshotActive() << std::noboolalpha << std::endl
161 << "\t" << "Active Height: " << chainman.ActiveHeight() << std::endl
162 << "\t" << "Active IBD: " << std::boolalpha << chainman.IsInitialBlockDownload() << std::noboolalpha << std::endl;
163 CBlockIndex* tip = chainman.ActiveTip();
164 if (tip) {
165 std::cout << "\t" << tip->ToString() << std::endl;
166 }
167 }
168
169 for (std::string line; std::getline(std::cin, line);) {
170 if (line.empty()) {
171 std::cerr << "Empty line found" << std::endl;
172 break;
173 }
174
175 std::shared_ptr<CBlock> blockptr = std::make_shared<CBlock>();
176 CBlock& block = *blockptr;
177
178 if (!DecodeHexBlk(block, line)) {
179 std::cerr << "Block decode failed" << std::endl;
180 break;
181 }
182
183 if (block.vtx.empty() || !block.vtx[0]->IsCoinBase()) {
184 std::cerr << "Block does not start with a coinbase" << std::endl;
185 break;
186 }
187
188 uint256 hash = block.GetHash();
189 {
190 LOCK(cs_main);
191 const CBlockIndex* pindex = chainman.m_blockman.LookupBlockIndex(hash);
192 if (pindex) {
193 if (pindex->IsValid(BLOCK_VALID_SCRIPTS)) {
194 std::cerr << "duplicate" << std::endl;
195 break;
196 }
197 if (pindex->nStatus & BLOCK_FAILED_MASK) {
198 std::cerr << "duplicate-invalid" << std::endl;
199 break;
200 }
201 }
202 }
203
204 {
205 LOCK(cs_main);
206 const CBlockIndex* pindex = chainman.m_blockman.LookupBlockIndex(block.hashPrevBlock);
207 if (pindex) {
208 chainman.UpdateUncommittedBlockStructures(block, pindex);
209 }
210 }
211
212 // Adapted from rpc/mining.cpp
214 {
215 public:
217 bool found;
219
220 explicit submitblock_StateCatcher(const uint256& hashIn) : hash(hashIn), found(false), state() {}
221
222 protected:
223 void BlockChecked(const CBlock& block, const BlockValidationState& stateIn) override
224 {
225 if (block.GetHash() != hash)
226 return;
227 found = true;
228 state = stateIn;
229 }
230 };
231
232 bool new_block;
233 auto sc = std::make_shared<submitblock_StateCatcher>(block.GetHash());
234 validation_signals.RegisterSharedValidationInterface(sc);
235 bool accepted = chainman.ProcessNewBlock(blockptr, /*force_processing=*/true, /*min_pow_checked=*/true, /*new_block=*/&new_block);
236 validation_signals.UnregisterSharedValidationInterface(sc);
237 if (!new_block && accepted) {
238 std::cerr << "duplicate" << std::endl;
239 break;
240 }
241 if (!sc->found) {
242 std::cerr << "inconclusive" << std::endl;
243 break;
244 }
245 std::cout << sc->state.ToString() << std::endl;
246 switch (sc->state.GetResult()) {
248 std::cerr << "initial value. Block has not yet been rejected" << std::endl;
249 break;
251 std::cerr << "the block header may be on a too-little-work chain" << std::endl;
252 break;
254 std::cerr << "invalid by consensus rules (excluding any below reasons)" << std::endl;
255 break;
257 std::cerr << "Invalid by a change to consensus rules more recent than SegWit." << std::endl;
258 break;
260 std::cerr << "this block was cached as being invalid and we didn't store the reason why" << std::endl;
261 break;
263 std::cerr << "invalid proof of work or time too old" << std::endl;
264 break;
266 std::cerr << "the block's data didn't match the data committed to by the PoW" << std::endl;
267 break;
269 std::cerr << "We don't have the previous block the checked one is built on" << std::endl;
270 break;
272 std::cerr << "A block this one builds on is invalid" << std::endl;
273 break;
275 std::cerr << "block timestamp was > 2 hours in the future (or our clock is bad)" << std::endl;
276 break;
278 std::cerr << "the block failed to meet one of our checkpoints" << std::endl;
279 break;
280 }
281 }
282
283epilogue:
284 // Without this precise shutdown sequence, there will be a lot of nullptr
285 // dereferencing and UB.
286 if (chainman.m_thread_load.joinable()) chainman.m_thread_load.join();
287
288 validation_signals.FlushBackgroundCallbacks();
289 {
290 LOCK(cs_main);
291 for (Chainstate* chainstate : chainman.GetAll()) {
292 if (chainstate->CanFlushToDisk()) {
293 chainstate->ForceFlushStateToDisk();
294 chainstate->ResetCoinsViews();
295 }
296 }
297 }
298}
@ BLOCK_VALID_SCRIPTS
Scripts & signatures ok.
Definition chain.h:115
@ BLOCK_FAILED_MASK
Definition chain.h:127
void DisableLogging() EXCLUSIVE_LOCKS_REQUIRED(!m_cs)
Disable logging This offers a slight speedup and slightly smaller memory usage compared to leaving th...
Definition logging.cpp:109
uint256 hashPrevBlock
Definition block.h:26
uint256 GetHash() const
Definition block.cpp:11
Definition block.h:69
std::vector< CTransactionRef > vtx
Definition block.h:72
The block chain is a tree shaped structure starting with the genesis block at the root,...
Definition chain.h:141
std::string ToString() const
Definition chain.cpp:15
bool IsValid(enum BlockStatus nUpTo=BLOCK_VALID_TRANSACTIONS) const EXCLUSIVE_LOCKS_REQUIRED(
Check whether this block index entry is valid up to the passed validity level.
Definition chain.h:295
static std::unique_ptr< const CChainParams > Main()
Implement this to subscribe to events generated in validation and mempool.
Chainstate stores and provides an API to update our local knowledge of the current best chain.
Definition validation.h:513
Provides an interface for creating and interacting with one or two chainstates: an IBD chainstate gen...
Definition validation.h:871
std::string ToString() const
Definition validation.h:128
Path class wrapper to block calls to the fs::path(std::string) implicit constructor and the fs::path:...
Definition fs.h:33
A base class defining functions for notifying about certain kernel events.
virtual void headerTip(SynchronizationState state, int64_t height, int64_t timestamp, bool presync)
virtual void fatalError(const bilingual_str &message)
The fatal error notification is sent to notify the user when an error occurs in kernel code that can'...
virtual void warningSet(Warning id, const bilingual_str &message)
virtual void progress(const bilingual_str &title, int progress_percent, bool resume_possible)
virtual void flushError(const bilingual_str &message)
The flush error notification is sent to notify the user that an error occurred while flushing block d...
virtual InterruptResult blockTip(SynchronizationState state, CBlockIndex &index)
virtual void warningUnset(Warning id)
void BlockChecked(const CBlock &block, const BlockValidationState &stateIn) override
Notifies listeners of a block validation result.
Definition mining.cpp:989
submitblock_StateCatcher(const uint256 &hashIn)
Definition mining.cpp:986
BlockValidationState state
Definition mining.cpp:984
256-bit opaque blob.
Definition uint256.h:178
Helper class that manages an interrupt flag, and allows a thread or signal to interrupt another threa...
@ BLOCK_CHECKPOINT
the block failed to meet one of our checkpoints
@ BLOCK_RECENT_CONSENSUS_CHANGE
Invalid by a change to consensus rules more recent than SegWit.
@ BLOCK_HEADER_LOW_WORK
the block header may be on a too-little-work chain
@ BLOCK_INVALID_HEADER
invalid proof of work or time too old
@ BLOCK_CACHED_INVALID
this block was cached as being invalid and we didn't store the reason why
@ BLOCK_CONSENSUS
invalid by consensus rules (excluding any below reasons)
@ BLOCK_MISSING_PREV
We don't have the previous block the checked one is built on.
@ BLOCK_INVALID_PREV
A block this one builds on is invalid.
@ BLOCK_MUTATED
the block's data didn't match the data committed to by the PoW
@ BLOCK_TIME_FUTURE
block timestamp was > 2 hours in the future (or our clock is bad)
@ BLOCK_RESULT_UNSET
initial value. Block has not yet been rejected
bool DecodeHexBlk(CBlock &, const std::string &strHexBlk)
int main(void)
Definition bench.c:156
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate.
Definition cs_main.cpp:8
BCLog::Logger & LogInstance()
Definition logging.cpp:23
static path absolute(const path &p)
Definition fs.h:82
static bool create_directories(const std::filesystem::path &p)
Create directory (and if necessary its parents), unless the leaf directory already exists or is a sym...
Definition fs.h:190
Warning
Definition warning.h:9
util::Result< void > SanityChecks(const Context &)
Ensure a usable environment with all necessary library support.
Definition checks.cpp:15
std::variant< std::monostate, Interrupted > InterruptResult
Simple result type for functions that need to propagate an interrupt status and don't have other retu...
ChainstateLoadResult LoadChainstate(ChainstateManager &chainman, const CacheSizes &cache_sizes, const ChainstateLoadOptions &options)
This sequence can have 4 types of outcomes:
ChainstateLoadResult VerifyLoadedChainstate(ChainstateManager &chainman, const ChainstateLoadOptions &options)
Bilingual messages:
Definition translation.h:18
std::string original
Definition translation.h:19
An options struct for BlockManager, more ergonomically referred to as BlockManager::Options due to th...
An options struct for ChainstateManager, more ergonomically referred to as ChainstateManager::Options...
Context struct holding the kernel library's logically global state, and passed to external libbitcoin...
Definition context.h:16
int64_t coins
Definition caches.h:17
int64_t block_tree_db
Definition caches.h:15
int64_t coins_db
Definition caches.h:16
#define LOCK(cs)
Definition sync.h:257
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
Definition sync.h:301
This header provides an interface and simple implementation for a task runner.
assert(!tx.IsCoinBase())
SynchronizationState
Current sync state passed to tip changed callbacks.
Definition validation.h:82