@@ -635,10 +635,6 @@ class MemPoolAccept
635
635
/* * Mempool entry constructed for this transaction. Constructed in PreChecks() but not
636
636
* inserted into the mempool until Finalize(). */
637
637
std::unique_ptr<CTxMemPoolEntry> m_entry;
638
- /* * Pointers to the transactions that have been removed from the mempool and replaced by
639
- * this transaction (everything in m_all_conflicting), used to return to the MemPoolAccept caller. Only populated if
640
- * validation is successful and the original transactions are removed. */
641
- std::list<CTransactionRef> m_replaced_transactions;
642
638
/* * Whether RBF-related data structures (m_conflicts, m_iters_conflicting, m_all_conflicting,
643
639
* m_replaced_transactions) include a sibling in addition to txns with conflicting inputs. */
644
640
bool m_sibling_eviction{false };
@@ -1566,21 +1562,21 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptMultipleTransactions(const std::
1566
1562
// a child that is below mempool minimum feerate. To avoid these behaviors, callers of
1567
1563
// AcceptMultipleTransactions need to restrict txns topology (e.g. to ancestor sets) and check
1568
1564
// the feerates of individuals and subsets.
1569
- const auto m_total_vsize = std::accumulate (workspaces.cbegin (), workspaces.cend (), int64_t {0 },
1565
+ m_subpackage. m_total_vsize = std::accumulate (workspaces.cbegin (), workspaces.cend (), int64_t {0 },
1570
1566
[](int64_t sum, auto & ws) { return sum + ws.m_vsize ; });
1571
- const auto m_total_modified_fees = std::accumulate (workspaces.cbegin (), workspaces.cend (), CAmount{0 },
1567
+ m_subpackage. m_total_modified_fees = std::accumulate (workspaces.cbegin (), workspaces.cend (), CAmount{0 },
1572
1568
[](CAmount sum, auto & ws) { return sum + ws.m_modified_fees ; });
1573
- const CFeeRate package_feerate (m_total_modified_fees, m_total_vsize);
1569
+ const CFeeRate package_feerate (m_subpackage. m_total_modified_fees , m_subpackage. m_total_vsize );
1574
1570
std::vector<Wtxid> all_package_wtxids;
1575
1571
all_package_wtxids.reserve (workspaces.size ());
1576
1572
std::transform (workspaces.cbegin (), workspaces.cend (), std::back_inserter (all_package_wtxids),
1577
1573
[](const auto & ws) { return ws.m_ptx ->GetWitnessHash (); });
1578
1574
TxValidationState placeholder_state;
1579
1575
if (args.m_package_feerates &&
1580
- !CheckFeeRate (m_total_vsize, m_total_modified_fees, placeholder_state)) {
1576
+ !CheckFeeRate (m_subpackage. m_total_vsize , m_subpackage. m_total_modified_fees , placeholder_state)) {
1581
1577
package_state.Invalid (PackageValidationResult::PCKG_TX, " transaction failed" );
1582
1578
return PackageMempoolAcceptResult (package_state, {{workspaces.back ().m_ptx ->GetWitnessHash (),
1583
- MempoolAcceptResult::FeeFailure (placeholder_state, CFeeRate (m_total_modified_fees, m_total_vsize), all_package_wtxids)}});
1579
+ MempoolAcceptResult::FeeFailure (placeholder_state, CFeeRate (m_subpackage. m_total_modified_fees , m_subpackage. m_total_vsize ), all_package_wtxids)}});
1584
1580
}
1585
1581
1586
1582
// Apply package mempool ancestor/descendant limits. Skip if there is only one transaction,
@@ -1603,7 +1599,7 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptMultipleTransactions(const std::
1603
1599
const auto effective_feerate_wtxids = args.m_package_feerates ? all_package_wtxids :
1604
1600
std::vector<Wtxid>{ws.m_ptx ->GetWitnessHash ()};
1605
1601
results.emplace (ws.m_ptx ->GetWitnessHash (),
1606
- MempoolAcceptResult::Success (std::move (ws .m_replaced_transactions ),
1602
+ MempoolAcceptResult::Success (std::move (m_subpackage .m_replaced_transactions ),
1607
1603
ws.m_vsize , ws.m_base_fees , effective_feerate,
1608
1604
effective_feerate_wtxids));
1609
1605
}
@@ -1853,6 +1849,7 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptPackage(const Package& package,
1853
1849
1854
1850
MempoolAcceptResult AcceptToMemoryPool (Chainstate& active_chainstate, const CTransactionRef& tx,
1855
1851
int64_t accept_time, bool bypass_limits, bool test_accept)
1852
+ EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
1856
1853
{
1857
1854
AssertLockHeld (::cs_main);
1858
1855
const CChainParams& chainparams{active_chainstate.m_chainman .GetParams ()};
@@ -2918,8 +2915,10 @@ bool Chainstate::FlushStateToDisk(
2918
2915
return FatalError (m_chainman.GetNotifications (), state, _ (" Disk space is too low!" ));
2919
2916
}
2920
2917
// Flush the chainstate (which may refer to block index entries).
2921
- if (!CoinsTip ().Flush ())
2918
+ const auto empty_cache{(mode == FlushStateMode::ALWAYS) || fCacheLarge || fCacheCritical || fFlushForPrune };
2919
+ if (empty_cache ? !CoinsTip ().Flush () : !CoinsTip ().Sync ()) {
2922
2920
return FatalError (m_chainman.GetNotifications (), state, _ (" Failed to write to coin database." ));
2921
+ }
2923
2922
m_last_flush = nNow;
2924
2923
full_flush_completed = true ;
2925
2924
TRACE5 (utxocache, flush,
@@ -4135,7 +4134,18 @@ bool IsBlockMutated(const CBlock& block, bool check_witness_root)
4135
4134
}
4136
4135
4137
4136
if (block.vtx .empty () || !block.vtx [0 ]->IsCoinBase ()) {
4138
- return false ;
4137
+ // Consider the block mutated if any transaction is 64 bytes in size (see 3.1
4138
+ // in "Weaknesses in Bitcoin’s Merkle Root Construction":
4139
+ // https://lists.linuxfoundation.org/pipermail/bitcoin-dev/attachments/20190225/a27d8837/attachment-0001.pdf).
4140
+ //
4141
+ // Note: This is not a consensus change as this only applies to blocks that
4142
+ // don't have a coinbase transaction and would therefore already be invalid.
4143
+ return std::any_of (block.vtx .begin (), block.vtx .end (),
4144
+ [](auto & tx) { return GetSerializeSize (TX_NO_WITNESS (tx)) == 64 ; });
4145
+ } else {
4146
+ // Theoretically it is still possible for a block with a 64 byte
4147
+ // coinbase transaction to be mutated but we neglect that possibility
4148
+ // here as it requires at least 224 bits of work.
4139
4149
}
4140
4150
4141
4151
if (!CheckWitnessMalleation (block, check_witness_root, state, 0 )) {
@@ -5201,6 +5211,14 @@ void ChainstateManager::LoadExternalBlockFile(
5201
5211
LogPrintf (" Loaded %i blocks from external file in %dms\n " , nLoaded, Ticks<std::chrono::milliseconds>(SteadyClock::now () - start));
5202
5212
}
5203
5213
5214
+ bool ChainstateManager::ShouldCheckBlockIndex () const
5215
+ {
5216
+ // Assert to verify Flatten() has been called.
5217
+ if (!*Assert (m_options.check_block_index )) return false ;
5218
+ if (GetRand (*m_options.check_block_index ) >= 1 ) return false ;
5219
+ return true ;
5220
+ }
5221
+
5204
5222
void ChainstateManager::CheckBlockIndex ()
5205
5223
{
5206
5224
if (!ShouldCheckBlockIndex ()) {
@@ -5217,19 +5235,30 @@ void ChainstateManager::CheckBlockIndex()
5217
5235
return ;
5218
5236
}
5219
5237
5220
- // Build forward-pointing map of the entire block tree.
5238
+ // Build forward-pointing data structure for the entire block tree.
5239
+ // For performance reasons, indexes of the best header chain are stored in a vector (within CChain).
5240
+ // All remaining blocks are stored in a multimap.
5241
+ // The best header chain can differ from the active chain: E.g. its entries may belong to blocks that
5242
+ // are not yet validated.
5243
+ CChain best_hdr_chain;
5244
+ assert (m_best_header);
5245
+ best_hdr_chain.SetTip (*m_best_header);
5246
+
5221
5247
std::multimap<CBlockIndex*,CBlockIndex*> forward;
5222
5248
for (auto & [_, block_index] : m_blockman.m_block_index ) {
5249
+ // Only save indexes in forward that are not part of the best header chain.
5250
+ if (!best_hdr_chain.Contains (&block_index)) {
5251
+ // Only genesis, which must be part of the best header chain, can have a nullptr parent.
5252
+ assert (block_index.pprev );
5253
+ forward.emplace (block_index.pprev , &block_index);
5223
5254
forward.emplace (block_index.pprev , &block_index);
5255
+ forward.emplace (block_index.pprev , &block_index);
5256
+ }
5224
5257
}
5258
+ assert (forward.size () + best_hdr_chain.Height () + 1 == m_blockman.m_block_index .size ());
5225
5259
5226
- assert (forward.size () == m_blockman.m_block_index .size ());
5227
-
5228
- std::pair<std::multimap<CBlockIndex*,CBlockIndex*>::iterator,std::multimap<CBlockIndex*,CBlockIndex*>::iterator> rangeGenesis = forward.equal_range (nullptr );
5229
- CBlockIndex *pindex = rangeGenesis.first ->second ;
5230
- rangeGenesis.first ++;
5231
- assert (rangeGenesis.first == rangeGenesis.second ); // There is only one index entry with parent nullptr.
5232
-
5260
+ CBlockIndex* pindex = best_hdr_chain[0 ];
5261
+ assert (pindex);
5233
5262
// Iterate over the entire block tree, using depth-first search.
5234
5263
// Along the way, remember whether there are blocks on the path from genesis
5235
5264
// block being explored which are the first to have certain properties.
@@ -5441,14 +5470,21 @@ void ChainstateManager::CheckBlockIndex()
5441
5470
// assert(pindex->GetBlockHash() == pindex->GetBlockHeader().GetHash()); // Perhaps too slow
5442
5471
// End: actual consistency checks.
5443
5472
5444
- // Try descending into the first subnode.
5473
+
5474
+ // Try descending into the first subnode. Always process forks first and the best header chain after.
5445
5475
snap_update_firsts ();
5446
5476
std::pair<std::multimap<CBlockIndex*,CBlockIndex*>::iterator,std::multimap<CBlockIndex*,CBlockIndex*>::iterator> range = forward.equal_range (pindex);
5447
5477
if (range.first != range.second ) {
5448
- // A subnode was found.
5478
+ // A subnode not part of the best header chain was found.
5449
5479
pindex = range.first ->second ;
5450
5480
nHeight++;
5451
5481
continue ;
5482
+ } else if (best_hdr_chain.Contains (pindex)) {
5483
+ // Descend further into best header chain.
5484
+ nHeight++;
5485
+ pindex = best_hdr_chain[nHeight];
5486
+ if (!pindex) break ; // we are finished, since the best header chain is always processed last
5487
+ continue ;
5452
5488
}
5453
5489
// This is a leaf node.
5454
5490
// Move upwards until we reach a node of which we have not yet visited the last child.
@@ -5474,9 +5510,15 @@ void ChainstateManager::CheckBlockIndex()
5474
5510
// Proceed to the next one.
5475
5511
rangePar.first ++;
5476
5512
if (rangePar.first != rangePar.second ) {
5477
- // Move to the sibling.
5513
+ // Move to a sibling not part of the best header chain .
5478
5514
pindex = rangePar.first ->second ;
5479
5515
break ;
5516
+ } else if (pindexPar == best_hdr_chain[nHeight - 1 ]) {
5517
+ // Move to pindex's sibling on the best-chain, if it has one.
5518
+ pindex = best_hdr_chain[nHeight];
5519
+ // There will not be a next block if (and only if) parent block is the best header.
5520
+ assert ((pindex == nullptr ) == (pindexPar == best_hdr_chain.Tip ()));
5521
+ break ;
5480
5522
} else {
5481
5523
// Move up further.
5482
5524
pindex = pindexPar;
@@ -5486,8 +5528,8 @@ void ChainstateManager::CheckBlockIndex()
5486
5528
}
5487
5529
}
5488
5530
5489
- // Check that we actually traversed the entire map .
5490
- assert (nNodes == forward.size ());
5531
+ // Check that we actually traversed the entire block index .
5532
+ assert (nNodes == forward.size () + best_hdr_chain. Height () + 1 );
5491
5533
}
5492
5534
5493
5535
std::string Chainstate::ToString ()
@@ -6337,13 +6379,14 @@ bool ChainstateManager::DeleteSnapshotChainstate()
6337
6379
Assert (m_snapshot_chainstate);
6338
6380
Assert (m_ibd_chainstate);
6339
6381
6340
- fs::path snapshot_datadir = GetSnapshotCoinsDBPath (*m_snapshot_chainstate );
6382
+ fs::path snapshot_datadir = Assert ( node::FindSnapshotChainstateDir (m_options. datadir )). value ( );
6341
6383
if (!DeleteCoinsDBFromDisk (snapshot_datadir, /* is_snapshot=*/ true )) {
6342
6384
LogPrintf (" Deletion of %s failed. Please remove it manually to continue reindexing.\n " ,
6343
6385
fs::PathToString (snapshot_datadir));
6344
6386
return false ;
6345
6387
}
6346
6388
m_active_chainstate = m_ibd_chainstate.get ();
6389
+ m_active_chainstate->m_mempool = m_snapshot_chainstate->m_mempool ;
6347
6390
m_snapshot_chainstate.reset ();
6348
6391
return true ;
6349
6392
}
0 commit comments