@@ -2152,29 +2152,45 @@ static int64_t nTimeFlush = 0;
2152
2152
static int64_t nTimeChainState = 0 ;
2153
2153
static int64_t nTimePostConnect = 0 ;
2154
2154
2155
+ /* *
2156
+ * Used to track conflicted transactions removed from mempool and transactions
2157
+ * applied to the UTXO state as a part of a single ActivateBestChainStep call.
2158
+ */
2159
+ struct ConnectTrace {
2160
+ std::vector<CTransactionRef> txConflicted;
2161
+ std::vector<std::pair<CBlockIndex*, std::shared_ptr<const CBlock> > > blocksConnected;
2162
+ };
2163
+
2155
2164
/* *
2156
2165
* Connect a new block to chainActive. pblock is either NULL or a pointer to a CBlock
2157
2166
* corresponding to pindexNew, to bypass loading it again from disk.
2167
+ *
2168
+ * The block is always added to connectTrace (either after loading from disk or by copying
2169
+ * pblock) - if that is not intended, care must be taken to remove the last entry in
2170
+ * blocksConnected in case of failure.
2158
2171
*/
2159
- bool static ConnectTip (CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const CBlock* pblock, std::vector<CTransactionRef> &txConflicted, std::vector<std::tuple<CTransactionRef,CBlockIndex*, int >> &txChanged )
2172
+ bool static ConnectTip (CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const std::shared_ptr< const CBlock>& pblock, ConnectTrace& connectTrace )
2160
2173
{
2161
2174
assert (pindexNew->pprev == chainActive.Tip ());
2162
2175
// Read block from disk.
2163
2176
int64_t nTime1 = GetTimeMicros ();
2164
- CBlock block;
2165
2177
if (!pblock) {
2166
- if (!ReadBlockFromDisk (block, pindexNew, chainparams.GetConsensus ()))
2178
+ std::shared_ptr<CBlock> pblockNew = std::make_shared<CBlock>();
2179
+ connectTrace.blocksConnected .emplace_back (pindexNew, pblockNew);
2180
+ if (!ReadBlockFromDisk (*pblockNew, pindexNew, chainparams.GetConsensus ()))
2167
2181
return AbortNode (state, " Failed to read block" );
2168
- pblock = █
2182
+ } else {
2183
+ connectTrace.blocksConnected .emplace_back (pindexNew, pblock);
2169
2184
}
2185
+ const CBlock& blockConnecting = *connectTrace.blocksConnected .back ().second ;
2170
2186
// Apply the block atomically to the chain state.
2171
2187
int64_t nTime2 = GetTimeMicros (); nTimeReadFromDisk += nTime2 - nTime1;
2172
2188
int64_t nTime3;
2173
2189
LogPrint (" bench" , " - Load block from disk: %.2fms [%.2fs]\n " , (nTime2 - nTime1) * 0.001 , nTimeReadFromDisk * 0.000001 );
2174
2190
{
2175
2191
CCoinsViewCache view (pcoinsTip);
2176
- bool rv = ConnectBlock (*pblock , state, pindexNew, view, chainparams);
2177
- GetMainSignals ().BlockChecked (*pblock , state);
2192
+ bool rv = ConnectBlock (blockConnecting , state, pindexNew, view, chainparams);
2193
+ GetMainSignals ().BlockChecked (blockConnecting , state);
2178
2194
if (!rv) {
2179
2195
if (state.IsInvalid ())
2180
2196
InvalidBlockFound (pindexNew, state);
@@ -2192,13 +2208,10 @@ bool static ConnectTip(CValidationState& state, const CChainParams& chainparams,
2192
2208
int64_t nTime5 = GetTimeMicros (); nTimeChainState += nTime5 - nTime4;
2193
2209
LogPrint (" bench" , " - Writing chainstate: %.2fms [%.2fs]\n " , (nTime5 - nTime4) * 0.001 , nTimeChainState * 0.000001 );
2194
2210
// Remove conflicting transactions from the mempool.;
2195
- mempool.removeForBlock (pblock-> vtx , pindexNew->nHeight , &txConflicted, !IsInitialBlockDownload ());
2211
+ mempool.removeForBlock (blockConnecting. vtx , pindexNew->nHeight , &connectTrace. txConflicted , !IsInitialBlockDownload ());
2196
2212
// Update chainActive & related variables.
2197
2213
UpdateTip (pindexNew, chainparams);
2198
2214
2199
- for (unsigned int i=0 ; i < pblock->vtx .size (); i++)
2200
- txChanged.emplace_back (pblock->vtx [i], pindexNew, i);
2201
-
2202
2215
int64_t nTime6 = GetTimeMicros (); nTimePostConnect += nTime6 - nTime5; nTimeTotal += nTime6 - nTime1;
2203
2216
LogPrint (" bench" , " - Connect postprocess: %.2fms [%.2fs]\n " , (nTime6 - nTime5) * 0.001 , nTimePostConnect * 0.000001 );
2204
2217
LogPrint (" bench" , " - Connect block: %.2fms [%.2fs]\n " , (nTime6 - nTime1) * 0.001 , nTimeTotal * 0.000001 );
@@ -2279,7 +2292,7 @@ static void PruneBlockIndexCandidates() {
2279
2292
* Try to make some progress towards making pindexMostWork the active block.
2280
2293
* pblock is either NULL or a pointer to a CBlock corresponding to pindexMostWork.
2281
2294
*/
2282
- static bool ActivateBestChainStep (CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const CBlock* pblock, bool & fInvalidFound , std::vector<CTransactionRef>& txConflicted, std::vector<std::tuple<CTransactionRef,CBlockIndex*, int >>& txChanged )
2295
+ static bool ActivateBestChainStep (CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr< const CBlock>& pblock, bool & fInvalidFound , ConnectTrace& connectTrace )
2283
2296
{
2284
2297
AssertLockHeld (cs_main);
2285
2298
const CBlockIndex *pindexOldTip = chainActive.Tip ();
@@ -2312,14 +2325,16 @@ static bool ActivateBestChainStep(CValidationState& state, const CChainParams& c
2312
2325
2313
2326
// Connect new blocks.
2314
2327
BOOST_REVERSE_FOREACH (CBlockIndex *pindexConnect, vpindexToConnect) {
2315
- if (!ConnectTip (state, chainparams, pindexConnect, pindexConnect == pindexMostWork ? pblock : NULL , txConflicted, txChanged )) {
2328
+ if (!ConnectTip (state, chainparams, pindexConnect, pindexConnect == pindexMostWork ? pblock : std::shared_ptr< const CBlock>(), connectTrace )) {
2316
2329
if (state.IsInvalid ()) {
2317
2330
// The block violates a consensus rule.
2318
2331
if (!state.CorruptionPossible ())
2319
2332
InvalidChainFound (vpindexToConnect.back ());
2320
2333
state = CValidationState ();
2321
2334
fInvalidFound = true ;
2322
2335
fContinue = false ;
2336
+ // If we didn't actually connect the block, don't notify listeners about it
2337
+ connectTrace.blocksConnected .pop_back ();
2323
2338
break ;
2324
2339
} else {
2325
2340
// A system error occurred (disk space, database error, ...).
@@ -2377,20 +2392,16 @@ static void NotifyHeaderTip() {
2377
2392
* or an activated best chain. pblock is either NULL or a pointer to a block
2378
2393
* that is already loaded (to avoid loading it again from disk).
2379
2394
*/
2380
- bool ActivateBestChain (CValidationState &state, const CChainParams& chainparams, const CBlock * pblock) {
2395
+ bool ActivateBestChain (CValidationState &state, const CChainParams& chainparams, std::shared_ptr< const CBlock> pblock) {
2381
2396
CBlockIndex *pindexMostWork = NULL ;
2382
2397
CBlockIndex *pindexNewTip = NULL ;
2383
- std::vector<std::tuple<CTransactionRef,CBlockIndex*,int >> txChanged;
2384
- if (pblock)
2385
- txChanged.reserve (pblock->vtx .size ());
2386
2398
do {
2387
- txChanged.clear ();
2388
2399
boost::this_thread::interruption_point ();
2389
2400
if (ShutdownRequested ())
2390
2401
break ;
2391
2402
2392
2403
const CBlockIndex *pindexFork;
2393
- std::vector<CTransactionRef> txConflicted ;
2404
+ ConnectTrace connectTrace ;
2394
2405
bool fInitialDownload ;
2395
2406
{
2396
2407
LOCK (cs_main);
@@ -2404,7 +2415,8 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
2404
2415
return true ;
2405
2416
2406
2417
bool fInvalidFound = false ;
2407
- if (!ActivateBestChainStep (state, chainparams, pindexMostWork, pblock && pblock->GetHash () == pindexMostWork->GetBlockHash () ? pblock : NULL , fInvalidFound , txConflicted, txChanged))
2418
+ std::shared_ptr<const CBlock> nullBlockPtr;
2419
+ if (!ActivateBestChainStep (state, chainparams, pindexMostWork, pblock && pblock->GetHash () == pindexMostWork->GetBlockHash () ? pblock : nullBlockPtr, fInvalidFound , connectTrace))
2408
2420
return false ;
2409
2421
2410
2422
if (fInvalidFound ) {
@@ -2421,13 +2433,17 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
2421
2433
2422
2434
// throw all transactions though the signal-interface
2423
2435
// while _not_ holding the cs_main lock
2424
- for (const auto & tx : txConflicted)
2436
+ for (const auto & tx : connectTrace. txConflicted )
2425
2437
{
2426
2438
GetMainSignals ().SyncTransaction (*tx, pindexNewTip, CMainSignals::SYNC_TRANSACTION_NOT_IN_BLOCK);
2427
2439
}
2428
2440
// ... and about transactions that got confirmed:
2429
- for (unsigned int i = 0 ; i < txChanged.size (); i++)
2430
- GetMainSignals ().SyncTransaction (*std::get<0 >(txChanged[i]), std::get<1 >(txChanged[i]), std::get<2 >(txChanged[i]));
2441
+ for (const auto & pair : connectTrace.blocksConnected ) {
2442
+ assert (pair.second );
2443
+ const CBlock& block = *(pair.second );
2444
+ for (unsigned int i = 0 ; i < block.vtx .size (); i++)
2445
+ GetMainSignals ().SyncTransaction (*block.vtx [i], pair.first , i);
2446
+ }
2431
2447
2432
2448
// Notify external listeners about the new tip.
2433
2449
GetMainSignals ().UpdatedBlockTip (pindexNewTip, pindexFork, fInitialDownload );
@@ -3112,7 +3128,7 @@ static bool AcceptBlock(const CBlock& block, CValidationState& state, const CCha
3112
3128
return true ;
3113
3129
}
3114
3130
3115
- bool ProcessNewBlock (const CChainParams& chainparams, const CBlock* pblock, bool fForceProcessing , const CDiskBlockPos* dbp, bool *fNewBlock )
3131
+ bool ProcessNewBlock (const CChainParams& chainparams, const std::shared_ptr< const CBlock> pblock, bool fForceProcessing , const CDiskBlockPos* dbp, bool *fNewBlock )
3116
3132
{
3117
3133
{
3118
3134
LOCK (cs_main);
0 commit comments