Bitcoin Core  24.99.0
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 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/checks.h>
15 #include <kernel/context.h>
17 
18 #include <chainparams.h>
19 #include <consensus/validation.h>
20 #include <core_io.h>
21 #include <node/blockstorage.h>
22 #include <node/caches.h>
23 #include <node/chainstate.h>
24 #include <scheduler.h>
25 #include <script/sigcache.h>
26 #include <util/system.h>
27 #include <util/thread.h>
28 #include <validation.h>
29 #include <validationinterface.h>
30 
31 #include <cassert>
32 #include <filesystem>
33 #include <functional>
34 #include <iosfwd>
35 
36 int main(int argc, char* argv[])
37 {
38  // SETUP: Argument parsing and handling
39  if (argc != 2) {
40  std::cerr
41  << "Usage: " << argv[0] << " DATADIR" << std::endl
42  << "Display DATADIR information, and process hex-encoded blocks on standard input." << std::endl
43  << std::endl
44  << "IMPORTANT: THIS EXECUTABLE IS EXPERIMENTAL, FOR TESTING ONLY, AND EXPECTED TO" << std::endl
45  << " BREAK IN FUTURE VERSIONS. DO NOT USE ON YOUR ACTUAL DATADIR." << std::endl;
46  return 1;
47  }
48  std::filesystem::path abs_datadir = std::filesystem::absolute(argv[1]);
50  gArgs.ForceSetArg("-datadir", abs_datadir.string());
51 
52 
53  // SETUP: Misc Globals
55  const CChainParams& chainparams = Params();
56 
57  kernel::Context kernel_context{};
58  // We can't use a goto here, but we can use an assert since none of the
59  // things instantiated so far requires running the epilogue to be torn down
60  // properly
61  assert(!kernel::SanityChecks(kernel_context).has_value());
62 
63  // Necessary for CheckInputScripts (eventually called by ProcessNewBlock),
64  // which will try the script cache first and fall back to actually
65  // performing the check with the signature cache.
66  kernel::ValidationCacheSizes validation_cache_sizes{};
67  Assert(InitSignatureCache(validation_cache_sizes.signature_cache_bytes));
68  Assert(InitScriptExecutionCache(validation_cache_sizes.script_execution_cache_bytes));
69 
70 
71  // SETUP: Scheduling and Background Signals
72  CScheduler scheduler{};
73  // Start the lightweight task scheduler thread
74  scheduler.m_service_thread = std::thread(util::TraceThread, "scheduler", [&] { scheduler.serviceQueue(); });
75 
76  // Gather some entropy once per minute.
77  scheduler.scheduleEvery(RandAddPeriodic, std::chrono::minutes{1});
78 
80 
81 
82  // SETUP: Chainstate
83  const ChainstateManager::Options chainman_opts{
84  .chainparams = chainparams,
85  .adjusted_time_callback = NodeClock::now,
86  };
87  ChainstateManager chainman{chainman_opts};
88 
89  node::CacheSizes cache_sizes;
90  cache_sizes.block_tree_db = 2 << 20;
91  cache_sizes.coins_db = 2 << 22;
92  cache_sizes.coins = (450 << 20) - (2 << 20) - (2 << 22);
94  options.check_interrupt = [] { return false; };
95  auto [status, error] = node::LoadChainstate(chainman, cache_sizes, options);
97  std::cerr << "Failed to load Chain state from your datadir." << std::endl;
98  goto epilogue;
99  } else {
100  std::tie(status, error) = node::VerifyLoadedChainstate(chainman, options);
101  if (status != node::ChainstateLoadStatus::SUCCESS) {
102  std::cerr << "Failed to verify loaded Chain state from your datadir." << std::endl;
103  goto epilogue;
104  }
105  }
106 
107  for (Chainstate* chainstate : WITH_LOCK(::cs_main, return chainman.GetAll())) {
108  BlockValidationState state;
109  if (!chainstate->ActivateBestChain(state, nullptr)) {
110  std::cerr << "Failed to connect best block (" << state.ToString() << ")" << std::endl;
111  goto epilogue;
112  }
113  }
114 
115  // Main program logic starts here
116  std::cout
117  << "Hello! I'm going to print out some information about your datadir." << std::endl
118  << "\t" << "Path: " << gArgs.GetDataDirNet() << std::endl;
119  {
120  LOCK(chainman.GetMutex());
121  std::cout
122  << "\t" << "Reindexing: " << std::boolalpha << node::fReindex.load() << std::noboolalpha << std::endl
123  << "\t" << "Snapshot Active: " << std::boolalpha << chainman.IsSnapshotActive() << std::noboolalpha << std::endl
124  << "\t" << "Active Height: " << chainman.ActiveHeight() << std::endl
125  << "\t" << "Active IBD: " << std::boolalpha << chainman.ActiveChainstate().IsInitialBlockDownload() << std::noboolalpha << std::endl;
126  CBlockIndex* tip = chainman.ActiveTip();
127  if (tip) {
128  std::cout << "\t" << tip->ToString() << std::endl;
129  }
130  }
131 
132  for (std::string line; std::getline(std::cin, line);) {
133  if (line.empty()) {
134  std::cerr << "Empty line found" << std::endl;
135  break;
136  }
137 
138  std::shared_ptr<CBlock> blockptr = std::make_shared<CBlock>();
139  CBlock& block = *blockptr;
140 
141  if (!DecodeHexBlk(block, line)) {
142  std::cerr << "Block decode failed" << std::endl;
143  break;
144  }
145 
146  if (block.vtx.empty() || !block.vtx[0]->IsCoinBase()) {
147  std::cerr << "Block does not start with a coinbase" << std::endl;
148  break;
149  }
150 
151  uint256 hash = block.GetHash();
152  {
153  LOCK(cs_main);
154  const CBlockIndex* pindex = chainman.m_blockman.LookupBlockIndex(hash);
155  if (pindex) {
156  if (pindex->IsValid(BLOCK_VALID_SCRIPTS)) {
157  std::cerr << "duplicate" << std::endl;
158  break;
159  }
160  if (pindex->nStatus & BLOCK_FAILED_MASK) {
161  std::cerr << "duplicate-invalid" << std::endl;
162  break;
163  }
164  }
165  }
166 
167  {
168  LOCK(cs_main);
169  const CBlockIndex* pindex = chainman.m_blockman.LookupBlockIndex(block.hashPrevBlock);
170  if (pindex) {
171  chainman.UpdateUncommittedBlockStructures(block, pindex);
172  }
173  }
174 
175  // Adapted from rpc/mining.cpp
177  {
178  public:
179  uint256 hash;
180  bool found;
182 
183  explicit submitblock_StateCatcher(const uint256& hashIn) : hash(hashIn), found(false), state() {}
184 
185  protected:
186  void BlockChecked(const CBlock& block, const BlockValidationState& stateIn) override
187  {
188  if (block.GetHash() != hash)
189  return;
190  found = true;
191  state = stateIn;
192  }
193  };
194 
195  bool new_block;
196  auto sc = std::make_shared<submitblock_StateCatcher>(block.GetHash());
198  bool accepted = chainman.ProcessNewBlock(blockptr, /*force_processing=*/true, /*min_pow_checked=*/true, /*new_block=*/&new_block);
200  if (!new_block && accepted) {
201  std::cerr << "duplicate" << std::endl;
202  break;
203  }
204  if (!sc->found) {
205  std::cerr << "inconclusive" << std::endl;
206  break;
207  }
208  std::cout << sc->state.ToString() << std::endl;
209  switch (sc->state.GetResult()) {
211  std::cerr << "initial value. Block has not yet been rejected" << std::endl;
212  break;
214  std::cerr << "the block header may be on a too-little-work chain" << std::endl;
215  break;
217  std::cerr << "invalid by consensus rules (excluding any below reasons)" << std::endl;
218  break;
220  std::cerr << "Invalid by a change to consensus rules more recent than SegWit." << std::endl;
221  break;
223  std::cerr << "this block was cached as being invalid and we didn't store the reason why" << std::endl;
224  break;
226  std::cerr << "invalid proof of work or time too old" << std::endl;
227  break;
229  std::cerr << "the block's data didn't match the data committed to by the PoW" << std::endl;
230  break;
232  std::cerr << "We don't have the previous block the checked one is built on" << std::endl;
233  break;
235  std::cerr << "A block this one builds on is invalid" << std::endl;
236  break;
238  std::cerr << "block timestamp was > 2 hours in the future (or our clock is bad)" << std::endl;
239  break;
241  std::cerr << "the block failed to meet one of our checkpoints" << std::endl;
242  break;
243  }
244  }
245 
246 epilogue:
247  // Without this precise shutdown sequence, there will be a lot of nullptr
248  // dereferencing and UB.
249  scheduler.stop();
250  if (chainman.m_load_block.joinable()) chainman.m_load_block.join();
252 
254  {
255  LOCK(cs_main);
256  for (Chainstate* chainstate : chainman.GetAll()) {
257  if (chainstate->CanFlushToDisk()) {
258  chainstate->ForceFlushStateToDisk();
259  chainstate->ResetCoinsViews();
260  }
261  }
262  }
264 }
int main(int argc, char *argv[])
@ BLOCK_VALID_SCRIPTS
Scripts & signatures ok. Implies all parents are also at least SCRIPTS.
Definition: chain.h:121
@ BLOCK_FAILED_MASK
Definition: chain.h:133
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate.
Definition: validation.cpp:121
void SelectParams(const std::string &network)
Sets the params returned by Params() to those for the given chain name.
const CChainParams & Params()
Return the currently selected parameters.
#define Assert(val)
Identity function.
Definition: check.h:74
void ForceSetArg(const std::string &strArg, const std::string &strValue)
Definition: system.cpp:693
const fs::path & GetDataDirNet() const
Get data directory path with appended network identifier.
Definition: system.h:303
static const std::string MAIN
Chain name strings.
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:152
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:313
CChainParams defines various tweakable parameters of a given instance of the Bitcoin system.
Definition: chainparams.h:70
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:39
std::thread m_service_thread
Definition: scheduler.h:44
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:438
Provides an interface for creating and interacting with one or two chainstates: an IBD chainstate gen...
Definition: validation.h:800
std::string ToString() const
Definition: validation.h:127
void BlockChecked(const CBlock &block, const BlockValidationState &stateIn) override
Notifies listeners of a block validation result.
Definition: mining.cpp:920
submitblock_StateCatcher(const uint256 &hashIn)
Definition: mining.cpp:917
BlockValidationState state
Definition: mining.cpp:915
256-bit opaque blob.
Definition: uint256.h:119
@ 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)
Definition: core_read.cpp:219
static path absolute(const path &p)
Definition: fs.h:81
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:188
std::optional< bilingual_str > SanityChecks(const Context &)
Ensure a usable environment with all necessary library support.
Definition: checks.cpp:16
ChainstateLoadResult LoadChainstate(ChainstateManager &chainman, const CacheSizes &cache_sizes, const ChainstateLoadOptions &options)
This sequence can have 4 types of outcomes:
Definition: chainstate.cpp:28
ChainstateLoadResult VerifyLoadedChainstate(ChainstateManager &chainman, const ChainstateLoadOptions &options)
Definition: chainstate.cpp:152
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:16
void RandAddPeriodic() noexcept
Gather entropy from various expensive sources, and feed them to the PRNG state.
Definition: random.cpp:582
bool InitSignatureCache(size_t max_size_bytes)
Definition: sigcache.cpp:96
static time_point now() noexcept
Return current system time or mocked time, if set.
Definition: time.cpp:72
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:20
int64_t coins
Definition: caches.h:17
int64_t block_tree_db
Definition: caches.h:15
int64_t coins_db
Definition: caches.h:16
std::function< bool()> check_interrupt
Definition: chainstate.h:30
#define LOCK(cs)
Definition: sync.h:261
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
Definition: sync.h:305
bool error(const char *fmt, const Args &... args)
Definition: system.h:48
ArgsManager gArgs
Definition: system.cpp:86
bool InitScriptExecutionCache(size_t max_size_bytes)
Initializes the script-execution cache.
void StopScriptCheckWorkerThreads()
Stop all of the script checking worker threads.
assert(!tx.IsCoinBase())
CMainSignals & GetMainSignals()
void UnregisterSharedValidationInterface(std::shared_ptr< CValidationInterface > callbacks)
Unregister subscriber.
void RegisterSharedValidationInterface(std::shared_ptr< CValidationInterface > callbacks)
Register subscriber.