@@ -332,6 +332,8 @@ BOOST_FIXTURE_TEST_CASE(package_submission_tests, TestChain100Setup)
332332// the mempool.
333333BOOST_FIXTURE_TEST_CASE (package_witness_swap_tests, TestChain100Setup)
334334{
335+ // Mine blocks to mature coinbases.
336+ mineBlocks (5 );
335337 LOCK (cs_main);
336338
337339 // 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)
446448 BOOST_CHECK (!m_node.mempool ->exists (GenTxid::Wtxid (ptx_child2->GetWitnessHash ())));
447449 BOOST_CHECK (m_node.mempool ->exists (GenTxid::Wtxid (ptx_grandchild->GetWitnessHash ())));
448450 }
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+ }
449561}
450562BOOST_AUTO_TEST_SUITE_END ()
0 commit comments