@@ -953,7 +953,18 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
953
953
CAmount inChainInputValue;
954
954
double dPriority = view.GetPriority (tx, chainActive.Height (), inChainInputValue);
955
955
956
- CTxMemPoolEntry entry (tx, nFees, GetTime (), dPriority, chainActive.Height (), pool.HasNoInputsOf (tx), inChainInputValue);
956
+ // Keep track of transactions that spend a coinbase, which we re-scan
957
+ // during reorgs to ensure COINBASE_MATURITY is still met.
958
+ bool fSpendsCoinbase = false ;
959
+ BOOST_FOREACH (const CTxIn &txin, tx.vin ) {
960
+ const CCoins *coins = view.AccessCoins (txin.prevout .hash );
961
+ if (coins->IsCoinBase ()) {
962
+ fSpendsCoinbase = true ;
963
+ break ;
964
+ }
965
+ }
966
+
967
+ CTxMemPoolEntry entry (tx, nFees, GetTime (), dPriority, chainActive.Height (), pool.HasNoInputsOf (tx), inChainInputValue, fSpendsCoinbase );
957
968
unsigned int nSize = entry.GetTxSize ();
958
969
959
970
// Don't accept it if it can't get into a block
@@ -2310,12 +2321,11 @@ void static UpdateTip(CBlockIndex *pindexNew) {
2310
2321
}
2311
2322
}
2312
2323
2313
- /* * Disconnect chainActive's tip. You want to manually re-limit mempool size after this */
2324
+ /* * Disconnect chainActive's tip. You probably want to call mempool.removeForReorg and manually re-limit mempool size after this, with cs_main held. */
2314
2325
bool static DisconnectTip (CValidationState& state, const Consensus::Params& consensusParams)
2315
2326
{
2316
2327
CBlockIndex *pindexDelete = chainActive.Tip ();
2317
2328
assert (pindexDelete);
2318
- mempool.check (pcoinsTip);
2319
2329
// Read block from disk.
2320
2330
CBlock block;
2321
2331
if (!ReadBlockFromDisk (block, pindexDelete, consensusParams))
@@ -2350,8 +2360,6 @@ bool static DisconnectTip(CValidationState& state, const Consensus::Params& cons
2350
2360
// UpdateTransactionsFromBlock finds descendants of any transactions in this
2351
2361
// block that were added back and cleans up the mempool state.
2352
2362
mempool.UpdateTransactionsFromBlock (vHashUpdate);
2353
- mempool.removeCoinbaseSpends (pcoinsTip, pindexDelete->nHeight );
2354
- mempool.check (pcoinsTip);
2355
2363
// Update chainActive and related variables.
2356
2364
UpdateTip (pindexDelete->pprev );
2357
2365
// Let wallets know transactions went from 1-confirmed to
@@ -2375,7 +2383,6 @@ static int64_t nTimePostConnect = 0;
2375
2383
bool static ConnectTip (CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const CBlock* pblock)
2376
2384
{
2377
2385
assert (pindexNew->pprev == chainActive.Tip ());
2378
- mempool.check (pcoinsTip);
2379
2386
// Read block from disk.
2380
2387
int64_t nTime1 = GetTimeMicros ();
2381
2388
CBlock block;
@@ -2412,7 +2419,6 @@ bool static ConnectTip(CValidationState& state, const CChainParams& chainparams,
2412
2419
// Remove conflicting transactions from the mempool.
2413
2420
list<CTransaction> txConflicted;
2414
2421
mempool.removeForBlock (pblock->vtx , pindexNew->nHeight , txConflicted, !IsInitialBlockDownload ());
2415
- mempool.check (pcoinsTip);
2416
2422
// Update chainActive & related variables.
2417
2423
UpdateTip (pindexNew);
2418
2424
// Tell wallet about transactions that went from mempool
@@ -2525,46 +2531,49 @@ static bool ActivateBestChainStep(CValidationState& state, const CChainParams& c
2525
2531
bool fContinue = true ;
2526
2532
int nHeight = pindexFork ? pindexFork->nHeight : -1 ;
2527
2533
while (fContinue && nHeight != pindexMostWork->nHeight ) {
2528
- // Don't iterate the entire list of potential improvements toward the best tip, as we likely only need
2529
- // a few blocks along the way.
2530
- int nTargetHeight = std::min (nHeight + 32 , pindexMostWork->nHeight );
2531
- vpindexToConnect.clear ();
2532
- vpindexToConnect.reserve (nTargetHeight - nHeight);
2533
- CBlockIndex *pindexIter = pindexMostWork->GetAncestor (nTargetHeight);
2534
- while (pindexIter && pindexIter->nHeight != nHeight) {
2535
- vpindexToConnect.push_back (pindexIter);
2536
- pindexIter = pindexIter->pprev ;
2537
- }
2538
- nHeight = nTargetHeight;
2539
-
2540
- // Connect new blocks.
2541
- BOOST_REVERSE_FOREACH (CBlockIndex *pindexConnect, vpindexToConnect) {
2542
- if (!ConnectTip (state, chainparams, pindexConnect, pindexConnect == pindexMostWork ? pblock : NULL )) {
2543
- if (state.IsInvalid ()) {
2544
- // The block violates a consensus rule.
2545
- if (!state.CorruptionPossible ())
2546
- InvalidChainFound (vpindexToConnect.back ());
2547
- state = CValidationState ();
2548
- fInvalidFound = true ;
2549
- fContinue = false ;
2550
- break ;
2534
+ // Don't iterate the entire list of potential improvements toward the best tip, as we likely only need
2535
+ // a few blocks along the way.
2536
+ int nTargetHeight = std::min (nHeight + 32 , pindexMostWork->nHeight );
2537
+ vpindexToConnect.clear ();
2538
+ vpindexToConnect.reserve (nTargetHeight - nHeight);
2539
+ CBlockIndex *pindexIter = pindexMostWork->GetAncestor (nTargetHeight);
2540
+ while (pindexIter && pindexIter->nHeight != nHeight) {
2541
+ vpindexToConnect.push_back (pindexIter);
2542
+ pindexIter = pindexIter->pprev ;
2543
+ }
2544
+ nHeight = nTargetHeight;
2545
+
2546
+ // Connect new blocks.
2547
+ BOOST_REVERSE_FOREACH (CBlockIndex *pindexConnect, vpindexToConnect) {
2548
+ if (!ConnectTip (state, chainparams, pindexConnect, pindexConnect == pindexMostWork ? pblock : NULL )) {
2549
+ if (state.IsInvalid ()) {
2550
+ // The block violates a consensus rule.
2551
+ if (!state.CorruptionPossible ())
2552
+ InvalidChainFound (vpindexToConnect.back ());
2553
+ state = CValidationState ();
2554
+ fInvalidFound = true ;
2555
+ fContinue = false ;
2556
+ break ;
2557
+ } else {
2558
+ // A system error occurred (disk space, database error, ...).
2559
+ return false ;
2560
+ }
2551
2561
} else {
2552
- // A system error occurred (disk space, database error, ...).
2553
- return false ;
2554
- }
2555
- } else {
2556
- PruneBlockIndexCandidates ();
2557
- if (!pindexOldTip || chainActive.Tip ()->nChainWork > pindexOldTip->nChainWork ) {
2558
- // We're in a better position than we were. Return temporarily to release the lock.
2559
- fContinue = false ;
2560
- break ;
2562
+ PruneBlockIndexCandidates ();
2563
+ if (!pindexOldTip || chainActive.Tip ()->nChainWork > pindexOldTip->nChainWork ) {
2564
+ // We're in a better position than we were. Return temporarily to release the lock.
2565
+ fContinue = false ;
2566
+ break ;
2567
+ }
2561
2568
}
2562
2569
}
2563
2570
}
2564
- }
2565
2571
2566
- if (fBlocksDisconnected )
2572
+ if (fBlocksDisconnected ) {
2573
+ mempool.removeForReorg (pcoinsTip, chainActive.Tip ()->nHeight + 1 , STANDARD_LOCKTIME_VERIFY_FLAGS);
2567
2574
mempool.TrimToSize (GetArg (" -maxmempool" , DEFAULT_MAX_MEMPOOL_SIZE) * 1000000 );
2575
+ }
2576
+ mempool.check (pcoinsTip);
2568
2577
2569
2578
// Callbacks/notifications for a new best chain.
2570
2579
if (fInvalidFound )
@@ -2672,6 +2681,7 @@ bool InvalidateBlock(CValidationState& state, const Consensus::Params& consensus
2672
2681
// ActivateBestChain considers blocks already in chainActive
2673
2682
// unconditionally valid already, so force disconnect away from it.
2674
2683
if (!DisconnectTip (state, consensusParams)) {
2684
+ mempool.removeForReorg (pcoinsTip, chainActive.Tip ()->nHeight + 1 , STANDARD_LOCKTIME_VERIFY_FLAGS);
2675
2685
return false ;
2676
2686
}
2677
2687
}
@@ -2689,6 +2699,7 @@ bool InvalidateBlock(CValidationState& state, const Consensus::Params& consensus
2689
2699
}
2690
2700
2691
2701
InvalidChainFound (pindex);
2702
+ mempool.removeForReorg (pcoinsTip, chainActive.Tip ()->nHeight + 1 , STANDARD_LOCKTIME_VERIFY_FLAGS);
2692
2703
return true ;
2693
2704
}
2694
2705
0 commit comments