Skip to content
Bitcoin Roots

v30.3-roots.1 · Commit 3: [PATCH 03/68] feat(policy): preserve Roots relay and network controls on Core 30.3

src/txmempool.cpp

Before: src/txmempool.cpp · After: src/txmempool.cpp

File metadata
index cae16a675bd4cc91a5603376c5e1f79674e81355..17ca9abc1c843b5ee54e2de9f97d56d041bba150 100644

Download original patch · Release notes

Diff rows 1–336 of 336. Line numbers refer to the original before/after files.

+ Added− RemovedUnmarked lines are context.

Scroll the code area horizontally to read long lines. Before is on the left; after is on the right. Unified view fits narrow screens more easily.

src/txmempool.cpp CHANGED
@@ -11,11 +11,16 @@
11
  #include <consensus/consensus.h>
12
  #include <consensus/tx_verify.h>
13
  #include <consensus/validation.h>
 
14
  #include <logging.h>
 
 
15
  #include <policy/policy.h>
16
  #include <policy/settings.h>
17
  #include <random.h>
 
18
  #include <tinyformat.h>
 
19
  #include <util/check.h>
20
  #include <util/feefrac.h>
21
  #include <util/moneystr.h>
@@ -37,6 +42,49 @@
37
  TRACEPOINT_SEMAPHORE(mempool, added);
38
  TRACEPOINT_SEMAPHORE(mempool, removed);
39
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
  bool TestLockPointValidity(CChain& active_chain, const LockPoints& lp)
41
  {
42
  AssertLockHeld(cs_main);
@@ -54,6 +102,13 @@ bool TestLockPointValidity(CChain& active_chain, const LockPoints& lp)
54
  return true;
55
  }
56
 
 
 
 
 
 
 
 
57
  void CTxMemPool::UpdateForDescendants(txiter updateIt, cacheMap& cachedDescendants,
58
  const std::set<Txid>& setExclude, std::set<Txid>& descendants_to_remove)
59
  {
@@ -404,7 +459,7 @@ void CTxMemPoolEntry::UpdateAncestorState(int32_t modifySize, CAmount modifyFee,
404
  static CTxMemPool::Options&& Flatten(CTxMemPool::Options&& opts, bilingual_str& error)
405
  {
406
  opts.check_ratio = std::clamp<int>(opts.check_ratio, 0, 1'000'000);
407
- int64_t descendant_limit_bytes = opts.limits.descendant_size_vbytes * 40;
408
  if (opts.max_size_bytes < 0 || opts.max_size_bytes < descendant_limit_bytes) {
409
  error = strprintf(_("-maxmempool must be at least %d MB"), std::ceil(descendant_limit_bytes / 1'000'000.0));
410
  }
@@ -414,6 +469,17 @@ static CTxMemPool::Options&& Flatten(CTxMemPool::Options&& opts, bilingual_str&
414
  CTxMemPool::CTxMemPool(Options opts, bilingual_str& error)
415
  : m_opts{Flatten(std::move(opts), error)}
416
  {
 
 
 
 
 
 
 
 
 
 
 
417
  }
418
 
419
  bool CTxMemPool::isSpent(const COutPoint& outpoint) const
@@ -453,11 +519,20 @@ void CTxMemPool::Apply(ChangeSet* changeset)
453
  ancestors = *Assume(changeset->CalculateMemPoolAncestors(tx_entry, Limits::NoLimits()));
454
  }
455
  // First splice this entry into mapTx.
 
456
  auto node_handle = changeset->m_to_add.extract(tx_entry);
457
  auto result = mapTx.insert(std::move(node_handle));
458
 
459
  Assume(result.inserted);
460
  txiter it = result.position;
 
 
 
 
 
 
 
 
461
 
462
  // Now update the entry for ancestors/descendants.
463
  if (ancestors.has_value()) {
@@ -510,6 +585,17 @@ void CTxMemPool::addNewTransaction(CTxMemPool::txiter newit, CTxMemPool::setEntr
510
  txns_randomized.emplace_back(tx.GetWitnessHash(), newit);
511
  newit->idx_randomized = txns_randomized.size() - 1;
512
 
 
 
 
 
 
 
 
 
 
 
 
513
  TRACEPOINT(mempool, added,
514
  entry.GetTx().GetHash().data(),
515
  entry.GetTxSize(),
@@ -538,6 +624,7 @@ void CTxMemPool::removeUnchecked(txiter it, MemPoolRemovalReason reason)
538
  std::chrono::duration_cast<std::chrono::duration<std::uint64_t>>(it->GetTime()).count()
539
  );
540
 
 
541
  for (const CTxIn& txin : it->GetTx().vin)
542
  mapNextTx.erase(txin.prevout);
543
 
@@ -555,6 +642,19 @@ void CTxMemPool::removeUnchecked(txiter it, MemPoolRemovalReason reason)
555
  txns_randomized.clear();
556
  }
557
 
 
 
 
 
 
 
 
 
 
 
 
 
 
558
  totalTxSize -= it->GetTxSize();
559
  m_total_fee -= it->GetFee();
560
  cachedInnerUsage -= it->DynamicMemoryUsage();
@@ -671,6 +771,7 @@ void CTxMemPool::removeForBlock(const std::vector<CTransactionRef>& vtx, unsigne
671
  if (mapTx.size() || mapNextTx.size() || mapDeltas.size()) {
672
  txs_removed_for_block.reserve(vtx.size());
673
  for (const auto& tx : vtx) {
 
674
  txiter it = mapTx.find(tx->GetHash());
675
  if (it != mapTx.end()) {
676
  setEntries stage;
@@ -689,6 +790,38 @@ void CTxMemPool::removeForBlock(const std::vector<CTransactionRef>& vtx, unsigne
689
  blockSinceLastRollingFeeBump = true;
690
  }
691
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
692
  void CTxMemPool::check(const CCoinsViewCache& active_coins_tip, int64_t spendheight) const
693
  {
694
  if (m_opts.check_ratio == 0) return;
@@ -708,6 +841,14 @@ void CTxMemPool::check(const CCoinsViewCache& active_coins_tip, int64_t spendhei
708
 
709
  for (const auto& it : GetSortedDepthAndScore()) {
710
  checkTotal += it->GetTxSize();
 
 
 
 
 
 
 
 
711
  check_total_fee += it->GetFee();
712
  innerUsage += it->DynamicMemoryUsage();
713
  const CTransaction& tx = it->GetTx();
@@ -843,6 +984,21 @@ std::vector<CTxMemPool::indexed_transaction_set::const_iterator> CTxMemPool::Get
843
  return iters;
844
  }
845
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
846
  std::vector<CTxMemPoolEntryRef> CTxMemPool::entryAll() const
847
  {
848
  AssertLockHeld(cs);
@@ -885,15 +1041,17 @@ CTransactionRef CTxMemPool::get(const Txid& hash) const
885
  return i->GetSharedTx();
886
  }
887
 
888
- void CTxMemPool::PrioritiseTransaction(const Txid& hash, const CAmount& nFeeDelta)
889
  {
890
  {
891
  LOCK(cs);
892
- CAmount &delta = mapDeltas[hash];
893
- delta = SaturatingAdd(delta, nFeeDelta);
 
894
  txiter it = mapTx.find(hash);
895
  if (it != mapTx.end()) {
896
  mapTx.modify(it, [&nFeeDelta](CTxMemPoolEntry& e) { e.UpdateModifiedFee(nFeeDelta); });
 
897
  // Now update all ancestors' modified fees with descendants
898
  auto ancestors{AssumeCalculateMemPoolAncestors(__func__, *it, Limits::NoLimits(), /*fSearchForParents=*/false)};
899
  for (txiter ancestorIt : ancestors) {
@@ -908,27 +1066,29 @@ void CTxMemPool::PrioritiseTransaction(const Txid& hash, const CAmount& nFeeDelt
908
  }
909
  ++nTransactionsUpdated;
910
  }
911
- if (delta == 0) {
912
  mapDeltas.erase(hash);
913
  LogPrintf("PrioritiseTransaction: %s (%sin mempool) delta cleared\n", hash.ToString(), it == mapTx.end() ? "not " : "");
914
  } else {
915
- LogPrintf("PrioritiseTransaction: %s (%sin mempool) fee += %s, new delta=%s\n",
916
  hash.ToString(),
917
  it == mapTx.end() ? "not " : "",
 
918
  FormatMoney(nFeeDelta),
919
- FormatMoney(delta));
920
  }
921
  }
922
  }
923
 
924
- void CTxMemPool::ApplyDelta(const Txid& hash, CAmount &nFeeDelta) const
925
  {
926
  AssertLockHeld(cs);
927
- std::map<Txid, CAmount>::const_iterator pos = mapDeltas.find(hash);
928
  if (pos == mapDeltas.end())
929
  return;
930
- const CAmount &delta = pos->second;
931
- nFeeDelta += delta;
 
932
  }
933
 
934
  void CTxMemPool::ClearPrioritisation(const Txid& hash)
@@ -948,7 +1108,7 @@ std::vector<CTxMemPool::delta_info> CTxMemPool::GetPrioritisedTransactions() con
948
  const bool in_mempool{iter != mapTx.end()};
949
  std::optional<CAmount> modified_fee;
950
  if (in_mempool) modified_fee = iter->GetModifiedFee();
951
- result.emplace_back(delta_info{in_mempool, delta, modified_fee, txid});
952
  }
953
  return result;
954
  }
@@ -1045,7 +1205,7 @@ void CCoinsViewMemPool::Reset()
1045
  size_t CTxMemPool::DynamicMemoryUsage() const {
1046
  LOCK(cs);
1047
  // Estimate the overhead of mapTx to be 15 pointers + an allocation, as no exact formula for boost::multi_index_contained is implemented.
1048
- return memusage::MallocUsage(sizeof(CTxMemPoolEntry) + 15 * sizeof(void*)) * mapTx.size() + memusage::DynamicUsage(mapNextTx) + memusage::DynamicUsage(mapDeltas) + memusage::DynamicUsage(txns_randomized) + cachedInnerUsage;
1049
  }
1050
 
1051
  void CTxMemPool::RemoveUnbroadcastTx(const Txid& txid, const bool unchecked) {
@@ -1385,13 +1545,15 @@ util::Result<std::pair<std::vector<FeeFrac>, std::vector<FeeFrac>>> CTxMemPool::
1385
  return std::make_pair(old_chunks, new_chunks);
1386
  }
1387
 
1388
- CTxMemPool::ChangeSet::TxHandle CTxMemPool::ChangeSet::StageAddition(const CTransactionRef& tx, const CAmount fee, int64_t time, unsigned int entry_height, uint64_t entry_sequence, bool spends_coinbase, int64_t sigops_cost, LockPoints lp)
1389
  {
1390
  LOCK(m_pool->cs);
1391
  Assume(m_to_add.find(tx->GetHash()) == m_to_add.end());
1392
- auto newit = m_to_add.emplace(tx, fee, time, entry_height, entry_sequence, spends_coinbase, sigops_cost, lp).first;
 
1393
  CAmount delta{0};
1394
- m_pool->ApplyDelta(tx->GetHash(), delta);
 
1395
  if (delta) m_to_add.modify(newit, [&delta](CTxMemPoolEntry& e) { e.UpdateModifiedFee(delta); });
1396
 
1397
  m_entry_vec.push_back(newit);
 
11
  #include <consensus/consensus.h>
12
  #include <consensus/tx_verify.h>
13
  #include <consensus/validation.h>
14
+ #include <crypto/ripemd160.h>
15
  #include <logging.h>
16
+ #include <policy/coin_age_priority.h>
17
+ #include <policy/fees.h>
18
  #include <policy/policy.h>
19
  #include <policy/settings.h>
20
  #include <random.h>
21
+ #include <scheduler.h>
22
  #include <tinyformat.h>
23
+ #include <script/script.h>
24
  #include <util/check.h>
25
  #include <util/feefrac.h>
26
  #include <util/moneystr.h>
 
42
  TRACEPOINT_SEMAPHORE(mempool, added);
43
  TRACEPOINT_SEMAPHORE(mempool, removed);
44
 
45
+ void CTxMemPoolEntry::UpdateCachedPriority(unsigned int current_height, CAmount value_in_current_block)
46
+ {
47
+ const int height_diff{int(current_height) - int(cachedHeight)};
48
+ cachedPriority += (double(height_diff) * inChainInputValue) / nModSize;
49
+ cachedHeight = current_height;
50
+ inChainInputValue += value_in_current_block;
51
+ assert(MoneyRange(inChainInputValue));
52
+ }
53
+
54
+ double CTxMemPoolEntry::GetPriority(unsigned int current_height) const
55
+ {
56
+ // This is accurate when the height range does not cross a block containing
57
+ // one of the transaction's inputs.
58
+ const int height_diff{int(current_height) - int(cachedHeight)};
59
+ const double priority{cachedPriority + (double(height_diff) * inChainInputValue) / nModSize};
60
+ return std::max(priority, 0.0);
61
+ }
62
+
63
+ namespace {
64
+ struct UpdatePriority {
65
+ unsigned int height;
66
+ CAmount value;
67
+
68
+ void operator()(CTxMemPoolEntry& entry) const
69
+ {
70
+ entry.UpdateCachedPriority(height, value);
71
+ }
72
+ };
73
+ } // namespace
74
+
75
+ void CTxMemPool::UpdateDependentPriorities(const CTransaction& tx, unsigned int block_height, bool add_to_chain)
76
+ {
77
+ LOCK(cs);
78
+ for (unsigned int i{0}; i < tx.vout.size(); ++i) {
79
+ const auto next_tx{mapNextTx.find(COutPoint{tx.GetHash(), i})};
80
+ if (next_tx == mapNextTx.end()) continue;
81
+
82
+ const txiter entry{mapTx.find(next_tx->second->GetHash())};
83
+ const CAmount value{add_to_chain ? tx.vout[i].nValue : -tx.vout[i].nValue};
84
+ mapTx.modify(entry, UpdatePriority{block_height, value});
85
+ }
86
+ }
87
+
88
  bool TestLockPointValidity(CChain& active_chain, const LockPoints& lp)
89
  {
90
  AssertLockHeld(cs_main);
 
102
  return true;
103
  }
104
 
105
+ uint160 ScriptHashkey(const CScript& script)
106
+ {
107
+ uint160 hash;
108
+ CRIPEMD160().Write(script.data(), script.size()).Finalize(hash.begin());
109
+ return hash;
110
+ }
111
+
112
  void CTxMemPool::UpdateForDescendants(txiter updateIt, cacheMap& cachedDescendants,
113
  const std::set<Txid>& setExclude, std::set<Txid>& descendants_to_remove)
114
  {
 
459
  static CTxMemPool::Options&& Flatten(CTxMemPool::Options&& opts, bilingual_str& error)
460
  {
461
  opts.check_ratio = std::clamp<int>(opts.check_ratio, 0, 1'000'000);
462
+ int64_t descendant_limit_bytes = maxmempoolMinimumBytes(opts.limits.descendant_size_vbytes);
463
  if (opts.max_size_bytes < 0 || opts.max_size_bytes < descendant_limit_bytes) {
464
  error = strprintf(_("-maxmempool must be at least %d MB"), std::ceil(descendant_limit_bytes / 1'000'000.0));
465
  }
 
469
  CTxMemPool::CTxMemPool(Options opts, bilingual_str& error)
470
  : m_opts{Flatten(std::move(opts), error)}
471
  {
472
+ Assert(m_opts.scheduler || !m_opts.dust_relay_target);
473
+ m_opts.dust_relay_feerate_floor = m_opts.dust_relay_feerate;
474
+ #ifdef BUILDING_FOR_LIBBITCOINKERNEL
475
+ assert(!m_opts.scheduler);
476
+ #else
477
+ if (m_opts.scheduler) {
478
+ m_opts.scheduler->scheduleEvery([this]{
479
+ UpdateDynamicDustFeerate();
480
+ }, DYNAMIC_DUST_FEERATE_UPDATE_INTERVAL);
481
+ }
482
+ #endif
483
  }
484
 
485
  bool CTxMemPool::isSpent(const COutPoint& outpoint) const
 
519
  ancestors = *Assume(changeset->CalculateMemPoolAncestors(tx_entry, Limits::NoLimits()));
520
  }
521
  // First splice this entry into mapTx.
522
+ #if BOOST_VERSION >= 107400
523
  auto node_handle = changeset->m_to_add.extract(tx_entry);
524
  auto result = mapTx.insert(std::move(node_handle));
525
 
526
  Assume(result.inserted);
527
  txiter it = result.position;
528
+ #else
529
+ // Boost 1.73 didn't support node extraction, so we have to copy
530
+ auto result = mapTx.emplace(CTxMemPoolEntry::ExplicitCopy, *tx_entry);
531
+ changeset->m_to_add.erase(tx_entry);
532
+
533
+ Assume(result.second);
534
+ txiter it = result.first;
535
+ #endif
536
 
537
  // Now update the entry for ancestors/descendants.
538
  if (ancestors.has_value()) {
 
585
  txns_randomized.emplace_back(tx.GetWitnessHash(), newit);
586
  newit->idx_randomized = txns_randomized.size() - 1;
587
 
588
+ for (auto& vSPK : entry.mapSPK) {
589
+ const uint160& SPKKey = vSPK.first;
590
+ const MemPool_SPK_State& claims = vSPK.second;
591
+ if (claims & MSS_CREATED) {
592
+ mapUsedSPK[SPKKey].first = &tx;
593
+ }
594
+ if (claims & MSS_SPENT) {
595
+ mapUsedSPK[SPKKey].second = &tx;
596
+ }
597
+ }
598
+
599
  TRACEPOINT(mempool, added,
600
  entry.GetTx().GetHash().data(),
601
  entry.GetTxSize(),
 
624
  std::chrono::duration_cast<std::chrono::duration<std::uint64_t>>(it->GetTime()).count()
625
  );
626
 
627
+ const CTransaction& tx = it->GetTx();
628
  for (const CTxIn& txin : it->GetTx().vin)
629
  mapNextTx.erase(txin.prevout);
630
 
 
642
  txns_randomized.clear();
643
  }
644
 
645
+ for (auto& vSPK : it->mapSPK) {
646
+ const uint160& SPKKey = vSPK.first;
647
+ if (mapUsedSPK[SPKKey].first == &tx) {
648
+ mapUsedSPK[SPKKey].first = NULL;
649
+ }
650
+ if (mapUsedSPK[SPKKey].second == &tx) {
651
+ mapUsedSPK[SPKKey].second = NULL;
652
+ }
653
+ if (!(mapUsedSPK[SPKKey].first || mapUsedSPK[SPKKey].second)) {
654
+ mapUsedSPK.erase(SPKKey);
655
+ }
656
+ }
657
+
658
  totalTxSize -= it->GetTxSize();
659
  m_total_fee -= it->GetFee();
660
  cachedInnerUsage -= it->DynamicMemoryUsage();
 
771
  if (mapTx.size() || mapNextTx.size() || mapDeltas.size()) {
772
  txs_removed_for_block.reserve(vtx.size());
773
  for (const auto& tx : vtx) {
774
+ UpdateDependentPriorities(*tx, nBlockHeight, true);
775
  txiter it = mapTx.find(tx->GetHash());
776
  if (it != mapTx.end()) {
777
  setEntries stage;
 
790
  blockSinceLastRollingFeeBump = true;
791
  }
792
 
793
+ #ifndef BUILDING_FOR_LIBBITCOINKERNEL
794
+ void CTxMemPool::UpdateDynamicDustFeerate()
795
+ {
796
+ CFeeRate est_feerate{0};
797
+ if (m_opts.dust_relay_target < 0 && m_opts.estimator) {
798
+ static constexpr double target_success_threshold{0.8};
799
+ est_feerate = m_opts.estimator->estimateRawFee(-m_opts.dust_relay_target, target_success_threshold, FeeEstimateHorizon::LONG_HALFLIFE, nullptr);
800
+ } else if (m_opts.dust_relay_target > 0) {
801
+ auto bytes_remaining = int64_t{m_opts.dust_relay_target} * 1'000;
802
+ LOCK(cs);
803
+ for (auto mi = mapTx.get<ancestor_score>().begin(); mi != mapTx.get<ancestor_score>().end(); ++mi) {
804
+ bytes_remaining -= mi->GetTxSize();
805
+ if (bytes_remaining <= 0) {
806
+ est_feerate = CFeeRate(mi->GetFee(), mi->GetTxSize());
807
+ break;
808
+ }
809
+ }
810
+ }
811
+
812
+ est_feerate = (est_feerate * m_opts.dust_relay_multiplier) / 1'000;
813
+
814
+ if (est_feerate < m_opts.dust_relay_feerate_floor) {
815
+ est_feerate = m_opts.dust_relay_feerate_floor;
816
+ }
817
+
818
+ if (m_opts.dust_relay_feerate != est_feerate) {
819
+ LogDebug(BCLog::MEMPOOL, "Updating dust feerate to %s\n", est_feerate.ToString(FeeEstimateMode::SAT_VB));
820
+ m_opts.dust_relay_feerate = est_feerate;
821
+ }
822
+ }
823
+ #endif
824
+
825
  void CTxMemPool::check(const CCoinsViewCache& active_coins_tip, int64_t spendheight) const
826
  {
827
  if (m_opts.check_ratio == 0) return;
 
841
 
842
  for (const auto& it : GetSortedDepthAndScore()) {
843
  checkTotal += it->GetTxSize();
844
+ const auto fresh_coin_age = GetCoinAge(it->GetTx(), active_coins_tip, spendheight);
845
+ const auto fresh_mod_vsize = CalculateModifiedSize(it->GetTx(), it->GetTxSize());
846
+ const double freshPriority = ComputePriority2(fresh_coin_age.inputs_coin_age, fresh_mod_vsize);
847
+ double cachePriority = it->GetPriority(spendheight);
848
+ double priDiff = cachePriority > freshPriority ? cachePriority - freshPriority : freshPriority - cachePriority;
849
+ // Verify that the difference between the on the fly calculation and a fresh calculation
850
+ // is small enough to be a result of double imprecision.
851
+ assert(priDiff < .0001 * freshPriority + 1);
852
  check_total_fee += it->GetFee();
853
  innerUsage += it->DynamicMemoryUsage();
854
  const CTransaction& tx = it->GetTx();
 
984
  return iters;
985
  }
986
 
987
+ void CTxMemPool::FindScriptPubKey(const std::set<CScript>& needles, std::map<COutPoint, Coin>& out_results) {
988
+ LOCK(cs);
989
+ for (const CTxMemPoolEntry& entry : mapTx) {
990
+ const CTransaction& tx = entry.GetTx();
991
+ const Txid& hash = tx.GetHash();
992
+ for (size_t txo_index = tx.vout.size(); txo_index > 0; ) {
993
+ --txo_index;
994
+ const CTxOut& txo = tx.vout[txo_index];
995
+ if (needles.count(txo.scriptPubKey)) {
996
+ out_results.emplace(COutPoint(hash, txo_index), Coin(txo, MEMPOOL_HEIGHT, false));
997
+ }
998
+ }
999
+ }
1000
+ }
1001
+
1002
  std::vector<CTxMemPoolEntryRef> CTxMemPool::entryAll() const
1003
  {
1004
  AssertLockHeld(cs);
 
1041
  return i->GetSharedTx();
1042
  }
1043
 
1044
+ void CTxMemPool::PrioritiseTransaction(const Txid& hash, double dPriorityDelta, const CAmount& nFeeDelta)
1045
  {
1046
  {
1047
  LOCK(cs);
1048
+ std::pair<double, CAmount> &deltas = mapDeltas[hash];
1049
+ deltas.first += dPriorityDelta;
1050
+ deltas.second = SaturatingAdd(deltas.second, nFeeDelta);
1051
  txiter it = mapTx.find(hash);
1052
  if (it != mapTx.end()) {
1053
  mapTx.modify(it, [&nFeeDelta](CTxMemPoolEntry& e) { e.UpdateModifiedFee(nFeeDelta); });
1054
+
1055
  // Now update all ancestors' modified fees with descendants
1056
  auto ancestors{AssumeCalculateMemPoolAncestors(__func__, *it, Limits::NoLimits(), /*fSearchForParents=*/false)};
1057
  for (txiter ancestorIt : ancestors) {
 
1066
  }
1067
  ++nTransactionsUpdated;
1068
  }
1069
+ if (deltas.first == 0. && deltas.second == 0) {
1070
  mapDeltas.erase(hash);
1071
  LogPrintf("PrioritiseTransaction: %s (%sin mempool) delta cleared\n", hash.ToString(), it == mapTx.end() ? "not " : "");
1072
  } else {
1073
+ LogPrintf("PrioritiseTransaction: %s (%sin mempool) priority += %f, fee += %s, new delta=%s\n",
1074
  hash.ToString(),
1075
  it == mapTx.end() ? "not " : "",
1076
+ dPriorityDelta,
1077
  FormatMoney(nFeeDelta),
1078
+ FormatMoney(deltas.second));
1079
  }
1080
  }
1081
  }
1082
 
1083
+ void CTxMemPool::ApplyDeltas(const Txid& hash, double &dPriorityDelta, CAmount &nFeeDelta) const
1084
  {
1085
  AssertLockHeld(cs);
1086
+ const auto pos = mapDeltas.find(hash);
1087
  if (pos == mapDeltas.end())
1088
  return;
1089
+ const std::pair<double, CAmount> &deltas = pos->second;
1090
+ dPriorityDelta += deltas.first;
1091
+ nFeeDelta += deltas.second;
1092
  }
1093
 
1094
  void CTxMemPool::ClearPrioritisation(const Txid& hash)
 
1108
  const bool in_mempool{iter != mapTx.end()};
1109
  std::optional<CAmount> modified_fee;
1110
  if (in_mempool) modified_fee = iter->GetModifiedFee();
1111
+ result.emplace_back(delta_info{in_mempool, delta.second, delta.first, modified_fee, txid});
1112
  }
1113
  return result;
1114
  }
 
1205
  size_t CTxMemPool::DynamicMemoryUsage() const {
1206
  LOCK(cs);
1207
  // Estimate the overhead of mapTx to be 15 pointers + an allocation, as no exact formula for boost::multi_index_contained is implemented.
1208
+ return memusage::MallocUsage(sizeof(CTxMemPoolEntry) + 15 * sizeof(void*)) * mapTx.size() + memusage::DynamicUsage(mapNextTx) + memusage::DynamicUsage(mapDeltas) + memusage::DynamicUsage(mapUsedSPK) + memusage::DynamicUsage(txns_randomized) + cachedInnerUsage;
1209
  }
1210
 
1211
  void CTxMemPool::RemoveUnbroadcastTx(const Txid& txid, const bool unchecked) {
 
1545
  return std::make_pair(old_chunks, new_chunks);
1546
  }
1547
 
1548
+ CTxMemPool::ChangeSet::TxHandle CTxMemPool::ChangeSet::StageAddition(const CTransactionRef& tx, const CAmount fee, int64_t time, unsigned int entry_height, uint64_t entry_sequence, const CoinAgeCache coin_age_cache, bool spends_coinbase, int32_t extra_weight, int64_t sigops_cost, LockPoints lp)
1549
  {
1550
  LOCK(m_pool->cs);
1551
  Assume(m_to_add.find(tx->GetHash()) == m_to_add.end());
1552
+ auto newit = m_to_add.emplace(tx, fee, time, entry_height, entry_sequence, coin_age_cache, spends_coinbase, /*extra_weight=*/ extra_weight, /*sigops_cost=*/ sigops_cost, lp).first;
1553
+ double priority_delta{0.};
1554
  CAmount delta{0};
1555
+ m_pool->ApplyDeltas(tx->GetHash(), priority_delta, delta);
1556
+ // NOTE: priority_delta is handled in addPriorityTxs
1557
  if (delta) m_to_add.modify(newit, [&delta](CTxMemPoolEntry& e) { e.UpdateModifiedFee(delta); });
1558
 
1559
  m_entry_vec.push_back(newit);