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);
|