Skip to content
Bitcoin Roots

v29.4-roots.1 · Commit 3: [PATCH 03/13] 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 401–800 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
@@ -907,29 +1060,63 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) (continued)
1098
+ }
1099
+ if (dust_penalty > 0) {
1100
+ m_subpackage.m_changeset->m_to_add.modify(ws.m_tx_handle, [&](CTxMemPoolEntry& e) {
1101
+ e.UpdateModifiedFee(-dust_penalty);
1102
+ });
1103
+ ws.m_modified_fees = SaturatingAdd(ws.m_modified_fees, -dust_penalty);
1104
+ }
1105
+ }
1106
+
923
1107
  // Enforces 0-fee for dust transactions, no incentive to be mined alone
924
- if (m_pool.m_opts.require_standard) {
1108
+ if (m_pool.m_opts.require_standard && !ignore_rejects.count("dust")) {
925
1109
  if (!PreCheckEphemeralTx(*ptx, m_pool.m_opts.dust_relay_feerate, ws.m_base_fees, ws.m_modified_fees, state)) {
926
1110
  return false; // state filled in by PreCheckEphemeralTx
927
1111
  }
928
1112
  }
929
1113
 
930
- if (nSigOpsCost > MAX_STANDARD_TX_SIGOPS_COST)
931
- return state.Invalid(TxValidationResult::TX_NOT_STANDARD, "bad-txns-too-many-sigops",
1114
+ // To avoid rejecting low-sigop bare-multisig transactions, the sigops
1115
+ // are counted a second time more accurately.
1116
+ if ((nSigOpsCost > MAX_STANDARD_TX_SIGOPS_COST) || (nBytesPerSigOpStrict && GetAccurateTransactionSigOpCost(tx, m_view, STANDARD_SCRIPT_VERIFY_FLAGS) > ws.m_vsize * WITNESS_SCALE_FACTOR / nBytesPerSigOpStrict)) {
1117
+ MaybeRejectDbg(TxValidationResult::TX_NOT_STANDARD, "bad-txns-too-many-sigops",
932
1118
  strprintf("%d", nSigOpsCost));
1119
+ }
933
1120
 
934
1121
  // No individual transactions are allowed below the min relay feerate except from disconnected blocks.
935
1122
  // This requirement, unlike CheckFeeRate, cannot be bypassed using m_package_feerates because,
@@ -937,7 +1124,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
937
1124
  // method of ensuring the tx remains bumped. For example, the fee-bumping child could disappear
938
1125
  // due to a replacement.
939
1126
  // The only exception is TRUC transactions.
940
- if (!bypass_limits && ws.m_ptx->version != TRUC_VERSION && ws.m_modified_fees < m_pool.m_opts.min_relay_feerate.GetFee(ws.m_vsize)) {
1127
+ if ((ws.m_ptx->version != TRUC_VERSION || m_pool.m_opts.truc_policy != TRUCPolicy::Enforce) && ws.m_modified_fees < m_pool.m_opts.min_relay_feerate.GetFee(ws.m_vsize) && !args.m_ignore_rejects.count(rejectmsg_lowfee_relay)) {
941
1128
  // Even though this is a fee-related failure, this result is TX_MEMPOOL_POLICY, not
942
1129
  // TX_RECONSIDERABLE, because it cannot be bypassed using package validation.
943
1130
  return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "min relay fee not met",
@@ -946,16 +1133,20 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
946
1133
  // No individual transactions are allowed below the mempool min feerate except from disconnected
947
1134
  // blocks and transactions in a package. Package transactions will be checked using package
948
1135
  // feerate later.
949
- if (!bypass_limits && !args.m_package_feerates && !CheckFeeRate(ws.m_vsize, ws.m_modified_fees, state)) return false;
1136
+ if (!args.m_package_feerates && !CheckFeeRate(ws.m_vsize, ws.m_modified_fees, state, args.m_ignore_rejects)) return false;
950
1137
 
951
- ws.m_iters_conflicting = m_pool.GetIterSet(ws.m_conflicts);
1138
+ std::set<Txid> conflicts_as_a_set;
1139
+ std::transform(ws.m_conflicts_incl_policy.begin(), ws.m_conflicts_incl_policy.end(),
1140
+ std::inserter(conflicts_as_a_set, conflicts_as_a_set.end()),
1141
+ [](const std::pair<Txid, bool>& pair){ return pair.first; });
1142
+ ws.m_iters_conflicting = m_pool.GetIterSet(conflicts_as_a_set);
952
1143
 
953
1144
  // Note that these modifications are only applicable to single transaction scenarios;
954
1145
  // carve-outs are disabled for multi-transaction evaluations.
955
1146
  CTxMemPool::Limits maybe_rbf_limits = m_pool.m_opts.limits;
956
1147
 
957
1148
  // Calculate in-mempool ancestors, up to a limit.
958
- if (ws.m_conflicts.size() == 1 && args.m_allow_carveouts) {
1149
+ if (ws.m_conflicts_incl_policy.size() == 1 && args.m_allow_carveouts) {
959
1150
  // In general, when we receive an RBF transaction with mempool conflicts, we want to know whether we
960
1151
  // would meet the chain limits after the conflicts have been removed. However, there isn't a practical
961
1152
  // way to do this short of calculating the ancestor and descendant sets with an overlay cache of
@@ -990,7 +1181,13 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
990
1181
  maybe_rbf_limits.descendant_size_vbytes += conflict->GetSizeWithDescendants();
991
1182
  }
992
1183
 
993
- if (auto ancestors{m_subpackage.m_changeset->CalculateMemPoolAncestors(ws.m_tx_handle, maybe_rbf_limits)}) {
1184
+ CTxMemPool::Limits limits;
1185
+ if (ignore_rejects.count("too-long-mempool-chain")) {
1186
+ limits = CTxMemPool::Limits::NoLimits();
1187
+ } else {
1188
+ limits = maybe_rbf_limits;
1189
+ }
1190
+ if (auto ancestors{m_subpackage.m_changeset->CalculateMemPoolAncestors(ws.m_tx_handle, limits)}) {
994
1191
  ws.m_ancestors = std::move(*ancestors);
995
1192
  } else {
996
1193
  // If CalculateMemPoolAncestors fails second time, we want the original error string.
@@ -1019,7 +1216,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
1019
1216
  .descendant_count = maybe_rbf_limits.descendant_count + 1,
1020
1217
  .descendant_size_vbytes = maybe_rbf_limits.descendant_size_vbytes + EXTRA_DESCENDANT_TX_SIZE_LIMIT,
1021
1218
  };
1022
- if (ws.m_vsize > EXTRA_DESCENDANT_TX_SIZE_LIMIT || ws.m_ptx->version == TRUC_VERSION) {
1219
+ if (ws.m_vsize > EXTRA_DESCENDANT_TX_SIZE_LIMIT || (ws.m_ptx->version == TRUC_VERSION && m_pool.m_opts.truc_policy == TRUCPolicy::Enforce)) {
1023
1220
  return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "too-long-mempool-chain", error_message);
1024
1221
  }
1025
1222
  if (auto ancestors_retry{m_subpackage.m_changeset->CalculateMemPoolAncestors(ws.m_tx_handle, cpfp_carve_out_limits)}) {
@@ -1032,8 +1229,8 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
1032
1229
  // Even though just checking direct mempool parents for inheritance would be sufficient, we
1033
1230
  // check using the full ancestor set here because it's more convenient to use what we have
1034
1231
  // already calculated.
1035
- if (!args.m_bypass_limits) {
1036
- if (const auto err{SingleTRUCChecks(ws.m_ptx, ws.m_ancestors, ws.m_conflicts, ws.m_vsize)}) {
1232
+ if (m_pool.m_opts.truc_policy == TRUCPolicy::Enforce && !ignore_rejects.count("truc")) {
1233
+ if (const auto err{SingleTRUCChecks(ws.m_ptx, "truc-", reason, ignore_rejects, ws.m_ancestors, conflicts_as_a_set, ws.m_vsize)}) {
1037
1234
  // Single transaction contexts only.
1038
1235
  if (args.m_allow_sibling_eviction && err->second != nullptr) {
1039
1236
  // We should only be considering where replacement is considered valid as well.
@@ -1041,7 +1238,8 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
1041
1238
 
1042
1239
  // Potential sibling eviction. Add the sibling to our list of mempool conflicts to be
1043
1240
  // included in RBF checks.
1044
- ws.m_conflicts.insert(err->second->GetHash());
1241
+ ws.m_conflicts_incl_policy.emplace(err->second->GetHash(), false);
1242
+ conflicts_as_a_set.insert(err->second->GetHash());
1045
1243
  // Adding the sibling to m_iters_conflicting here means that it doesn't count towards
1046
1244
  // RBF Carve Out above. This is correct, since removing to-be-replaced transactions from
1047
1245
  // the descendant count is done separately in SingleTRUCChecks for TRUC transactions.
@@ -1052,7 +1250,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
1052
1250
  // (which is normally done in PreChecks). However, the only way a TRUC transaction can
1053
1251
  // have a non-TRUC and non-BIP125 descendant is due to a reorg.
1054
1252
  } else {
1055
- return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "TRUC-violation", err->first);
1253
+ return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, reason, err->first);
1056
1254
  }
1057
1255
  }
1058
1256
  }
@@ -1061,18 +1259,22 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
1061
1259
  // that we have the set of all ancestors we can detect this
1062
1260
  // pathological case by making sure ws.m_conflicts and ws.m_ancestors don't
1063
1261
  // intersect.
1064
- if (const auto err_string{EntriesAndTxidsDisjoint(ws.m_ancestors, ws.m_conflicts, hash)}) {
1262
+ bool has_policy_conflict{false};
1263
+ if (const auto err_string{EntriesAndTxidsDisjoint(ws.m_ancestors, ws.m_conflicts_incl_policy, hash, &has_policy_conflict)}) {
1065
1264
  // We classify this as a consensus error because a transaction depending on something it
1066
1265
  // conflicts with would be inconsistent.
1067
1266
  return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-spends-conflicting-tx", *err_string);
1068
1267
  }
1268
+ if (has_policy_conflict) {
1269
+ MaybeReject(TxValidationResult::TX_MEMPOOL_POLICY, "txn-spk-reused-chained");
1270
+ }
1069
1271
 
1070
1272
  // We want to detect conflicts in any tx in a package to trigger package RBF logic
1071
- m_subpackage.m_rbf |= !ws.m_conflicts.empty();
1273
+ m_subpackage.m_rbf |= !ws.m_conflicts_incl_policy.empty();
1072
1274
  return true;
1073
1275
  }
1074
1276
 
1075
- bool MemPoolAccept::ReplacementChecks(Workspace& ws)
1277
+ bool MemPoolAccept::ReplacementChecks(ATMPArgs& args, Workspace& ws)
1076
1278
  {
1077
1279
  AssertLockHeld(cs_main);
1078
1280
  AssertLockHeld(m_pool.cs);
@@ -1091,27 +1293,31 @@ bool MemPoolAccept::ReplacementChecks(Workspace& ws)
1091
1293
  // guarantee that this is incentive-compatible for miners, because it is possible for a
1092
1294
  // descendant transaction of a direct conflict to pay a higher feerate than the transaction that
1093
1295
  // might replace them, under these rules.
1296
+ if (!args.m_ignore_rejects.count("insufficient fee")) {
1094
1297
  if (const auto err_string{PaysMoreThanConflicts(ws.m_iters_conflicting, newFeeRate, hash)}) {
1095
1298
  // This fee-related failure is TX_RECONSIDERABLE because validating in a package may change
1096
1299
  // the result.
1097
1300
  return state.Invalid(TxValidationResult::TX_RECONSIDERABLE,
1098
1301
  strprintf("insufficient fee%s", ws.m_sibling_eviction ? " (including sibling eviction)" : ""), *err_string);
1099
1302
  }
1303
+ } // ignore_rejects
1100
1304
 
1101
1305
  CTxMemPool::setEntries all_conflicts;
1102
1306
 
1103
1307
  // Calculate all conflicting entries and enforce Rule #5.
1104
- if (const auto err_string{GetEntriesForConflicts(tx, m_pool, ws.m_iters_conflicting, all_conflicts)}) {
1308
+ if (const auto err_string{GetEntriesForConflicts(tx, m_pool, ws.m_iters_conflicting, all_conflicts, args.m_ignore_rejects)}) {
1105
1309
  return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY,
1106
1310
  strprintf("too many potential replacements%s", ws.m_sibling_eviction ? " (including sibling eviction)" : ""), *err_string);
1107
1311
  }
1108
1312
  // Enforce Rule #2.
1313
+ if (!args.m_ignore_rejects.count("replacement-adds-unconfirmed")) {
1109
1314
  if (const auto err_string{HasNoNewUnconfirmed(tx, m_pool, all_conflicts)}) {
1110
1315
  // Sibling eviction is only done for TRUC transactions, which cannot have multiple ancestors.
1111
1316
  Assume(!ws.m_sibling_eviction);
1112
1317
  return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY,
1113
1318
  strprintf("replacement-adds-unconfirmed%s", ws.m_sibling_eviction ? " (including sibling eviction)" : ""), *err_string);
1114
1319
  }
1320
+ } // ignore_rejects
1115
1321
 
1116
1322
  // Check if it's economically rational to mine this transaction rather than the ones it
1117
1323
  // replaces and pays for its own relay fees. Enforce Rules #3 and #4.
@@ -1119,12 +1325,14 @@ bool MemPoolAccept::ReplacementChecks(Workspace& ws)
1119
1325
  m_subpackage.m_conflicting_fees += it->GetModifiedFee();
1120
1326
  m_subpackage.m_conflicting_size += it->GetTxSize();
1121
1327
  }
1328
+ if (!args.m_ignore_rejects.count("insufficient fee")) {
1122
1329
  if (const auto err_string{PaysForRBF(m_subpackage.m_conflicting_fees, ws.m_modified_fees, ws.m_vsize,
1123
1330
  m_pool.m_opts.incremental_relay_feerate, hash)}) {
1124
1331
  // Result may change in a package context
1125
1332
  return state.Invalid(TxValidationResult::TX_RECONSIDERABLE,
1126
1333
  strprintf("insufficient fee%s", ws.m_sibling_eviction ? " (including sibling eviction)" : ""), *err_string);
1127
1334
  }
1335
+ } // ignore_rejects
1128
1336
 
1129
1337
  // Add all the to-be-removed transactions to the changeset.
1130
1338
  for (auto it : all_conflicts) {
@@ -1133,7 +1341,7 @@ bool MemPoolAccept::ReplacementChecks(Workspace& ws)
1133
1341
  return true;
1134
1342
  }
1135
1343
 
1136
- bool MemPoolAccept::PackageMempoolChecks(const std::vector<CTransactionRef>& txns,
1344
+ bool MemPoolAccept::PackageMempoolChecks(const ATMPArgs& args, const std::vector<CTransactionRef>& txns,
1137
1345
  std::vector<Workspace>& workspaces,
1138
1346
  const int64_t total_vsize,
1139
1347
  PackageValidationState& package_state)
@@ -1147,7 +1355,13 @@ bool MemPoolAccept::PackageMempoolChecks(const std::vector<CTransactionRef>& txn
1147
1355
 
1148
1356
  assert(txns.size() == workspaces.size());
1149
1357
 
1150
- auto result = m_pool.CheckPackageLimits(txns, total_vsize);
1358
+ util::Result<void> result = [&]() EXCLUSIVE_LOCKS_REQUIRED(m_pool.cs) {
1359
+ if (args.m_ignore_rejects.count("package-mempool-limits")) {
1360
+ return util::Result<void>();
1361
+ } else {
1362
+ return m_pool.CheckPackageLimits(txns, total_vsize);
1363
+ }
1364
+ }();
1151
1365
  if (!result) {
1152
1366
  // This is a package-wide error, separate from an individual transaction error.
1153
1367
  return package_state.Invalid(PackageValidationResult::PCKG_POLICY, "package-mempool-limits", util::ErrorString(result).original);
@@ -1233,6 +1447,77 @@ bool MemPoolAccept::PackageMempoolChecks(const std::vector<CTransactionRef>& txn
1233
1447
  return true;
1234
1448
  }
1235
1449
 
1450
+ unsigned int PolicyScriptVerifyFlags(const ignore_rejects_type& ignore_rejects)
1451
+ {
1452
+ if (ignore_rejects.empty()) {
1453
+ return STANDARD_SCRIPT_VERIFY_FLAGS;
1454
+ }
1455
+ if (ignore_rejects.count("non-mandatory-script-verify-flag")) {
1456
+ return MANDATORY_SCRIPT_VERIFY_FLAGS;
1457
+ }
1458
+
1459
+ unsigned int flags = STANDARD_SCRIPT_VERIFY_FLAGS;
1460
+ if (ignore_rejects.count("non-mandatory-script-verify-flag-upgradable")) {
1461
+ constexpr unsigned int upgradable_policy_flags =
1462
+ SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS |
1463
+ SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM |
1464
+ SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION |
1465
+ SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS |
1466
+ SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE;
1467
+ flags &= ~upgradable_policy_flags;
1468
+ } else {
1469
+ if (ignore_rejects.count("non-mandatory-script-verify-flag-upgradable-nops")) {
1470
+ flags &= ~SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS;
1471
+ }
1472
+ if (ignore_rejects.count("non-mandatory-script-verify-flag-upgradable-witness_program")) {
1473
+ flags &= ~SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM;
1474
+ }
1475
+ if (ignore_rejects.count("non-mandatory-script-verify-flag-upgradable-taproot_version")) {
1476
+ flags &= ~SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION;
1477
+ }
1478
+ if (ignore_rejects.count("non-mandatory-script-verify-flag-upgradable-op_success")) {
1479
+ flags &= ~SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS;
1480
+ }
1481
+ if (ignore_rejects.count("non-mandatory-script-verify-flag-upgradable-pubkeytype")) {
1482
+ flags &= ~SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE;
1483
+ }
1484
+ }
1485
+ if (ignore_rejects.count("non-mandatory-script-verify-flag-bip62")) {
1486
+ constexpr unsigned int bip62_policy_flags =
1487
+ SCRIPT_VERIFY_LOW_S |
1488
+ SCRIPT_VERIFY_SIGPUSHONLY | // NOTE: not actually set ever
1489
+ SCRIPT_VERIFY_MINIMALDATA;
1490
+ flags &= ~bip62_policy_flags;
1491
+ } else {
1492
+ if (ignore_rejects.count("non-mandatory-script-verify-flag-low_s")) {
1493
+ flags &= ~SCRIPT_VERIFY_LOW_S;
1494
+ }
1495
+ if (ignore_rejects.count("non-mandatory-script-verify-flag-minimaldata")) {
1496
+ flags &= ~SCRIPT_VERIFY_MINIMALDATA;
1497
+ }
1498
+ if (ignore_rejects.count("non-mandatory-script-verify-flag-cleanstack")) {
1499
+ flags &= ~SCRIPT_VERIFY_CLEANSTACK;
1500
+ }
1501
+ }
1502
+ if (ignore_rejects.count("non-mandatory-script-verify-flag-strictenc")) {
1503
+ flags &= ~SCRIPT_VERIFY_STRICTENC;
1504
+ }
1505
+ if (ignore_rejects.count("non-mandatory-script-verify-flag-minimalif")) {
1506
+ flags &= ~SCRIPT_VERIFY_MINIMALIF;
1507
+ }
1508
+ if (ignore_rejects.count("non-mandatory-script-verify-flag-nullfail")) {
1509
+ flags &= ~SCRIPT_VERIFY_NULLFAIL;
1510
+ }
1511
+ if (ignore_rejects.count("non-mandatory-script-verify-flag-witness_pubkeytype")) {
1512
+ flags &= ~SCRIPT_VERIFY_WITNESS_PUBKEYTYPE;
1513
+ }
1514
+ if (ignore_rejects.count("non-mandatory-script-verify-flag-const_scriptcode")) {
1515
+ flags &= ~SCRIPT_VERIFY_CONST_SCRIPTCODE;
1516
+ }
1517
+ flags |= MANDATORY_SCRIPT_VERIFY_FLAGS; // for safety
1518
+ return flags;
1519
+ }
1520
+
1236
1521
  bool MemPoolAccept::PolicyScriptChecks(const ATMPArgs& args, Workspace& ws)
1237
1522
  {
1238
1523
  AssertLockHeld(cs_main);
@@ -1240,7 +1525,7 @@ bool MemPoolAccept::PolicyScriptChecks(const ATMPArgs& args, Workspace& ws)
1240
1525
  const CTransaction& tx = *ws.m_ptx;
1241
1526
  TxValidationState& state = ws.m_state;
1242
1527
 
1243
- constexpr unsigned int scriptVerifyFlags = STANDARD_SCRIPT_VERIFY_FLAGS;
1528
+ const unsigned int scriptVerifyFlags = PolicyScriptVerifyFlags(args.m_ignore_rejects);
1244
1529
 
1245
1530
  // Check input scripts and signatures.
1246
1531
  // This is done last to help prevent CPU exhaustion denial-of-service attacks.
@@ -1282,7 +1567,7 @@ bool MemPoolAccept::ConsensusScriptChecks(const ATMPArgs& args, Workspace& ws)
1282
1567
  unsigned int currentBlockScriptVerifyFlags{GetBlockScriptFlags(*m_active_chainstate.m_chain.Tip(), m_active_chainstate.m_chainman)};
1283
1568
  if (!CheckInputsFromMempoolAndCache(tx, state, m_view, m_pool, currentBlockScriptVerifyFlags,
1284
1569
  ws.m_precomputed_txdata, m_active_chainstate.CoinsTip(), GetValidationCache())) {
1285
- LogPrintf("BUG! PLEASE REPORT THIS! CheckInputScripts failed against latest-block but not STANDARD flags %s, %s\n", hash.ToString(), state.ToString());
1570
+ LogError("BUG! PLEASE REPORT THIS! CheckInputScripts failed against latest-block but not STANDARD flags %s, %s", hash.ToString(), state.ToString());
1286
1571
  return Assume(false);
1287
1572
  }
1288
1573
 
@@ -1408,7 +1693,7 @@ bool MemPoolAccept::SubmitPackage(const ATMPArgs& args, std::vector<Workspace>&
1408
1693
  const CTransaction& tx = *ws.m_ptx;
1409
1694
  const auto tx_info = NewMempoolTransactionInfo(ws.m_ptx, ws.m_base_fees,
1410
1695
  ws.m_vsize, (*iter)->GetHeight(),
1411
- args.m_bypass_limits, args.m_package_submission,
1696
+ args.m_ignore_rejects, args.m_package_submission,
1412
1697
  IsCurrentForFeeEstimation(m_active_chainstate),
1413
1698
  m_pool.HasNoInputsOf(tx));
1414
1699
  m_pool.m_opts.signals->TransactionAddedToMempool(tx_info, m_pool.GetAndIncrementSequence());
@@ -1448,7 +1733,7 @@ MempoolAcceptResult MemPoolAccept::AcceptSingleTransaction(const CTransactionRef
1448
1733
  }
1449
1734
  }
1450
1735
 
1451
- if (m_subpackage.m_rbf && !ReplacementChecks(ws)) {
1736
+ if (m_subpackage.m_rbf && !ReplacementChecks(args, ws)) {
1452
1737
  if (ws.m_state.GetResult() == TxValidationResult::TX_RECONSIDERABLE) {
1453
1738
  // Failed for incentives-based fee reasons. Provide the effective feerate and which tx was included.
1454
1739
  return MempoolAcceptResult::FeeFailure(ws.m_state, CFeeRate(ws.m_modified_fees, ws.m_vsize), single_wtxid);
@@ -1472,7 +1757,7 @@ MempoolAcceptResult MemPoolAccept::AcceptSingleTransaction(const CTransactionRef
1472
1757
  FinalizeSubpackage(args);
1473
1758
 
1474
1759
  // Limit the mempool, if appropriate.
1475
- if (!args.m_package_submission && !args.m_bypass_limits) {
1760
+ if (!args.m_package_submission && !args.m_ignore_rejects.count(rejectmsg_mempoolfull)) {
1476
1761
  LimitMempoolSize(m_pool, m_active_chainstate.CoinsTip());
1477
1762
  if (!m_pool.exists(GenTxid::Txid(ws.m_hash))) {
1478
1763
  // The tx no longer meets our (new) mempool minimum feerate but could be reconsidered in a package.
@@ -1487,7 +1772,7 @@ MempoolAcceptResult MemPoolAccept::AcceptSingleTransaction(const CTransactionRef
1487
1772
  Assume(iter.has_value());
1488
1773
  const auto tx_info = NewMempoolTransactionInfo(ws.m_ptx, ws.m_base_fees,
1489
1774
  ws.m_vsize, (*iter)->GetHeight(),
1490
- args.m_bypass_limits, args.m_package_submission,
1775
+ args.m_ignore_rejects, args.m_package_submission,
1491
1776
  IsCurrentForFeeEstimation(m_active_chainstate),
1492
1777
  m_pool.HasNoInputsOf(tx));
1493
1778
  m_pool.m_opts.signals->TransactionAddedToMempool(tx_info, m_pool.GetAndIncrementSequence());
@@ -1554,12 +1839,14 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptMultipleTransactions(const std::
1554
1839
 
1555
1840
  // At this point we have all in-mempool ancestors, and we know every transaction's vsize.
1556
1841
  // Run the TRUC checks on the package.
1842
+ if (m_pool.m_opts.truc_policy == TRUCPolicy::Enforce) {
1843
+ std::string reason;
1557
1844
  for (Workspace& ws : workspaces) {
1558
- if (auto err{PackageTRUCChecks(ws.m_ptx, ws.m_vsize, txns, ws.m_ancestors)}) {
1559
- package_state.Invalid(PackageValidationResult::PCKG_POLICY, "TRUC-violation", err.value());
1845
+ if (auto err{PackageTRUCChecks(ws.m_ptx, ws.m_vsize, "truc-", reason, args.m_ignore_rejects, txns, ws.m_ancestors)}) {
1846
+ package_state.Invalid(PackageValidationResult::PCKG_POLICY, reason, err.value());
1560
1847
  return PackageMempoolAcceptResult(package_state, {});
1561
1848
  }
1562
- }
1849
+ }}
1563
1850
 
1564
1851
  // Transactions must meet two minimum feerates: the mempool minimum fee and min relay fee.
1565
1852
  // For transactions consisting of exactly one child and its parents, it suffices to use the
@@ -1581,7 +1868,8 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptMultipleTransactions(const std::
1581
1868
  [](const auto& ws) { return ws.m_ptx->GetWitnessHash(); });
1582
1869
  TxValidationState placeholder_state;
1583
1870
  if (args.m_package_feerates &&
1584
- !CheckFeeRate(m_subpackage.m_total_vsize, m_subpackage.m_total_modified_fees, placeholder_state)) {
1871
+ (!args.m_ignore_rejects.count("package-fee-too-low")) &&
1872
+ !CheckFeeRate(m_subpackage.m_total_vsize, m_subpackage.m_total_modified_fees, placeholder_state, empty_ignore_rejects)) {
1585
1873
  package_state.Invalid(PackageValidationResult::PCKG_TX, "transaction failed");
1586
1874
  return PackageMempoolAcceptResult(package_state, {{workspaces.back().m_ptx->GetWitnessHash(),
1587
1875
  MempoolAcceptResult::FeeFailure(placeholder_state, CFeeRate(m_subpackage.m_total_modified_fees, m_subpackage.m_total_vsize), all_package_wtxids)}});
@@ -1589,12 +1877,12 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptMultipleTransactions(const std::
1589
1877
 
1590
1878
  // Apply package mempool ancestor/descendant limits. Skip if there is only one transaction,
1591
1879
  // because it's unnecessary.
1592
- if (txns.size() > 1 && !PackageMempoolChecks(txns, workspaces, m_subpackage.m_total_vsize, package_state)) {
1880
+ if (txns.size() > 1 && !PackageMempoolChecks(args, txns, workspaces, m_subpackage.m_total_vsize, package_state)) {
1593
1881
  return PackageMempoolAcceptResult(package_state, std::move(results));
1594
1882
  }
1595
1883
 
1596
1884
  // Now that we've bounded the resulting possible ancestry count, check package for dust spends
1597
- if (m_pool.m_opts.require_standard) {
1885
+ if (m_pool.m_opts.require_standard && !(args.m_ignore_rejects.count("dust") || args.m_ignore_rejects.count("unspent-dust") || args.m_ignore_rejects.count("missing-ephemeral-spends"))) {
1598
1886
  TxValidationState child_state;
1599
1887
  Wtxid child_wtxid;
1600
1888
  if (!CheckEphemeralSpends(txns, m_pool.m_opts.dust_relay_feerate, m_pool, child_state, child_wtxid)) {
@@ -1880,7 +2168,7 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptPackage(const Package& package,
1880
2168
  } // anon namespace
1881
2169
 
1882
2170
  MempoolAcceptResult AcceptToMemoryPool(Chainstate& active_chainstate, const CTransactionRef& tx,
1883
- int64_t accept_time, bool bypass_limits, bool test_accept)
2171
+ int64_t accept_time, const ignore_rejects_type& ignore_rejects, bool test_accept)
1884
2172
  {
1885
2173
  AssertLockHeld(::cs_main);
1886
2174
  const CChainParams& chainparams{active_chainstate.m_chainman.GetParams()};
@@ -1888,7 +2176,7 @@ MempoolAcceptResult AcceptToMemoryPool(Chainstate& active_chainstate, const CTra
1888
2176
  CTxMemPool& pool{*active_chainstate.GetMempool()};
1889
2177
 
1890
2178
  std::vector<COutPoint> coins_to_uncache;
1891
- auto args = MemPoolAccept::ATMPArgs::SingleAccept(chainparams, accept_time, bypass_limits, coins_to_uncache, test_accept);
2179
+ auto args = MemPoolAccept::ATMPArgs::SingleAccept(chainparams, accept_time, ignore_rejects, coins_to_uncache, test_accept);
1892
2180
  MempoolAcceptResult result = MemPoolAccept(pool, active_chainstate).AcceptSingleTransaction(tx, args);
1893
2181
  if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) {
1894
2182
  // Remove coins that were not present in the coins cache before calling
@@ -1910,7 +2198,7 @@ MempoolAcceptResult AcceptToMemoryPool(Chainstate& active_chainstate, const CTra
1910
2198
  }
1911
2199
 
1912
2200
  PackageMempoolAcceptResult ProcessNewPackage(Chainstate& active_chainstate, CTxMemPool& pool,
1913
- const Package& package, bool test_accept, const std::optional<CFeeRate>& client_maxfeerate)
2201
+ const Package& package, bool test_accept, const std::optional<CFeeRate>& client_maxfeerate, const ignore_rejects_type& ignore_rejects)
1914
2202
  {
1915
2203
  AssertLockHeld(cs_main);
1916
2204
  assert(!package.empty());
@@ -1921,10 +2209,10 @@ PackageMempoolAcceptResult ProcessNewPackage(Chainstate& active_chainstate, CTxM
1921
2209
  auto result = [&]() EXCLUSIVE_LOCKS_REQUIRED(cs_main) {
1922
2210
  AssertLockHeld(cs_main);
1923
2211
  if (test_accept) {
1924
- auto args = MemPoolAccept::ATMPArgs::PackageTestAccept(chainparams, GetTime(), coins_to_uncache);
2212
+ auto args = MemPoolAccept::ATMPArgs::PackageTestAccept(chainparams, GetTime(), ignore_rejects, coins_to_uncache);
1925
2213
  return MemPoolAccept(pool, active_chainstate).AcceptMultipleTransactions(package, args);
1926
2214
  } else {
1927
- auto args = MemPoolAccept::ATMPArgs::PackageChildWithParents(chainparams, GetTime(), coins_to_uncache, client_maxfeerate);
2215
+ auto args = MemPoolAccept::ATMPArgs::PackageChildWithParents(chainparams, GetTime(), coins_to_uncache, client_maxfeerate, ignore_rejects);
1928
2216
  return MemPoolAccept(pool, active_chainstate).AcceptPackage(package, args);