Branch data Line data Source code
1 : : // Copyright (c) 2017-2021 The Bitcoin Core developers
2 : : // Distributed under the MIT software license, see the accompanying
3 : : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 : :
5 : : #include <consensus/validation.h>
6 : : #include <key_io.h>
7 : : #include <policy/packages.h>
8 : : #include <policy/policy.h>
9 : : #include <policy/truc_policy.h>
10 : : #include <primitives/transaction.h>
11 : : #include <random.h>
12 : : #include <script/script.h>
13 : : #include <test/util/setup_common.h>
14 : : #include <test/util/txmempool.h>
15 : : #include <validation.h>
16 : :
17 : : #include <boost/test/unit_test.hpp>
18 : :
19 : :
20 : : BOOST_AUTO_TEST_SUITE(txvalidation_tests)
21 : :
22 : : /**
23 : : * Ensure that the mempool won't accept coinbase transactions.
24 : : */
25 [ + - + - : 7 : BOOST_FIXTURE_TEST_CASE(tx_mempool_reject_coinbase, TestChain100Setup)
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- ]
26 : : {
27 [ + - + - : 1 : CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;
+ - ]
28 [ + - ]: 1 : CMutableTransaction coinbaseTx;
29 : :
30 : 1 : coinbaseTx.version = 1;
31 [ + - ]: 1 : coinbaseTx.vin.resize(1);
32 [ + - ]: 1 : coinbaseTx.vout.resize(1);
33 [ + - + - ]: 1 : coinbaseTx.vin[0].scriptSig = CScript() << OP_11 << OP_EQUAL;
34 : 1 : coinbaseTx.vout[0].nValue = 1 * CENT;
35 : 1 : coinbaseTx.vout[0].scriptPubKey = scriptPubKey;
36 : :
37 [ + - + - : 3 : BOOST_CHECK(CTransaction(coinbaseTx).IsCoinBase());
+ - + - ]
38 : :
39 [ + - ]: 1 : LOCK(cs_main);
40 : :
41 [ + - ]: 1 : unsigned int initialPoolSize = m_node.mempool->size();
42 [ + - + - ]: 2 : const MempoolAcceptResult result = m_node.chainman->ProcessTransaction(MakeTransactionRef(coinbaseTx));
43 : :
44 [ + - + - : 2 : BOOST_CHECK(result.m_result_type == MempoolAcceptResult::ResultType::INVALID);
+ - ]
45 : :
46 : : // Check that the transaction hasn't been added to mempool.
47 [ + - + - : 1 : BOOST_CHECK_EQUAL(m_node.mempool->size(), initialPoolSize);
+ - ]
48 : :
49 : : // Check that the validation state reflects the unsuccessful attempt.
50 [ + - + - : 2 : BOOST_CHECK(result.m_state.IsInvalid());
+ - ]
51 [ + - + - : 1 : BOOST_CHECK_EQUAL(result.m_state.GetRejectReason(), "coinbase");
+ - ]
52 [ + - + - ]: 2 : BOOST_CHECK(result.m_state.GetResult() == TxValidationResult::TX_CONSENSUS);
53 [ + - ]: 3 : }
54 : :
55 : : // Generate a number of random, nonexistent outpoints.
56 : 8 : static inline std::vector<COutPoint> random_outpoints(size_t num_outpoints) {
57 : 8 : std::vector<COutPoint> outpoints;
58 [ + + ]: 125 : for (size_t i{0}; i < num_outpoints; ++i) {
59 [ + - ]: 117 : outpoints.emplace_back(Txid::FromUint256(GetRandHash()), 0);
60 : : }
61 : 8 : return outpoints;
62 : 0 : }
63 : :
64 : 1 : static inline std::vector<CPubKey> random_keys(size_t num_keys) {
65 : 1 : std::vector<CPubKey> keys;
66 [ + - ]: 1 : keys.reserve(num_keys);
67 [ + + ]: 3 : for (size_t i{0}; i < num_keys; ++i) {
68 : 2 : CKey key;
69 [ + - ]: 2 : key.MakeNewKey(true);
70 [ + - + - ]: 2 : keys.emplace_back(key.GetPubKey());
71 : 2 : }
72 : 1 : return keys;
73 : 0 : }
74 : :
75 : : // Creates a placeholder tx (not valid) with 25 outputs. Specify the version and the inputs.
76 : 22 : static inline CTransactionRef make_tx(const std::vector<COutPoint>& inputs, int32_t version)
77 : : {
78 : 22 : CMutableTransaction mtx = CMutableTransaction{};
79 : 22 : mtx.version = version;
80 [ + - ]: 22 : mtx.vin.resize(inputs.size());
81 [ + - ]: 22 : mtx.vout.resize(25);
82 [ + + ]: 149 : for (size_t i{0}; i < inputs.size(); ++i) {
83 : 127 : mtx.vin[i].prevout = inputs[i];
84 : : }
85 [ + + ]: 572 : for (auto i{0}; i < 25; ++i) {
86 [ + - ]: 550 : mtx.vout[i].scriptPubKey = CScript() << OP_TRUE;
87 : 550 : mtx.vout[i].nValue = 10000;
88 : : }
89 [ + - ]: 44 : return MakeTransactionRef(mtx);
90 : 22 : }
91 : :
92 [ + - + - : 7 : BOOST_FIXTURE_TEST_CASE(version3_tests, RegTestingSetup)
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- ]
93 : : {
94 : : // Test TRUC policy helper functions
95 : 1 : CTxMemPool& pool = *Assert(m_node.mempool);
96 [ + - ]: 1 : LOCK2(cs_main, pool.cs);
97 : 1 : TestMemPoolEntryHelper entry;
98 [ + - ]: 1 : std::set<Txid> empty_conflicts_set;
99 : 1 : CTxMemPool::setEntries empty_ancestors;
100 : :
101 [ + - + - ]: 1 : auto mempool_tx_v3 = make_tx(random_outpoints(1), /*version=*/3);
102 [ + - + - ]: 1 : pool.addUnchecked(entry.FromTx(mempool_tx_v3));
103 [ + - + - ]: 1 : auto mempool_tx_v2 = make_tx(random_outpoints(1), /*version=*/2);
104 [ + - + - ]: 1 : pool.addUnchecked(entry.FromTx(mempool_tx_v2));
105 : : // Default values.
106 : 1 : CTxMemPool::Limits m_limits{};
107 : :
108 : : // Cannot spend from an unconfirmed TRUC transaction unless this tx is also TRUC.
109 : 1 : {
110 : : // mempool_tx_v3
111 : : // ^
112 : : // tx_v2_from_v3
113 [ + - + - : 2 : auto tx_v2_from_v3 = make_tx({COutPoint{mempool_tx_v3->GetHash(), 0}}, /*version=*/2);
+ - ]
114 [ + - + - ]: 1 : auto ancestors_v2_from_v3{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v2_from_v3), m_limits)};
115 [ + - ]: 1 : const auto expected_error_str{strprintf("non-version=3 tx %s (wtxid=%s) cannot spend from version=3 tx %s (wtxid=%s)",
116 [ + - + - ]: 2 : tx_v2_from_v3->GetHash().ToString(), tx_v2_from_v3->GetWitnessHash().ToString(),
117 [ + - + - : 3 : mempool_tx_v3->GetHash().ToString(), mempool_tx_v3->GetWitnessHash().ToString())};
+ - + - ]
118 [ + - + - ]: 1 : auto result_v2_from_v3{SingleTRUCChecks(tx_v2_from_v3, *ancestors_v2_from_v3, empty_conflicts_set, GetVirtualTransactionSize(*tx_v2_from_v3))};
119 [ + - + - ]: 1 : BOOST_CHECK_EQUAL(result_v2_from_v3->first, expected_error_str);
120 [ + - + - ]: 1 : BOOST_CHECK_EQUAL(result_v2_from_v3->second, nullptr);
121 : :
122 [ + + + - : 3 : Package package_v3_v2{mempool_tx_v3, tx_v2_from_v3};
- - - - ]
123 [ + - + - : 1 : BOOST_CHECK_EQUAL(*PackageTRUCChecks(tx_v2_from_v3, GetVirtualTransactionSize(*tx_v2_from_v3), package_v3_v2, empty_ancestors), expected_error_str);
+ - + - ]
124 [ + - + - ]: 2 : CTxMemPool::setEntries entries_mempool_v3{pool.GetIter(mempool_tx_v3->GetHash().ToUint256()).value()};
125 [ + - + - : 3 : BOOST_CHECK_EQUAL(*PackageTRUCChecks(tx_v2_from_v3, GetVirtualTransactionSize(*tx_v2_from_v3), {tx_v2_from_v3}, entries_mempool_v3), expected_error_str);
+ - + - +
+ + - - -
- - ]
126 : :
127 : : // mempool_tx_v3 mempool_tx_v2
128 : : // ^ ^
129 : : // tx_v2_from_v2_and_v3
130 [ + - + - : 2 : auto tx_v2_from_v2_and_v3 = make_tx({COutPoint{mempool_tx_v3->GetHash(), 0}, COutPoint{mempool_tx_v2->GetHash(), 0}}, /*version=*/2);
+ - ]
131 [ + - + - ]: 1 : auto ancestors_v2_from_both{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v2_from_v2_and_v3), m_limits)};
132 [ + - ]: 1 : const auto expected_error_str_2{strprintf("non-version=3 tx %s (wtxid=%s) cannot spend from version=3 tx %s (wtxid=%s)",
133 [ + - + - ]: 2 : tx_v2_from_v2_and_v3->GetHash().ToString(), tx_v2_from_v2_and_v3->GetWitnessHash().ToString(),
134 [ + - + - : 3 : mempool_tx_v3->GetHash().ToString(), mempool_tx_v3->GetWitnessHash().ToString())};
+ - + - ]
135 [ + - + - ]: 1 : auto result_v2_from_both{SingleTRUCChecks(tx_v2_from_v2_and_v3, *ancestors_v2_from_both, empty_conflicts_set, GetVirtualTransactionSize(*tx_v2_from_v2_and_v3))};
136 [ + - + - ]: 1 : BOOST_CHECK_EQUAL(result_v2_from_both->first, expected_error_str_2);
137 [ + - + - ]: 1 : BOOST_CHECK_EQUAL(result_v2_from_both->second, nullptr);
138 : :
139 [ + + + - : 4 : Package package_v3_v2_v2{mempool_tx_v3, mempool_tx_v2, tx_v2_from_v2_and_v3};
- - - - ]
140 [ + - + - : 1 : BOOST_CHECK_EQUAL(*PackageTRUCChecks(tx_v2_from_v2_and_v3, GetVirtualTransactionSize(*tx_v2_from_v2_and_v3), package_v3_v2_v2, empty_ancestors), expected_error_str_2);
+ - + - ]
141 [ + - + - ]: 2 : }
142 : :
143 : : // TRUC cannot spend from an unconfirmed non-TRUC transaction.
144 : 1 : {
145 : : // mempool_tx_v2
146 : : // ^
147 : : // tx_v3_from_v2
148 [ + - + - : 2 : auto tx_v3_from_v2 = make_tx({COutPoint{mempool_tx_v2->GetHash(), 0}}, /*version=*/3);
+ - ]
149 [ + - + - ]: 1 : auto ancestors_v3_from_v2{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v3_from_v2), m_limits)};
150 [ + - ]: 1 : const auto expected_error_str{strprintf("version=3 tx %s (wtxid=%s) cannot spend from non-version=3 tx %s (wtxid=%s)",
151 [ + - + - ]: 2 : tx_v3_from_v2->GetHash().ToString(), tx_v3_from_v2->GetWitnessHash().ToString(),
152 [ + - + - : 3 : mempool_tx_v2->GetHash().ToString(), mempool_tx_v2->GetWitnessHash().ToString())};
+ - + - ]
153 [ + - + - ]: 1 : auto result_v3_from_v2{SingleTRUCChecks(tx_v3_from_v2, *ancestors_v3_from_v2, empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_from_v2))};
154 [ + - + - ]: 1 : BOOST_CHECK_EQUAL(result_v3_from_v2->first, expected_error_str);
155 [ + - + - ]: 1 : BOOST_CHECK_EQUAL(result_v3_from_v2->second, nullptr);
156 : :
157 [ + + + - : 3 : Package package_v2_v3{mempool_tx_v2, tx_v3_from_v2};
- - - - ]
158 [ + - + - : 1 : BOOST_CHECK_EQUAL(*PackageTRUCChecks(tx_v3_from_v2, GetVirtualTransactionSize(*tx_v3_from_v2), package_v2_v3, empty_ancestors), expected_error_str);
+ - + - ]
159 [ + - + - ]: 2 : CTxMemPool::setEntries entries_mempool_v2{pool.GetIter(mempool_tx_v2->GetHash().ToUint256()).value()};
160 [ + - + - : 3 : BOOST_CHECK_EQUAL(*PackageTRUCChecks(tx_v3_from_v2, GetVirtualTransactionSize(*tx_v3_from_v2), {tx_v3_from_v2}, entries_mempool_v2), expected_error_str);
+ - + - +
+ + - - -
- - ]
161 : :
162 : : // mempool_tx_v3 mempool_tx_v2
163 : : // ^ ^
164 : : // tx_v3_from_v2_and_v3
165 [ + - + - : 2 : auto tx_v3_from_v2_and_v3 = make_tx({COutPoint{mempool_tx_v3->GetHash(), 0}, COutPoint{mempool_tx_v2->GetHash(), 0}}, /*version=*/3);
+ - ]
166 [ + - + - ]: 1 : auto ancestors_v3_from_both{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v3_from_v2_and_v3), m_limits)};
167 [ + - ]: 1 : const auto expected_error_str_2{strprintf("version=3 tx %s (wtxid=%s) cannot spend from non-version=3 tx %s (wtxid=%s)",
168 [ + - + - ]: 2 : tx_v3_from_v2_and_v3->GetHash().ToString(), tx_v3_from_v2_and_v3->GetWitnessHash().ToString(),
169 [ + - + - : 3 : mempool_tx_v2->GetHash().ToString(), mempool_tx_v2->GetWitnessHash().ToString())};
+ - + - ]
170 [ + - + - ]: 1 : auto result_v3_from_both{SingleTRUCChecks(tx_v3_from_v2_and_v3, *ancestors_v3_from_both, empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_from_v2_and_v3))};
171 [ + - + - ]: 1 : BOOST_CHECK_EQUAL(result_v3_from_both->first, expected_error_str_2);
172 [ + - + - ]: 1 : BOOST_CHECK_EQUAL(result_v3_from_both->second, nullptr);
173 : :
174 : : // tx_v3_from_v2_and_v3 also violates TRUC_ANCESTOR_LIMIT.
175 [ + - ]: 1 : const auto expected_error_str_3{strprintf("tx %s (wtxid=%s) would have too many ancestors",
176 [ + - + - : 2 : tx_v3_from_v2_and_v3->GetHash().ToString(), tx_v3_from_v2_and_v3->GetWitnessHash().ToString())};
+ - ]
177 [ + + + - : 4 : Package package_v3_v2_v3{mempool_tx_v3, mempool_tx_v2, tx_v3_from_v2_and_v3};
- - - - ]
178 [ + - + - : 1 : BOOST_CHECK_EQUAL(*PackageTRUCChecks(tx_v3_from_v2_and_v3, GetVirtualTransactionSize(*tx_v3_from_v2_and_v3), package_v3_v2_v3, empty_ancestors), expected_error_str_3);
+ - + - ]
179 [ + - + - ]: 2 : }
180 : : // V3 from V3 is ok, and non-V3 from non-V3 is ok.
181 : 1 : {
182 : : // mempool_tx_v3
183 : : // ^
184 : : // tx_v3_from_v3
185 [ + - + - : 2 : auto tx_v3_from_v3 = make_tx({COutPoint{mempool_tx_v3->GetHash(), 0}}, /*version=*/3);
+ - ]
186 [ + - + - ]: 1 : auto ancestors_v3{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v3_from_v3), m_limits)};
187 [ + - + - : 2 : BOOST_CHECK(SingleTRUCChecks(tx_v3_from_v3, *ancestors_v3, empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_from_v3))
+ - + - +
- ]
188 : : == std::nullopt);
189 : :
190 [ + + + - : 3 : Package package_v3_v3{mempool_tx_v3, tx_v3_from_v3};
- - - - ]
191 [ + - + - : 2 : BOOST_CHECK(PackageTRUCChecks(tx_v3_from_v3, GetVirtualTransactionSize(*tx_v3_from_v3), package_v3_v3, empty_ancestors) == std::nullopt);
+ - + - +
- ]
192 : :
193 : : // mempool_tx_v2
194 : : // ^
195 : : // tx_v2_from_v2
196 [ + - + - : 2 : auto tx_v2_from_v2 = make_tx({COutPoint{mempool_tx_v2->GetHash(), 0}}, /*version=*/2);
+ - ]
197 [ + - + - ]: 1 : auto ancestors_v2{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v2_from_v2), m_limits)};
198 [ + - + - : 2 : BOOST_CHECK(SingleTRUCChecks(tx_v2_from_v2, *ancestors_v2, empty_conflicts_set, GetVirtualTransactionSize(*tx_v2_from_v2))
+ - + - +
- ]
199 : : == std::nullopt);
200 : :
201 [ + + + - : 3 : Package package_v2_v2{mempool_tx_v2, tx_v2_from_v2};
- - - - ]
202 [ + - + - : 2 : BOOST_CHECK(PackageTRUCChecks(tx_v2_from_v2, GetVirtualTransactionSize(*tx_v2_from_v2), package_v2_v2, empty_ancestors) == std::nullopt);
+ - + - ]
203 [ + - + - ]: 2 : }
204 : :
205 : : // Tx spending TRUC cannot have too many mempool ancestors
206 : : // Configuration where the tx has multiple direct parents.
207 : 1 : {
208 : 1 : Package package_multi_parents;
209 : 1 : std::vector<COutPoint> mempool_outpoints;
210 [ + - ]: 1 : mempool_outpoints.emplace_back(mempool_tx_v3->GetHash(), 0);
211 [ + - ]: 1 : package_multi_parents.emplace_back(mempool_tx_v3);
212 [ + + ]: 3 : for (size_t i{0}; i < 2; ++i) {
213 [ + - + - ]: 2 : auto mempool_tx = make_tx(random_outpoints(i + 1), /*version=*/3);
214 [ + - + - ]: 2 : pool.addUnchecked(entry.FromTx(mempool_tx));
215 [ + - ]: 2 : mempool_outpoints.emplace_back(mempool_tx->GetHash(), 0);
216 [ + - ]: 2 : package_multi_parents.emplace_back(mempool_tx);
217 : 2 : }
218 [ + - ]: 1 : auto tx_v3_multi_parent = make_tx(mempool_outpoints, /*version=*/3);
219 [ + - ]: 1 : package_multi_parents.emplace_back(tx_v3_multi_parent);
220 [ + - + - ]: 1 : auto ancestors{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v3_multi_parent), m_limits)};
221 [ + - + - ]: 1 : BOOST_CHECK_EQUAL(ancestors->size(), 3);
222 [ + - ]: 1 : const auto expected_error_str{strprintf("tx %s (wtxid=%s) would have too many ancestors",
223 [ + - + - : 2 : tx_v3_multi_parent->GetHash().ToString(), tx_v3_multi_parent->GetWitnessHash().ToString())};
+ - ]
224 [ + - + - ]: 1 : auto result{SingleTRUCChecks(tx_v3_multi_parent, *ancestors, empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_multi_parent))};
225 [ + - + - ]: 1 : BOOST_CHECK_EQUAL(result->first, expected_error_str);
226 [ + - + - ]: 1 : BOOST_CHECK_EQUAL(result->second, nullptr);
227 : :
228 [ + - + - : 1 : BOOST_CHECK_EQUAL(*PackageTRUCChecks(tx_v3_multi_parent, GetVirtualTransactionSize(*tx_v3_multi_parent), package_multi_parents, empty_ancestors),
+ - + - ]
229 : : expected_error_str);
230 [ + - ]: 2 : }
231 : :
232 : : // Configuration where the tx is in a multi-generation chain.
233 : 1 : {
234 : 1 : Package package_multi_gen;
235 : 1 : CTransactionRef middle_tx;
236 [ + - ]: 1 : auto last_outpoint{random_outpoints(1)[0]};
237 [ + + ]: 3 : for (size_t i{0}; i < 2; ++i) {
238 [ + - + - : 4 : auto mempool_tx = make_tx({last_outpoint}, /*version=*/3);
+ - ]
239 [ + - + - ]: 2 : pool.addUnchecked(entry.FromTx(mempool_tx));
240 [ + - ]: 2 : last_outpoint = COutPoint{mempool_tx->GetHash(), 0};
241 [ + - ]: 2 : package_multi_gen.emplace_back(mempool_tx);
242 [ + + ]: 2 : if (i == 1) middle_tx = mempool_tx;
243 : 2 : }
244 [ + - + - : 2 : auto tx_v3_multi_gen = make_tx({last_outpoint}, /*version=*/3);
+ - ]
245 [ + - ]: 1 : package_multi_gen.emplace_back(tx_v3_multi_gen);
246 [ + - + - ]: 1 : auto ancestors{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v3_multi_gen), m_limits)};
247 [ + - ]: 1 : const auto expected_error_str{strprintf("tx %s (wtxid=%s) would have too many ancestors",
248 [ + - + - : 2 : tx_v3_multi_gen->GetHash().ToString(), tx_v3_multi_gen->GetWitnessHash().ToString())};
+ - ]
249 [ + - + - ]: 1 : auto result{SingleTRUCChecks(tx_v3_multi_gen, *ancestors, empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_multi_gen))};
250 [ + - + - ]: 1 : BOOST_CHECK_EQUAL(result->first, expected_error_str);
251 [ + - + - ]: 1 : BOOST_CHECK_EQUAL(result->second, nullptr);
252 : :
253 : : // Middle tx is what triggers a failure for the grandchild:
254 [ + - + - : 1 : BOOST_CHECK_EQUAL(*PackageTRUCChecks(middle_tx, GetVirtualTransactionSize(*middle_tx), package_multi_gen, empty_ancestors), expected_error_str);
+ - + - ]
255 [ + - + - : 2 : BOOST_CHECK(PackageTRUCChecks(tx_v3_multi_gen, GetVirtualTransactionSize(*tx_v3_multi_gen), package_multi_gen, empty_ancestors) == std::nullopt);
+ - + - ]
256 [ + - + - ]: 3 : }
257 : :
258 : : // Tx spending TRUC cannot be too large in virtual size.
259 [ + - ]: 1 : auto many_inputs{random_outpoints(100)};
260 [ + - ]: 1 : many_inputs.emplace_back(mempool_tx_v3->GetHash(), 0);
261 : 1 : {
262 [ + - ]: 1 : auto tx_v3_child_big = make_tx(many_inputs, /*version=*/3);
263 [ + - ]: 1 : const auto vsize{GetVirtualTransactionSize(*tx_v3_child_big)};
264 [ + - + - ]: 1 : auto ancestors{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v3_child_big), m_limits)};
265 [ + - ]: 1 : const auto expected_error_str{strprintf("version=3 child tx %s (wtxid=%s) is too big: %u > %u virtual bytes",
266 [ + - + - : 2 : tx_v3_child_big->GetHash().ToString(), tx_v3_child_big->GetWitnessHash().ToString(), vsize, TRUC_CHILD_MAX_VSIZE)};
+ - ]
267 [ + - + - ]: 1 : auto result{SingleTRUCChecks(tx_v3_child_big, *ancestors, empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_child_big))};
268 [ + - + - ]: 1 : BOOST_CHECK_EQUAL(result->first, expected_error_str);
269 [ + - + - ]: 1 : BOOST_CHECK_EQUAL(result->second, nullptr);
270 : :
271 [ + + + - : 3 : Package package_child_big{mempool_tx_v3, tx_v3_child_big};
- - - - ]
272 [ + - + - : 1 : BOOST_CHECK_EQUAL(*PackageTRUCChecks(tx_v3_child_big, GetVirtualTransactionSize(*tx_v3_child_big), package_child_big, empty_ancestors),
+ - + - ]
273 : : expected_error_str);
274 [ + - ]: 1 : }
275 : :
276 : : // Tx spending TRUC cannot have too many sigops.
277 : : // This child has 10 P2WSH multisig inputs.
278 [ + - ]: 1 : auto multisig_outpoints{random_outpoints(10)};
279 [ + - ]: 1 : multisig_outpoints.emplace_back(mempool_tx_v3->GetHash(), 0);
280 [ + - ]: 1 : auto keys{random_keys(2)};
281 : 1 : CScript script_multisig;
282 [ + - ]: 1 : script_multisig << OP_1;
283 [ + + ]: 3 : for (const auto& key : keys) {
284 [ + - ]: 2 : script_multisig << ToByteVector(key);
285 : : }
286 [ + - + - ]: 1 : script_multisig << OP_2 << OP_CHECKMULTISIG;
287 : 1 : {
288 [ + - ]: 1 : CMutableTransaction mtx_many_sigops = CMutableTransaction{};
289 : 1 : mtx_many_sigops.version = TRUC_VERSION;
290 [ + + ]: 12 : for (const auto& outpoint : multisig_outpoints) {
291 [ + - ]: 11 : mtx_many_sigops.vin.emplace_back(outpoint);
292 [ + - + - ]: 22 : mtx_many_sigops.vin.back().scriptWitness.stack.emplace_back(script_multisig.begin(), script_multisig.end());
293 : : }
294 [ + - ]: 1 : mtx_many_sigops.vout.resize(1);
295 [ + - ]: 1 : mtx_many_sigops.vout.back().scriptPubKey = CScript() << OP_TRUE;
296 : 1 : mtx_many_sigops.vout.back().nValue = 10000;
297 [ + - ]: 1 : auto tx_many_sigops{MakeTransactionRef(mtx_many_sigops)};
298 : :
299 [ + - + - ]: 1 : auto ancestors{pool.CalculateMemPoolAncestors(entry.FromTx(tx_many_sigops), m_limits)};
300 : : // legacy uses fAccurate = false, and the maximum number of multisig keys is used
301 [ + - ]: 1 : const int64_t total_sigops{static_cast<int64_t>(tx_many_sigops->vin.size()) * static_cast<int64_t>(script_multisig.GetSigOpCount(/*fAccurate=*/false))};
302 [ + - + - ]: 1 : BOOST_CHECK_EQUAL(total_sigops, tx_many_sigops->vin.size() * MAX_PUBKEYS_PER_MULTISIG);
303 [ + - ]: 1 : const int64_t bip141_vsize{GetVirtualTransactionSize(*tx_many_sigops)};
304 : : // Weight limit is not reached...
305 [ + - + - : 2 : BOOST_CHECK(SingleTRUCChecks(tx_many_sigops, *ancestors, empty_conflicts_set, bip141_vsize) == std::nullopt);
+ - + - ]
306 : : // ...but sigop limit is.
307 : 1 : const auto expected_error_str{strprintf("version=3 child tx %s (wtxid=%s) is too big: %u > %u virtual bytes",
308 [ + - + - ]: 2 : tx_many_sigops->GetHash().ToString(), tx_many_sigops->GetWitnessHash().ToString(),
309 [ + - + - ]: 2 : total_sigops * DEFAULT_BYTES_PER_SIGOP / WITNESS_SCALE_FACTOR, TRUC_CHILD_MAX_VSIZE)};
310 : 2 : auto result{SingleTRUCChecks(tx_many_sigops, *ancestors, empty_conflicts_set,
311 [ + - + - ]: 1 : GetVirtualTransactionSize(*tx_many_sigops, /*nSigOpCost=*/total_sigops, /*bytes_per_sigop=*/ DEFAULT_BYTES_PER_SIGOP))};
312 [ + - + - ]: 1 : BOOST_CHECK_EQUAL(result->first, expected_error_str);
313 [ + - + - ]: 1 : BOOST_CHECK_EQUAL(result->second, nullptr);
314 : :
315 [ + + + - : 3 : Package package_child_sigops{mempool_tx_v3, tx_many_sigops};
- - - - ]
316 [ + - + - : 1 : BOOST_CHECK_EQUAL(*PackageTRUCChecks(tx_many_sigops, total_sigops * DEFAULT_BYTES_PER_SIGOP / WITNESS_SCALE_FACTOR, package_child_sigops, empty_ancestors),
+ - ]
317 : : expected_error_str);
318 [ + - ]: 2 : }
319 : :
320 : : // Parent + child with TRUC in the mempool. Child is allowed as long as it is under TRUC_CHILD_MAX_VSIZE.
321 [ + - + - : 2 : auto tx_mempool_v3_child = make_tx({COutPoint{mempool_tx_v3->GetHash(), 0}}, /*version=*/3);
+ - ]
322 : 1 : {
323 [ + - + - : 2 : BOOST_CHECK(GetTransactionWeight(*tx_mempool_v3_child) <= TRUC_CHILD_MAX_VSIZE * WITNESS_SCALE_FACTOR);
+ - ]
324 [ + - + - ]: 1 : auto ancestors{pool.CalculateMemPoolAncestors(entry.FromTx(tx_mempool_v3_child), m_limits)};
325 [ + - + - : 2 : BOOST_CHECK(SingleTRUCChecks(tx_mempool_v3_child, *ancestors, empty_conflicts_set, GetVirtualTransactionSize(*tx_mempool_v3_child)) == std::nullopt);
+ - + - +
- ]
326 [ + - + - ]: 1 : pool.addUnchecked(entry.FromTx(tx_mempool_v3_child));
327 : :
328 [ + + + - : 3 : Package package_v3_1p1c{mempool_tx_v3, tx_mempool_v3_child};
- - - - ]
329 [ + - + - : 2 : BOOST_CHECK(PackageTRUCChecks(tx_mempool_v3_child, GetVirtualTransactionSize(*tx_mempool_v3_child), package_v3_1p1c, empty_ancestors) == std::nullopt);
+ - + - ]
330 : 1 : }
331 : :
332 : : // A TRUC transaction cannot have more than 1 descendant. Sibling is returned when exactly 1 exists.
333 : 1 : {
334 [ + - + - : 2 : auto tx_v3_child2 = make_tx({COutPoint{mempool_tx_v3->GetHash(), 1}}, /*version=*/3);
+ - ]
335 : :
336 : : // Configuration where parent already has 1 other child in mempool
337 [ + - + - ]: 1 : auto ancestors_1sibling{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v3_child2), m_limits)};
338 [ + - ]: 1 : const auto expected_error_str{strprintf("tx %s (wtxid=%s) would exceed descendant count limit",
339 [ + - + - : 2 : mempool_tx_v3->GetHash().ToString(), mempool_tx_v3->GetWitnessHash().ToString())};
+ - ]
340 [ + - + - ]: 1 : auto result_with_sibling_eviction{SingleTRUCChecks(tx_v3_child2, *ancestors_1sibling, empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_child2))};
341 [ + - + - ]: 1 : BOOST_CHECK_EQUAL(result_with_sibling_eviction->first, expected_error_str);
342 : : // The other mempool child is returned to allow for sibling eviction.
343 [ + - + - ]: 1 : BOOST_CHECK_EQUAL(result_with_sibling_eviction->second, tx_mempool_v3_child);
344 : :
345 : : // If directly replacing the child, make sure there is no double-counting.
346 [ + - + - : 3 : BOOST_CHECK(SingleTRUCChecks(tx_v3_child2, *ancestors_1sibling, {tx_mempool_v3_child->GetHash()}, GetVirtualTransactionSize(*tx_v3_child2))
+ - + - +
- + - ]
347 : : == std::nullopt);
348 : :
349 [ + + + - : 4 : Package package_v3_1p2c{mempool_tx_v3, tx_mempool_v3_child, tx_v3_child2};
- - - - ]
350 [ + - + - : 1 : BOOST_CHECK_EQUAL(*PackageTRUCChecks(tx_v3_child2, GetVirtualTransactionSize(*tx_v3_child2), package_v3_1p2c, empty_ancestors),
+ - + - ]
351 : : expected_error_str);
352 : :
353 : : // Configuration where parent already has 2 other children in mempool (no sibling eviction allowed). This may happen as the result of a reorg.
354 [ + - + - ]: 1 : pool.addUnchecked(entry.FromTx(tx_v3_child2));
355 [ + - + - : 2 : auto tx_v3_child3 = make_tx({COutPoint{mempool_tx_v3->GetHash(), 24}}, /*version=*/3);
+ - ]
356 [ + - ]: 1 : auto entry_mempool_parent = pool.GetIter(mempool_tx_v3->GetHash().ToUint256()).value();
357 [ + - + - ]: 1 : BOOST_CHECK_EQUAL(entry_mempool_parent->GetCountWithDescendants(), 3);
358 [ + - + - ]: 1 : auto ancestors_2siblings{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v3_child3), m_limits)};
359 : :
360 [ + - + - ]: 1 : auto result_2children{SingleTRUCChecks(tx_v3_child3, *ancestors_2siblings, empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_child3))};
361 [ + - + - ]: 1 : BOOST_CHECK_EQUAL(result_2children->first, expected_error_str);
362 : : // The other mempool child is not returned because sibling eviction is not allowed.
363 [ + - + - ]: 1 : BOOST_CHECK_EQUAL(result_2children->second, nullptr);
364 [ + - + - ]: 2 : }
365 : :
366 : : // Sibling eviction: parent already has 1 other child, which also has its own child (no sibling eviction allowed). This may happen as the result of a reorg.
367 : 1 : {
368 [ + - + - ]: 1 : auto tx_mempool_grandparent = make_tx(random_outpoints(1), /*version=*/3);
369 [ + - + - : 2 : auto tx_mempool_sibling = make_tx({COutPoint{tx_mempool_grandparent->GetHash(), 0}}, /*version=*/3);
+ - ]
370 [ + - + - : 2 : auto tx_mempool_nibling = make_tx({COutPoint{tx_mempool_sibling->GetHash(), 0}}, /*version=*/3);
+ - ]
371 [ + - + - : 2 : auto tx_to_submit = make_tx({COutPoint{tx_mempool_grandparent->GetHash(), 1}}, /*version=*/3);
+ - ]
372 : :
373 [ + - + - ]: 1 : pool.addUnchecked(entry.FromTx(tx_mempool_grandparent));
374 [ + - + - ]: 1 : pool.addUnchecked(entry.FromTx(tx_mempool_sibling));
375 [ + - + - ]: 1 : pool.addUnchecked(entry.FromTx(tx_mempool_nibling));
376 : :
377 [ + - + - ]: 1 : auto ancestors_3gen{pool.CalculateMemPoolAncestors(entry.FromTx(tx_to_submit), m_limits)};
378 [ + - ]: 1 : const auto expected_error_str{strprintf("tx %s (wtxid=%s) would exceed descendant count limit",
379 [ + - + - : 2 : tx_mempool_grandparent->GetHash().ToString(), tx_mempool_grandparent->GetWitnessHash().ToString())};
+ - ]
380 [ + - + - ]: 1 : auto result_3gen{SingleTRUCChecks(tx_to_submit, *ancestors_3gen, empty_conflicts_set, GetVirtualTransactionSize(*tx_to_submit))};
381 [ + - + - ]: 1 : BOOST_CHECK_EQUAL(result_3gen->first, expected_error_str);
382 : : // The other mempool child is not returned because sibling eviction is not allowed.
383 [ + - + - ]: 1 : BOOST_CHECK_EQUAL(result_3gen->second, nullptr);
384 [ + - + - : 5 : }
+ - + - +
- ]
385 : :
386 : : // Configuration where tx has multiple generations of descendants is not tested because that is
387 : : // equivalent to the tx with multiple generations of ancestors.
388 [ + - + - : 42 : }
- + + - +
- + - + -
+ - - + +
- + - - +
+ - + - +
- + - + -
- + + - +
- - + + -
+ - - + +
- + - - +
+ - + - -
+ + - + -
- + + - +
- + - - +
+ - + - +
- + - ]
389 : :
390 : : BOOST_AUTO_TEST_SUITE_END()
|