1
+ #include < addresstype.h>
1
2
#include < boost/test/unit_test.hpp>
2
3
#include < interfaces/mining.h>
3
4
#include < node/miner.h>
5
+ #include < node/transaction.h>
4
6
#include < sv2/messages.h>
5
7
#include < sv2/template_provider.h>
6
8
#include < test/util/net.h>
7
9
#include < test/util/setup_common.h>
10
+ #include < test/util/transaction_utils.h>
8
11
#include < util/sock.h>
12
+ #include < util/strencodings.h>
9
13
10
14
#include < memory>
11
15
@@ -164,7 +168,47 @@ BOOST_AUTO_TEST_CASE(client_tests)
164
168
// There should now be one template
165
169
BOOST_REQUIRE_EQUAL (tester.GetBlockTemplateCount (), 1 );
166
170
167
- // Get the template id
171
+ // Move mock time
172
+ // If the mempool doesn't change, no new template is generated.
173
+ SetMockTime (GetMockTime () + std::chrono::seconds{10 });
174
+ BOOST_REQUIRE_EQUAL (tester.GetBlockTemplateCount (), 1 );
175
+
176
+ // Create a transaction with a large fee
177
+ size_t tx_size;
178
+ CKey key = GenerateRandomKey ();
179
+ CScript locking_script = GetScriptForDestination (PKHash (key.GetPubKey ()));
180
+ // Don't hold on to the transaction
181
+ {
182
+ LOCK (cs_main);
183
+ BOOST_REQUIRE_EQUAL (m_node.mempool ->size (), 0 );
184
+
185
+ auto mtx = CreateValidMempoolTransaction (/* input_transaction=*/ m_coinbase_txns[0 ], /* input_vout=*/ 0 ,
186
+ /* input_height=*/ 0 , /* input_signing_key=*/ coinbaseKey,
187
+ /* output_destination=*/ locking_script,
188
+ /* output_amount=*/ CAmount (49 * COIN), /* submit=*/ true );
189
+ CTransactionRef tx = MakeTransactionRef (mtx);
190
+
191
+ // Get serialized transaction size
192
+ DataStream ss;
193
+ ss << TX_WITH_WITNESS (tx);
194
+ tx_size = ss.size ();
195
+
196
+ BOOST_REQUIRE_EQUAL (m_node.mempool ->size (), 1 );
197
+ }
198
+
199
+ // Move mock time
200
+ SetMockTime (GetMockTime () + std::chrono::seconds{tester.m_tp_options .fee_check_interval });
201
+
202
+ // Briefly wait for block creation
203
+ UninterruptibleSleep (std::chrono::milliseconds{200 });
204
+
205
+ // Expect our peer to receive a NewTemplate message
206
+ // This time it should contain the 32 byte prevhash (unchanged)
207
+ constexpr size_t expected_len = SV2_HEADER_ENCRYPTED_SIZE + 91 + 32 + Poly1305::TAGLEN;
208
+ BOOST_TEST_MESSAGE (" Receive NewTemplate" );
209
+ BOOST_REQUIRE_EQUAL (tester.PeerReceiveBytes (), expected_len);
210
+
211
+ // Get the latest template id
168
212
uint64_t template_id = 0 ;
169
213
{
170
214
LOCK (tester.m_tp ->m_tp_mutex );
@@ -175,6 +219,10 @@ BOOST_AUTO_TEST_CASE(client_tests)
175
219
}
176
220
}
177
221
222
+ BOOST_REQUIRE_EQUAL (template_id, 2 );
223
+
224
+ UninterruptibleSleep (std::chrono::milliseconds{200 });
225
+
178
226
// Have the peer send us RequestTransactionData
179
227
// We should reply with RequestTransactionData.Success
180
228
node::Sv2NetHeader req_tx_data_header{node::Sv2MsgType::REQUEST_TRANSACTION_DATA, 8 };
@@ -188,15 +236,49 @@ BOOST_AUTO_TEST_CASE(client_tests)
188
236
tester.receiveMessage (msg);
189
237
const size_t template_id_size = 8 ;
190
238
const size_t excess_data_size = 2 + 32 ;
191
- size_t tx_list_size = 2 ; // no transactions, so transaction_list is 0x0100
239
+ size_t tx_list_size = 2 + 3 + tx_size;
240
+ BOOST_TEST_MESSAGE (" Receive RequestTransactionData.Success" );
241
+ BOOST_REQUIRE_EQUAL (tester.PeerReceiveBytes (), SV2_HEADER_ENCRYPTED_SIZE + template_id_size + excess_data_size + tx_list_size + Poly1305::TAGLEN);
242
+ {
243
+ LOCK (cs_main);
244
+
245
+ // RBF the transaction with with > DEFAULT_SV2_FEE_DELTA
246
+ CreateValidMempoolTransaction (/* input_transaction=*/ m_coinbase_txns[0 ], /* input_vout=*/ 0 ,
247
+ /* input_height=*/ 0 , /* input_signing_key=*/ coinbaseKey,
248
+ /* output_destination=*/ locking_script,
249
+ /* output_amount=*/ CAmount (48 * COIN), /* submit=*/ true );
250
+
251
+ BOOST_REQUIRE_EQUAL (m_node.mempool ->size (), 1 );
252
+ }
253
+
254
+ // Move mock time
255
+ SetMockTime (GetMockTime () + std::chrono::seconds{tester.m_tp_options .fee_check_interval });
256
+
257
+ // Briefly wait for the timer in ThreadSv2Handler and block creation
258
+ UninterruptibleSleep (std::chrono::milliseconds{200 });
259
+
260
+ // Wait a bit more for macOS native CI
261
+ UninterruptibleSleep (std::chrono::milliseconds{1000 });
262
+
263
+ // Expect our peer to receive a NewTemplate message
264
+ BOOST_REQUIRE_EQUAL (tester.PeerReceiveBytes (), SV2_HEADER_ENCRYPTED_SIZE + 91 + 32 + Poly1305::TAGLEN);
265
+
266
+ // Check that there's a new template
267
+ BOOST_REQUIRE_EQUAL (tester.GetBlockTemplateCount (), 3 );
268
+
269
+ // Have the peer send us RequestTransactionData for the old template
270
+ // We should reply with RequestTransactionData.Success, and the original
271
+ // (replaced) transaction
272
+ tester.receiveMessage (msg);
273
+ tx_list_size = 2 + 3 + tx_size;
192
274
BOOST_REQUIRE_EQUAL (tester.PeerReceiveBytes (), SV2_HEADER_ENCRYPTED_SIZE + template_id_size + excess_data_size + tx_list_size + Poly1305::TAGLEN);
193
275
194
- // Create a new block
276
+ BOOST_TEST_MESSAGE ( " Create a new block" );
195
277
mineBlocks (1 );
196
278
197
279
// We should send out another NewTemplate and SetNewPrevHash
198
280
// The new template contains the new prevhash.
199
- BOOST_REQUIRE_EQUAL (tester.PeerReceiveBytes (), 2 * SV2_HEADER_ENCRYPTED_SIZE + 91 + 80 + 2 * Poly1305::TAGLEN);
281
+ BOOST_REQUIRE_EQUAL (tester.PeerReceiveBytes (), 2 * SV2_HEADER_ENCRYPTED_SIZE + 91 + 32 + 80 + 2 * Poly1305::TAGLEN);
200
282
// The SetNewPrevHash message is redundant
201
283
// TODO: don't send it?
202
284
// Background: in the future we want to send an empty or optimistic template
@@ -205,7 +287,7 @@ BOOST_AUTO_TEST_CASE(client_tests)
205
287
// a new block, and construct a better template _after_ that.
206
288
207
289
// Templates are briefly preserved
208
- BOOST_REQUIRE_EQUAL (tester.GetBlockTemplateCount (), 2 );
290
+ BOOST_REQUIRE_EQUAL (tester.GetBlockTemplateCount (), 4 );
209
291
210
292
// Do not provide transactions for stale templates
211
293
// TODO
@@ -217,6 +299,9 @@ BOOST_AUTO_TEST_CASE(client_tests)
217
299
SetMockTime (GetMockTime () + std::chrono::seconds{15 });
218
300
UninterruptibleSleep (std::chrono::milliseconds{1100 });
219
301
BOOST_REQUIRE_EQUAL (tester.GetBlockTemplateCount (), 1 );
302
+
303
+ // Mine a block in order to interrupt waitNext()
304
+ mineBlocks (1 );
220
305
}
221
306
222
307
BOOST_AUTO_TEST_SUITE_END ()
0 commit comments