@@ -332,6 +332,8 @@ BOOST_FIXTURE_TEST_CASE(package_submission_tests, TestChain100Setup)
332
332
// the mempool.
333
333
BOOST_FIXTURE_TEST_CASE (package_witness_swap_tests, TestChain100Setup)
334
334
{
335
+ // Mine blocks to mature coinbases.
336
+ mineBlocks (5 );
335
337
LOCK (cs_main);
336
338
337
339
// Transactions with a same-txid-different-witness transaction in the mempool should be ignored,
@@ -446,5 +448,115 @@ BOOST_FIXTURE_TEST_CASE(package_witness_swap_tests, TestChain100Setup)
446
448
BOOST_CHECK (!m_node.mempool ->exists (GenTxid::Wtxid (ptx_child2->GetWitnessHash ())));
447
449
BOOST_CHECK (m_node.mempool ->exists (GenTxid::Wtxid (ptx_grandchild->GetWitnessHash ())));
448
450
}
451
+
452
+ // A package Package{parent1, parent2, parent3, child} where the parents are a mixture of
453
+ // identical-tx-in-mempool, same-txid-different-witness-in-mempool, and new transactions.
454
+ Package package_mixed;
455
+
456
+ // Give all the parents anyone-can-spend scripts so we don't have to deal with signing the child.
457
+ CScript acs_script = CScript () << OP_TRUE;
458
+ CScript acs_spk = GetScriptForDestination (WitnessV0ScriptHash (acs_script));
459
+ CScriptWitness acs_witness;
460
+ acs_witness.stack .push_back (std::vector<unsigned char >(acs_script.begin (), acs_script.end ()));
461
+
462
+ // parent1 will already be in the mempool
463
+ auto mtx_parent1 = CreateValidMempoolTransaction (/* input_transaction=*/ m_coinbase_txns[1 ], /* vout=*/ 0 ,
464
+ /* input_height=*/ 0 , /* input_signing_key=*/ coinbaseKey,
465
+ /* output_destination=*/ acs_spk,
466
+ /* output_amount=*/ CAmount (49 * COIN), /* submit=*/ true );
467
+ CTransactionRef ptx_parent1 = MakeTransactionRef (mtx_parent1);
468
+ package_mixed.push_back (ptx_parent1);
469
+
470
+ // parent2 will have a same-txid-different-witness tx already in the mempool
471
+ CScript grandparent2_script = CScript () << OP_DROP << OP_TRUE;
472
+ CScript grandparent2_spk = GetScriptForDestination (WitnessV0ScriptHash (grandparent2_script));
473
+ CScriptWitness parent2_witness1;
474
+ parent2_witness1.stack .push_back (std::vector<unsigned char >(1 ));
475
+ parent2_witness1.stack .push_back (std::vector<unsigned char >(grandparent2_script.begin (), grandparent2_script.end ()));
476
+ CScriptWitness parent2_witness2;
477
+ parent2_witness2.stack .push_back (std::vector<unsigned char >(2 ));
478
+ parent2_witness2.stack .push_back (std::vector<unsigned char >(grandparent2_script.begin (), grandparent2_script.end ()));
479
+
480
+ // Create grandparent2 creating an output with multiple spending paths. Submit to mempool.
481
+ auto mtx_grandparent2 = CreateValidMempoolTransaction (/* input_transaction=*/ m_coinbase_txns[2 ], /* vout=*/ 0 ,
482
+ /* input_height=*/ 0 , /* input_signing_key=*/ coinbaseKey,
483
+ /* output_destination=*/ grandparent2_spk,
484
+ /* output_amount=*/ CAmount (49 * COIN), /* submit=*/ true );
485
+ CTransactionRef ptx_grandparent2 = MakeTransactionRef (mtx_grandparent2);
486
+
487
+ CMutableTransaction mtx_parent2_v1;
488
+ mtx_parent2_v1.nVersion = 1 ;
489
+ mtx_parent2_v1.vin .resize (1 );
490
+ mtx_parent2_v1.vin [0 ].prevout .hash = ptx_grandparent2->GetHash ();
491
+ mtx_parent2_v1.vin [0 ].prevout .n = 0 ;
492
+ mtx_parent2_v1.vin [0 ].scriptSig = CScript ();
493
+ mtx_parent2_v1.vin [0 ].scriptWitness = parent2_witness1;
494
+ mtx_parent2_v1.vout .resize (1 );
495
+ mtx_parent2_v1.vout [0 ].nValue = CAmount (48 * COIN);
496
+ mtx_parent2_v1.vout [0 ].scriptPubKey = acs_spk;
497
+
498
+ CMutableTransaction mtx_parent2_v2{mtx_parent2_v1};
499
+ mtx_parent2_v2.vin [0 ].scriptWitness = parent2_witness2;
500
+
501
+ CTransactionRef ptx_parent2_v1 = MakeTransactionRef (mtx_parent2_v1);
502
+ CTransactionRef ptx_parent2_v2 = MakeTransactionRef (mtx_parent2_v2);
503
+ // Put parent2_v1 in the package, submit parent2_v2 to the mempool.
504
+ const MempoolAcceptResult parent2_v2_result = m_node.chainman ->ProcessTransaction (ptx_parent2_v2);
505
+ BOOST_CHECK (parent2_v2_result.m_result_type == MempoolAcceptResult::ResultType::VALID);
506
+ package_mixed.push_back (ptx_parent2_v1);
507
+
508
+ // parent3 will be a new transaction
509
+ auto mtx_parent3 = CreateValidMempoolTransaction (/* input_transaction=*/ m_coinbase_txns[3 ], /* vout=*/ 0 ,
510
+ /* input_height=*/ 0 , /* input_signing_key=*/ coinbaseKey,
511
+ /* output_destination=*/ acs_spk,
512
+ /* output_amount=*/ CAmount (49 * COIN), /* submit=*/ false );
513
+ CTransactionRef ptx_parent3 = MakeTransactionRef (mtx_parent3);
514
+ package_mixed.push_back (ptx_parent3);
515
+
516
+ // child spends parent1, parent2, and parent3
517
+ CKey mixed_grandchild_key;
518
+ mixed_grandchild_key.MakeNewKey (true );
519
+ CScript mixed_child_spk = GetScriptForDestination (WitnessV0KeyHash (mixed_grandchild_key.GetPubKey ()));
520
+
521
+ CMutableTransaction mtx_mixed_child;
522
+ mtx_mixed_child.vin .push_back (CTxIn (COutPoint (ptx_parent1->GetHash (), 0 )));
523
+ mtx_mixed_child.vin .push_back (CTxIn (COutPoint (ptx_parent2_v1->GetHash (), 0 )));
524
+ mtx_mixed_child.vin .push_back (CTxIn (COutPoint (ptx_parent3->GetHash (), 0 )));
525
+ mtx_mixed_child.vin [0 ].scriptWitness = acs_witness;
526
+ mtx_mixed_child.vin [1 ].scriptWitness = acs_witness;
527
+ mtx_mixed_child.vin [2 ].scriptWitness = acs_witness;
528
+ mtx_mixed_child.vout .push_back (CTxOut (145 * COIN, mixed_child_spk));
529
+ CTransactionRef ptx_mixed_child = MakeTransactionRef (mtx_mixed_child);
530
+ package_mixed.push_back (ptx_mixed_child);
531
+
532
+ // Submit package:
533
+ // parent1 should be ignored
534
+ // parent2_v1 should be ignored (and v2 wtxid returned)
535
+ // parent3 should be accepted
536
+ // child should be accepted
537
+ {
538
+ const auto mixed_result = ProcessNewPackage (m_node.chainman ->ActiveChainstate (), *m_node.mempool , package_mixed, false );
539
+ BOOST_CHECK_MESSAGE (mixed_result.m_state .IsValid (), mixed_result.m_state .GetRejectReason ());
540
+ auto it_parent1 = mixed_result.m_tx_results .find (ptx_parent1->GetWitnessHash ());
541
+ auto it_parent2 = mixed_result.m_tx_results .find (ptx_parent2_v1->GetWitnessHash ());
542
+ auto it_parent3 = mixed_result.m_tx_results .find (ptx_parent3->GetWitnessHash ());
543
+ auto it_child = mixed_result.m_tx_results .find (ptx_mixed_child->GetWitnessHash ());
544
+ BOOST_CHECK (it_parent1 != mixed_result.m_tx_results .end ());
545
+ BOOST_CHECK (it_parent2 != mixed_result.m_tx_results .end ());
546
+ BOOST_CHECK (it_parent3 != mixed_result.m_tx_results .end ());
547
+ BOOST_CHECK (it_child != mixed_result.m_tx_results .end ());
548
+
549
+ BOOST_CHECK (it_parent1->second .m_result_type == MempoolAcceptResult::ResultType::MEMPOOL_ENTRY);
550
+ BOOST_CHECK (it_parent2->second .m_result_type == MempoolAcceptResult::ResultType::DIFFERENT_WITNESS);
551
+ BOOST_CHECK (it_parent3->second .m_result_type == MempoolAcceptResult::ResultType::VALID);
552
+ BOOST_CHECK (it_child->second .m_result_type == MempoolAcceptResult::ResultType::VALID);
553
+ BOOST_CHECK_EQUAL (ptx_parent2_v2->GetWitnessHash (), it_parent2->second .m_other_wtxid .value ());
554
+
555
+ BOOST_CHECK (m_node.mempool ->exists (GenTxid::Txid (ptx_parent1->GetHash ())));
556
+ BOOST_CHECK (m_node.mempool ->exists (GenTxid::Txid (ptx_parent2_v1->GetHash ())));
557
+ BOOST_CHECK (!m_node.mempool ->exists (GenTxid::Wtxid (ptx_parent2_v1->GetWitnessHash ())));
558
+ BOOST_CHECK (m_node.mempool ->exists (GenTxid::Txid (ptx_parent3->GetHash ())));
559
+ BOOST_CHECK (m_node.mempool ->exists (GenTxid::Txid (ptx_mixed_child->GetHash ())));
560
+ }
449
561
}
450
562
BOOST_AUTO_TEST_SUITE_END ()
0 commit comments