Skip to content

Commit a80d809

Browse files
committed
unit test: add CheckConflictTopology case for not the only child
1 parent 69bd18c commit a80d809

File tree

1 file changed

+58
-0
lines changed

1 file changed

+58
-0
lines changed

src/test/rbf_tests.cpp

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,37 @@ static inline CTransactionRef make_tx(const std::vector<CTransactionRef>& inputs
3737
return MakeTransactionRef(tx);
3838
}
3939

40+
// Make two child transactions from parent (which must have at least 2 outputs).
41+
// Each tx will have the same outputs, using the amounts specified in output_values.
42+
static inline std::pair<CTransactionRef, CTransactionRef> make_two_siblings(const CTransactionRef parent,
43+
const std::vector<CAmount>& output_values)
44+
{
45+
assert(parent->vout.size() >= 2);
46+
47+
// First tx takes first parent output
48+
CMutableTransaction tx1 = CMutableTransaction();
49+
tx1.vin.resize(1);
50+
tx1.vout.resize(output_values.size());
51+
52+
tx1.vin[0].prevout.hash = parent->GetHash();
53+
tx1.vin[0].prevout.n = 0;
54+
// Add a witness so wtxid != txid
55+
CScriptWitness witness;
56+
witness.stack.emplace_back(10);
57+
tx1.vin[0].scriptWitness = witness;
58+
59+
for (size_t i = 0; i < output_values.size(); ++i) {
60+
tx1.vout[i].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
61+
tx1.vout[i].nValue = output_values[i];
62+
}
63+
64+
// Second tx takes second parent output
65+
CMutableTransaction tx2 = tx1;
66+
tx2.vin[0].prevout.n = 1;
67+
68+
return std::make_pair(MakeTransactionRef(tx1), MakeTransactionRef(tx2));
69+
}
70+
4071
static CTransactionRef add_descendants(const CTransactionRef& tx, int32_t num_descendants, CTxMemPool& pool)
4172
EXCLUSIVE_LOCKS_REQUIRED(::cs_main, pool.cs)
4273
{
@@ -67,6 +98,20 @@ static CTransactionRef add_descendant_to_parents(const std::vector<CTransactionR
6798
return child_tx;
6899
}
69100

101+
// Makes two children for a single parent
102+
static std::pair<CTransactionRef, CTransactionRef> add_children_to_parent(const CTransactionRef parent, CTxMemPool& pool)
103+
EXCLUSIVE_LOCKS_REQUIRED(::cs_main, pool.cs)
104+
{
105+
AssertLockHeld(::cs_main);
106+
AssertLockHeld(pool.cs);
107+
TestMemPoolEntryHelper entry;
108+
// Assumes this isn't already spent in mempool
109+
auto children_tx = make_two_siblings(/*parent=*/parent, /*output_values=*/{50 * CENT});
110+
pool.addUnchecked(entry.FromTx(children_tx.first));
111+
pool.addUnchecked(entry.FromTx(children_tx.second));
112+
return children_tx;
113+
}
114+
70115
BOOST_FIXTURE_TEST_CASE(rbf_helper_functions, TestChain100Setup)
71116
{
72117
CTxMemPool& pool = *Assert(m_node.mempool);
@@ -116,6 +161,10 @@ BOOST_FIXTURE_TEST_CASE(rbf_helper_functions, TestChain100Setup)
116161
const auto tx12 = make_tx(/*inputs=*/ {m_coinbase_txns[8]}, /*output_values=*/ {995 * CENT});
117162
pool.addUnchecked(entry.Fee(normal_fee).FromTx(tx12));
118163

164+
// Will make two children of this single parent
165+
const auto tx13 = make_tx(/*inputs=*/ {m_coinbase_txns[9]}, /*output_values=*/ {995 * CENT, 995 * CENT});
166+
pool.addUnchecked(entry.Fee(normal_fee).FromTx(tx13));
167+
119168
const auto entry1_normal = pool.GetIter(tx1->GetHash()).value();
120169
const auto entry2_normal = pool.GetIter(tx2->GetHash()).value();
121170
const auto entry3_low = pool.GetIter(tx3->GetHash()).value();
@@ -128,6 +177,7 @@ BOOST_FIXTURE_TEST_CASE(rbf_helper_functions, TestChain100Setup)
128177
const auto entry10_unchained = pool.GetIter(tx10->GetHash()).value();
129178
const auto entry11_unchained = pool.GetIter(tx11->GetHash()).value();
130179
const auto entry12_unchained = pool.GetIter(tx12->GetHash()).value();
180+
const auto entry13_unchained = pool.GetIter(tx13->GetHash()).value();
131181

132182
BOOST_CHECK_EQUAL(entry1_normal->GetFee(), normal_fee);
133183
BOOST_CHECK_EQUAL(entry2_normal->GetFee(), normal_fee);
@@ -292,6 +342,14 @@ BOOST_FIXTURE_TEST_CASE(rbf_helper_functions, TestChain100Setup)
292342
BOOST_CHECK_EQUAL(pool.CheckConflictTopology({entry11_unchained}).value(), strprintf("%s is not the only parent of child %s", entry11_unchained->GetSharedTx()->GetHash().ToString(), entry_two_parent_child->GetSharedTx()->GetHash().ToString()));
293343
BOOST_CHECK_EQUAL(pool.CheckConflictTopology({entry12_unchained}).value(), strprintf("%s is not the only parent of child %s", entry12_unchained->GetSharedTx()->GetHash().ToString(), entry_two_parent_child->GetSharedTx()->GetHash().ToString()));
294344
BOOST_CHECK_EQUAL(pool.CheckConflictTopology({entry_two_parent_child}).value(), strprintf("%s has 2 ancestors, max 1 allowed", entry_two_parent_child->GetSharedTx()->GetHash().ToString()));
345+
346+
// Single parent with two children, we will conflict with the siblings directly only
347+
const auto two_siblings = add_children_to_parent(tx13, pool);
348+
const auto entry_sibling_1 = pool.GetIter(two_siblings.first->GetHash()).value();
349+
const auto entry_sibling_2 = pool.GetIter(two_siblings.second->GetHash()).value();
350+
BOOST_CHECK_EQUAL(pool.CheckConflictTopology({entry_sibling_1}).value(), strprintf("%s is not the only child of parent %s", entry_sibling_1->GetSharedTx()->GetHash().ToString(), entry13_unchained->GetSharedTx()->GetHash().ToString()));
351+
BOOST_CHECK_EQUAL(pool.CheckConflictTopology({entry_sibling_2}).value(), strprintf("%s is not the only child of parent %s", entry_sibling_2->GetSharedTx()->GetHash().ToString(), entry13_unchained->GetSharedTx()->GetHash().ToString()));
352+
295353
}
296354

297355
BOOST_FIXTURE_TEST_CASE(improves_feerate, TestChain100Setup)

0 commit comments

Comments
 (0)