Bitcoin Core  29.1.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/chainparams.h>
16 #include <kernel/checks.h>
17 #include <kernel/context.h>
18 #include <kernel/warning.h>
19 
20 #include <consensus/validation.h>
21 #include <core_io.h>
22 #include <kernel/caches.h>
23 #include <logging.h>
24 #include <node/blockstorage.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>
30 #include <util/signalinterrupt.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 
43 int 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 
110 
111  // SETUP: Chainstate
112  auto chainparams = CChainParams::Main();
113  const ChainstateManager::Options chainman_opts{
114  .chainparams = *chainparams,
115  .datadir = abs_datadir,
116  .notifications = *notifications,
117  .signals = &validation_signals,
118  };
119  const node::BlockManager::Options blockman_opts{
120  .chainparams = chainman_opts.chainparams,
121  .blocks_dir = abs_datadir / "blocks",
122  .notifications = chainman_opts.notifications,
123  .block_tree_db_params = DBParams{
124  .path = abs_datadir / "blocks" / "index",
125  .cache_bytes = cache_sizes.block_tree_db,
126  },
127  };
128  util::SignalInterrupt interrupt;
129  ChainstateManager chainman{interrupt, chainman_opts, blockman_opts};
130 
132  auto [status, error] = node::LoadChainstate(chainman, cache_sizes, options);
133  if (status != node::ChainstateLoadStatus::SUCCESS) {
134  std::cerr << "Failed to load Chain state from your datadir." << std::endl;
135  goto epilogue;
136  } else {
137  std::tie(status, error) = node::VerifyLoadedChainstate(chainman, options);
138  if (status != node::ChainstateLoadStatus::SUCCESS) {
139  std::cerr << "Failed to verify loaded Chain state from your datadir." << std::endl;
140  goto epilogue;
141  }
142  }
143 
144  for (Chainstate* chainstate : WITH_LOCK(::cs_main, return chainman.GetAll())) {
145  BlockValidationState state;
146  if (!chainstate->ActivateBestChain(state, nullptr)) {
147  std::cerr << "Failed to connect best block (" << state.ToString() << ")" << std::endl;
148  goto epilogue;
149  }
150  }
151 
152  // Main program logic starts here
153  std::cout
154  << "Hello! I'm going to print out some information about your datadir." << std::endl
155  << "\t"
156  << "Path: " << abs_datadir << std::endl;
157  {
158  LOCK(chainman.GetMutex());
159  std::cout
160  << "\t" << "Blockfiles Indexed: " << std::boolalpha << chainman.m_blockman.m_blockfiles_indexed.load() << std::noboolalpha << std::endl
161  << "\t" << "Snapshot Active: " << std::boolalpha << chainman.IsSnapshotActive() << std::noboolalpha << std::endl
162  << "\t" << "Active Height: " << chainman.ActiveHeight() << std::endl
163  << "\t" << "Active IBD: " << std::boolalpha << chainman.IsInitialBlockDownload() << std::noboolalpha << std::endl;
164  CBlockIndex* tip = chainman.ActiveTip();
165  if (tip) {
166  std::cout << "\t" << tip->ToString() << std::endl;
167  }
168  }
169 
170  for (std::string line; std::getline(std::cin, line);) {
171  if (line.empty()) {
172  std::cerr << "Empty line found" << std::endl;
173  break;
174  }
175 
176  std::shared_ptr<CBlock> blockptr = std::make_shared<CBlock>();
177  CBlock& block = *blockptr;
178 
179  if (!DecodeHexBlk(block, line)) {
180  std::cerr << "Block decode failed" << std::endl;
181  break;
182  }
183 
184  {
185  LOCK(cs_main);
186  const CBlockIndex* pindex = chainman.m_blockman.LookupBlockIndex(block.hashPrevBlock);
187  if (pindex) {
188  chainman.UpdateUncommittedBlockStructures(block, pindex);
189  }
190  }
191 
192  // Adapted from rpc/mining.cpp
194  {
195  public:
196  uint256 hash;
197  bool found;
199 
200  explicit submitblock_StateCatcher(const uint256& hashIn) : hash(hashIn), found(false), state() {}
201 
202  protected:
203  void BlockChecked(const CBlock& block, const BlockValidationState& stateIn) override
204  {
205  if (block.GetHash() != hash)
206  return;
207  found = true;
208  state = stateIn;
209  }
210  };
211 
212  bool new_block;
213  auto sc = std::make_shared<submitblock_StateCatcher>(block.GetHash());
214  validation_signals.RegisterSharedValidationInterface(sc);
215  bool accepted = chainman.ProcessNewBlock(blockptr, /*force_processing=*/true, /*min_pow_checked=*/true, /*new_block=*/&new_block);
216  validation_signals.UnregisterSharedValidationInterface(sc);
217  if (!new_block && accepted) {
218  std::cerr << "duplicate" << std::endl;
219  break;
220  }
221  if (!sc->found) {
222  std::cerr << "inconclusive" << std::endl;
223  break;
224  }
225  std::cout << sc->state.ToString() << std::endl;
226  switch (sc->state.GetResult()) {
228  std::cerr << "initial value. Block has not yet been rejected" << std::endl;
229  break;
231  std::cerr << "the block header may be on a too-little-work chain" << std::endl;
232  break;
234  std::cerr << "invalid by consensus rules (excluding any below reasons)" << std::endl;
235  break;
237  std::cerr << "this block was cached as being invalid and we didn't store the reason why" << std::endl;
238  break;
240  std::cerr << "invalid proof of work or time too old" << std::endl;
241  break;
243  std::cerr << "the block's data didn't match the data committed to by the PoW" << std::endl;
244  break;
246  std::cerr << "We don't have the previous block the checked one is built on" << std::endl;
247  break;
249  std::cerr << "A block this one builds on is invalid" << std::endl;
250  break;
252  std::cerr << "block timestamp was > 2 hours in the future (or our clock is bad)" << std::endl;
253  break;
255  std::cerr << "the block failed to meet one of our checkpoints" << std::endl;
256  break;
257  }
258  }
259 
260 epilogue:
261  // Without this precise shutdown sequence, there will be a lot of nullptr
262  // dereferencing and UB.
263  validation_signals.FlushBackgroundCallbacks();
264  {
265  LOCK(cs_main);
266  for (Chainstate* chainstate : chainman.GetAll()) {
267  if (chainstate->CanFlushToDisk()) {
268  chainstate->ForceFlushStateToDisk();
269  chainstate->ResetCoinsViews();
270  }
271  }
272  }
273 }
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:111
virtual void warningUnset(Warning id)
fs::path path
Location in the filesystem where leveldb data will be stored.
Definition: dbwrapper.h:36
std::string ToString() const
Definition: chain.cpp:15
bool DecodeHexBlk(CBlock &, const std::string &strHexBlk)
Definition: core_read.cpp:220
SynchronizationState
Current sync state passed to tip changed callbacks.
Definition: validation.h:85
BCLog::Logger & LogInstance()
Definition: logging.cpp:26
assert(!tx.IsCoinBase())
BlockValidationState state
Definition: mining.cpp:1019
Bilingual messages:
Definition: translation.h:24
Definition: block.h:68
ChainstateLoadResult VerifyLoadedChainstate(ChainstateManager &chainman, const ChainstateLoadOptions &options)
Definition: chainstate.cpp:229
We don&#39;t have the previous block the checked one is built on.
Provides an interface for creating and interacting with one or two chainstates: an IBD chainstate gen...
Definition: validation.h:865
invalid proof of work or time too old
std::variant< std::monostate, Interrupted > InterruptResult
Simple result type for functions that need to propagate an interrupt status and don&#39;t have other retu...
virtual void progress(const bilingual_str &title, int progress_percent, bool resume_possible)
void BlockChecked(const CBlock &block, const BlockValidationState &stateIn) override
Notifies listeners of a block validation result.
Definition: mining.cpp:1024
An options struct for ChainstateManager, more ergonomically referred to as ChainstateManager::Options...
the block header may be on a too-little-work chain
util::Result< void > SanityChecks(const Context &)
Ensure a usable environment with all necessary library support.
Definition: checks.cpp:15
int main(int argc, char *argv[])
submitblock_StateCatcher(const uint256 &hashIn)
Definition: mining.cpp:1021
Warning
Definition: warning.h:9
Implement this to subscribe to events generated in validation and mempool.
static std::unique_ptr< const CChainParams > Main()
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&#39;...
initial value. Block has not yet been rejected
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...
An options struct for BlockManager, more ergonomically referred to as BlockManager::Options due to th...
virtual void headerTip(SynchronizationState state, int64_t height, int64_t timestamp, bool presync)
Chainstate stores and provides an API to update our local knowledge of the current best chain...
Definition: validation.h:504
this block was cached as being invalid and we didn&#39;t store the reason why
#define LOCK(cs)
Definition: sync.h:257
std::string ToString() const
Definition: validation.h:112
the block failed to meet one of our checkpoints
const CChainParams & chainparams
virtual void warningSet(Warning id, const bilingual_str &message)
static constexpr size_t DEFAULT_KERNEL_CACHE
Suggested default amount of cache reserved for the kernel (bytes)
Definition: caches.h:13
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
A base class defining functions for notifying about certain kernel events.
#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.
Helper class that manages an interrupt flag, and allows a thread or signal to interrupt another threa...
uint256 GetHash() const
Definition: block.cpp:11
256-bit opaque blob.
Definition: uint256.h:201
invalid by consensus rules (excluding any below reasons)
the block&#39;s data didn&#39;t match the data committed to by the PoW
std::string original
Definition: translation.h:25
The block chain is a tree shaped structure starting with the genesis block at the root...
Definition: chain.h:140
A block this one builds on is invalid.
Context struct holding the kernel library&#39;s logically global state, and passed to external libbitcoin...
Definition: context.h:16
Application-specific storage settings.
Definition: dbwrapper.h:34
block timestamp was > 2 hours in the future (or our clock is bad)
ChainstateLoadResult LoadChainstate(ChainstateManager &chainman, const CacheSizes &cache_sizes, const ChainstateLoadOptions &options)
Definition: chainstate.cpp:144
Path class wrapper to block calls to the fs::path(std::string) implicit constructor and the fs::path:...
Definition: fs.h:32
static path absolute(const path &p)
Definition: fs.h:82
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate...
Definition: cs_main.cpp:8
virtual InterruptResult blockTip(SynchronizationState state, CBlockIndex &index)