Skip to content
Bitcoin Roots

v29.4-roots.2 · Commit 3: [PATCH 03/21] policy: restore conservative relay and network controls

src/validation.cpp

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

File metadata
index ff281bc1a6f885fd9efe1f01cfc2b91d230df084..c2530e7d119fcc4fe7fb0f89824eeaad60e13a37 100644

Download original patch · Release notes

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

+ Added− RemovedUnmarked lines are context.

Scroll the code area horizontally to read long lines. The two line-number columns refer to before and after.

src/validation.cpp CHANGED
@@ -104,6 +104,8 @@ const std::vector<std::string> CHECKLEVEL_DOC {
104
104
  "level 4 tries to reconnect the blocks",
105
105
  "each level includes the checks of the previous levels",
106
106
  };
107
+
108
+ SpkReuseModes SpkReuseMode{SRM_ALLOW};
107
109
  /** The number of blocks to keep below the deepest prune lock.
108
110
  * There is nothing special about this number. It is higher than what we
109
111
  * expect to see in regular mainnet reorgs, but not so high that it would
@@ -270,7 +272,39 @@ bool CheckSequenceLocksAtTip(CBlockIndex* tip,
270
272
  // Returns the script flags which should be checked for a given block
271
273
  static unsigned int GetBlockScriptFlags(const CBlockIndex& block_index, const ChainstateManager& chainman);
272
274
 
273
- static void LimitMempoolSize(CTxMemPool& pool, CCoinsViewCache& coins_cache)
275
+ /** Compute accurate total signature operation cost of a transaction.
276
+ * Not consensus-critical, since legacy sigops counting is always used in the protocol.
277
+ */
278
+ int64_t GetAccurateTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& inputs, int flags)
279
+ {
280
+ if (tx.IsCoinBase()) {
281
+ return 0;
282
+ }
283
+
284
+ unsigned int nSigOps = 0;
285
+ for (const auto& txin : tx.vin) {
286
+ nSigOps += txin.scriptSig.GetSigOpCount(false);
287
+ }
288
+
289
+ if (flags & SCRIPT_VERIFY_P2SH) {
290
+ nSigOps += GetP2SHSigOpCount(tx, inputs);
291
+ }
292
+
293
+ nSigOps *= WITNESS_SCALE_FACTOR;
294
+
295
+ if (flags & SCRIPT_VERIFY_WITNESS) {
296
+ for (const auto& txin : tx.vin) {
297
+ const Coin& coin = inputs.AccessCoin(txin.prevout);
298
+ assert(!coin.IsSpent());
299
+ const CTxOut &prevout = coin.out;
300
+ nSigOps += CountWitnessSigOps(txin.scriptSig, prevout.scriptPubKey, &txin.scriptWitness, flags);
301
+ }
302
+ }
303
+
304
+ return nSigOps;
305
+ }
306
+
307
+ void LimitMempoolSize(CTxMemPool& pool, CCoinsViewCache& coins_cache)
274
308
  EXCLUSIVE_LOCKS_REQUIRED(::cs_main, pool.cs)
275
309
  {
276
310
  AssertLockHeld(::cs_main);
@@ -457,7 +491,7 @@ public:
457
491
  struct ATMPArgs {
458
492
  const CChainParams& m_chainparams;
459
493
  const int64_t m_accept_time;
460
- const bool m_bypass_limits;
494
+ const ignore_rejects_type& m_ignore_rejects;
461
495
  /*
462
496
  * Return any outpoints which were not previously present in the coins
463
497
  * cache, but were added as a result of validating the tx for mempool
@@ -494,11 +528,11 @@ public:
494
528
 
495
529
  /** Parameters for single transaction mempool validation. */
496
530
  static ATMPArgs SingleAccept(const CChainParams& chainparams, int64_t accept_time,
497
- bool bypass_limits, std::vector<COutPoint>& coins_to_uncache,
531
+ const ignore_rejects_type& ignore_rejects, std::vector<COutPoint>& coins_to_uncache,
498
532
  bool test_accept) {
499
533
  return ATMPArgs{/* m_chainparams */ chainparams,
500
534
  /* m_accept_time */ accept_time,
501
- /* m_bypass_limits */ bypass_limits,
535
+ /* m_ignore_rejects */ ignore_rejects,
502
536
  /* m_coins_to_uncache */ coins_to_uncache,
503
537
  /* m_test_accept */ test_accept,
504
538
  /* m_allow_replacement */ true,
@@ -512,10 +546,10 @@ public:
512
546
 
513
547
  /** Parameters for test package mempool validation through testmempoolaccept. */
514
548
  static ATMPArgs PackageTestAccept(const CChainParams& chainparams, int64_t accept_time,
515
- std::vector<COutPoint>& coins_to_uncache) {
549
+ const ignore_rejects_type& ignore_rejects, std::vector<COutPoint>& coins_to_uncache) {
516
550
  return ATMPArgs{/* m_chainparams */ chainparams,
517
551
  /* m_accept_time */ accept_time,
518
- /* m_bypass_limits */ false,
552
+ /* m_ignore_rejects */ ignore_rejects,
519
553
  /* m_coins_to_uncache */ coins_to_uncache,
520
554
  /* m_test_accept */ true,
521
555
  /* m_allow_replacement */ false,
@@ -529,10 +563,10 @@ public:
529
563
 
530
564
  /** Parameters for child-with-unconfirmed-parents package validation. */
531
565
  static ATMPArgs PackageChildWithParents(const CChainParams& chainparams, int64_t accept_time,
532
- std::vector<COutPoint>& coins_to_uncache, const std::optional<CFeeRate>& client_maxfeerate) {
566
+ std::vector<COutPoint>& coins_to_uncache, const std::optional<CFeeRate>& client_maxfeerate, const ignore_rejects_type& ignore_rejects) {
533
567
  return ATMPArgs{/* m_chainparams */ chainparams,
534
568
  /* m_accept_time */ accept_time,
535
- /* m_bypass_limits */ false,
569
+ /* m_ignore_rejects */ ignore_rejects,
536
570
  /* m_coins_to_uncache */ coins_to_uncache,
537
571
  /* m_test_accept */ false,
538
572
  /* m_allow_replacement */ true,
@@ -548,7 +582,7 @@ public:
548
582
  static ATMPArgs SingleInPackageAccept(const ATMPArgs& package_args) {
549
583
  return ATMPArgs{/* m_chainparams */ package_args.m_chainparams,
550
584
  /* m_accept_time */ package_args.m_accept_time,
551
- /* m_bypass_limits */ false,
585
+ empty_ignore_rejects,
552
586
  /* m_coins_to_uncache */ package_args.m_coins_to_uncache,
553
587
  /* m_test_accept */ package_args.m_test_accept,
554
588
  /* m_allow_replacement */ true,
@@ -565,7 +599,7 @@ public:
565
599
  // mixing up the order of the arguments. Use static functions above instead.
566
600
  ATMPArgs(const CChainParams& chainparams,
567
601
  int64_t accept_time,
568
- bool bypass_limits,
602
+ const ignore_rejects_type& ignore_rejects,
569
603
  std::vector<COutPoint>& coins_to_uncache,
570
604
  bool test_accept,
571
605
  bool allow_replacement,
@@ -576,7 +610,7 @@ public:
576
610
  bool allow_carveouts)
577
611
  : m_chainparams{chainparams},
578
612
  m_accept_time{accept_time},
579
- m_bypass_limits{bypass_limits},
613
+ m_ignore_rejects{ignore_rejects},
580
614
  m_coins_to_uncache{coins_to_uncache},
581
615
  m_test_accept{test_accept},
582
616
  m_allow_replacement{allow_replacement},
@@ -636,7 +670,8 @@ private:
636
670
  explicit Workspace(const CTransactionRef& ptx) : m_ptx(ptx), m_hash(ptx->GetHash()) {}
637
671
  /** Txids of mempool transactions that this transaction directly conflicts with or may
638
672
  * replace via sibling eviction. */
639
- std::set<Txid> m_conflicts;
673
+ /** .second=true is a consensus conflict, and .second=false is a policy conflict. */
674
+ std::map<Txid, bool> m_conflicts_incl_policy;
640
675
  /** Iterators to mempool entries that this transaction directly conflicts with or may
641
676
  * replace via sibling eviction. */
642
677
  CTxMemPool::setEntries m_iters_conflicting;
@@ -670,6 +705,23 @@ private:
670
705
  PrecomputedTransactionData m_precomputed_txdata;
671
706
  };
672
707
 
708
+ static inline bool MaybeReject_(TxValidationResult reason, const std::string& reason_str, const std::string& debug_msg, const ignore_rejects_type& ignore_rejects, TxValidationState& state) {
709
+ if (ignore_rejects.count(reason_str)) {
710
+ return false;
711
+ }
712
+
713
+ state.Invalid(reason, reason_str, debug_msg);
714
+ return true;
715
+ }
716
+
717
+ #define MaybeRejectDbg(reason, reason_str, debug_msg) do { \
718
+ if (MaybeReject_(reason, reason_str, debug_msg, ignore_rejects, state)) { \
719
+ return false; \
720
+ } \
721
+ } while(0)
722
+
723
+ #define MaybeReject(reason, reason_str) MaybeRejectDbg(reason, reason_str, "")
724
+
673
725
  // Run the policy checks on a given transaction, excluding any script checks.
674
726
  // Looks up inputs, calculates feerate, considers replacement, evaluates
675
727
  // package limits, etc. As this function can be invoked for "free" by a peer,
@@ -677,11 +729,11 @@ private:
677
729
  bool PreChecks(ATMPArgs& args, Workspace& ws) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs);
678
730
 
679
731
  // Run checks for mempool replace-by-fee, only used in AcceptSingleTransaction.
680
- bool ReplacementChecks(Workspace& ws) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs);
732
+ bool ReplacementChecks(ATMPArgs& args, Workspace& ws) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs);
681
733
 
682
734
  // Enforce package mempool ancestor/descendant limits (distinct from individual
683
735
  // ancestor/descendant limits done in PreChecks) and run Package RBF checks.
684
- bool PackageMempoolChecks(const std::vector<CTransactionRef>& txns,
736
+ bool PackageMempoolChecks(const ATMPArgs& args, const std::vector<CTransactionRef>& txns,
685
737
  std::vector<Workspace>& workspaces,
686
738
  int64_t total_vsize,
687
739
  PackageValidationState& package_state) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs);
@@ -707,16 +759,16 @@ private:
707
759
  EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs);
708
760
 
709
761
  // Compare a package's feerate against minimum allowed.
710
- bool CheckFeeRate(size_t package_size, CAmount package_fee, TxValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(::cs_main, m_pool.cs)
762
+ bool CheckFeeRate(size_t package_size, CAmount package_fee, TxValidationState& state, const ignore_rejects_type& ignore_rejects) EXCLUSIVE_LOCKS_REQUIRED(::cs_main, m_pool.cs)
711
763
  {
712
764
  AssertLockHeld(::cs_main);
713
765
  AssertLockHeld(m_pool.cs);
714
766
  CAmount mempoolRejectFee = m_pool.GetMinFee().GetFee(package_size);
715
- if (mempoolRejectFee > 0 && package_fee < mempoolRejectFee) {
767
+ if (mempoolRejectFee > 0 && package_fee < mempoolRejectFee && !ignore_rejects.count(rejectmsg_lowfee_mempool)) {
716
768
  return state.Invalid(TxValidationResult::TX_RECONSIDERABLE, "mempool min fee not met", strprintf("%d < %d", package_fee, mempoolRejectFee));
717
769
  }
718
770
 
719
- if (package_fee < m_pool.m_opts.min_relay_feerate.GetFee(package_size)) {
771
+ if (package_fee < m_pool.m_opts.min_relay_feerate.GetFee(package_size) && !ignore_rejects.count(rejectmsg_lowfee_relay)) {
720
772
  return state.Invalid(TxValidationResult::TX_RECONSIDERABLE, "min relay fee not met",
721
773
  strprintf("%d < %d", package_fee, m_pool.m_opts.min_relay_feerate.GetFee(package_size)));
722
774
  }
@@ -781,7 +833,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
781
833
 
782
834
  // Copy/alias what we need out of args
783
835
  const int64_t nAcceptTime = args.m_accept_time;
784
- const bool bypass_limits = args.m_bypass_limits;
836
+ const ignore_rejects_type& ignore_rejects = args.m_ignore_rejects;
785
837
  std::vector<COutPoint>& coins_to_uncache = args.m_coins_to_uncache;
786
838
 
787
839
  // Alias what we need out of ws
@@ -795,21 +847,25 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
795
847
  if (tx.IsCoinBase())
796
848
  return state.Invalid(TxValidationResult::TX_CONSENSUS, "coinbase");
797
849
 
850
+ if (tx.version == TRUC_VERSION && m_pool.m_opts.truc_policy == TRUCPolicy::Reject) {
851
+ return state.Invalid(TxValidationResult::TX_NOT_STANDARD, "version");
852
+ }
853
+
798
854
  // Rather not work on nonstandard transactions (unless -testnet/-regtest)
799
855
  std::string reason;
800
- if (m_pool.m_opts.require_standard && !IsStandardTx(tx, m_pool.m_opts.max_datacarrier_bytes, m_pool.m_opts.permit_bare_multisig, m_pool.m_opts.dust_relay_feerate, reason)) {
856
+ if (m_pool.m_opts.require_standard && !IsStandardTx(tx, m_pool.m_opts, reason, ignore_rejects)) {
801
857
  return state.Invalid(TxValidationResult::TX_NOT_STANDARD, reason);
802
858
  }
803
859
 
804
860
  // Transactions smaller than 65 non-witness bytes are not relayed to mitigate CVE-2017-12842.
805
861
  if (::GetSerializeSize(TX_NO_WITNESS(tx)) < MIN_STANDARD_TX_NONWITNESS_SIZE)
806
- return state.Invalid(TxValidationResult::TX_NOT_STANDARD, "tx-size-small");
862
+ MaybeReject(TxValidationResult::TX_NOT_STANDARD, "tx-size-small");
807
863
 
808
864
  // Only accept nLockTime-using transactions that can be mined in the next
809
865
  // block; we don't want our mempool filled up with transactions that can't
810
866
  // be mined yet.
811
867
  if (!CheckFinalTxAtTip(*Assert(m_active_chainstate.m_chain.Tip()), tx)) {
812
- return state.Invalid(TxValidationResult::TX_PREMATURE_SPEND, "non-final");
868
+ MaybeReject(TxValidationResult::TX_PREMATURE_SPEND, "non-final");
813
869
  }
814
870
 
815
871
  if (m_pool.exists(GenTxid::Wtxid(tx.GetWitnessHash()))) {
@@ -821,16 +877,68 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
821
877
  return state.Invalid(TxValidationResult::TX_CONFLICT, "txn-same-nonwitness-data-in-mempool");
822
878
  }
823
879
 
880
+ auto spk_reuse_mode = SpkReuseMode;
881
+ if (ignore_rejects.count("txn-spk-reused")) {
882
+ spk_reuse_mode = SRM_ALLOW;
883
+ }
884
+ SPKStates_t mapSPK;
885
+
824
886
  // Check for conflicts with in-memory transactions
825
887
  for (const CTxIn &txin : tx.vin)
826
888
  {
827
889
  const CTransaction* ptxConflicting = m_pool.GetConflictTx(txin.prevout);
828
890
  if (ptxConflicting) {
829
891
  if (!args.m_allow_replacement) {
830
- // Transaction conflicts with a mempool tx, but we're not allowing replacements in this context.
892
+ // Transaction conflicts with a mempool tx, but we're not allowing replacements.
831
893
  return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "bip125-replacement-disallowed");
832
894
  }
833
- ws.m_conflicts.insert(ptxConflicting->GetHash());
895
+ if (!ws.m_conflicts_incl_policy.count(ptxConflicting->GetHash()))
896
+ {
897
+ // Transactions that don't explicitly signal replaceability are
898
+ // *not* replaceable with the current logic, even if one of their
899
+ // unconfirmed ancestors signals replaceability. This diverges
900
+ // from BIP125's inherited signaling description (see CVE-2021-31876).
901
+ // Applications relying on first-seen mempool behavior should
902
+ // check all unconfirmed ancestors; otherwise an opt-in ancestor
903
+ // might be replaced, causing removal of this descendant.
904
+ //
905
+ // All TRUC transactions are considered replaceable.
906
+ //
907
+ // Replaceability signaling of the original transactions may be
908
+ // ignored due to node setting.
909
+ bool allow_rbf;
910
+ if (m_pool.m_opts.rbf_policy == RBFPolicy::Always || ignore_rejects.count("txn-mempool-conflict")) {
911
+ allow_rbf = true;
912
+ } else if (m_pool.m_opts.rbf_policy == RBFPolicy::Never) {
913
+ allow_rbf = false;
914
+ } else {
915
+ allow_rbf = SignalsOptInRBF(*ptxConflicting) || ptxConflicting->version == TRUC_VERSION;
916
+ }
917
+ if (!allow_rbf) {
918
+ return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "txn-mempool-conflict");
919
+ }
920
+
921
+ ws.m_conflicts_incl_policy.emplace(ptxConflicting->GetHash(), true);
922
+ }
923
+ }
924
+ }
925
+
926
+ if (spk_reuse_mode != SRM_ALLOW) {
927
+ for (const CTxOut& txout : tx.vout) {
928
+ uint160 hashSPK = ScriptHashkey(txout.scriptPubKey);
929
+ const auto& SPKUsedIn = m_pool.mapUsedSPK.find(hashSPK);
930
+ if (SPKUsedIn != m_pool.mapUsedSPK.end()) {
931
+ if (SPKUsedIn->second.first) {
932
+ ws.m_conflicts_incl_policy.emplace(SPKUsedIn->second.first->GetHash(), false);
933
+ }
934
+ if (SPKUsedIn->second.second) {
935
+ ws.m_conflicts_incl_policy.emplace(SPKUsedIn->second.second->GetHash(), false);
936
+ }
937
+ }
938
+ if (mapSPK.find(hashSPK) != mapSPK.end()) {
939
+ MaybeReject(TxValidationResult::TX_MEMPOOL_POLICY, "txn-spk-reused-twinoutputs");
940
+ }
941
+ mapSPK[hashSPK] = MemPool_SPK_State(mapSPK[hashSPK] | MSS_CREATED);
834
942
  }
835
943
  }
836
944
 
@@ -876,22 +984,67 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
876
984
  // Pass in m_view which has all of the relevant inputs cached. Note that, since m_view's
877
985
  // backend was removed, it no longer pulls coins from the mempool.
878
986
  const std::optional<LockPoints> lock_points{CalculateLockPointsAtTip(m_active_chainstate.m_chain.Tip(), m_view, tx)};
987
+ // NOTE: The miner doesn't check this again, so for now it may not be overridden.
879
988
  if (!lock_points.has_value() || !CheckSequenceLocksAtTip(m_active_chainstate.m_chain.Tip(), *lock_points)) {
880
989
  return state.Invalid(TxValidationResult::TX_PREMATURE_SPEND, "non-BIP68-final");
881
990
  }
882
991
 
883
992
  // The mempool holds txs for the next block, so pass height+1 to CheckTxInputs
884
- if (!Consensus::CheckTxInputs(tx, state, m_view, m_active_chainstate.m_chain.Height() + 1, ws.m_base_fees)) {
993
+ const auto block_height_current = m_active_chainstate.m_chain.Height();
994
+ const auto block_height_next = block_height_current + 1;
995
+ if (!Consensus::CheckTxInputs(tx, state, m_view, block_height_next, ws.m_base_fees)) {
885
996
  return false; // state filled in by CheckTxInputs
886
997
  }
887
998
 
888
- if (m_pool.m_opts.require_standard && !AreInputsStandard(tx, m_view)) {
889
- return state.Invalid(TxValidationResult::TX_INPUTS_NOT_STANDARD, "bad-txns-nonstandard-inputs");
999
+ if (m_pool.m_opts.minrelaymaturity) {
1000
+ auto max_coin_height = block_height_next - m_pool.m_opts.minrelaymaturity;
1001
+ static_assert(std::is_signed_v<decltype(max_coin_height)>, "Unsigned max_coin_height needs a range check");
1002
+ for (const CTxIn &txin : tx.vin) {
1003
+ const Coin &coin = m_view.AccessCoin(txin.prevout);
1004
+ if (coin.nHeight > max_coin_height) {
1005
+ MaybeReject(TxValidationResult::TX_PREMATURE_SPEND, "bad-txns-input-immature-depth");
1006
+ }
1007
+ }
1008
+ }
1009
+
1010
+ if (spk_reuse_mode != SRM_ALLOW) {
1011
+ for (const CTxIn& txin : tx.vin) {
1012
+ const Coin &coin = m_view.AccessCoin(txin.prevout);
1013
+ uint160 hashSPK = ScriptHashkey(coin.out.scriptPubKey);
1014
+
1015
+ SPKStates_t::iterator mssit = mapSPK.find(hashSPK);
1016
+ if (mssit != mapSPK.end()) {
1017
+ if (mssit->second & MSS_CREATED) {
1018
+ MaybeReject(TxValidationResult::TX_MEMPOOL_POLICY, "txn-spk-reused-change");
1019
+ }
1020
+ }
1021
+ const auto& SPKit = m_pool.mapUsedSPK.find(hashSPK);
1022
+ if (SPKit != m_pool.mapUsedSPK.end()) {
1023
+ if (SPKit->second.second /* Spent */) {
1024
+ ws.m_conflicts_incl_policy.emplace(SPKit->second.second->GetHash(), false);
1025
+ }
1026
+ }
1027
+ mapSPK[hashSPK] = MemPool_SPK_State(mapSPK[hashSPK] | MSS_SPENT);
1028
+ }
1029
+ }
1030
+
1031
+ if (m_pool.m_opts.require_standard && !AreInputsStandard(tx, m_view, m_pool.m_opts, "bad-txns-input-", reason, ignore_rejects)) {
1032
+ return state.Invalid(TxValidationResult::TX_INPUTS_NOT_STANDARD, reason);
1033
+ }
1034
+
1035
+ if (m_pool.m_opts.datacarrier_fullcount || !m_pool.m_opts.accept_non_std_datacarrier) {
1036
+ const auto dcb = DatacarrierBytes(tx, m_view);
1037
+ if (dcb.second > 0 && !(m_pool.m_opts.accept_non_std_datacarrier || ignore_rejects.count("txn-datacarrier-nonstandard"))) {
1038
+ return state.Invalid(TxValidationResult::TX_INPUTS_NOT_STANDARD, "txn-datacarrier-nonstandard");
1039
+ }
1040
+ if (m_pool.m_opts.datacarrier_fullcount && (!ignore_rejects.count("txn-datacarrier-exceeded")) && dcb.first + dcb.second > m_pool.m_opts.max_datacarrier_bytes.value_or(0)) {
1041
+ return state.Invalid(TxValidationResult::TX_INPUTS_NOT_STANDARD, "txn-datacarrier-exceeded");
1042
+ }
890
1043
  }
891
1044
 
892
1045
  // Check for non-standard witnesses.
893
- if (tx.HasWitness() && m_pool.m_opts.require_standard && !IsWitnessStandard(tx, m_view)) {
894
- return state.Invalid(TxValidationResult::TX_WITNESS_MUTATED, "bad-witness-nonstandard");
1046
+ if (tx.HasWitness() && m_pool.m_opts.require_standard && !IsWitnessStandard(tx, m_view, "bad-witness-", reason, ignore_rejects)) {
1047
+ return state.Invalid(TxValidationResult::TX_WITNESS_MUTATED, reason);
895
1048
  }
896
1049
 
897
1050
  int64_t nSigOpsCost = GetTransactionSigOpCost(tx, m_view, STANDARD_SCRIPT_VERIFY_FLAGS);
@@ -907,29 +1060,63 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
907
1060
  }
908
1061
  }
909
1062
 
910
- // Set entry_sequence to 0 when bypass_limits is used; this allows txs from a block
1063
+ // Since entries arrive *after* the tip's height, their priority is for the height+1
1064
+ const auto coin_age = GetCoinAge(tx, m_view, block_height_next);
1065
+
1066
+ if (coin_age.inputs_coin_age < m_pool.m_opts.minrelaycoinblocks) {
1067
+ MaybeReject(TxValidationResult::TX_PREMATURE_SPEND, "bad-txns-input-immature-coinblocks");
1068
+ }
1069
+
1070
+ // Set entry_sequence to 0 when rejectmsg_zero_mempool_entry_seq is used; this allows txs from a block
911
1071
  // reorg to be marked earlier than any child txs that were already in the mempool.
912
- const uint64_t entry_sequence = bypass_limits ? 0 : m_pool.GetSequence();
1072
+ const uint64_t entry_sequence = args.m_ignore_rejects.count(rejectmsg_zero_mempool_entry_seq) ? 0 : m_pool.GetSequence();
1073
+ int32_t extra_weight = CalculateExtraTxWeight(*ptx, m_view, ::g_weight_per_data_byte);
913
1074
  if (!m_subpackage.m_changeset) {
914
1075
  m_subpackage.m_changeset = m_pool.GetChangeSet();
915
1076
  }
916
- ws.m_tx_handle = m_subpackage.m_changeset->StageAddition(ptx, ws.m_base_fees, nAcceptTime, m_active_chainstate.m_chain.Height(), entry_sequence, fSpendsCoinbase, nSigOpsCost, lock_points.value());
1077
+ ws.m_tx_handle = m_subpackage.m_changeset->StageAddition(ptx, ws.m_base_fees, nAcceptTime, block_height_current, entry_sequence, coin_age, fSpendsCoinbase, /*extra_weight=*/ extra_weight, /*sigops_cost=*/ nSigOpsCost, lock_points.value());
1078
+
1079
+ if (spk_reuse_mode != SRM_ALLOW) {
1080
+ m_subpackage.m_changeset->m_to_add.modify(ws.m_tx_handle, [=](CTxMemPoolEntry& e) {
1081
+ e.mapSPK = mapSPK;
1082
+ });
1083
+ }
917
1084
 
918
1085
  // ws.m_modified_fees includes any fee deltas from PrioritiseTransaction
919
1086
  ws.m_modified_fees = ws.m_tx_handle->GetModifiedFee();
920
1087
 
921
1088
  ws.m_vsize = ws.m_tx_handle->GetTxSize();
922
1089
 
1090
+ // Reduce effective fee by dust threshold for each sub-dust output
1091
+ if (m_pool.m_opts.subdustfeepenalty) {
1092
+ CAmount dust_penalty{0};
1093
+ for (const auto& txout : tx.vout) {
1094
+ const CAmount dust_threshold = GetDustThreshold(txout, m_pool.m_opts.dust_relay_feerate);
1095
+ if (txout.nValue < dust_threshold) {
1096
+ dust_penalty = SaturatingAdd(dust_penalty, dust_threshold - txout.nValue);
1097
+ }