@@ -116,6 +116,9 @@ BOOST_FIXTURE_TEST_CASE(ephemeral_tests, RegTestingSetup)
116
116
TestMemPoolEntryHelper entry;
117
117
CTxMemPool::setEntries empty_ancestors;
118
118
119
+ TxValidationState child_state;
120
+ Txid child_txid;
121
+
119
122
// Arbitrary non-0 feerate for these tests
120
123
CFeeRate dustrelay (DUST_RELAY_TX_FEE);
121
124
@@ -131,88 +134,145 @@ BOOST_FIXTURE_TEST_CASE(ephemeral_tests, RegTestingSetup)
131
134
// We first start with nothing "in the mempool", using package checks
132
135
133
136
// Trivial single transaction with no dust
134
- BOOST_CHECK (!CheckEphemeralSpends ({dust_spend}, dustrelay, pool));
137
+ BOOST_CHECK (CheckEphemeralSpends ({dust_spend}, dustrelay, pool, child_state, child_txid));
138
+ BOOST_CHECK (child_state.IsValid ());
139
+ BOOST_CHECK_EQUAL (child_txid, Txid ());
135
140
136
141
// Now with dust, ok because the tx has no dusty parents
137
- BOOST_CHECK (!CheckEphemeralSpends ({grandparent_tx_1}, dustrelay, pool));
142
+ BOOST_CHECK (CheckEphemeralSpends ({grandparent_tx_1}, dustrelay, pool, child_state, child_txid));
143
+ BOOST_CHECK (child_state.IsValid ());
144
+ BOOST_CHECK_EQUAL (child_txid, Txid ());
138
145
139
146
// Dust checks pass
140
- BOOST_CHECK (!CheckEphemeralSpends ({grandparent_tx_1, dust_spend}, CFeeRate (0 ), pool));
141
- BOOST_CHECK (!CheckEphemeralSpends ({grandparent_tx_1, dust_spend}, dustrelay, pool));
147
+ BOOST_CHECK (CheckEphemeralSpends ({grandparent_tx_1, dust_spend}, CFeeRate (0 ), pool, child_state, child_txid));
148
+ BOOST_CHECK (child_state.IsValid ());
149
+ BOOST_CHECK_EQUAL (child_txid, Txid ());
150
+ BOOST_CHECK (CheckEphemeralSpends ({grandparent_tx_1, dust_spend}, dustrelay, pool, child_state, child_txid));
151
+ BOOST_CHECK (child_state.IsValid ());
152
+ BOOST_CHECK_EQUAL (child_txid, Txid ());
142
153
143
154
auto dust_non_spend = make_tx ({COutPoint{dust_txid, dust_index - 1 }}, /* version=*/ 2 );
144
155
145
156
// Child spending non-dust only from parent should be disallowed even if dust otherwise spent
146
157
const auto dust_non_spend_txid{dust_non_spend->GetHash ()};
147
158
const Txid null_txid;
148
159
assert (dust_non_spend_txid != null_txid);
149
- BOOST_CHECK_EQUAL (CheckEphemeralSpends ({grandparent_tx_1, dust_non_spend, dust_spend}, dustrelay, pool).value_or (null_txid), dust_non_spend_txid);
150
- BOOST_CHECK_EQUAL (CheckEphemeralSpends ({grandparent_tx_1, dust_spend, dust_non_spend}, dustrelay, pool).value_or (null_txid), dust_non_spend_txid);
151
- BOOST_CHECK_EQUAL (CheckEphemeralSpends ({grandparent_tx_1, dust_non_spend}, dustrelay, pool).value_or (null_txid), dust_non_spend_txid);
160
+ BOOST_CHECK (!CheckEphemeralSpends ({grandparent_tx_1, dust_non_spend, dust_spend}, dustrelay, pool, child_state, child_txid));
161
+ BOOST_CHECK (!child_state.IsValid ());
162
+ BOOST_CHECK_EQUAL (child_txid, dust_non_spend_txid);
163
+ child_state = TxValidationState ();
164
+ child_txid = Txid ();
165
+
166
+ BOOST_CHECK (!CheckEphemeralSpends ({grandparent_tx_1, dust_spend, dust_non_spend}, dustrelay, pool, child_state, child_txid));
167
+ BOOST_CHECK (!child_state.IsValid ());
168
+ BOOST_CHECK_EQUAL (child_txid, dust_non_spend_txid);
169
+ child_state = TxValidationState ();
170
+ child_txid = Txid ();
171
+
172
+ BOOST_CHECK (!CheckEphemeralSpends ({grandparent_tx_1, dust_non_spend}, dustrelay, pool, child_state, child_txid));
173
+ BOOST_CHECK (!child_state.IsValid ());
174
+ BOOST_CHECK_EQUAL (child_txid, dust_non_spend_txid);
175
+ child_state = TxValidationState ();
176
+ child_txid = Txid ();
152
177
153
178
auto grandparent_tx_2 = make_ephemeral_tx (random_outpoints (1 ), /* version=*/ 2 );
154
179
const auto dust_txid_2 = grandparent_tx_2->GetHash ();
155
180
156
181
// Spend dust from one but not another is ok, as long as second grandparent has no child
157
- BOOST_CHECK (!CheckEphemeralSpends ({grandparent_tx_1, grandparent_tx_2, dust_spend}, dustrelay, pool));
182
+ BOOST_CHECK (CheckEphemeralSpends ({grandparent_tx_1, grandparent_tx_2, dust_spend}, dustrelay, pool, child_state, child_txid));
183
+ BOOST_CHECK (child_state.IsValid ());
184
+ BOOST_CHECK_EQUAL (child_txid, Txid ());
158
185
159
186
auto dust_non_spend_both_parents = make_tx ({COutPoint{dust_txid, dust_index}, COutPoint{dust_txid_2, dust_index - 1 }}, /* version=*/ 2 );
160
187
// But if we spend from the parent, it must spend dust
161
- BOOST_CHECK_EQUAL (CheckEphemeralSpends ({grandparent_tx_1, grandparent_tx_2, dust_non_spend_both_parents}, dustrelay, pool).value_or (null_txid), dust_non_spend_both_parents->GetHash ());
188
+ BOOST_CHECK (!CheckEphemeralSpends ({grandparent_tx_1, grandparent_tx_2, dust_non_spend_both_parents}, dustrelay, pool, child_state, child_txid));
189
+ BOOST_CHECK (!child_state.IsValid ());
190
+ BOOST_CHECK_EQUAL (child_txid, dust_non_spend_both_parents->GetHash ());
191
+ child_state = TxValidationState ();
192
+ child_txid = Txid ();
162
193
163
194
auto dust_spend_both_parents = make_tx ({COutPoint{dust_txid, dust_index}, COutPoint{dust_txid_2, dust_index}}, /* version=*/ 2 );
164
- BOOST_CHECK (!CheckEphemeralSpends ({grandparent_tx_1, grandparent_tx_2, dust_spend_both_parents}, dustrelay, pool));
195
+ BOOST_CHECK (CheckEphemeralSpends ({grandparent_tx_1, grandparent_tx_2, dust_spend_both_parents}, dustrelay, pool, child_state, child_txid));
196
+ BOOST_CHECK (child_state.IsValid ());
197
+ BOOST_CHECK_EQUAL (child_txid, Txid ());
165
198
166
199
// Spending other outputs is also correct, as long as the dusty one is spent
167
200
const std::vector<COutPoint> all_outpoints{COutPoint (dust_txid, 0 ), COutPoint (dust_txid, 1 ), COutPoint (dust_txid, 2 ),
168
201
COutPoint (dust_txid_2, 0 ), COutPoint (dust_txid_2, 1 ), COutPoint (dust_txid_2, 2 )};
169
202
auto dust_spend_all_outpoints = make_tx (all_outpoints, /* version=*/ 2 );
170
- BOOST_CHECK (!CheckEphemeralSpends ({grandparent_tx_1, grandparent_tx_2, dust_spend_all_outpoints}, dustrelay, pool));
203
+ BOOST_CHECK (CheckEphemeralSpends ({grandparent_tx_1, grandparent_tx_2, dust_spend_all_outpoints}, dustrelay, pool, child_state, child_txid));
204
+ BOOST_CHECK (child_state.IsValid ());
205
+ BOOST_CHECK_EQUAL (child_txid, Txid ());
171
206
172
207
// 2 grandparents with dust <- 1 dust-spending parent with dust <- child with no dust
173
208
auto parent_with_dust = make_ephemeral_tx ({COutPoint{dust_txid, dust_index}, COutPoint{dust_txid_2, dust_index}}, /* version=*/ 2 );
174
209
// Ok for parent to have dust
175
- BOOST_CHECK (!CheckEphemeralSpends ({grandparent_tx_1, grandparent_tx_2, parent_with_dust}, dustrelay, pool));
210
+ BOOST_CHECK (CheckEphemeralSpends ({grandparent_tx_1, grandparent_tx_2, parent_with_dust}, dustrelay, pool, child_state, child_txid));
211
+ BOOST_CHECK (child_state.IsValid ());
212
+ BOOST_CHECK_EQUAL (child_txid, Txid ());
176
213
auto child_no_dust = make_tx ({COutPoint{parent_with_dust->GetHash (), dust_index}}, /* version=*/ 2 );
177
- BOOST_CHECK (!CheckEphemeralSpends ({grandparent_tx_1, grandparent_tx_2, parent_with_dust, child_no_dust}, dustrelay, pool));
214
+ BOOST_CHECK (CheckEphemeralSpends ({grandparent_tx_1, grandparent_tx_2, parent_with_dust, child_no_dust}, dustrelay, pool, child_state, child_txid));
215
+ BOOST_CHECK (child_state.IsValid ());
216
+ BOOST_CHECK_EQUAL (child_txid, Txid ());
178
217
179
218
// 2 grandparents with dust <- 1 dust-spending parent with dust <- child with dust
180
219
auto child_with_dust = make_ephemeral_tx ({COutPoint{parent_with_dust->GetHash (), dust_index}}, /* version=*/ 2 );
181
- BOOST_CHECK (!CheckEphemeralSpends ({grandparent_tx_1, grandparent_tx_2, parent_with_dust, child_with_dust}, dustrelay, pool));
220
+ BOOST_CHECK (CheckEphemeralSpends ({grandparent_tx_1, grandparent_tx_2, parent_with_dust, child_with_dust}, dustrelay, pool, child_state, child_txid));
221
+ BOOST_CHECK (child_state.IsValid ());
222
+ BOOST_CHECK_EQUAL (child_txid, Txid ());
182
223
183
224
// Tests with parents in mempool
184
225
185
226
// Nothing in mempool, this should pass for any transaction
186
- BOOST_CHECK (!CheckEphemeralSpends ({grandparent_tx_1}, dustrelay, pool));
227
+ BOOST_CHECK (CheckEphemeralSpends ({grandparent_tx_1}, dustrelay, pool, child_state, child_txid));
228
+ BOOST_CHECK (child_state.IsValid ());
229
+ BOOST_CHECK_EQUAL (child_txid, Txid ());
187
230
188
231
// Add first grandparent to mempool and fetch entry
189
232
pool.addUnchecked (entry.FromTx (grandparent_tx_1));
190
233
191
234
// Ignores ancestors that aren't direct parents
192
- BOOST_CHECK (!CheckEphemeralSpends ({child_no_dust}, dustrelay, pool));
235
+ BOOST_CHECK (CheckEphemeralSpends ({child_no_dust}, dustrelay, pool, child_state, child_txid));
236
+ BOOST_CHECK (child_state.IsValid ());
237
+ BOOST_CHECK_EQUAL (child_txid, Txid ());
193
238
194
239
// Valid spend of dust with grandparent in mempool
195
- BOOST_CHECK (!CheckEphemeralSpends ({parent_with_dust}, dustrelay, pool));
240
+ BOOST_CHECK (CheckEphemeralSpends ({parent_with_dust}, dustrelay, pool, child_state, child_txid));
241
+ BOOST_CHECK (child_state.IsValid ());
242
+ BOOST_CHECK_EQUAL (child_txid, Txid ());
196
243
197
244
// Second grandparent in same package
198
- BOOST_CHECK (!CheckEphemeralSpends ({parent_with_dust, grandparent_tx_2}, dustrelay, pool));
245
+ BOOST_CHECK (CheckEphemeralSpends ({parent_with_dust, grandparent_tx_2}, dustrelay, pool, child_state, child_txid));
246
+ BOOST_CHECK (child_state.IsValid ());
247
+ BOOST_CHECK_EQUAL (child_txid, Txid ());
248
+
199
249
// Order in package doesn't matter
200
- BOOST_CHECK (!CheckEphemeralSpends ({grandparent_tx_2, parent_with_dust}, dustrelay, pool));
250
+ BOOST_CHECK (CheckEphemeralSpends ({grandparent_tx_2, parent_with_dust}, dustrelay, pool, child_state, child_txid));
251
+ BOOST_CHECK (child_state.IsValid ());
252
+ BOOST_CHECK_EQUAL (child_txid, Txid ());
201
253
202
254
// Add second grandparent to mempool
203
255
pool.addUnchecked (entry.FromTx (grandparent_tx_2));
204
256
205
257
// Only spends single dust out of two direct parents
206
- BOOST_CHECK_EQUAL (CheckEphemeralSpends ({dust_non_spend_both_parents}, dustrelay, pool).value_or (null_txid), dust_non_spend_both_parents->GetHash ());
258
+ BOOST_CHECK (!CheckEphemeralSpends ({dust_non_spend_both_parents}, dustrelay, pool, child_state, child_txid));
259
+ BOOST_CHECK (!child_state.IsValid ());
260
+ BOOST_CHECK_EQUAL (child_txid, dust_non_spend_both_parents->GetHash ());
261
+ child_state = TxValidationState ();
262
+ child_txid = Txid ();
207
263
208
264
// Spends both parents' dust
209
- BOOST_CHECK (!CheckEphemeralSpends ({parent_with_dust}, dustrelay, pool));
265
+ BOOST_CHECK (CheckEphemeralSpends ({parent_with_dust}, dustrelay, pool, child_state, child_txid));
266
+ BOOST_CHECK (child_state.IsValid ());
267
+ BOOST_CHECK_EQUAL (child_txid, Txid ());
210
268
211
269
// Now add dusty parent to mempool
212
270
pool.addUnchecked (entry.FromTx (parent_with_dust));
213
271
214
272
// Passes dust checks even with non-parent ancestors
215
- BOOST_CHECK (!CheckEphemeralSpends ({child_no_dust}, dustrelay, pool));
273
+ BOOST_CHECK (CheckEphemeralSpends ({child_no_dust}, dustrelay, pool, child_state, child_txid));
274
+ BOOST_CHECK (child_state.IsValid ());
275
+ BOOST_CHECK_EQUAL (child_txid, Txid ());
216
276
}
217
277
218
278
BOOST_FIXTURE_TEST_CASE (version3_tests, RegTestingSetup)
0 commit comments