Skip to content

Commit cf65351

Browse files
committed
Give separate reject reasons to each TRUC check
1 parent 416646d commit cf65351

File tree

5 files changed

+53
-21
lines changed

5 files changed

+53
-21
lines changed

src/policy/truc_policy.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ struct ParentInfo {
5656
};
5757

5858
std::optional<std::string> PackageTRUCChecks(const CTransactionRef& ptx, int64_t vsize,
59+
const std::string& reason_prefix, std::string& out_reason,
5960
const Package& package,
6061
const CTxMemPool::setEntries& mempool_ancestors)
6162
{
@@ -69,11 +70,13 @@ std::optional<std::string> PackageTRUCChecks(const CTransactionRef& ptx, int64_t
6970
if (ptx->version == TRUC_VERSION) {
7071
// SingleTRUCChecks should have checked this already.
7172
if (!Assume(vsize <= TRUC_MAX_VSIZE)) {
73+
out_reason = reason_prefix + "vsize-toobig";
7274
return strprintf("version=3 tx %s (wtxid=%s) is too big: %u > %u virtual bytes",
7375
ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString(), vsize, TRUC_MAX_VSIZE);
7476
}
7577

7678
if (mempool_ancestors.size() + in_package_parents.size() + 1 > TRUC_ANCESTOR_LIMIT) {
79+
out_reason = reason_prefix + "ancestors-toomany";
7780
return strprintf("tx %s (wtxid=%s) would have too many ancestors",
7881
ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString());
7982
}
@@ -82,6 +85,7 @@ std::optional<std::string> PackageTRUCChecks(const CTransactionRef& ptx, int64_t
8285
if (has_parent) {
8386
// A TRUC child cannot be too large.
8487
if (vsize > TRUC_CHILD_MAX_VSIZE) {
88+
out_reason = reason_prefix + "child-toobig";
8589
return strprintf("version=3 child tx %s (wtxid=%s) is too big: %u > %u virtual bytes",
8690
ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString(),
8791
vsize, TRUC_CHILD_MAX_VSIZE);
@@ -107,6 +111,7 @@ std::optional<std::string> PackageTRUCChecks(const CTransactionRef& ptx, int64_t
107111

108112
// If there is a parent, it must have the right version.
109113
if (parent_info.m_version != TRUC_VERSION) {
114+
out_reason = reason_prefix + "spends-nontruc";
110115
return strprintf("version=3 tx %s (wtxid=%s) cannot spend from non-version=3 tx %s (wtxid=%s)",
111116
ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString(),
112117
parent_info.m_txid.ToString(), parent_info.m_wtxid.ToString());
@@ -121,20 +126,23 @@ std::optional<std::string> PackageTRUCChecks(const CTransactionRef& ptx, int64_t
121126
// sibling is to-be-replaced (done in SingleTRUCChecks) because these transactions
122127
// are within the same package.
123128
if (input.prevout.hash == parent_info.m_txid) {
129+
out_reason = reason_prefix + "sibling-known";
124130
return strprintf("tx %s (wtxid=%s) would exceed descendant count limit",
125131
parent_info.m_txid.ToString(),
126132
parent_info.m_wtxid.ToString());
127133
}
128134

129135
// This tx can't have both a parent and an in-package child.
130136
if (input.prevout.hash == ptx->GetHash()) {
137+
out_reason = reason_prefix + "parent-and-child-both";
131138
return strprintf("tx %s (wtxid=%s) would have too many ancestors",
132139
package_tx->GetHash().ToString(), package_tx->GetWitnessHash().ToString());
133140
}
134141
}
135142
}
136143

137144
if (parent_info.m_has_mempool_descendant) {
145+
out_reason = reason_prefix + "descendant-toomany";
138146
return strprintf("tx %s (wtxid=%s) would exceed descendant count limit",
139147
parent_info.m_txid.ToString(), parent_info.m_wtxid.ToString());
140148
}
@@ -143,13 +151,15 @@ std::optional<std::string> PackageTRUCChecks(const CTransactionRef& ptx, int64_t
143151
// Non-TRUC transactions cannot have TRUC parents.
144152
for (auto it : mempool_ancestors) {
145153
if (it->GetTx().version == TRUC_VERSION) {
154+
out_reason = reason_prefix + "spent-by-nontruc";
146155
return strprintf("non-version=3 tx %s (wtxid=%s) cannot spend from version=3 tx %s (wtxid=%s)",
147156
ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString(),
148157
it->GetSharedTx()->GetHash().ToString(), it->GetSharedTx()->GetWitnessHash().ToString());
149158
}
150159
}
151160
for (const auto& index: in_package_parents) {
152161
if (package.at(index)->version == TRUC_VERSION) {
162+
out_reason = reason_prefix + "spent-by-nontruc";
153163
return strprintf("non-version=3 tx %s (wtxid=%s) cannot spend from version=3 tx %s (wtxid=%s)",
154164
ptx->GetHash().ToString(),
155165
ptx->GetWitnessHash().ToString(),
@@ -162,18 +172,21 @@ std::optional<std::string> PackageTRUCChecks(const CTransactionRef& ptx, int64_t
162172
}
163173

164174
std::optional<std::pair<std::string, CTransactionRef>> SingleTRUCChecks(const CTransactionRef& ptx,
175+
const std::string& reason_prefix, std::string& out_reason,
165176
const CTxMemPool::setEntries& mempool_ancestors,
166177
const std::set<Txid>& direct_conflicts,
167178
int64_t vsize)
168179
{
169180
// Check TRUC and non-TRUC inheritance.
170181
for (const auto& entry : mempool_ancestors) {
171182
if (ptx->version != TRUC_VERSION && entry->GetTx().version == TRUC_VERSION) {
183+
out_reason = reason_prefix + "spent-by-nontruc";
172184
return std::make_pair(strprintf("non-version=3 tx %s (wtxid=%s) cannot spend from version=3 tx %s (wtxid=%s)",
173185
ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString(),
174186
entry->GetSharedTx()->GetHash().ToString(), entry->GetSharedTx()->GetWitnessHash().ToString()),
175187
nullptr);
176188
} else if (ptx->version == TRUC_VERSION && entry->GetTx().version != TRUC_VERSION) {
189+
out_reason = reason_prefix + "spends-nontruc";
177190
return std::make_pair(strprintf("version=3 tx %s (wtxid=%s) cannot spend from non-version=3 tx %s (wtxid=%s)",
178191
ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString(),
179192
entry->GetSharedTx()->GetHash().ToString(), entry->GetSharedTx()->GetWitnessHash().ToString()),
@@ -189,13 +202,15 @@ std::optional<std::pair<std::string, CTransactionRef>> SingleTRUCChecks(const CT
189202
if (ptx->version != TRUC_VERSION) return std::nullopt;
190203

191204
if (vsize > TRUC_MAX_VSIZE) {
205+
out_reason = reason_prefix + "vsize-toobig";
192206
return std::make_pair(strprintf("version=3 tx %s (wtxid=%s) is too big: %u > %u virtual bytes",
193207
ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString(), vsize, TRUC_MAX_VSIZE),
194208
nullptr);
195209
}
196210

197211
// Check that TRUC_ANCESTOR_LIMIT would not be violated.
198212
if (mempool_ancestors.size() + 1 > TRUC_ANCESTOR_LIMIT) {
213+
out_reason = reason_prefix + "ancestors-toomany";
199214
return std::make_pair(strprintf("tx %s (wtxid=%s) would have too many ancestors",
200215
ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString()),
201216
nullptr);
@@ -205,6 +220,7 @@ std::optional<std::pair<std::string, CTransactionRef>> SingleTRUCChecks(const CT
205220
if (mempool_ancestors.size() > 0) {
206221
// If this transaction spends TRUC parents, it cannot be too large.
207222
if (vsize > TRUC_CHILD_MAX_VSIZE) {
223+
out_reason = reason_prefix + "child-toobig";
208224
return std::make_pair(strprintf("version=3 child tx %s (wtxid=%s) is too big: %u > %u virtual bytes",
209225
ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString(), vsize, TRUC_CHILD_MAX_VSIZE),
210226
nullptr);
@@ -233,6 +249,7 @@ std::optional<std::pair<std::string, CTransactionRef>> SingleTRUCChecks(const CT
233249

234250
// Return the sibling if its eviction can be considered. Provide the "descendant count
235251
// limit" string either way, as the caller may decide not to do sibling eviction.
252+
out_reason = reason_prefix + "descendants-toomany";
236253
return std::make_pair(strprintf("tx %u (wtxid=%s) would exceed descendant count limit",
237254
parent_entry->GetSharedTx()->GetHash().ToString(),
238255
parent_entry->GetSharedTx()->GetWitnessHash().ToString()),

src/policy/truc_policy.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ static_assert(TRUC_MAX_VSIZE + TRUC_CHILD_MAX_VSIZE <= DEFAULT_DESCENDANT_SIZE_L
6262
* applicable.
6363
*/
6464
std::optional<std::pair<std::string, CTransactionRef>> SingleTRUCChecks(const CTransactionRef& ptx,
65+
const std::string& reason_prefix, std::string& out_reason,
6566
const CTxMemPool::setEntries& mempool_ancestors,
6667
const std::set<Txid>& direct_conflicts,
6768
int64_t vsize);
@@ -88,6 +89,7 @@ std::optional<std::pair<std::string, CTransactionRef>> SingleTRUCChecks(const CT
8889
* @returns debug string if an error occurs, std::nullopt otherwise.
8990
* */
9091
std::optional<std::string> PackageTRUCChecks(const CTransactionRef& ptx, int64_t vsize,
92+
const std::string& reason_prefix, std::string& out_reason,
9193
const Package& package,
9294
const CTxMemPool::setEntries& mempool_ancestors);
9395

src/test/txvalidation_tests.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,18 @@
2020

2121
BOOST_AUTO_TEST_SUITE(txvalidation_tests)
2222

23+
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)
24+
{
25+
std::string dummy;
26+
return SingleTRUCChecks(ptx, dummy, dummy, mempool_ancestors, direct_conflicts, vsize);
27+
}
28+
29+
std::optional<std::string> PackageTRUCChecks(const CTransactionRef& ptx, int64_t vsize, const Package& package, const CTxMemPool::setEntries& mempool_ancestors)
30+
{
31+
std::string dummy;
32+
return PackageTRUCChecks(ptx, vsize, dummy, dummy, package, mempool_ancestors);
33+
}
34+
2335
/**
2436
* Ensure that the mempool won't accept coinbase transactions.
2537
*/

src/validation.cpp

Lines changed: 5 additions & 4 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, ws.m_ancestors, ws.m_conflicts, ws.m_vsize)}) {
1066+
if (const auto err{SingleTRUCChecks(ws.m_ptx, "truc-", reason, 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.
@@ -1082,7 +1082,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
10821082
// (which is normally done in PreChecks). However, the only way a TRUC transaction can
10831083
// have a non-TRUC and non-BIP125 descendant is due to a reorg.
10841084
} else {
1085-
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "TRUC-violation", err->first);
1085+
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, reason, err->first);
10861086
}
10871087
}
10881088

@@ -1588,9 +1588,10 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptMultipleTransactions(const std::
15881588

15891589
// At this point we have all in-mempool ancestors, and we know every transaction's vsize.
15901590
// Run the TRUC checks on the package.
1591+
std::string reason;
15911592
for (Workspace& ws : workspaces) {
1592-
if (auto err{PackageTRUCChecks(ws.m_ptx, ws.m_vsize, txns, ws.m_ancestors)}) {
1593-
package_state.Invalid(PackageValidationResult::PCKG_POLICY, "TRUC-violation", err.value());
1593+
if (auto err{PackageTRUCChecks(ws.m_ptx, ws.m_vsize, "truc-", reason, txns, ws.m_ancestors)}) {
1594+
package_state.Invalid(PackageValidationResult::PCKG_POLICY, reason, err.value());
15941595
return PackageMempoolAcceptResult(package_state, {});
15951596
}
15961597
}

0 commit comments

Comments
 (0)