| 431 | } |
| 432 | |
| 433 | void CTxMemPool::check(const CCoinsViewCache& active_coins_tip, int64_t spendheight) const |
| 434 | { |
| 435 | if (m_opts.check_ratio == 0) return; |
| 436 | |
| 437 | if (FastRandomContext().randrange(m_opts.check_ratio) >= 1) return; |
| 438 | |
| 439 | AssertLockHeld(::cs_main); |
| 440 | LOCK(cs); |
| 441 | LogDebug(BCLog::MEMPOOL, "Checking mempool with %u transactions and %u inputs\n", (unsigned int)mapTx.size(), (unsigned int)mapNextTx.size()); |
| 442 | |
| 443 | uint64_t checkTotal = 0; |
| 444 | CAmount check_total_fee{0}; |
| 445 | CAmount check_total_modified_fee{0}; |
| 446 | int64_t check_total_adjusted_weight{0}; |
| 447 | uint64_t innerUsage = 0; |
| 448 | |
| 449 | assert(!m_txgraph->IsOversized(TxGraph::Level::MAIN)); |
| 450 | m_txgraph->SanityCheck(); |
| 451 | |
| 452 | CCoinsViewCache mempoolDuplicate(const_cast<CCoinsViewCache*>(&active_coins_tip)); |
| 453 | |
| 454 | const auto score_with_topo{GetSortedScoreWithTopology()}; |
| 455 | |
| 456 | // Number of chunks is bounded by number of transactions. |
| 457 | const auto diagram{GetFeerateDiagram()}; |
| 458 | assert(diagram.size() <= score_with_topo.size() + 1); |
| 459 | assert(diagram.size() >= 1); |
| 460 | |
| 461 | std::optional<Wtxid> last_wtxid = std::nullopt; |
| 462 | auto diagram_iter = diagram.cbegin(); |
| 463 | |
| 464 | for (const auto& it : score_with_topo) { |
| 465 | // GetSortedScoreWithTopology() contains the same chunks as the feerate |
| 466 | // diagram. We do not know where the chunk boundaries are, but we can |
| 467 | // check that there are points at which they match the cumulative fee |
| 468 | // and weight. |
| 469 | // The feerate diagram should never get behind the current transaction |
| 470 | // size totals. |
| 471 | assert(diagram_iter->size >= check_total_adjusted_weight); |
| 472 | if (diagram_iter->fee == check_total_modified_fee && |
| 473 | diagram_iter->size == check_total_adjusted_weight) { |
| 474 | ++diagram_iter; |
| 475 | } |
| 476 | checkTotal += it->GetTxSize(); |
| 477 | check_total_adjusted_weight += it->GetAdjustedWeight(); |
| 478 | check_total_fee += it->GetFee(); |
| 479 | check_total_modified_fee += it->GetModifiedFee(); |
| 480 | innerUsage += it->DynamicMemoryUsage(); |
| 481 | const CTransaction& tx = it->GetTx(); |
| 482 | |
| 483 | // CompareMiningScoreWithTopology should agree with GetSortedScoreWithTopology() |
| 484 | if (last_wtxid) { |
| 485 | assert(CompareMiningScoreWithTopology(*last_wtxid, tx.GetWitnessHash())); |
| 486 | } |
| 487 | last_wtxid = tx.GetWitnessHash(); |
| 488 | |
| 489 | std::set<CTxMemPoolEntry::CTxMemPoolEntryRef, CompareIteratorByHash> setParentCheck; |
| 490 | std::set<CTxMemPoolEntry::CTxMemPoolEntryRef, CompareIteratorByHash> setParentsStored; |
no test coverage detected