BSHA3  0.17.99
P2P Blockchain, based on Bitcoin
base.cpp
Go to the documentation of this file.
1 // Copyright (c) 2017-2018 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 <shutdown.h>
8 #include <tinyformat.h>
9 #include <ui_interface.h>
10 #include <util.h>
11 #include <validation.h>
12 #include <warnings.h>
13 
14 constexpr char DB_BEST_BLOCK = 'B';
15 
16 constexpr int64_t SYNC_LOG_INTERVAL = 30; // seconds
17 constexpr int64_t SYNC_LOCATOR_WRITE_INTERVAL = 30; // seconds
18 
19 template<typename... Args>
20 static void FatalError(const char* fmt, const Args&... args)
21 {
22  std::string strMessage = tfm::format(fmt, args...);
23  SetMiscWarning(strMessage);
24  LogPrintf("*** %s\n", strMessage);
25  uiInterface.ThreadSafeMessageBox(
26  "Error: A fatal internal error occurred, see debug.log for details",
28  StartShutdown();
29 }
30 
31 BaseIndex::DB::DB(const fs::path& path, size_t n_cache_size, bool f_memory, bool f_wipe, bool f_obfuscate) :
32  CDBWrapper(path, n_cache_size, f_memory, f_wipe, f_obfuscate)
33 {}
34 
36 {
37  bool success = Read(DB_BEST_BLOCK, locator);
38  if (!success) {
39  locator.SetNull();
40  }
41  return success;
42 }
43 
45 {
46  return Write(DB_BEST_BLOCK, locator);
47 }
48 
50 {
51  Interrupt();
52  Stop();
53 }
54 
56 {
57  CBlockLocator locator;
58  if (!GetDB().ReadBestBlock(locator)) {
59  locator.SetNull();
60  }
61 
62  LOCK(cs_main);
65  return true;
66 }
67 
68 static const CBlockIndex* NextSyncBlock(const CBlockIndex* pindex_prev) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
69 {
71 
72  if (!pindex_prev) {
73  return chainActive.Genesis();
74  }
75 
76  const CBlockIndex* pindex = chainActive.Next(pindex_prev);
77  if (pindex) {
78  return pindex;
79  }
80 
81  return chainActive.Next(chainActive.FindFork(pindex_prev));
82 }
83 
85 {
86  const CBlockIndex* pindex = m_best_block_index.load();
87  if (!m_synced) {
88  auto& consensus_params = Params().GetConsensus();
89 
90  int64_t last_log_time = 0;
91  int64_t last_locator_write_time = 0;
92  while (true) {
93  if (m_interrupt) {
94  WriteBestBlock(pindex);
95  return;
96  }
97 
98  {
99  LOCK(cs_main);
100  const CBlockIndex* pindex_next = NextSyncBlock(pindex);
101  if (!pindex_next) {
102  WriteBestBlock(pindex);
103  m_best_block_index = pindex;
104  m_synced = true;
105  break;
106  }
107  pindex = pindex_next;
108  }
109 
110  int64_t current_time = GetTime();
111  if (last_log_time + SYNC_LOG_INTERVAL < current_time) {
112  LogPrintf("Syncing %s with block chain from height %d\n",
113  GetName(), pindex->nHeight);
114  last_log_time = current_time;
115  }
116 
117  if (last_locator_write_time + SYNC_LOCATOR_WRITE_INTERVAL < current_time) {
118  WriteBestBlock(pindex);
119  last_locator_write_time = current_time;
120  }
121 
122  CBlock block;
123  if (!ReadBlockFromDisk(block, pindex, consensus_params)) {
124  FatalError("%s: Failed to read block %s from disk",
125  __func__, pindex->GetBlockHash().ToString());
126  return;
127  }
128  if (!WriteBlock(block, pindex)) {
129  FatalError("%s: Failed to write block %s to index database",
130  __func__, pindex->GetBlockHash().ToString());
131  return;
132  }
133  }
134  }
135 
136  if (pindex) {
137  LogPrintf("%s is enabled at height %d\n", GetName(), pindex->nHeight);
138  } else {
139  LogPrintf("%s is enabled\n", GetName());
140  }
141 }
142 
143 bool BaseIndex::WriteBestBlock(const CBlockIndex* block_index)
144 {
145  LOCK(cs_main);
146  if (!GetDB().WriteBestBlock(chainActive.GetLocator(block_index))) {
147  return error("%s: Failed to write locator to disk", __func__);
148  }
149  return true;
150 }
151 
152 void BaseIndex::BlockConnected(const std::shared_ptr<const CBlock>& block, const CBlockIndex* pindex,
153  const std::vector<CTransactionRef>& txn_conflicted)
154 {
155  if (!m_synced) {
156  return;
157  }
158 
159  const CBlockIndex* best_block_index = m_best_block_index.load();
160  if (!best_block_index) {
161  if (pindex->nHeight != 0) {
162  FatalError("%s: First block connected is not the genesis block (height=%d)",
163  __func__, pindex->nHeight);
164  return;
165  }
166  } else {
167  // Ensure block connects to an ancestor of the current best block. This should be the case
168  // most of the time, but may not be immediately after the sync thread catches up and sets
169  // m_synced. Consider the case where there is a reorg and the blocks on the stale branch are
170  // in the ValidationInterface queue backlog even after the sync thread has caught up to the
171  // new chain tip. In this unlikely event, log a warning and let the queue clear.
172  if (best_block_index->GetAncestor(pindex->nHeight - 1) != pindex->pprev) {
173  LogPrintf("%s: WARNING: Block %s does not connect to an ancestor of " /* Continued */
174  "known best chain (tip=%s); not updating index\n",
175  __func__, pindex->GetBlockHash().ToString(),
176  best_block_index->GetBlockHash().ToString());
177  return;
178  }
179  }
180 
181  if (WriteBlock(*block, pindex)) {
182  m_best_block_index = pindex;
183  } else {
184  FatalError("%s: Failed to write block %s to index",
185  __func__, pindex->GetBlockHash().ToString());
186  return;
187  }
188 }
189 
191 {
192  if (!m_synced) {
193  return;
194  }
195 
196  const uint256& locator_tip_hash = locator.vHave.front();
197  const CBlockIndex* locator_tip_index;
198  {
199  LOCK(cs_main);
200  locator_tip_index = LookupBlockIndex(locator_tip_hash);
201  }
202 
203  if (!locator_tip_index) {
204  FatalError("%s: First block (hash=%s) in locator was not found",
205  __func__, locator_tip_hash.ToString());
206  return;
207  }
208 
209  // This checks that ChainStateFlushed callbacks are received after BlockConnected. The check may fail
210  // immediately after the sync thread catches up and sets m_synced. Consider the case where
211  // there is a reorg and the blocks on the stale branch are in the ValidationInterface queue
212  // backlog even after the sync thread has caught up to the new chain tip. In this unlikely
213  // event, log a warning and let the queue clear.
214  const CBlockIndex* best_block_index = m_best_block_index.load();
215  if (best_block_index->GetAncestor(locator_tip_index->nHeight) != locator_tip_index) {
216  LogPrintf("%s: WARNING: Locator contains block (hash=%s) not on known best " /* Continued */
217  "chain (tip=%s); not writing index locator\n",
218  __func__, locator_tip_hash.ToString(),
219  best_block_index->GetBlockHash().ToString());
220  return;
221  }
222 
223  if (!GetDB().WriteBestBlock(locator)) {
224  error("%s: Failed to write locator to disk", __func__);
225  }
226 }
227 
229 {
231 
232  if (!m_synced) {
233  return false;
234  }
235 
236  {
237  // Skip the queue-draining stuff if we know we're caught up with
238  // chainActive.Tip().
239  LOCK(cs_main);
240  const CBlockIndex* chain_tip = chainActive.Tip();
241  const CBlockIndex* best_block_index = m_best_block_index.load();
242  if (best_block_index->GetAncestor(chain_tip->nHeight) == chain_tip) {
243  return true;
244  }
245  }
246 
247  LogPrintf("%s: %s is catching up on block notifications\n", __func__, GetName());
249  return true;
250 }
251 
253 {
254  m_interrupt();
255 }
256 
258 {
259  // Need to register this ValidationInterface before running Init(), so that
260  // callbacks are not missed if Init sets m_synced to true.
262  if (!Init()) {
263  FatalError("%s: %s failed to initialize", __func__, GetName());
264  return;
265  }
266 
267  m_thread_sync = std::thread(&TraceThread<std::function<void()>>, GetName(),
268  std::bind(&BaseIndex::ThreadSync, this));
269 }
270 
272 {
274 
275  if (m_thread_sync.joinable()) {
276  m_thread_sync.join();
277  }
278 }
constexpr int64_t SYNC_LOCATOR_WRITE_INTERVAL
Definition: base.cpp:17
void SyncWithValidationInterfaceQueue()
This is a synonym for the following, which asserts certain locks are not held: std::promise<void> pro...
virtual bool Init()
Initialize internal state from the database and block index.
Definition: base.cpp:55
CThreadInterrupt m_interrupt
Definition: base.h:48
void ChainStateFlushed(const CBlockLocator &locator) override
Notifies listeners of the new active block chain on-disk.
Definition: base.cpp:190
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:128
std::atomic< bool > m_synced
Whether the index is in sync with the main chain.
Definition: base.h:42
CBlockIndex * pprev
pointer to the index of the predecessor of this block
Definition: chain.h:177
Definition: block.h:74
constexpr int64_t SYNC_LOG_INTERVAL
Definition: base.cpp:16
CBlockIndex * Genesis() const
Returns the index entry for the genesis block of this chain, or nullptr if none.
Definition: chain.h:440
void UnregisterValidationInterface(CValidationInterface *pwalletIn)
Unregister a wallet from core.
void Stop()
Stops the instance from staying in sync with blockchain updates.
Definition: base.cpp:271
std::thread m_thread_sync
Definition: base.h:47
virtual bool WriteBlock(const CBlock &block, const CBlockIndex *pindex)
Write update index entries for a newly connected block.
Definition: base.h:70
uint256 GetBlockHash() const
Definition: chain.h:292
#define AssertLockHeld(cs)
Definition: sync.h:70
virtual ~BaseIndex()
Destructor interrupts sync thread if running and blocks until it exits.
Definition: base.cpp:49
void SetNull()
Definition: block.h:146
void Interrupt()
Definition: base.cpp:252
CCriticalSection cs_main
Definition: validation.cpp:216
#define LOCK(cs)
Definition: sync.h:181
bool BlockUntilSyncedToCurrentChain()
Blocks the current thread until the index is caught up to the current state of the block chain...
Definition: base.cpp:228
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:967
void TraceThread(const char *name, Callable func)
Definition: util.h:317
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:468
void Start()
Start initializes the sync state and registers the instance as a ValidationInterface so that it stays...
Definition: base.cpp:257
std::string ToString() const
Definition: uint256.cpp:62
std::vector< uint256 > vHave
Definition: block.h:130
bool WriteBestBlock(const CBlockIndex *block_index)
Write the current chain block locator to the DB.
Definition: base.cpp:143
void RegisterValidationInterface(CValidationInterface *pwalletIn)
Register a wallet to receive updates from core.
bool WriteBestBlock(const CBlockLocator &locator)
Write block locator of the chain that the txindex is in sync with.
Definition: base.cpp:44
256-bit opaque blob.
Definition: uint256.h:122
#define EXCLUSIVE_LOCKS_REQUIRED(...)
Definition: threadsafety.h:51
The block chain is a tree shaped structure starting with the genesis block at the root...
Definition: chain.h:170
const CChainParams & Params()
Return the currently selected parameters.
CBlockIndex * FindForkInGlobalIndex(const CChain &chain, const CBlockLocator &locator)
Find the last common block between the parameter chain and a locator.
Definition: validation.cpp:278
constexpr char DB_BEST_BLOCK
Definition: base.cpp:14
CBlockIndex * Tip() const
Returns the index entry for the tip of this chain, or nullptr if none.
Definition: chain.h:445
void SetMiscWarning(const std::string &strWarning)
Definition: warnings.cpp:16
CBlockLocator GetLocator(const CBlockIndex *pindex=nullptr) const
Return a CBlockLocator that refers to a block in this chain (by default the tip). ...
Definition: chain.cpp:23
#define AssertLockNotHeld(cs)
Definition: sync.h:71
bool error(const char *fmt, const Args &... args)
Definition: util.h:59
void BlockConnected(const std::shared_ptr< const CBlock > &block, const CBlockIndex *pindex, const std::vector< CTransactionRef > &txn_conflicted) override
Notifies listeners of a block being connected.
Definition: base.cpp:152
void StartShutdown()
Definition: shutdown.cpp:12
void ThreadSync()
Sync the index with the block index starting from the current best block.
Definition: base.cpp:84
virtual const char * GetName() const =0
Get the name of the index for display in logs.
int64_t GetTime()
GetTimeMicros() and GetTimeMillis() both return the system time, but in different units...
Definition: utiltime.cpp:20
CClientUIInterface uiInterface
int nHeight
height of the entry in the chain. The genesis block has height 0
Definition: chain.h:183
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:31
const Consensus::Params & GetConsensus() const
Definition: chainparams.h:60
bool ReadBlockFromDisk(CBlock &block, const CDiskBlockPos &pos, const Consensus::Params &consensusParams)
Functions for disk access for blocks.
bool ReadBestBlock(CBlockLocator &locator) const
Read block locator of the chain that the txindex is in sync with.
Definition: base.cpp:35
CBlockIndex * GetAncestor(int height)
Efficiently find an ancestor of this block.
Definition: chain.cpp:110
CChain & chainActive
The currently-connected chain of blocks (protected by cs_main).
Definition: validation.cpp:219
const CBlockIndex * FindFork(const CBlockIndex *pindex) const
Find the last common block between this chain and a block index entry.
Definition: chain.cpp:51
virtual DB & GetDB() const =0
std::atomic< const CBlockIndex * > m_best_block_index
The last block in the chain that the index is in sync with.
Definition: base.h:45
CBlockIndex * LookupBlockIndex(const uint256 &hash)
Definition: validation.h:431