Branch data Line data Source code
1 : : // Copyright (c) 2021-2022 The Bitcoin Core developers
2 : : // Distributed under the MIT software license, see the accompanying
3 : : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 : : #include <common/system.h>
5 : : #include <policy/rbf.h>
6 : : #include <random.h>
7 : : #include <test/util/txmempool.h>
8 : : #include <txmempool.h>
9 : : #include <util/time.h>
10 : :
11 : : #include <test/util/setup_common.h>
12 : :
13 : : #include <boost/test/unit_test.hpp>
14 : : #include <optional>
15 : : #include <vector>
16 : :
17 : 0 : BOOST_FIXTURE_TEST_SUITE(rbf_tests, TestingSetup)
18 : 0 :
19 : 0 : static inline CTransactionRef make_tx(const std::vector<CTransactionRef>& inputs,
20 : : const std::vector<CAmount>& output_values)
21 : : {
22 : 0 : CMutableTransaction tx = CMutableTransaction();
23 : 0 : tx.vin.resize(inputs.size());
24 : 0 : tx.vout.resize(output_values.size());
25 : 0 : for (size_t i = 0; i < inputs.size(); ++i) {
26 : 0 : tx.vin[i].prevout.hash = inputs[i]->GetHash();
27 : 0 : tx.vin[i].prevout.n = 0;
28 : : // Add a witness so wtxid != txid
29 : 0 : CScriptWitness witness;
30 : 0 : witness.stack.push_back(std::vector<unsigned char>(i + 10));
31 : 0 : tx.vin[i].scriptWitness = witness;
32 : 0 : }
33 : 0 : for (size_t i = 0; i < output_values.size(); ++i) {
34 : 0 : tx.vout[i].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
35 : 0 : tx.vout[i].nValue = output_values[i];
36 : 0 : }
37 : 0 : return MakeTransactionRef(tx);
38 : 0 : }
39 : :
40 : 0 : static void add_descendants(const CTransactionRef& tx, int32_t num_descendants, CTxMemPool& pool)
41 : : EXCLUSIVE_LOCKS_REQUIRED(::cs_main, pool.cs)
42 : : {
43 : 0 : AssertLockHeld(::cs_main);
44 : 0 : AssertLockHeld(pool.cs);
45 : 0 : TestMemPoolEntryHelper entry;
46 : : // Assumes this isn't already spent in mempool
47 : 0 : auto tx_to_spend = tx;
48 : 0 : for (int32_t i{0}; i < num_descendants; ++i) {
49 : 0 : auto next_tx = make_tx(/*inputs=*/{tx_to_spend}, /*output_values=*/{(50 - i) * CENT});
50 : 0 : pool.addUnchecked(entry.FromTx(next_tx));
51 : 0 : tx_to_spend = next_tx;
52 : 0 : }
53 : 0 : }
54 : :
55 : 0 : BOOST_FIXTURE_TEST_CASE(rbf_helper_functions, TestChain100Setup)
56 : : {
57 : 0 : CTxMemPool& pool = *Assert(m_node.mempool);
58 : 0 : LOCK2(::cs_main, pool.cs);
59 : 0 : TestMemPoolEntryHelper entry;
60 : :
61 : 0 : const CAmount low_fee{CENT/100};
62 : 0 : const CAmount normal_fee{CENT/10};
63 : 0 : const CAmount high_fee{CENT};
64 : :
65 : : // Create a parent tx1 and child tx2 with normal fees:
66 : 0 : const auto tx1 = make_tx(/*inputs=*/ {m_coinbase_txns[0]}, /*output_values=*/ {10 * COIN});
67 : 0 : pool.addUnchecked(entry.Fee(normal_fee).FromTx(tx1));
68 : 0 : const auto tx2 = make_tx(/*inputs=*/ {tx1}, /*output_values=*/ {995 * CENT});
69 : 0 : pool.addUnchecked(entry.Fee(normal_fee).FromTx(tx2));
70 : :
71 : : // Create a low-feerate parent tx3 and high-feerate child tx4 (cpfp)
72 : 0 : const auto tx3 = make_tx(/*inputs=*/ {m_coinbase_txns[1]}, /*output_values=*/ {1099 * CENT});
73 : 0 : pool.addUnchecked(entry.Fee(low_fee).FromTx(tx3));
74 : 0 : const auto tx4 = make_tx(/*inputs=*/ {tx3}, /*output_values=*/ {999 * CENT});
75 : 0 : pool.addUnchecked(entry.Fee(high_fee).FromTx(tx4));
76 : :
77 : : // Create a parent tx5 and child tx6 where both have very low fees
78 : 0 : const auto tx5 = make_tx(/*inputs=*/ {m_coinbase_txns[2]}, /*output_values=*/ {1099 * CENT});
79 : 0 : pool.addUnchecked(entry.Fee(low_fee).FromTx(tx5));
80 : 0 : const auto tx6 = make_tx(/*inputs=*/ {tx5}, /*output_values=*/ {1098 * CENT});
81 : 0 : pool.addUnchecked(entry.Fee(low_fee).FromTx(tx6));
82 : : // Make tx6's modified fee much higher than its base fee. This should cause it to pass
83 : : // the fee-related checks despite being low-feerate.
84 : 0 : pool.PrioritiseTransaction(tx6->GetHash(), 1 * COIN);
85 : :
86 : : // Two independent high-feerate transactions, tx7 and tx8
87 : 0 : const auto tx7 = make_tx(/*inputs=*/ {m_coinbase_txns[3]}, /*output_values=*/ {999 * CENT});
88 : 0 : pool.addUnchecked(entry.Fee(high_fee).FromTx(tx7));
89 : 0 : const auto tx8 = make_tx(/*inputs=*/ {m_coinbase_txns[4]}, /*output_values=*/ {999 * CENT});
90 : 0 : pool.addUnchecked(entry.Fee(high_fee).FromTx(tx8));
91 : :
92 : 0 : const auto entry1 = pool.GetIter(tx1->GetHash()).value();
93 : 0 : const auto entry2 = pool.GetIter(tx2->GetHash()).value();
94 : 0 : const auto entry3 = pool.GetIter(tx3->GetHash()).value();
95 : 0 : const auto entry4 = pool.GetIter(tx4->GetHash()).value();
96 : 0 : const auto entry5 = pool.GetIter(tx5->GetHash()).value();
97 : 0 : const auto entry6 = pool.GetIter(tx6->GetHash()).value();
98 : 0 : const auto entry7 = pool.GetIter(tx7->GetHash()).value();
99 : 0 : const auto entry8 = pool.GetIter(tx8->GetHash()).value();
100 : :
101 : 0 : BOOST_CHECK_EQUAL(entry1->GetFee(), normal_fee);
102 : 0 : BOOST_CHECK_EQUAL(entry2->GetFee(), normal_fee);
103 : 0 : BOOST_CHECK_EQUAL(entry3->GetFee(), low_fee);
104 : 0 : BOOST_CHECK_EQUAL(entry4->GetFee(), high_fee);
105 : 0 : BOOST_CHECK_EQUAL(entry5->GetFee(), low_fee);
106 : 0 : BOOST_CHECK_EQUAL(entry6->GetFee(), low_fee);
107 : 0 : BOOST_CHECK_EQUAL(entry7->GetFee(), high_fee);
108 : 0 : BOOST_CHECK_EQUAL(entry8->GetFee(), high_fee);
109 : :
110 : 0 : CTxMemPool::setEntries set_12_normal{entry1, entry2};
111 : 0 : CTxMemPool::setEntries set_34_cpfp{entry3, entry4};
112 : 0 : CTxMemPool::setEntries set_56_low{entry5, entry6};
113 : 0 : CTxMemPool::setEntries all_entries{entry1, entry2, entry3, entry4, entry5, entry6, entry7, entry8};
114 : 0 : CTxMemPool::setEntries empty_set;
115 : :
116 : 0 : const auto unused_txid{GetRandHash()};
117 : :
118 : : // Tests for PaysMoreThanConflicts
119 : : // These tests use feerate, not absolute fee.
120 : 0 : BOOST_CHECK(PaysMoreThanConflicts(/*iters_conflicting=*/set_12_normal,
121 : : /*replacement_feerate=*/CFeeRate(entry1->GetModifiedFee() + 1, entry1->GetTxSize() + 2),
122 : : /*txid=*/unused_txid).has_value());
123 : : // Replacement must be strictly greater than the originals.
124 : 0 : BOOST_CHECK(PaysMoreThanConflicts(set_12_normal, CFeeRate(entry1->GetModifiedFee(), entry1->GetTxSize()), unused_txid).has_value());
125 : 0 : BOOST_CHECK(PaysMoreThanConflicts(set_12_normal, CFeeRate(entry1->GetModifiedFee() + 1, entry1->GetTxSize()), unused_txid) == std::nullopt);
126 : : // These tests use modified fees (including prioritisation), not base fees.
127 : 0 : BOOST_CHECK(PaysMoreThanConflicts({entry5}, CFeeRate(entry5->GetModifiedFee() + 1, entry5->GetTxSize()), unused_txid) == std::nullopt);
128 : 0 : BOOST_CHECK(PaysMoreThanConflicts({entry6}, CFeeRate(entry6->GetFee() + 1, entry6->GetTxSize()), unused_txid).has_value());
129 : 0 : BOOST_CHECK(PaysMoreThanConflicts({entry6}, CFeeRate(entry6->GetModifiedFee() + 1, entry6->GetTxSize()), unused_txid) == std::nullopt);
130 : : // PaysMoreThanConflicts checks individual feerate, not ancestor feerate. This test compares
131 : : // replacement_feerate and entry4's feerate, which are the same. The replacement_feerate is
132 : : // considered too low even though entry4 has a low ancestor feerate.
133 : 0 : BOOST_CHECK(PaysMoreThanConflicts(set_34_cpfp, CFeeRate(entry4->GetModifiedFee(), entry4->GetTxSize()), unused_txid).has_value());
134 : :
135 : : // Tests for EntriesAndTxidsDisjoint
136 : 0 : BOOST_CHECK(EntriesAndTxidsDisjoint(empty_set, {tx1->GetHash()}, unused_txid) == std::nullopt);
137 : 0 : BOOST_CHECK(EntriesAndTxidsDisjoint(set_12_normal, {tx3->GetHash()}, unused_txid) == std::nullopt);
138 : : // EntriesAndTxidsDisjoint uses txids, not wtxids.
139 : 0 : BOOST_CHECK(EntriesAndTxidsDisjoint({entry2}, {tx2->GetWitnessHash()}, unused_txid) == std::nullopt);
140 : 0 : BOOST_CHECK(EntriesAndTxidsDisjoint({entry2}, {tx2->GetHash()}, unused_txid).has_value());
141 : 0 : BOOST_CHECK(EntriesAndTxidsDisjoint(set_12_normal, {tx1->GetHash()}, unused_txid).has_value());
142 : 0 : BOOST_CHECK(EntriesAndTxidsDisjoint(set_12_normal, {tx2->GetHash()}, unused_txid).has_value());
143 : : // EntriesAndTxidsDisjoint does not calculate descendants of iters_conflicting; it uses whatever
144 : : // the caller passed in. As such, no error is returned even though entry2 is a descendant of tx1.
145 : 0 : BOOST_CHECK(EntriesAndTxidsDisjoint({entry2}, {tx1->GetHash()}, unused_txid) == std::nullopt);
146 : :
147 : : // Tests for PaysForRBF
148 : 0 : const CFeeRate incremental_relay_feerate{DEFAULT_INCREMENTAL_RELAY_FEE};
149 : 0 : const CFeeRate higher_relay_feerate{2 * DEFAULT_INCREMENTAL_RELAY_FEE};
150 : : // Must pay at least as much as the original.
151 : 0 : BOOST_CHECK(PaysForRBF(/*original_fees=*/high_fee,
152 : : /*replacement_fees=*/high_fee,
153 : : /*replacement_vsize=*/1,
154 : : /*relay_fee=*/CFeeRate(0),
155 : : /*txid=*/unused_txid)
156 : : == std::nullopt);
157 : 0 : BOOST_CHECK(PaysForRBF(high_fee, high_fee - 1, 1, CFeeRate(0), unused_txid).has_value());
158 : 0 : BOOST_CHECK(PaysForRBF(high_fee + 1, high_fee, 1, CFeeRate(0), unused_txid).has_value());
159 : : // Additional fees must cover the replacement's vsize at incremental relay fee
160 : 0 : BOOST_CHECK(PaysForRBF(high_fee, high_fee + 1, 2, incremental_relay_feerate, unused_txid).has_value());
161 : 0 : BOOST_CHECK(PaysForRBF(high_fee, high_fee + 2, 2, incremental_relay_feerate, unused_txid) == std::nullopt);
162 : 0 : BOOST_CHECK(PaysForRBF(high_fee, high_fee + 2, 2, higher_relay_feerate, unused_txid).has_value());
163 : 0 : BOOST_CHECK(PaysForRBF(high_fee, high_fee + 4, 2, higher_relay_feerate, unused_txid) == std::nullopt);
164 : 0 : BOOST_CHECK(PaysForRBF(low_fee, high_fee, 99999999, incremental_relay_feerate, unused_txid).has_value());
165 : 0 : BOOST_CHECK(PaysForRBF(low_fee, high_fee + 99999999, 99999999, incremental_relay_feerate, unused_txid) == std::nullopt);
166 : :
167 : : // Tests for GetEntriesForConflicts
168 : 0 : CTxMemPool::setEntries all_parents{entry1, entry3, entry5, entry7, entry8};
169 : 0 : CTxMemPool::setEntries all_children{entry2, entry4, entry6};
170 : 0 : const std::vector<CTransactionRef> parent_inputs({m_coinbase_txns[0], m_coinbase_txns[1], m_coinbase_txns[2],
171 : 0 : m_coinbase_txns[3], m_coinbase_txns[4]});
172 : 0 : const auto conflicts_with_parents = make_tx(parent_inputs, {50 * CENT});
173 : 0 : CTxMemPool::setEntries all_conflicts;
174 : 0 : BOOST_CHECK(GetEntriesForConflicts(/*tx=*/ *conflicts_with_parents.get(),
175 : : /*pool=*/ pool,
176 : : /*iters_conflicting=*/ all_parents,
177 : : /*all_conflicts=*/ all_conflicts) == std::nullopt);
178 : 0 : BOOST_CHECK(all_conflicts == all_entries);
179 : 0 : auto conflicts_size = all_conflicts.size();
180 : 0 : all_conflicts.clear();
181 : :
182 : 0 : add_descendants(tx2, 23, pool);
183 : 0 : BOOST_CHECK(GetEntriesForConflicts(*conflicts_with_parents.get(), pool, all_parents, all_conflicts) == std::nullopt);
184 : 0 : conflicts_size += 23;
185 : 0 : BOOST_CHECK_EQUAL(all_conflicts.size(), conflicts_size);
186 : 0 : all_conflicts.clear();
187 : :
188 : 0 : add_descendants(tx4, 23, pool);
189 : 0 : BOOST_CHECK(GetEntriesForConflicts(*conflicts_with_parents.get(), pool, all_parents, all_conflicts) == std::nullopt);
190 : 0 : conflicts_size += 23;
191 : 0 : BOOST_CHECK_EQUAL(all_conflicts.size(), conflicts_size);
192 : 0 : all_conflicts.clear();
193 : :
194 : 0 : add_descendants(tx6, 23, pool);
195 : 0 : BOOST_CHECK(GetEntriesForConflicts(*conflicts_with_parents.get(), pool, all_parents, all_conflicts) == std::nullopt);
196 : 0 : conflicts_size += 23;
197 : 0 : BOOST_CHECK_EQUAL(all_conflicts.size(), conflicts_size);
198 : 0 : all_conflicts.clear();
199 : :
200 : 0 : add_descendants(tx7, 23, pool);
201 : 0 : BOOST_CHECK(GetEntriesForConflicts(*conflicts_with_parents.get(), pool, all_parents, all_conflicts) == std::nullopt);
202 : 0 : conflicts_size += 23;
203 : 0 : BOOST_CHECK_EQUAL(all_conflicts.size(), conflicts_size);
204 : 0 : BOOST_CHECK_EQUAL(all_conflicts.size(), 100);
205 : 0 : all_conflicts.clear();
206 : :
207 : : // Exceeds maximum number of conflicts.
208 : 0 : add_descendants(tx8, 1, pool);
209 : 0 : BOOST_CHECK(GetEntriesForConflicts(*conflicts_with_parents.get(), pool, all_parents, all_conflicts).has_value());
210 : :
211 : : // Tests for HasNoNewUnconfirmed
212 : 0 : const auto spends_unconfirmed = make_tx({tx1}, {36 * CENT});
213 : 0 : for (const auto& input : spends_unconfirmed->vin) {
214 : : // Spends unconfirmed inputs.
215 : 0 : BOOST_CHECK(pool.exists(GenTxid::Txid(input.prevout.hash)));
216 : : }
217 : 0 : BOOST_CHECK(HasNoNewUnconfirmed(/*tx=*/ *spends_unconfirmed.get(),
218 : : /*pool=*/ pool,
219 : : /*iters_conflicting=*/ all_entries) == std::nullopt);
220 : 0 : BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, {entry2}) == std::nullopt);
221 : 0 : BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, empty_set).has_value());
222 : :
223 : 0 : const auto spends_new_unconfirmed = make_tx({tx1, tx8}, {36 * CENT});
224 : 0 : BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, {entry2}).has_value());
225 : 0 : BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, all_entries).has_value());
226 : :
227 : 0 : const auto spends_conflicting_confirmed = make_tx({m_coinbase_txns[0], m_coinbase_txns[1]}, {45 * CENT});
228 : 0 : BOOST_CHECK(HasNoNewUnconfirmed(*spends_conflicting_confirmed.get(), pool, {entry1, entry3}) == std::nullopt);
229 : 0 : }
230 : :
231 : 0 : BOOST_AUTO_TEST_SUITE_END()
|