@@ -70,6 +70,16 @@ static CTransactionRef MakeTransactionSpending(const std::vector<COutPoint>& out
70
70
return MakeTransactionRef (tx);
71
71
}
72
72
73
+ // Make another (not necessarily valid) tx with the same txid but different wtxid.
74
+ static CTransactionRef MakeMutation (const CTransactionRef& ptx)
75
+ {
76
+ CMutableTransaction tx (*ptx);
77
+ tx.vin [0 ].scriptWitness .stack .push_back ({5 });
78
+ auto mutated_tx = MakeTransactionRef (tx);
79
+ assert (ptx->GetHash () == mutated_tx->GetHash ());
80
+ return mutated_tx;
81
+ }
82
+
73
83
static bool EqualTxns (const std::set<CTransactionRef>& set_txns, const std::vector<CTransactionRef>& vec_txns)
74
84
{
75
85
if (vec_txns.size () != set_txns.size ()) return false ;
@@ -180,6 +190,49 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
180
190
BOOST_CHECK (orphanage.CountOrphans () == 0 );
181
191
}
182
192
193
+ BOOST_AUTO_TEST_CASE (same_txid_diff_witness)
194
+ {
195
+ FastRandomContext det_rand{true };
196
+ TxOrphanage orphanage;
197
+ NodeId peer{0 };
198
+
199
+ std::vector<COutPoint> empty_outpoints;
200
+ auto parent = MakeTransactionSpending (empty_outpoints, det_rand);
201
+
202
+ // Create children to go into orphanage.
203
+ auto child_normal = MakeTransactionSpending ({{parent->GetHash (), 0 }}, det_rand);
204
+ auto child_mutated = MakeMutation (child_normal);
205
+
206
+ const auto & normal_wtxid = child_normal->GetWitnessHash ();
207
+ const auto & mutated_wtxid = child_mutated->GetWitnessHash ();
208
+ BOOST_CHECK (normal_wtxid != mutated_wtxid);
209
+
210
+ BOOST_CHECK (orphanage.AddTx (child_normal, peer));
211
+ // EraseTx fails as transaction by this wtxid doesn't exist.
212
+ BOOST_CHECK_EQUAL (orphanage.EraseTx (mutated_wtxid), 0 );
213
+ BOOST_CHECK (orphanage.HaveTx (normal_wtxid));
214
+ BOOST_CHECK (!orphanage.HaveTx (mutated_wtxid));
215
+
216
+ // Must succeed. Both transactions should be present in orphanage.
217
+ BOOST_CHECK (orphanage.AddTx (child_mutated, peer));
218
+ BOOST_CHECK (orphanage.HaveTx (normal_wtxid));
219
+ BOOST_CHECK (orphanage.HaveTx (mutated_wtxid));
220
+
221
+ // Outpoints map should track all entries: check that both are returned as children of the parent.
222
+ std::set<CTransactionRef> expected_children{child_normal, child_mutated};
223
+ BOOST_CHECK (EqualTxns (expected_children, orphanage.GetChildrenFromSamePeer (parent, peer)));
224
+
225
+ // Erase by wtxid: mutated first
226
+ BOOST_CHECK_EQUAL (orphanage.EraseTx (mutated_wtxid), 1 );
227
+ BOOST_CHECK (orphanage.HaveTx (normal_wtxid));
228
+ BOOST_CHECK (!orphanage.HaveTx (mutated_wtxid));
229
+
230
+ BOOST_CHECK_EQUAL (orphanage.EraseTx (normal_wtxid), 1 );
231
+ BOOST_CHECK (!orphanage.HaveTx (normal_wtxid));
232
+ BOOST_CHECK (!orphanage.HaveTx (mutated_wtxid));
233
+ }
234
+
235
+
183
236
BOOST_AUTO_TEST_CASE (get_children)
184
237
{
185
238
FastRandomContext det_rand{true };
0 commit comments