Bitcoin Core  0.20.99
P2P Digital Currency
base.cpp
Go to the documentation of this file.
1 // Copyright (c) 2017-2020 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 #include <chainparams.h>
6 #include <index/base.h>
7 #include <node/ui_interface.h>
8 #include <shutdown.h>
9 #include <tinyformat.h>
10 #include <util/system.h>
11 #include <util/translation.h>
12 #include <validation.h>
13 #include <warnings.h>
14 
15 constexpr char DB_BEST_BLOCK = 'B';
16 
17 constexpr int64_t SYNC_LOG_INTERVAL = 30; // seconds
18 constexpr int64_t SYNC_LOCATOR_WRITE_INTERVAL = 30; // seconds
19 
20 template <typename... Args>
21 static void FatalError(const char* fmt, const Args&... args)
22 {
23  std::string strMessage = tfm::format(fmt, args...);
24  SetMiscWarning(Untranslated(strMessage));
25  LogPrintf("*** %s\n", strMessage);
26  AbortError(_("A fatal internal error occurred, see debug.log for details"));
27  StartShutdown();
28 }
29 
30 BaseIndex::DB::DB(const fs::path& path, size_t n_cache_size, bool f_memory, bool f_wipe, bool f_obfuscate) :
31  CDBWrapper(path, n_cache_size, f_memory, f_wipe, f_obfuscate)
32 {}
33 
35 {
36  bool success = Read(DB_BEST_BLOCK, locator);
37  if (!success) {
38  locator.SetNull();
39  }
40  return success;
41 }
42 
44 {
45  batch.Write(DB_BEST_BLOCK, locator);
46 }
47 
49 {
50  Interrupt();
51  Stop();
52 }
53 
55 {
56  CBlockLocator locator;
57  if (!GetDB().ReadBestBlock(locator)) {
58  locator.SetNull();
59  }
60 
61  LOCK(cs_main);
62  if (locator.IsNull()) {
63  m_best_block_index = nullptr;
64  } else {
66  }
68  return true;
69 }
70 
72 {
74 
75  if (!pindex_prev) {
77  }
78 
79  const CBlockIndex* pindex = ::ChainActive().Next(pindex_prev);
80  if (pindex) {
81  return pindex;
82  }
83 
84  return ::ChainActive().Next(::ChainActive().FindFork(pindex_prev));
85 }
86 
88 {
89  const CBlockIndex* pindex = m_best_block_index.load();
90  if (!m_synced) {
91  auto& consensus_params = Params().GetConsensus();
92 
93  int64_t last_log_time = 0;
94  int64_t last_locator_write_time = 0;
95  while (true) {
96  if (m_interrupt) {
97  m_best_block_index = pindex;
98  // No need to handle errors in Commit. If it fails, the error will be already be
99  // logged. The best way to recover is to continue, as index cannot be corrupted by
100  // a missed commit to disk for an advanced index state.
101  Commit();
102  return;
103  }
104 
105  {
106  LOCK(cs_main);
107  const CBlockIndex* pindex_next = NextSyncBlock(pindex);
108  if (!pindex_next) {
109  m_best_block_index = pindex;
110  m_synced = true;
111  // No need to handle errors in Commit. See rationale above.
112  Commit();
113  break;
114  }
115  if (pindex_next->pprev != pindex && !Rewind(pindex, pindex_next->pprev)) {
116  FatalError("%s: Failed to rewind index %s to a previous chain tip",
117  __func__, GetName());
118  return;
119  }
120  pindex = pindex_next;
121  }
122 
123  int64_t current_time = GetTime();
124  if (last_log_time + SYNC_LOG_INTERVAL < current_time) {
125  LogPrintf("Syncing %s with block chain from height %d\n",
126  GetName(), pindex->nHeight);
127  last_log_time = current_time;
128  }
129 
130  if (last_locator_write_time + SYNC_LOCATOR_WRITE_INTERVAL < current_time) {
131  m_best_block_index = pindex;
132  last_locator_write_time = current_time;
133  // No need to handle errors in Commit. See rationale above.
134  Commit();
135  }
136 
137  CBlock block;
138  if (!ReadBlockFromDisk(block, pindex, consensus_params)) {
139  FatalError("%s: Failed to read block %s from disk",
140  __func__, pindex->GetBlockHash().ToString());
141  return;
142  }
143  if (!WriteBlock(block, pindex)) {
144  FatalError("%s: Failed to write block %s to index database",
145  __func__, pindex->GetBlockHash().ToString());
146  return;
147  }
148  }
149  }
150 
151  if (pindex) {
152  LogPrintf("%s is enabled at height %d\n", GetName(), pindex->nHeight);
153  } else {
154  LogPrintf("%s is enabled\n", GetName());
155  }
156 }
157 
159 {
160  CDBBatch batch(GetDB());
161  if (!CommitInternal(batch) || !GetDB().WriteBatch(batch)) {
162  return error("%s: Failed to commit latest %s state", __func__, GetName());
163  }
164  return true;
165 }
166 
168 {
169  LOCK(cs_main);
170  GetDB().WriteBestBlock(batch, ::ChainActive().GetLocator(m_best_block_index));
171  return true;
172 }
173 
174 bool BaseIndex::Rewind(const CBlockIndex* current_tip, const CBlockIndex* new_tip)
175 {
176  assert(current_tip == m_best_block_index);
177  assert(current_tip->GetAncestor(new_tip->nHeight) == new_tip);
178 
179  // In the case of a reorg, ensure persisted block locator is not stale.
180  m_best_block_index = new_tip;
181  if (!Commit()) {
182  // If commit fails, revert the best block index to avoid corruption.
183  m_best_block_index = current_tip;
184  return false;
185  }
186 
187  return true;
188 }
189 
190 void BaseIndex::BlockConnected(const std::shared_ptr<const CBlock>& block, const CBlockIndex* pindex)
191 {
192  if (!m_synced) {
193  return;
194  }
195 
196  const CBlockIndex* best_block_index = m_best_block_index.load();
197  if (!best_block_index) {
198  if (pindex->nHeight != 0) {
199  FatalError("%s: First block connected is not the genesis block (height=%d)",
200  __func__, pindex->nHeight);
201  return;
202  }
203  } else {
204  // Ensure block connects to an ancestor of the current best block. This should be the case
205  // most of the time, but may not be immediately after the sync thread catches up and sets
206  // m_synced. Consider the case where there is a reorg and the blocks on the stale branch are
207  // in the ValidationInterface queue backlog even after the sync thread has caught up to the
208  // new chain tip. In this unlikely event, log a warning and let the queue clear.
209  if (best_block_index->GetAncestor(pindex->nHeight - 1) != pindex->pprev) {
210  LogPrintf("%s: WARNING: Block %s does not connect to an ancestor of " /* Continued */
211  "known best chain (tip=%s); not updating index\n",
212  __func__, pindex->GetBlockHash().ToString(),
213  best_block_index->GetBlockHash().ToString());
214  return;
215  }
216  if (best_block_index != pindex->pprev && !Rewind(best_block_index, pindex->pprev)) {
217  FatalError("%s: Failed to rewind index %s to a previous chain tip",
218  __func__, GetName());
219  return;
220  }
221  }
222 
223  if (WriteBlock(*block, pindex)) {
224  m_best_block_index = pindex;
225  } else {
226  FatalError("%s: Failed to write block %s to index",
227  __func__, pindex->GetBlockHash().ToString());
228  return;
229  }
230 }
231 
233 {
234  if (!m_synced) {
235  return;
236  }
237 
238  const uint256& locator_tip_hash = locator.vHave.front();
239  const CBlockIndex* locator_tip_index;
240  {
241  LOCK(cs_main);
242  locator_tip_index = LookupBlockIndex(locator_tip_hash);
243  }
244 
245  if (!locator_tip_index) {
246  FatalError("%s: First block (hash=%s) in locator was not found",
247  __func__, locator_tip_hash.ToString());
248  return;
249  }
250 
251  // This checks that ChainStateFlushed callbacks are received after BlockConnected. The check may fail
252  // immediately after the sync thread catches up and sets m_synced. Consider the case where
253  // there is a reorg and the blocks on the stale branch are in the ValidationInterface queue
254  // backlog even after the sync thread has caught up to the new chain tip. In this unlikely
255  // event, log a warning and let the queue clear.
256  const CBlockIndex* best_block_index = m_best_block_index.load();
257  if (best_block_index->GetAncestor(locator_tip_index->nHeight) != locator_tip_index) {
258  LogPrintf("%s: WARNING: Locator contains block (hash=%s) not on known best " /* Continued */
259  "chain (tip=%s); not writing index locator\n",
260  __func__, locator_tip_hash.ToString(),
261  best_block_index->GetBlockHash().ToString());
262  return;
263  }
264 
265  // No need to handle errors in Commit. If it fails, the error will be already be logged. The
266  // best way to recover is to continue, as index cannot be corrupted by a missed commit to disk
267  // for an advanced index state.
268  Commit();
269 }
270 
272 {
274 
275  if (!m_synced) {
276  return false;
277  }
278 
279  {
280  // Skip the queue-draining stuff if we know we're caught up with
281  // ::ChainActive().Tip().
282  LOCK(cs_main);
283  const CBlockIndex* chain_tip = ::ChainActive().Tip();
284  const CBlockIndex* best_block_index = m_best_block_index.load();
285  if (best_block_index->GetAncestor(chain_tip->nHeight) == chain_tip) {
286  return true;
287  }
288  }
289 
290  LogPrintf("%s: %s is catching up on block notifications\n", __func__, GetName());
292  return true;
293 }
294 
296 {
297  m_interrupt();
298 }
299 
301 {
302  // Need to register this ValidationInterface before running Init(), so that
303  // callbacks are not missed if Init sets m_synced to true.
305  if (!Init()) {
306  FatalError("%s: %s failed to initialize", __func__, GetName());
307  return;
308  }
309 
310  m_thread_sync = std::thread(&TraceThread<std::function<void()>>, GetName(),
311  std::bind(&BaseIndex::ThreadSync, this));
312 }
313 
315 {
317 
318  if (m_thread_sync.joinable()) {
319  m_thread_sync.join();
320  }
321 }
322 
324 {
325  IndexSummary summary{};
326  summary.name = GetName();
327  summary.synced = m_synced;
328  summary.best_block_height = m_best_block_index.load()->nHeight;
329  return summary;
330 }
constexpr int64_t SYNC_LOCATOR_WRITE_INTERVAL
Definition: base.cpp:18
void SyncWithValidationInterfaceQueue()
This is a synonym for the following, which asserts certain locks are not held: std::promise<void> pro...
bool Commit()
Write the current index state (eg.
Definition: base.cpp:158
virtual bool Init()
Initialize internal state from the database and block index.
Definition: base.cpp:54
CThreadInterrupt m_interrupt
Definition: base.h:60
void ChainStateFlushed(const CBlockLocator &locator) override
Notifies listeners of the new active block chain on-disk.
Definition: base.cpp:232
Describes a place in the block chain to another node such that if the other node doesn&#39;t have the sam...
Definition: block.h:114
std::atomic< bool > m_synced
Whether the index is in sync with the main chain.
Definition: base.h:54
CBlockIndex * pprev
pointer to the index of the predecessor of this block
Definition: chain.h:144
Batch of changes queued to be written to a CDBWrapper.
Definition: dbwrapper.h:46
Definition: block.h:62
CChain & ChainActive()
Please prefer the identical ChainstateManager::ActiveChain.
Definition: validation.cpp:113
void SetMiscWarning(const bilingual_str &warning)
Definition: warnings.cpp:20
bool ReadBlockFromDisk(CBlock &block, const FlatFilePos &pos, const Consensus::Params &consensusParams)
Functions for disk access for blocks.
bilingual_str Untranslated(std::string original)
Mark a bilingual_str as untranslated.
Definition: translation.h:40
constexpr int64_t SYNC_LOG_INTERVAL
Definition: base.cpp:17
static void LogPrintf(const char *fmt, const Args &... args)
Definition: logging.h:166
CBlockIndex * Genesis() const
Returns the index entry for the genesis block of this chain, or nullptr if none.
Definition: chain.h:385
bool IsNull() const
Definition: block.h:135
virtual bool Rewind(const CBlockIndex *current_tip, const CBlockIndex *new_tip)
Rewind index to an earlier chain tip during a chain reorg.
Definition: base.cpp:174
void Stop()
Stops the instance from staying in sync with blockchain updates.
Definition: base.cpp:314
std::thread m_thread_sync
Definition: base.h:59
virtual bool WriteBlock(const CBlock &block, const CBlockIndex *pindex)
Write update index entries for a newly connected block.
Definition: base.h:88
uint256 GetBlockHash() const
Definition: chain.h:233
virtual ~BaseIndex()
Destructor interrupts sync thread if running and blocks until it exits.
Definition: base.cpp:48
void SetNull()
Definition: block.h:130
void Interrupt()
Definition: base.cpp:295
void WriteBestBlock(CDBBatch &batch, const CBlockLocator &locator)
Write block locator of the chain that the txindex is in sync with.
Definition: base.cpp:43
static const CBlockIndex * NextSyncBlock(const CBlockIndex *pindex_prev) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
Definition: base.cpp:71
#define LOCK(cs)
Definition: sync.h:230
bilingual_str _(const char *psz)
Translation function.
Definition: translation.h:57
AssertLockHeld(mempool.cs)
void format(std::ostream &out, const char *fmt, const Args &... args)
Format list of arguments to the stream according to given format string.
Definition: tinyformat.h:1062
CBlockIndex * Next(const CBlockIndex *pindex) const
Find the successor of a block in this chain, or nullptr if the given index is not found or is the tip...
Definition: chain.h:407
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate...
Definition: validation.cpp:129
constexpr auto AbortError
Definition: ui_interface.h:117
void Write(const K &key, const V &value)
Definition: dbwrapper.h:72
void Start()
Start initializes the sync state and registers the instance as a ValidationInterface so that it stays...
Definition: base.cpp:300
virtual bool CommitInternal(CDBBatch &batch)
Virtual method called internally by Commit that can be overridden to atomically commit more index sta...
Definition: base.cpp:167
std::string ToString() const
Definition: uint256.cpp:64
std::vector< uint256 > vHave
Definition: block.h:116
bool Read(const K &key, V &value) const
Definition: dbwrapper.h:230
void TraceThread(const char *name, Callable func)
Definition: system.h:432
CBlockIndex * LookupBlockIndex(const uint256 &hash)
Definition: validation.cpp:173
void UnregisterValidationInterface(CValidationInterface *callbacks)
Unregister subscriber.
256-bit opaque blob.
Definition: uint256.h:123
std::string name
Definition: base.h:17
#define EXCLUSIVE_LOCKS_REQUIRED(...)
Definition: threadsafety.h:49
The block chain is a tree shaped structure starting with the genesis block at the root...
Definition: chain.h:137
const CChainParams & Params()
Return the currently selected parameters.
void BlockConnected(const std::shared_ptr< const CBlock > &block, const CBlockIndex *pindex) override
Notifies listeners of a block being connected.
Definition: base.cpp:190
static void FatalError(const char *fmt, const Args &... args)
Definition: base.cpp:21
CBlockIndex * FindForkInGlobalIndex(const CChain &chain, const CBlockLocator &locator)
Find the last common block between the parameter chain and a locator.
Definition: validation.cpp:180
constexpr char DB_BEST_BLOCK
Definition: base.cpp:15
CBlockIndex * Tip() const
Returns the index entry for the tip of this chain, or nullptr if none.
Definition: chain.h:390
#define AssertLockNotHeld(cs)
Definition: sync.h:80
void StartShutdown()
Definition: shutdown.cpp:12
void RegisterValidationInterface(CValidationInterface *callbacks)
Register subscriber.
void ThreadSync()
Sync the index with the block index starting from the current best block.
Definition: base.cpp:87
virtual const char * GetName() const =0
Get the name of the index for display in logs.
bool WriteBatch(CDBBatch &batch, bool fSync=false)
Definition: dbwrapper.cpp:183
int nHeight
height of the entry in the chain. The genesis block has height 0
Definition: chain.h:150
DB(const fs::path &path, size_t n_cache_size, bool f_memory=false, bool f_wipe=false, bool f_obfuscate=false)
Definition: base.cpp:30
const Consensus::Params & GetConsensus() const
Definition: chainparams.h:65
bool ReadBestBlock(CBlockLocator &locator) const
Read block locator of the chain that the txindex is in sync with.
Definition: base.cpp:34
CBlockIndex * GetAncestor(int height)
Efficiently find an ancestor of this block.
Definition: chain.cpp:111
int64_t GetTime()
Return system time (or mocked time, if set)
Definition: time.cpp:23
virtual DB & GetDB() const =0
bool error(const char *fmt, const Args &... args)
Definition: system.h:52
std::atomic< const CBlockIndex * > m_best_block_index
The last block in the chain that the index is in sync with.
Definition: base.h:57
bool BlockUntilSyncedToCurrentChain() const
Blocks the current thread until the index is caught up to the current state of the block chain...
Definition: base.cpp:271
IndexSummary GetSummary() const
Get a summary of the index and its state.
Definition: base.cpp:323