Bitcoin ABC 0.32.4
P2P Digital Currency
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 ABC'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 ABC'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
19#include <chainparams.h>
20#include <common/args.h>
21#include <config.h>
23#include <core_io.h>
24#include <kernel/caches.h>
25#include <logging.h>
26#include <node/blockstorage.h>
27#include <node/chainstate.h>
28#include <scheduler.h>
29#include <script/scriptcache.h>
30#include <script/sigcache.h>
31#include <util/chaintype.h>
32#include <util/thread.h>
33#include <util/translation.h>
34#include <validation.h>
35#include <validationinterface.h>
36
37#include <cassert>
38#include <cstdint>
39#include <filesystem>
40#include <functional>
41#include <iosfwd>
42#include <memory>
43
44int main(int argc, char *argv[]) {
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 << "Usage: " << argv[0] << " DATADIR" << std::endl
54 << "Display DATADIR information, and process hex-encoded "
55 "blocks on standard input."
56 << std::endl
57 << std::endl
58 << "IMPORTANT: THIS EXECUTABLE IS EXPERIMENTAL, FOR TESTING "
59 "ONLY, AND EXPECTED TO"
60 << std::endl
61 << " BREAK IN FUTURE VERSIONS. DO NOT USE ON YOUR "
62 "ACTUAL DATADIR."
63 << std::endl;
64 return 1;
65 }
66 std::filesystem::path abs_datadir = std::filesystem::absolute(argv[1]);
68 gArgs.ForceSetArg("-datadir", abs_datadir.string());
69
70 // SETUP: Misc Globals
72
74 auto &config = const_cast<Config &>(GetConfig());
75 config.SetChainParams(*chainparams);
76
77 // ECC_Start, etc.
78 kernel::Context kernel_context{};
79 // We can't use a goto here, but we can use an assert since none of the
80 // things instantiated so far requires running the epilogue to be torn down
81 // properly
82 assert(kernel::SanityChecks(kernel_context));
83
84 // SETUP: Scheduling and Background Signals
85 CScheduler scheduler{};
86 // Start the lightweight task scheduler thread
87 scheduler.m_service_thread = std::thread(util::TraceThread, "scheduler",
88 [&] { scheduler.serviceQueue(); });
89
90 // Gather some entropy once per minute.
91 scheduler.scheduleEvery(
92 [] {
94 return true;
95 },
96 std::chrono::minutes{1});
97
99
100 class KernelNotifications : public kernel::Notifications {
101 public:
102 void blockTip(SynchronizationState, CBlockIndex &) override {
103 std::cout << "Block tip changed" << std::endl;
104 }
105 void headerTip(SynchronizationState, int64_t height, int64_t timestamp,
106 bool presync) override {
107 std::cout << "Header tip changed: " << height << ", " << timestamp
108 << ", " << presync << std::endl;
109 }
110 void progress(const bilingual_str &title, int progress_percent,
111 bool resume_possible) override {
112 std::cout << "Progress: " << title.original << ", "
113 << progress_percent << ", " << resume_possible
114 << std::endl;
115 }
116 void warning(const std::string &warning) override {
117 std::cout << "Warning: " << warning << std::endl;
118 }
119 void flushError(const std::string &debug_message) override {
120 std::cerr << "Error flushing block data to disk: " << debug_message
121 << std::endl;
122 }
123 void fatalError(const std::string &debug_message,
124 const bilingual_str &user_message) override {
125 std::cerr << "Error: " << debug_message << std::endl;
126 std::cerr << (user_message.empty()
127 ? "A fatal internal error occurred."
128 : user_message.original)
129 << std::endl;
130 }
131 };
132 auto notifications = std::make_unique<KernelNotifications>();
133
134 // SETUP: Chainstate
135 const ChainstateManager::Options chainman_opts{
136 .config = config,
137 .datadir = gArgs.GetDataDirNet(),
138 .adjusted_time_callback = NodeClock::now,
139 .notifications = *notifications,
140 };
141 const node::BlockManager::Options blockman_opts{
142 .chainparams = chainman_opts.config.GetChainParams(),
143 .blocks_dir = gArgs.GetBlocksDirPath(),
144 .notifications = chainman_opts.notifications,
145 };
146 ChainstateManager chainman{kernel_context.interrupt, chainman_opts,
147 blockman_opts};
148
151 options.check_interrupt = [] { return false; };
152 auto [status, error] = node::LoadChainstate(chainman, cache_sizes, options);
154 std::cerr << "Failed to load Chain state from your datadir."
155 << std::endl;
156 goto epilogue;
157 }
158 std::tie(status, error) = node::VerifyLoadedChainstate(chainman, options);
160 std::cerr << "Failed to verify loaded Chain state from your datadir."
161 << std::endl;
162 goto epilogue;
163 }
164
165 for (Chainstate *chainstate :
166 WITH_LOCK(::cs_main, return chainman.GetAll())) {
168 if (!chainstate->ActivateBestChain(state, nullptr)) {
169 std::cerr << "Failed to connect best block (" << state.ToString()
170 << ")" << std::endl;
171 goto epilogue;
172 }
173 }
174
175 // Main program logic starts here
176 std::cout
177 << "Hello! I'm going to print out some information about your datadir."
178 << std::endl;
179 {
180 LOCK(chainman.GetMutex());
181 std::cout << "\t"
182 << "Path: " << gArgs.GetDataDirNet() << std::endl
183 << "\t"
184 << "Reindexing: " << std::boolalpha << node::fReindex.load()
185 << std::noboolalpha << std::endl
186 << "\t"
187 << "Snapshot Active: " << std::boolalpha
188 << chainman.IsSnapshotActive() << std::noboolalpha
189 << std::endl
190 << "\t"
191 << "Active Height: " << chainman.ActiveHeight() << std::endl
192 << "\t"
193 << "Active IBD: " << std::boolalpha
194 << chainman.IsInitialBlockDownload() << std::noboolalpha
195 << std::endl;
196 CBlockIndex *tip = chainman.ActiveTip();
197 if (tip) {
198 std::cout << "\t" << tip->ToString() << std::endl;
199 }
200 }
201
202 for (std::string line; std::getline(std::cin, line);) {
203 if (line.empty()) {
204 std::cerr << "Empty line found" << std::endl;
205 break;
206 }
207
208 std::shared_ptr<CBlock> blockptr = std::make_shared<CBlock>();
209 CBlock &block = *blockptr;
210
211 if (!DecodeHexBlk(block, line)) {
212 std::cerr << "Block decode failed" << std::endl;
213 break;
214 }
215
216 if (block.vtx.empty() || !block.vtx[0]->IsCoinBase()) {
217 std::cerr << "Block does not start with a coinbase" << std::endl;
218 break;
219 }
220
221 BlockHash hash = block.GetHash();
222 {
223 LOCK(cs_main);
224 const CBlockIndex *pindex =
225 chainman.m_blockman.LookupBlockIndex(hash);
226 if (pindex) {
227 if (pindex->IsValid(BlockValidity::SCRIPTS)) {
228 std::cerr << "Duplicate" << std::endl;
229 break;
230 }
231 if (pindex->nStatus.hasFailed()) {
232 std::cerr << "Duplicate-invalid" << std::endl;
233 break;
234 }
235 }
236 }
237
238 // Adapted from rpc/mining.cpp
240 public:
242 bool found;
244
245 explicit submitblock_StateCatcher(const BlockHash &hashIn)
246 : hash(hashIn), found(false), state() {}
247
248 protected:
249 void BlockChecked(const CBlock &block,
250 const BlockValidationState &stateIn) override {
251 if (block.GetHash() != hash) {
252 return;
253 }
254 found = true;
255 state = stateIn;
256 }
257 };
258
259 bool new_block;
260 auto sc = std::make_shared<submitblock_StateCatcher>(block.GetHash());
262 bool accepted = chainman.ProcessNewBlock(blockptr,
263 /*force_processing=*/true,
264 /*min_pow_checked=*/true,
265 /*new_block=*/&new_block);
267 if (!new_block && accepted) {
268 std::cerr << "Duplicate" << std::endl;
269 break;
270 }
271 if (!sc->found) {
272 std::cerr << "Inconclusive" << std::endl;
273 break;
274 }
275 std::cout << sc->state.ToString() << std::endl;
276 switch (sc->state.GetResult()) {
278 std::cerr << "Initial value. Block has not yet been rejected"
279 << std::endl;
280 break;
282 std::cerr
283 << "the block header may be on a too-little-work chain"
284 << std::endl;
285 break;
287 std::cerr << "Invalid by consensus rules (excluding any below "
288 "reasons)"
289 << std::endl;
290 break;
292 std::cerr << "This block was cached as being invalid and we "
293 "didn't store the reason why"
294 << std::endl;
295 break;
297 std::cerr << "Invalid proof of work or time too old"
298 << std::endl;
299 break;
301 std::cerr << "The block's data didn't match the data committed "
302 "to by the PoW"
303 << std::endl;
304 break;
306 std::cerr << "We don't have the previous block the checked one "
307 "is built on"
308 << std::endl;
309 break;
311 std::cerr << "A block this one builds on is invalid"
312 << std::endl;
313 break;
315 std::cerr << "Block timestamp was > 2 hours in the future (or "
316 "our clock is bad)"
317 << std::endl;
318 break;
320 std::cerr << "The block failed to meet one of our checkpoints"
321 << std::endl;
322 break;
323 }
324 }
325
326epilogue:
327 // Without this precise shutdown sequence, there will be a lot of nullptr
328 // dereferencing and UB.
329 scheduler.stop();
330 if (chainman.m_thread_load.joinable()) {
331 chainman.m_thread_load.join();
332 }
334
336 {
337 LOCK(cs_main);
338 for (Chainstate *chainstate : chainman.GetAll()) {
339 if (chainstate->CanFlushToDisk()) {
340 chainstate->ForceFlushStateToDisk();
341 chainstate->ResetCoinsViews();
342 }
343 }
344 }
346}
ArgsManager gArgs
Definition: args.cpp:40
int main(int argc, char *argv[])
@ SCRIPTS
Scripts & signatures ok.
void SelectParams(const ChainType chain)
Sets the params returned by Params() to those for the given BIP70 chain name.
Definition: chainparams.cpp:50
void ForceSetArg(const std::string &strArg, const std::string &strValue)
Definition: args.cpp:566
fs::path GetDataDirNet() const
Get data directory path with appended network identifier.
Definition: args.h:239
fs::path GetBlocksDirPath() const
Get blocks directory path.
Definition: args.cpp:300
void DisableLogging() EXCLUSIVE_LOCKS_REQUIRED(!m_cs)
This offers a slight speedup and slightly smaller memory usage compared to leaving the logging system...
Definition: logging.cpp:119
BlockHash GetHash() const
Definition: block.cpp:11
Definition: block.h:60
std::vector< CTransactionRef > vtx
Definition: block.h:63
The block chain is a tree shaped structure starting with the genesis block at the root,...
Definition: blockindex.h:25
bool IsValid(enum BlockValidity nUpTo=BlockValidity::TRANSACTIONS) const EXCLUSIVE_LOCKS_REQUIRED(
Check whether this block index entry is valid up to the passed validity level.
Definition: blockindex.h:191
std::string ToString() const
Definition: blockindex.cpp:30
static std::unique_ptr< const CChainParams > Main(const ChainOptions &options)
void UnregisterBackgroundSignalScheduler()
Unregister a CScheduler to give callbacks which should run in the background - these callbacks will n...
void RegisterBackgroundSignalScheduler(CScheduler &scheduler)
Register a CScheduler to give callbacks which should run in the background (may only be called once)
void FlushBackgroundCallbacks()
Call any remaining callbacks on the calling thread.
Simple class for background tasks that should be run periodically or once "after a while".
Definition: scheduler.h:41
std::thread m_service_thread
Definition: scheduler.h:46
Implement this to subscribe to events generated in validation.
Chainstate stores and provides an API to update our local knowledge of the current best chain.
Definition: validation.h:734
Provides an interface for creating and interacting with one or two chainstates: an IBD chainstate gen...
Definition: validation.h:1186
Definition: config.h:19
virtual void SetChainParams(const CChainParams chainParamsIn)=0
std::string ToString() const
Definition: validation.h:125
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 flushError(const std::string &debug_message)
The flush error notification is sent to notify the user that an error occurred while flushing block d...
virtual void fatalError(const std::string &debug_message, const bilingual_str &user_message={})
The fatal error notification is sent to notify the user when an error occurs in kernel code that can'...
virtual void warning(const std::string &warning)
virtual void progress(const bilingual_str &title, int progress_percent, bool resume_possible)
virtual void blockTip(SynchronizationState state, CBlockIndex &index)
void BlockChecked(const CBlock &block, const BlockValidationState &stateIn) override
Notifies listeners of a block validation result.
Definition: mining.cpp:1286
submitblock_StateCatcher(const uint256 &hashIn)
Definition: mining.cpp:1283
BlockValidationState state
Definition: mining.cpp:1281
const Config & GetConfig()
Definition: config.cpp:40
@ BLOCK_CHECKPOINT
the block failed to meet one of our checkpoints
@ 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)
Definition: core_read.cpp:234
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate.
Definition: cs_main.cpp:7
static constexpr int64_t DEFAULT_KERNEL_CACHE
Suggested default amount of cache reserved for the kernel (bytes)
Definition: caches.h:14
BCLog::Logger & LogInstance()
Definition: logging.cpp:25
static path absolute(const path &p)
Definition: fs.h:101
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:184
util::Result< void > SanityChecks(const Context &)
Ensure a usable environment with all necessary library support.
Definition: checks.cpp:14
ChainstateLoadResult LoadChainstate(ChainstateManager &chainman, const CacheSizes &cache_sizes, const ChainstateLoadOptions &options)
Definition: chainstate.cpp:171
ChainstateLoadResult VerifyLoadedChainstate(ChainstateManager &chainman, const ChainstateLoadOptions &options)
Definition: chainstate.cpp:275
std::atomic_bool fReindex
void TraceThread(std::string_view thread_name, std::function< void()> thread_func)
A wrapper for do-something-once thread functions.
Definition: thread.cpp:14
void RandAddPeriodic() noexcept
Gather entropy from various expensive sources, and feed them to the PRNG state.
Definition: random.cpp:648
A BlockHash is a unqiue identifier for a block.
Definition: blockhash.h:13
static time_point now() noexcept
Return current system time or mocked time, if set.
Definition: time.cpp:71
Bilingual messages:
Definition: translation.h:17
bool empty() const
Definition: translation.h:27
std::string original
Definition: translation.h:18
An options struct for BlockManager, more ergonomically referred to as BlockManager::Options due to th...
const CChainParams & chainparams
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:22
std::function< bool()> check_interrupt
Definition: chainstate.h:38
#define LOCK(cs)
Definition: sync.h:306
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
Definition: sync.h:357
void StopScriptCheckWorkerThreads()
Stop all of the script checking worker threads.
assert(!tx.IsCoinBase())
SynchronizationState
Current sync state passed to tip changed callbacks.
Definition: validation.h:119
CMainSignals & GetMainSignals()
void UnregisterSharedValidationInterface(std::shared_ptr< CValidationInterface > callbacks)
Unregister subscriber.
void RegisterSharedValidationInterface(std::shared_ptr< CValidationInterface > callbacks)
Register subscriber.