v30.3-roots.1 · Commit 3: [PATCH 03/68] feat(policy): preserve Roots relay and network controls on Core 30.3
src/validation.cpp
Before: src/validation.cpp · After: src/validation.cpp
File metadata
index 21ccf045fbfcd200ec1dea6ad867a65eec02dfbc..89daf215e6c9aec6905aa611c1c360fc980e9921 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
|
@@ -926,29 +1079,63 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) (continued)
|
|
|
1117
|
+
}
|
|
1118
|
+
if (dust_penalty > 0) {
|
|
1119
|
+
m_subpackage.m_changeset->m_to_add.modify(ws.m_tx_handle, [&](CTxMemPoolEntry& e) {
|
|
1120
|
+
e.UpdateModifiedFee(-dust_penalty);
|
|
1121
|
+
});
|
|
1122
|
+
ws.m_modified_fees = SaturatingAdd(ws.m_modified_fees, -dust_penalty);
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
|
|
942
1126
|
// Enforces 0-fee for dust transactions, no incentive to be mined alone
|
|
943
|
-
if (m_pool.m_opts.require_standard) {
|
|
1127
|
+
if (m_pool.m_opts.require_standard && !ignore_rejects.count("dust")) {
|
|
944
1128
|
if (!PreCheckEphemeralTx(*ptx, m_pool.m_opts.dust_relay_feerate, ws.m_base_fees, ws.m_modified_fees, state)) {
|
|
945
1129
|
return false; // state filled in by PreCheckEphemeralTx
|
|
946
1130
|
}
|
|
947
1131
|
}
|
|
948
1132
|
|
|
949
|
-
if (nSigOpsCost > MAX_STANDARD_TX_SIGOPS_COST)
|
|
950
|
-
return state.Invalid(TxValidationResult::TX_NOT_STANDARD, "bad-txns-too-many-sigops",
|
|
1133
|
+
// To avoid rejecting low-sigop bare-multisig transactions, the sigops
|
|
1134
|
+
// are counted a second time more accurately.
|
|
1135
|
+
if ((nSigOpsCost > MAX_STANDARD_TX_SIGOPS_COST) || (nBytesPerSigOpStrict && GetAccurateTransactionSigOpCost(tx, m_view, STANDARD_SCRIPT_VERIFY_FLAGS) > ws.m_vsize * WITNESS_SCALE_FACTOR / nBytesPerSigOpStrict)) {
|
|
1136
|
+
MaybeRejectDbg(TxValidationResult::TX_NOT_STANDARD, "bad-txns-too-many-sigops",
|
|
951
1137
|
strprintf("%d", nSigOpsCost));
|
|
1138
|
+
}
|
|
952
1139
|
|
|
953
1140
|
// No individual transactions are allowed below the min relay feerate except from disconnected blocks.
|
|
954
1141
|
// This requirement, unlike CheckFeeRate, cannot be bypassed using m_package_feerates because,
|
|
@@ -956,7 +1143,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
|
|
|
956
1143
|
// method of ensuring the tx remains bumped. For example, the fee-bumping child could disappear
|
|
957
1144
|
// due to a replacement.
|
|
958
1145
|
// The only exception is TRUC transactions.
|
|
959
|
-
if (!bypass_limits && ws.m_ptx->version != TRUC_VERSION && ws.m_modified_fees < m_pool.m_opts.min_relay_feerate.GetFee(ws.m_vsize)) {
|
|
1146
|
+
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)) {
|
|
960
1147
|
// Even though this is a fee-related failure, this result is TX_MEMPOOL_POLICY, not
|
|
961
1148
|
// TX_RECONSIDERABLE, because it cannot be bypassed using package validation.
|
|
962
1149
|
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "min relay fee not met",
|
|
@@ -965,16 +1152,20 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
|
|
|
965
1152
|
// No individual transactions are allowed below the mempool min feerate except from disconnected
|
|
966
1153
|
// blocks and transactions in a package. Package transactions will be checked using package
|
|
967
1154
|
// feerate later.
|
|
968
|
-
if (!bypass_limits && !args.m_package_feerates && !CheckFeeRate(ws.m_vsize, ws.m_modified_fees, state)) return false;
|
|
1155
|
+
if (!args.m_package_feerates && !CheckFeeRate(ws.m_vsize, ws.m_modified_fees, state, args.m_ignore_rejects)) return false;
|
|
969
1156
|
|
|
970
|
-
ws.m_iters_conflicting = m_pool.GetIterSet(ws.m_conflicts);
|
|
1157
|
+
std::set<Txid> conflicts_as_a_set;
|
|
1158
|
+
std::transform(ws.m_conflicts_incl_policy.begin(), ws.m_conflicts_incl_policy.end(),
|
|
1159
|
+
std::inserter(conflicts_as_a_set, conflicts_as_a_set.end()),
|
|
1160
|
+
[](const std::pair<Txid, bool>& pair){ return pair.first; });
|
|
1161
|
+
ws.m_iters_conflicting = m_pool.GetIterSet(conflicts_as_a_set);
|
|
971
1162
|
|
|
972
1163
|
// Note that these modifications are only applicable to single transaction scenarios;
|
|
973
1164
|
// carve-outs are disabled for multi-transaction evaluations.
|
|
974
1165
|
CTxMemPool::Limits maybe_rbf_limits = m_pool.m_opts.limits;
|
|
975
1166
|
|
|
976
1167
|
// Calculate in-mempool ancestors, up to a limit.
|
|
977
|
-
if (ws.m_conflicts.size() == 1 && args.m_allow_carveouts) {
|
|
1168
|
+
if (ws.m_conflicts_incl_policy.size() == 1 && args.m_allow_carveouts) {
|
|
978
1169
|
// In general, when we receive an RBF transaction with mempool conflicts, we want to know whether we
|
|
979
1170
|
// would meet the chain limits after the conflicts have been removed. However, there isn't a practical
|
|
980
1171
|
// way to do this short of calculating the ancestor and descendant sets with an overlay cache of
|
|
@@ -1009,7 +1200,13 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
|
|
|
1009
1200
|
maybe_rbf_limits.descendant_size_vbytes += conflict->GetSizeWithDescendants();
|
|
1010
1201
|
}
|
|
1011
1202
|
|
|
1012
|
-
if (auto ancestors{m_subpackage.m_changeset->CalculateMemPoolAncestors(ws.m_tx_handle, maybe_rbf_limits)}) {
|
|
1203
|
+
CTxMemPool::Limits limits;
|
|
1204
|
+
if (ignore_rejects.count("too-long-mempool-chain")) {
|
|
1205
|
+
limits = CTxMemPool::Limits::NoLimits();
|
|
1206
|
+
} else {
|
|
1207
|
+
limits = maybe_rbf_limits;
|
|
1208
|
+
}
|
|
1209
|
+
if (auto ancestors{m_subpackage.m_changeset->CalculateMemPoolAncestors(ws.m_tx_handle, limits)}) {
|
|
1013
1210
|
ws.m_ancestors = std::move(*ancestors);
|
|
1014
1211
|
} else {
|
|
1015
1212
|
// If CalculateMemPoolAncestors fails second time, we want the original error string.
|
|
@@ -1038,7 +1235,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
|
|
|
1038
1235
|
.descendant_count = maybe_rbf_limits.descendant_count + 1,
|
|
1039
1236
|
.descendant_size_vbytes = maybe_rbf_limits.descendant_size_vbytes + EXTRA_DESCENDANT_TX_SIZE_LIMIT,
|
|
1040
1237
|
};
|
|
1041
|
-
if (ws.m_vsize > EXTRA_DESCENDANT_TX_SIZE_LIMIT || ws.m_ptx->version == TRUC_VERSION) {
|
|
1238
|
+
if (ws.m_vsize > EXTRA_DESCENDANT_TX_SIZE_LIMIT || (ws.m_ptx->version == TRUC_VERSION && m_pool.m_opts.truc_policy == TRUCPolicy::Enforce)) {
|
|
1042
1239
|
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "too-long-mempool-chain", error_message);
|
|
1043
1240
|
}
|
|
1044
1241
|
if (auto ancestors_retry{m_subpackage.m_changeset->CalculateMemPoolAncestors(ws.m_tx_handle, cpfp_carve_out_limits)}) {
|
|
@@ -1051,8 +1248,8 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
|
|
|
1051
1248
|
// Even though just checking direct mempool parents for inheritance would be sufficient, we
|
|
1052
1249
|
// check using the full ancestor set here because it's more convenient to use what we have
|
|
1053
1250
|
// already calculated.
|
|
1054
|
-
if (!args.m_bypass_limits) {
|
|
1055
|
-
if (const auto err{SingleTRUCChecks(ws.m_ptx, ws.m_ancestors, ws.m_conflicts, ws.m_vsize)}) {
|
|
1251
|
+
if (m_pool.m_opts.truc_policy == TRUCPolicy::Enforce && !ignore_rejects.count("truc")) {
|
|
1252
|
+
if (const auto err{SingleTRUCChecks(ws.m_ptx, "truc-", reason, ignore_rejects, ws.m_ancestors, conflicts_as_a_set, ws.m_vsize)}) {
|
|
1056
1253
|
// Single transaction contexts only.
|
|
1057
1254
|
if (args.m_allow_sibling_eviction && err->second != nullptr) {
|
|
1058
1255
|
// We should only be considering where replacement is considered valid as well.
|
|
@@ -1060,7 +1257,8 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
|
|
|
1060
1257
|
|
|
1061
1258
|
// Potential sibling eviction. Add the sibling to our list of mempool conflicts to be
|
|
1062
1259
|
// included in RBF checks.
|
|
1063
|
-
ws.m_conflicts.insert(err->second->GetHash());
|
|
1260
|
+
ws.m_conflicts_incl_policy.emplace(err->second->GetHash(), false);
|
|
1261
|
+
conflicts_as_a_set.insert(err->second->GetHash());
|
|
1064
1262
|
// Adding the sibling to m_iters_conflicting here means that it doesn't count towards
|
|
1065
1263
|
// RBF Carve Out above. This is correct, since removing to-be-replaced transactions from
|
|
1066
1264
|
// the descendant count is done separately in SingleTRUCChecks for TRUC transactions.
|
|
@@ -1071,7 +1269,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
|
|
|
1071
1269
|
// (which is normally done in PreChecks). However, the only way a TRUC transaction can
|
|
1072
1270
|
// have a non-TRUC and non-BIP125 descendant is due to a reorg.
|
|
1073
1271
|
} else {
|
|
1074
|
-
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "TRUC-violation", err->first);
|
|
1272
|
+
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, reason, err->first);
|
|
1075
1273
|
}
|
|
1076
1274
|
}
|
|
1077
1275
|
}
|
|
@@ -1080,18 +1278,22 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
|
|
|
1080
1278
|
// that we have the set of all ancestors we can detect this
|
|
1081
1279
|
// pathological case by making sure ws.m_conflicts and ws.m_ancestors don't
|
|
1082
1280
|
// intersect.
|
|
1083
|
-
if (const auto err_string{EntriesAndTxidsDisjoint(ws.m_ancestors, ws.m_conflicts, hash)}) {
|
|
1281
|
+
bool has_policy_conflict{false};
|
|
1282
|
+
if (const auto err_string{EntriesAndTxidsDisjoint(ws.m_ancestors, ws.m_conflicts_incl_policy, hash, &has_policy_conflict)}) {
|
|
1084
1283
|
// We classify this as a consensus error because a transaction depending on something it
|
|
1085
1284
|
// conflicts with would be inconsistent.
|
|
1086
1285
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-spends-conflicting-tx", *err_string);
|
|
1087
1286
|
}
|
|
1287
|
+
if (has_policy_conflict) {
|
|
1288
|
+
MaybeReject(TxValidationResult::TX_MEMPOOL_POLICY, "txn-spk-reused-chained");
|
|
1289
|
+
}
|
|
1088
1290
|
|
|
1089
1291
|
// We want to detect conflicts in any tx in a package to trigger package RBF logic
|
|
1090
|
-
m_subpackage.m_rbf |= !ws.m_conflicts.empty();
|
|
1292
|
+
m_subpackage.m_rbf |= !ws.m_conflicts_incl_policy.empty();
|
|
1091
1293
|
return true;
|
|
1092
1294
|
}
|
|
1093
1295
|
|
|
1094
|
-
bool MemPoolAccept::ReplacementChecks(Workspace& ws)
|
|
1296
|
+
bool MemPoolAccept::ReplacementChecks(ATMPArgs& args, Workspace& ws)
|
|
1095
1297
|
{
|
|
1096
1298
|
AssertLockHeld(cs_main);
|
|
1097
1299
|
AssertLockHeld(m_pool.cs);
|
|
@@ -1110,27 +1312,31 @@ bool MemPoolAccept::ReplacementChecks(Workspace& ws)
|
|
|
1110
1312
|
// guarantee that this is incentive-compatible for miners, because it is possible for a
|
|
1111
1313
|
// descendant transaction of a direct conflict to pay a higher feerate than the transaction that
|
|
1112
1314
|
// might replace them, under these rules.
|
|
1315
|
+
if (!args.m_ignore_rejects.count("insufficient fee")) {
|
|
1113
1316
|
if (const auto err_string{PaysMoreThanConflicts(ws.m_iters_conflicting, newFeeRate, hash)}) {
|
|
1114
1317
|
// This fee-related failure is TX_RECONSIDERABLE because validating in a package may change
|
|
1115
1318
|
// the result.
|
|
1116
1319
|
return state.Invalid(TxValidationResult::TX_RECONSIDERABLE,
|
|
1117
1320
|
strprintf("insufficient fee%s", ws.m_sibling_eviction ? " (including sibling eviction)" : ""), *err_string);
|
|
1118
1321
|
}
|
|
1322
|
+
} // ignore_rejects
|
|
1119
1323
|
|
|
1120
1324
|
CTxMemPool::setEntries all_conflicts;
|
|
1121
1325
|
|
|
1122
1326
|
// Calculate all conflicting entries and enforce Rule #5.
|
|
1123
|
-
if (const auto err_string{GetEntriesForConflicts(tx, m_pool, ws.m_iters_conflicting, all_conflicts)}) {
|
|
1327
|
+
if (const auto err_string{GetEntriesForConflicts(tx, m_pool, ws.m_iters_conflicting, all_conflicts, args.m_ignore_rejects)}) {
|
|
1124
1328
|
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY,
|
|
1125
1329
|
strprintf("too many potential replacements%s", ws.m_sibling_eviction ? " (including sibling eviction)" : ""), *err_string);
|
|
1126
1330
|
}
|
|
1127
1331
|
// Enforce Rule #2.
|
|
1332
|
+
if (!args.m_ignore_rejects.count("replacement-adds-unconfirmed")) {
|
|
1128
1333
|
if (const auto err_string{HasNoNewUnconfirmed(tx, m_pool, all_conflicts)}) {
|
|
1129
1334
|
// Sibling eviction is only done for TRUC transactions, which cannot have multiple ancestors.
|
|
1130
1335
|
Assume(!ws.m_sibling_eviction);
|
|
1131
1336
|
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY,
|
|
1132
1337
|
strprintf("replacement-adds-unconfirmed%s", ws.m_sibling_eviction ? " (including sibling eviction)" : ""), *err_string);
|
|
1133
1338
|
}
|
|
1339
|
+
} // ignore_rejects
|
|
1134
1340
|
|
|
1135
1341
|
// Check if it's economically rational to mine this transaction rather than the ones it
|
|
1136
1342
|
// replaces and pays for its own relay fees. Enforce Rules #3 and #4.
|
|
@@ -1138,12 +1344,14 @@ bool MemPoolAccept::ReplacementChecks(Workspace& ws)
|
|
|
1138
1344
|
m_subpackage.m_conflicting_fees += it->GetModifiedFee();
|
|
1139
1345
|
m_subpackage.m_conflicting_size += it->GetTxSize();
|
|
1140
1346
|
}
|
|
1347
|
+
if (!args.m_ignore_rejects.count("insufficient fee")) {
|
|
1141
1348
|
if (const auto err_string{PaysForRBF(m_subpackage.m_conflicting_fees, ws.m_modified_fees, ws.m_vsize,
|
|
1142
1349
|
m_pool.m_opts.incremental_relay_feerate, hash)}) {
|
|
1143
1350
|
// Result may change in a package context
|
|
1144
1351
|
return state.Invalid(TxValidationResult::TX_RECONSIDERABLE,
|
|
1145
1352
|
strprintf("insufficient fee%s", ws.m_sibling_eviction ? " (including sibling eviction)" : ""), *err_string);
|
|
1146
1353
|
}
|
|
1354
|
+
} // ignore_rejects
|
|
1147
1355
|
|
|
1148
1356
|
// Add all the to-be-removed transactions to the changeset.
|
|
1149
1357
|
for (auto it : all_conflicts) {
|
|
@@ -1152,7 +1360,7 @@ bool MemPoolAccept::ReplacementChecks(Workspace& ws)
|
|
|
1152
1360
|
return true;
|
|
1153
1361
|
}
|
|
1154
1362
|
|
|
1155
|
-
bool MemPoolAccept::PackageMempoolChecks(const std::vector<CTransactionRef>& txns,
|
|
1363
|
+
bool MemPoolAccept::PackageMempoolChecks(const ATMPArgs& args, const std::vector<CTransactionRef>& txns,
|
|
1156
1364
|
std::vector<Workspace>& workspaces,
|
|
1157
1365
|
const int64_t total_vsize,
|
|
1158
1366
|
PackageValidationState& package_state)
|
|
@@ -1165,7 +1373,13 @@ bool MemPoolAccept::PackageMempoolChecks(const std::vector<CTransactionRef>& txn
|
|
|
1165
1373
|
|
|
1166
1374
|
assert(txns.size() == workspaces.size());
|
|
1167
1375
|
|
|
1168
|
-
auto result = m_pool.CheckPackageLimits(txns, total_vsize);
|
|
1376
|
+
util::Result<void> result = [&]() EXCLUSIVE_LOCKS_REQUIRED(m_pool.cs) {
|
|
1377
|
+
if (args.m_ignore_rejects.count("package-mempool-limits")) {
|
|
1378
|
+
return util::Result<void>();
|
|
1379
|
+
} else {
|
|
1380
|
+
return m_pool.CheckPackageLimits(txns, total_vsize);
|
|
1381
|
+
}
|
|
1382
|
+
}();
|
|
1169
1383
|
if (!result) {
|
|
1170
1384
|
// This is a package-wide error, separate from an individual transaction error.
|
|
1171
1385
|
return package_state.Invalid(PackageValidationResult::PCKG_POLICY, "package-mempool-limits", util::ErrorString(result).original);
|
|
@@ -1251,6 +1465,77 @@ bool MemPoolAccept::PackageMempoolChecks(const std::vector<CTransactionRef>& txn
|
|
|
1251
1465
|
return true;
|
|
1252
1466
|
}
|
|
1253
1467
|
|
|
1468
|
+
unsigned int PolicyScriptVerifyFlags(const ignore_rejects_type& ignore_rejects)
|
|
1469
|
+
{
|
|
1470
|
+
if (ignore_rejects.empty()) {
|
|
1471
|
+
return STANDARD_SCRIPT_VERIFY_FLAGS;
|
|
1472
|
+
}
|
|
1473
|
+
if (ignore_rejects.count("non-mandatory-script-verify-flag")) {
|
|
1474
|
+
return MANDATORY_SCRIPT_VERIFY_FLAGS;
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1477
|
+
unsigned int flags = STANDARD_SCRIPT_VERIFY_FLAGS;
|
|
1478
|
+
if (ignore_rejects.count("non-mandatory-script-verify-flag-upgradable")) {
|
|
1479
|
+
constexpr unsigned int upgradable_policy_flags =
|
|
1480
|
+
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS |
|
|
1481
|
+
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM |
|
|
1482
|
+
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION |
|
|
1483
|
+
SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS |
|
|
1484
|
+
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE;
|
|
1485
|
+
flags &= ~upgradable_policy_flags;
|
|
1486
|
+
} else {
|
|
1487
|
+
if (ignore_rejects.count("non-mandatory-script-verify-flag-upgradable-nops")) {
|
|
1488
|
+
flags &= ~SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS;
|
|
1489
|
+
}
|
|
1490
|
+
if (ignore_rejects.count("non-mandatory-script-verify-flag-upgradable-witness_program")) {
|
|
1491
|
+
flags &= ~SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM;
|
|
1492
|
+
}
|
|
1493
|
+
if (ignore_rejects.count("non-mandatory-script-verify-flag-upgradable-taproot_version")) {
|
|
1494
|
+
flags &= ~SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION;
|
|
1495
|
+
}
|
|
1496
|
+
if (ignore_rejects.count("non-mandatory-script-verify-flag-upgradable-op_success")) {
|
|
1497
|
+
flags &= ~SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS;
|
|
1498
|
+
}
|
|
1499
|
+
if (ignore_rejects.count("non-mandatory-script-verify-flag-upgradable-pubkeytype")) {
|
|
1500
|
+
flags &= ~SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE;
|
|
1501
|
+
}
|
|
1502
|
+
}
|
|
1503
|
+
if (ignore_rejects.count("non-mandatory-script-verify-flag-bip62")) {
|
|
1504
|
+
constexpr unsigned int bip62_policy_flags =
|
|
1505
|
+
SCRIPT_VERIFY_LOW_S |
|
|
1506
|
+
SCRIPT_VERIFY_SIGPUSHONLY | // NOTE: not actually set ever
|
|
1507
|
+
SCRIPT_VERIFY_MINIMALDATA;
|
|
1508
|
+
flags &= ~bip62_policy_flags;
|
|
1509
|
+
} else {
|
|
1510
|
+
if (ignore_rejects.count("non-mandatory-script-verify-flag-low_s")) {
|
|
1511
|
+
flags &= ~SCRIPT_VERIFY_LOW_S;
|
|
1512
|
+
}
|
|
1513
|
+
if (ignore_rejects.count("non-mandatory-script-verify-flag-minimaldata")) {
|
|
1514
|
+
flags &= ~SCRIPT_VERIFY_MINIMALDATA;
|
|
1515
|
+
}
|
|
1516
|
+
if (ignore_rejects.count("non-mandatory-script-verify-flag-cleanstack")) {
|
|
1517
|
+
flags &= ~SCRIPT_VERIFY_CLEANSTACK;
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1520
|
+
if (ignore_rejects.count("non-mandatory-script-verify-flag-strictenc")) {
|
|
1521
|
+
flags &= ~SCRIPT_VERIFY_STRICTENC;
|
|
1522
|
+
}
|
|
1523
|
+
if (ignore_rejects.count("non-mandatory-script-verify-flag-minimalif")) {
|
|
1524
|
+
flags &= ~SCRIPT_VERIFY_MINIMALIF;
|
|
1525
|
+
}
|
|
1526
|
+
if (ignore_rejects.count("non-mandatory-script-verify-flag-nullfail")) {
|
|
1527
|
+
flags &= ~SCRIPT_VERIFY_NULLFAIL;
|
|
1528
|
+
}
|
|
1529
|
+
if (ignore_rejects.count("non-mandatory-script-verify-flag-witness_pubkeytype")) {
|
|
1530
|
+
flags &= ~SCRIPT_VERIFY_WITNESS_PUBKEYTYPE;
|
|
1531
|
+
}
|
|
1532
|
+
if (ignore_rejects.count("non-mandatory-script-verify-flag-const_scriptcode")) {
|
|
1533
|
+
flags &= ~SCRIPT_VERIFY_CONST_SCRIPTCODE;
|
|
1534
|
+
}
|
|
1535
|
+
flags |= MANDATORY_SCRIPT_VERIFY_FLAGS; // for safety
|
|
1536
|
+
return flags;
|
|
1537
|
+
}
|
|
1538
|
+
|
|
1254
1539
|
bool MemPoolAccept::PolicyScriptChecks(const ATMPArgs& args, Workspace& ws)
|
|
1255
1540
|
{
|
|
1256
1541
|
AssertLockHeld(cs_main);
|
|
@@ -1258,7 +1543,7 @@ bool MemPoolAccept::PolicyScriptChecks(const ATMPArgs& args, Workspace& ws)
|
|
|
1258
1543
|
const CTransaction& tx = *ws.m_ptx;
|
|
1259
1544
|
TxValidationState& state = ws.m_state;
|
|
1260
1545
|
|
|
1261
|
-
constexpr unsigned int scriptVerifyFlags = STANDARD_SCRIPT_VERIFY_FLAGS;
|
|
1546
|
+
const unsigned int scriptVerifyFlags = PolicyScriptVerifyFlags(args.m_ignore_rejects);
|
|
1262
1547
|
|
|
1263
1548
|
// Check input scripts and signatures.
|
|
1264
1549
|
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
|
|
@@ -1300,7 +1585,7 @@ bool MemPoolAccept::ConsensusScriptChecks(const ATMPArgs& args, Workspace& ws)
|
|
|
1300
1585
|
unsigned int currentBlockScriptVerifyFlags{GetBlockScriptFlags(*m_active_chainstate.m_chain.Tip(), m_active_chainstate.m_chainman)};
|
|
1301
1586
|
if (!CheckInputsFromMempoolAndCache(tx, state, m_view, m_pool, currentBlockScriptVerifyFlags,
|
|
1302
1587
|
ws.m_precomputed_txdata, m_active_chainstate.CoinsTip(), GetValidationCache())) {
|
|
1303
|
-
LogPrintf("BUG! PLEASE REPORT THIS! CheckInputScripts failed against latest-block but not STANDARD flags %s, %s\n", hash.ToString(), state.ToString());
|
|
1588
|
+
LogError("BUG! PLEASE REPORT THIS! CheckInputScripts failed against latest-block but not STANDARD flags %s, %s", hash.ToString(), state.ToString());
|
|
1304
1589
|
return Assume(false);
|
|
1305
1590
|
}
|
|
1306
1591
|
|
|
@@ -1425,7 +1710,7 @@ bool MemPoolAccept::SubmitPackage(const ATMPArgs& args, std::vector<Workspace>&
|
|
|
1425
1710
|
const CTransaction& tx = *ws.m_ptx;
|
|
1426
1711
|
const auto tx_info = NewMempoolTransactionInfo(ws.m_ptx, ws.m_base_fees,
|
|
1427
1712
|
ws.m_vsize, (*iter)->GetHeight(),
|
|
1428
|
-
args.m_bypass_limits, args.m_package_submission,
|
|
1713
|
+
args.m_ignore_rejects, args.m_package_submission,
|
|
1429
1714
|
IsCurrentForFeeEstimation(m_active_chainstate),
|
|
1430
1715
|
m_pool.HasNoInputsOf(tx));
|
|
1431
1716
|
m_pool.m_opts.signals->TransactionAddedToMempool(tx_info, m_pool.GetAndIncrementSequence());
|
|
@@ -1465,7 +1750,7 @@ MempoolAcceptResult MemPoolAccept::AcceptSingleTransaction(const CTransactionRef
|
|
|
1465
1750
|
}
|
|
1466
1751
|
}
|
|
1467
1752
|
|
|
1468
|
-
if (m_subpackage.m_rbf && !ReplacementChecks(ws)) {
|
|
1753
|
+
if (m_subpackage.m_rbf && !ReplacementChecks(args, ws)) {
|
|
1469
1754
|
if (ws.m_state.GetResult() == TxValidationResult::TX_RECONSIDERABLE) {
|
|
1470
1755
|
// Failed for incentives-based fee reasons. Provide the effective feerate and which tx was included.
|
|
1471
1756
|
return MempoolAcceptResult::FeeFailure(ws.m_state, CFeeRate(ws.m_modified_fees, ws.m_vsize), single_wtxid);
|
|
@@ -1489,7 +1774,7 @@ MempoolAcceptResult MemPoolAccept::AcceptSingleTransaction(const CTransactionRef
|
|
|
1489
1774
|
FinalizeSubpackage(args);
|
|
1490
1775
|
|
|
1491
1776
|
// Limit the mempool, if appropriate.
|
|
1492
|
-
if (!args.m_package_submission && !args.m_bypass_limits) {
|
|
1777
|
+
if (!args.m_package_submission && !args.m_ignore_rejects.count(rejectmsg_mempoolfull)) {
|
|
1493
1778
|
LimitMempoolSize(m_pool, m_active_chainstate.CoinsTip());
|
|
1494
1779
|
// If mempool contents change, then the m_view cache is dirty. Given this isn't a package
|
|
1495
1780
|
// submission, we won't be using the cache anymore, but clear it anyway for clarity.
|
|
@@ -1508,7 +1793,7 @@ MempoolAcceptResult MemPoolAccept::AcceptSingleTransaction(const CTransactionRef
|
|
|
1508
1793
|
Assume(iter.has_value());
|
|
1509
1794
|
const auto tx_info = NewMempoolTransactionInfo(ws.m_ptx, ws.m_base_fees,
|
|
1510
1795
|
ws.m_vsize, (*iter)->GetHeight(),
|
|
1511
|
-
args.m_bypass_limits, args.m_package_submission,
|
|
1796
|
+
args.m_ignore_rejects, args.m_package_submission,
|
|
1512
1797
|
IsCurrentForFeeEstimation(m_active_chainstate),
|
|
1513
1798
|
m_pool.HasNoInputsOf(tx));
|
|
1514
1799
|
m_pool.m_opts.signals->TransactionAddedToMempool(tx_info, m_pool.GetAndIncrementSequence());
|
|
@@ -1575,12 +1860,14 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptMultipleTransactions(const std::
|
|
|
1575
1860
|
|
|
1576
1861
|
// At this point we have all in-mempool ancestors, and we know every transaction's vsize.
|
|
1577
1862
|
// Run the TRUC checks on the package.
|
|
1863
|
+
if (m_pool.m_opts.truc_policy == TRUCPolicy::Enforce) {
|
|
1864
|
+
std::string reason;
|
|
1578
1865
|
for (Workspace& ws : workspaces) {
|
|
1579
|
-
if (auto err{PackageTRUCChecks(ws.m_ptx, ws.m_vsize, txns, ws.m_ancestors)}) {
|
|
1580
|
-
package_state.Invalid(PackageValidationResult::PCKG_POLICY, "TRUC-violation", err.value());
|
|
1866
|
+
if (auto err{PackageTRUCChecks(ws.m_ptx, ws.m_vsize, "truc-", reason, args.m_ignore_rejects, txns, ws.m_ancestors)}) {
|
|
1867
|
+
package_state.Invalid(PackageValidationResult::PCKG_POLICY, reason, err.value());
|
|
1581
1868
|
return PackageMempoolAcceptResult(package_state, {});
|
|
1582
1869
|
}
|
|
1583
|
-
}
|
|
1870
|
+
}}
|
|
1584
1871
|
|
|
1585
1872
|
// Transactions must meet two minimum feerates: the mempool minimum fee and min relay fee.
|
|
1586
1873
|
// For transactions consisting of exactly one child and its parents, it suffices to use the
|
|
@@ -1602,7 +1889,8 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptMultipleTransactions(const std::
|
|
|
1602
1889
|
[](const auto& ws) { return ws.m_ptx->GetWitnessHash(); });
|
|
1603
1890
|
TxValidationState placeholder_state;
|
|
1604
1891
|
if (args.m_package_feerates &&
|
|
1605
|
-
!CheckFeeRate(m_subpackage.m_total_vsize, m_subpackage.m_total_modified_fees, placeholder_state)) {
|
|
1892
|
+
(!args.m_ignore_rejects.count("package-fee-too-low")) &&
|
|
1893
|
+
!CheckFeeRate(m_subpackage.m_total_vsize, m_subpackage.m_total_modified_fees, placeholder_state, empty_ignore_rejects)) {
|
|
1606
1894
|
package_state.Invalid(PackageValidationResult::PCKG_TX, "transaction failed");
|
|
1607
1895
|
return PackageMempoolAcceptResult(package_state, {{workspaces.back().m_ptx->GetWitnessHash(),
|
|
1608
1896
|
MempoolAcceptResult::FeeFailure(placeholder_state, CFeeRate(m_subpackage.m_total_modified_fees, m_subpackage.m_total_vsize), all_package_wtxids)}});
|
|
@@ -1610,12 +1898,12 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptMultipleTransactions(const std::
|
|
|
1610
1898
|
|
|
1611
1899
|
// Apply package mempool ancestor/descendant limits. Skip if there is only one transaction,
|
|
1612
1900
|
// because it's unnecessary.
|
|
1613
|
-
if (txns.size() > 1 && !PackageMempoolChecks(txns, workspaces, m_subpackage.m_total_vsize, package_state)) {
|
|
1901
|
+
if (txns.size() > 1 && !PackageMempoolChecks(args, txns, workspaces, m_subpackage.m_total_vsize, package_state)) {
|
|
1614
1902
|
return PackageMempoolAcceptResult(package_state, std::move(results));
|
|
1615
1903
|
}
|
|
1616
1904
|
|
|
1617
1905
|
// Now that we've bounded the resulting possible ancestry count, check package for dust spends
|
|
1618
|
-
if (m_pool.m_opts.require_standard) {
|
|
1906
|
+
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"))) {
|
|
1619
1907
|
TxValidationState child_state;
|
|
1620
1908
|
Wtxid child_wtxid;
|
|
1621
1909
|
if (!CheckEphemeralSpends(txns, m_pool.m_opts.dust_relay_feerate, m_pool, child_state, child_wtxid)) {
|
|
@@ -1865,7 +2153,7 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptPackage(const Package& package,
|
|
|
1865
2153
|
} // anon namespace
|
|
1866
2154
|
|
|
1867
2155
|
MempoolAcceptResult AcceptToMemoryPool(Chainstate& active_chainstate, const CTransactionRef& tx,
|
|
1868
|
-
int64_t accept_time, bool bypass_limits, bool test_accept)
|
|
2156
|
+
int64_t accept_time, const ignore_rejects_type& ignore_rejects, bool test_accept)
|
|
1869
2157
|
{
|
|
1870
2158
|
AssertLockHeld(::cs_main);
|
|
1871
2159
|
const CChainParams& chainparams{active_chainstate.m_chainman.GetParams()};
|
|
@@ -1873,7 +2161,7 @@ MempoolAcceptResult AcceptToMemoryPool(Chainstate& active_chainstate, const CTra
|
|
|
1873
2161
|
CTxMemPool& pool{*active_chainstate.GetMempool()};
|
|
1874
2162
|
|
|
1875
2163
|
std::vector<COutPoint> coins_to_uncache;
|
|
1876
|
-
auto args = MemPoolAccept::ATMPArgs::SingleAccept(chainparams, accept_time, bypass_limits, coins_to_uncache, test_accept);
|
|
2164
|
+
auto args = MemPoolAccept::ATMPArgs::SingleAccept(chainparams, accept_time, ignore_rejects, coins_to_uncache, test_accept);
|
|
1877
2165
|
MempoolAcceptResult result = MemPoolAccept(pool, active_chainstate).AcceptSingleTransaction(tx, args);
|
|
1878
2166
|
if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) {
|
|
1879
2167
|
// Remove coins that were not present in the coins cache before calling
|
|
@@ -1895,7 +2183,7 @@ MempoolAcceptResult AcceptToMemoryPool(Chainstate& active_chainstate, const CTra
|
|
|
1895
2183
|
}
|
|
1896
2184
|
|
|
1897
2185
|
PackageMempoolAcceptResult ProcessNewPackage(Chainstate& active_chainstate, CTxMemPool& pool,
|
|
1898
|
-
const Package& package, bool test_accept, const std::optional<CFeeRate>& client_maxfeerate)
|
|
2186
|
+
const Package& package, bool test_accept, const std::optional<CFeeRate>& client_maxfeerate, const ignore_rejects_type& ignore_rejects)
|
|
1899
2187
|
{
|
|
1900
2188
|
AssertLockHeld(cs_main);
|
|
1901
2189
|
assert(!package.empty());
|
|
@@ -1906,10 +2194,10 @@ PackageMempoolAcceptResult ProcessNewPackage(Chainstate& active_chainstate, CTxM
|
|
|
1906
2194
|
auto result = [&]() EXCLUSIVE_LOCKS_REQUIRED(cs_main) {
|
|
1907
2195
|
AssertLockHeld(cs_main);
|
|
1908
2196
|
if (test_accept) {
|
|
1909
|
-
auto args = MemPoolAccept::ATMPArgs::PackageTestAccept(chainparams, GetTime(), coins_to_uncache);
|
|
2197
|
+
auto args = MemPoolAccept::ATMPArgs::PackageTestAccept(chainparams, GetTime(), ignore_rejects, coins_to_uncache);
|
|
1910
2198
|
return MemPoolAccept(pool, active_chainstate).AcceptMultipleTransactions(package, args);
|
|
1911
2199
|
} else {
|
|
1912
|
-
auto args = MemPoolAccept::ATMPArgs::PackageChildWithParents(chainparams, GetTime(), coins_to_uncache, client_maxfeerate);
|
|
2200
|
+
auto args = MemPoolAccept::ATMPArgs::PackageChildWithParents(chainparams, GetTime(), coins_to_uncache, client_maxfeerate, ignore_rejects);
|
|
1913
2201
|
return MemPoolAccept(pool, active_chainstate).AcceptPackage(package, args);
|