Skip to content

Commit a25c462

Browse files
committed
Support manually overriding TRUC policy checks
1 parent cf65351 commit a25c462

File tree

4 files changed

+22
-18
lines changed

4 files changed

+22
-18
lines changed

src/policy/truc_policy.cpp

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ struct ParentInfo {
5757

5858
std::optional<std::string> PackageTRUCChecks(const CTransactionRef& ptx, int64_t vsize,
5959
const std::string& reason_prefix, std::string& out_reason,
60+
const ignore_rejects_type& ignore_rejects,
6061
const Package& package,
6162
const CTxMemPool::setEntries& mempool_ancestors)
6263
{
@@ -69,13 +70,13 @@ std::optional<std::string> PackageTRUCChecks(const CTransactionRef& ptx, int64_t
6970
// Now we have all ancestors, so we can start checking TRUC rules.
7071
if (ptx->version == TRUC_VERSION) {
7172
// SingleTRUCChecks should have checked this already.
72-
if (!Assume(vsize <= TRUC_MAX_VSIZE)) {
73+
if (vsize > TRUC_MAX_VSIZE && !ignore_rejects.count(reason_prefix + "vsize-toobig")) {
7374
out_reason = reason_prefix + "vsize-toobig";
7475
return strprintf("version=3 tx %s (wtxid=%s) is too big: %u > %u virtual bytes",
7576
ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString(), vsize, TRUC_MAX_VSIZE);
7677
}
7778

78-
if (mempool_ancestors.size() + in_package_parents.size() + 1 > TRUC_ANCESTOR_LIMIT) {
79+
if (mempool_ancestors.size() + in_package_parents.size() + 1 > TRUC_ANCESTOR_LIMIT && !ignore_rejects.count(reason_prefix + "ancestors-toomany")) {
7980
out_reason = reason_prefix + "ancestors-toomany";
8081
return strprintf("tx %s (wtxid=%s) would have too many ancestors",
8182
ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString());
@@ -84,7 +85,7 @@ std::optional<std::string> PackageTRUCChecks(const CTransactionRef& ptx, int64_t
8485
const bool has_parent{mempool_ancestors.size() + in_package_parents.size() > 0};
8586
if (has_parent) {
8687
// A TRUC child cannot be too large.
87-
if (vsize > TRUC_CHILD_MAX_VSIZE) {
88+
if (vsize > TRUC_CHILD_MAX_VSIZE && !ignore_rejects.count(reason_prefix + "child-toobig")) {
8889
out_reason = reason_prefix + "child-toobig";
8990
return strprintf("version=3 child tx %s (wtxid=%s) is too big: %u > %u virtual bytes",
9091
ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString(),
@@ -110,7 +111,7 @@ std::optional<std::string> PackageTRUCChecks(const CTransactionRef& ptx, int64_t
110111
}();
111112

112113
// If there is a parent, it must have the right version.
113-
if (parent_info.m_version != TRUC_VERSION) {
114+
if (parent_info.m_version != TRUC_VERSION && !ignore_rejects.count(reason_prefix + "spends-nontruc")) {
114115
out_reason = reason_prefix + "spends-nontruc";
115116
return strprintf("version=3 tx %s (wtxid=%s) cannot spend from non-version=3 tx %s (wtxid=%s)",
116117
ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString(),
@@ -125,15 +126,15 @@ std::optional<std::string> PackageTRUCChecks(const CTransactionRef& ptx, int64_t
125126
// Fail if we find another tx with the same parent. We don't check whether the
126127
// sibling is to-be-replaced (done in SingleTRUCChecks) because these transactions
127128
// are within the same package.
128-
if (input.prevout.hash == parent_info.m_txid) {
129+
if (input.prevout.hash == parent_info.m_txid && !ignore_rejects.count(reason_prefix + "sibling-known")) {
129130
out_reason = reason_prefix + "sibling-known";
130131
return strprintf("tx %s (wtxid=%s) would exceed descendant count limit",
131132
parent_info.m_txid.ToString(),
132133
parent_info.m_wtxid.ToString());
133134
}
134135

135136
// This tx can't have both a parent and an in-package child.
136-
if (input.prevout.hash == ptx->GetHash()) {
137+
if (input.prevout.hash == ptx->GetHash() && !ignore_rejects.count(reason_prefix + "parent-and-child-both")) {
137138
out_reason = reason_prefix + "parent-and-child-both";
138139
return strprintf("tx %s (wtxid=%s) would have too many ancestors",
139140
package_tx->GetHash().ToString(), package_tx->GetWitnessHash().ToString());
@@ -150,15 +151,15 @@ std::optional<std::string> PackageTRUCChecks(const CTransactionRef& ptx, int64_t
150151
} else {
151152
// Non-TRUC transactions cannot have TRUC parents.
152153
for (auto it : mempool_ancestors) {
153-
if (it->GetTx().version == TRUC_VERSION) {
154+
if (it->GetTx().version == TRUC_VERSION && !ignore_rejects.count(reason_prefix + "spent-by-nontruc")) {
154155
out_reason = reason_prefix + "spent-by-nontruc";
155156
return strprintf("non-version=3 tx %s (wtxid=%s) cannot spend from version=3 tx %s (wtxid=%s)",
156157
ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString(),
157158
it->GetSharedTx()->GetHash().ToString(), it->GetSharedTx()->GetWitnessHash().ToString());
158159
}
159160
}
160161
for (const auto& index: in_package_parents) {
161-
if (package.at(index)->version == TRUC_VERSION) {
162+
if (package.at(index)->version == TRUC_VERSION && !ignore_rejects.count(reason_prefix + "spent-by-nontruc")) {
162163
out_reason = reason_prefix + "spent-by-nontruc";
163164
return strprintf("non-version=3 tx %s (wtxid=%s) cannot spend from version=3 tx %s (wtxid=%s)",
164165
ptx->GetHash().ToString(),
@@ -173,19 +174,20 @@ std::optional<std::string> PackageTRUCChecks(const CTransactionRef& ptx, int64_t
173174

174175
std::optional<std::pair<std::string, CTransactionRef>> SingleTRUCChecks(const CTransactionRef& ptx,
175176
const std::string& reason_prefix, std::string& out_reason,
177+
const ignore_rejects_type& ignore_rejects,
176178
const CTxMemPool::setEntries& mempool_ancestors,
177179
const std::set<Txid>& direct_conflicts,
178180
int64_t vsize)
179181
{
180182
// Check TRUC and non-TRUC inheritance.
181183
for (const auto& entry : mempool_ancestors) {
182-
if (ptx->version != TRUC_VERSION && entry->GetTx().version == TRUC_VERSION) {
184+
if (ptx->version != TRUC_VERSION && entry->GetTx().version == TRUC_VERSION && !ignore_rejects.count(reason_prefix + "spent-by-nontruc")) {
183185
out_reason = reason_prefix + "spent-by-nontruc";
184186
return std::make_pair(strprintf("non-version=3 tx %s (wtxid=%s) cannot spend from version=3 tx %s (wtxid=%s)",
185187
ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString(),
186188
entry->GetSharedTx()->GetHash().ToString(), entry->GetSharedTx()->GetWitnessHash().ToString()),
187189
nullptr);
188-
} else if (ptx->version == TRUC_VERSION && entry->GetTx().version != TRUC_VERSION) {
190+
} else if (ptx->version == TRUC_VERSION && entry->GetTx().version != TRUC_VERSION && !ignore_rejects.count(reason_prefix + "spends-nontruc")) {
189191
out_reason = reason_prefix + "spends-nontruc";
190192
return std::make_pair(strprintf("version=3 tx %s (wtxid=%s) cannot spend from non-version=3 tx %s (wtxid=%s)",
191193
ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString(),
@@ -201,15 +203,15 @@ std::optional<std::pair<std::string, CTransactionRef>> SingleTRUCChecks(const CT
201203
// The rest of the rules only apply to transactions with version=3.
202204
if (ptx->version != TRUC_VERSION) return std::nullopt;
203205

204-
if (vsize > TRUC_MAX_VSIZE) {
206+
if (vsize > TRUC_MAX_VSIZE && !ignore_rejects.count(reason_prefix + "vsize-toobig")) {
205207
out_reason = reason_prefix + "vsize-toobig";
206208
return std::make_pair(strprintf("version=3 tx %s (wtxid=%s) is too big: %u > %u virtual bytes",
207209
ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString(), vsize, TRUC_MAX_VSIZE),
208210
nullptr);
209211
}
210212

211213
// Check that TRUC_ANCESTOR_LIMIT would not be violated.
212-
if (mempool_ancestors.size() + 1 > TRUC_ANCESTOR_LIMIT) {
214+
if (mempool_ancestors.size() + 1 > TRUC_ANCESTOR_LIMIT && !ignore_rejects.count(reason_prefix + "ancestors-toomany")) {
213215
out_reason = reason_prefix + "ancestors-toomany";
214216
return std::make_pair(strprintf("tx %s (wtxid=%s) would have too many ancestors",
215217
ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString()),
@@ -219,7 +221,7 @@ std::optional<std::pair<std::string, CTransactionRef>> SingleTRUCChecks(const CT
219221
// Remaining checks only pertain to transactions with unconfirmed ancestors.
220222
if (mempool_ancestors.size() > 0) {
221223
// If this transaction spends TRUC parents, it cannot be too large.
222-
if (vsize > TRUC_CHILD_MAX_VSIZE) {
224+
if (vsize > TRUC_CHILD_MAX_VSIZE && !ignore_rejects.count(reason_prefix + "child-toobig")) {
223225
out_reason = reason_prefix + "child-toobig";
224226
return std::make_pair(strprintf("version=3 child tx %s (wtxid=%s) is too big: %u > %u virtual bytes",
225227
ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString(), vsize, TRUC_CHILD_MAX_VSIZE),
@@ -238,7 +240,7 @@ std::optional<std::pair<std::string, CTransactionRef>> SingleTRUCChecks(const CT
238240
const bool child_will_be_replaced = !children.empty() &&
239241
std::any_of(children.cbegin(), children.cend(),
240242
[&direct_conflicts](const CTxMemPoolEntry& child){return direct_conflicts.count(child.GetTx().GetHash()) > 0;});
241-
if (parent_entry->GetCountWithDescendants() + 1 > TRUC_DESCENDANT_LIMIT && !child_will_be_replaced) {
243+
if (parent_entry->GetCountWithDescendants() + 1 > TRUC_DESCENDANT_LIMIT && (!child_will_be_replaced) && !ignore_rejects.count(reason_prefix + "descendants-toomany")) {
242244
// Allow sibling eviction for TRUC transaction: if another child already exists, even if
243245
// we don't conflict inputs with it, consider evicting it under RBF rules. We rely on TRUC rules
244246
// only permitting 1 descendant, as otherwise we would need to have logic for deciding

src/policy/truc_policy.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ static_assert(TRUC_MAX_VSIZE + TRUC_CHILD_MAX_VSIZE <= DEFAULT_DESCENDANT_SIZE_L
6363
*/
6464
std::optional<std::pair<std::string, CTransactionRef>> SingleTRUCChecks(const CTransactionRef& ptx,
6565
const std::string& reason_prefix, std::string& out_reason,
66+
const ignore_rejects_type& ignore_rejects,
6667
const CTxMemPool::setEntries& mempool_ancestors,
6768
const std::set<Txid>& direct_conflicts,
6869
int64_t vsize);
@@ -90,6 +91,7 @@ std::optional<std::pair<std::string, CTransactionRef>> SingleTRUCChecks(const CT
9091
* */
9192
std::optional<std::string> PackageTRUCChecks(const CTransactionRef& ptx, int64_t vsize,
9293
const std::string& reason_prefix, std::string& out_reason,
94+
const ignore_rejects_type& ignore_rejects,
9395
const Package& package,
9496
const CTxMemPool::setEntries& mempool_ancestors);
9597

src/test/txvalidation_tests.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@ BOOST_AUTO_TEST_SUITE(txvalidation_tests)
2323
std::optional<std::pair<std::string, CTransactionRef>> SingleTRUCChecks(const CTransactionRef& ptx, const CTxMemPool::setEntries& mempool_ancestors, const std::set<Txid>& direct_conflicts, int64_t vsize)
2424
{
2525
std::string dummy;
26-
return SingleTRUCChecks(ptx, dummy, dummy, mempool_ancestors, direct_conflicts, vsize);
26+
return SingleTRUCChecks(ptx, dummy, dummy, empty_ignore_rejects, mempool_ancestors, direct_conflicts, vsize);
2727
}
2828

2929
std::optional<std::string> PackageTRUCChecks(const CTransactionRef& ptx, int64_t vsize, const Package& package, const CTxMemPool::setEntries& mempool_ancestors)
3030
{
3131
std::string dummy;
32-
return PackageTRUCChecks(ptx, vsize, dummy, dummy, package, mempool_ancestors);
32+
return PackageTRUCChecks(ptx, vsize, dummy, dummy, empty_ignore_rejects, package, mempool_ancestors);
3333
}
3434

3535
/**

src/validation.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1063,7 +1063,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
10631063
// Even though just checking direct mempool parents for inheritance would be sufficient, we
10641064
// check using the full ancestor set here because it's more convenient to use what we have
10651065
// already calculated.
1066-
if (const auto err{SingleTRUCChecks(ws.m_ptx, "truc-", reason, ws.m_ancestors, ws.m_conflicts, ws.m_vsize)}) {
1066+
if (const auto err{SingleTRUCChecks(ws.m_ptx, "truc-", reason, ignore_rejects, ws.m_ancestors, ws.m_conflicts, ws.m_vsize)}) {
10671067
// Single transaction contexts only.
10681068
if (args.m_allow_sibling_eviction && err->second != nullptr) {
10691069
// We should only be considering where replacement is considered valid as well.
@@ -1590,7 +1590,7 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptMultipleTransactions(const std::
15901590
// Run the TRUC checks on the package.
15911591
std::string reason;
15921592
for (Workspace& ws : workspaces) {
1593-
if (auto err{PackageTRUCChecks(ws.m_ptx, ws.m_vsize, "truc-", reason, txns, ws.m_ancestors)}) {
1593+
if (auto err{PackageTRUCChecks(ws.m_ptx, ws.m_vsize, "truc-", reason, args.m_ignore_rejects, txns, ws.m_ancestors)}) {
15941594
package_state.Invalid(PackageValidationResult::PCKG_POLICY, reason, err.value());
15951595
return PackageMempoolAcceptResult(package_state, {});
15961596
}

0 commit comments

Comments
 (0)