1414
1515#include < boost/test/unit_test.hpp>
1616
17- std::vector<CTransactionRef> extra_txn ;
17+ const std::vector<CTransactionRef> empty_extra_txn ;
1818
1919BOOST_FIXTURE_TEST_SUITE (blockencodings_tests, RegTestingSetup)
2020
21- static CBlock BuildBlockTestCase() {
22- CBlock block;
21+ static CMutableTransaction BuildTransactionTestCase() {
2322 CMutableTransaction tx;
2423 tx.vin .resize (1 );
2524 tx.vin [0 ].scriptSig .resize (10 );
2625 tx.vout .resize (1 );
2726 tx.vout [0 ].nValue = 42 ;
27+ return tx;
28+ }
29+
30+ static CBlock BuildBlockTestCase (FastRandomContext& ctx) {
31+ CBlock block;
32+ CMutableTransaction tx = BuildTransactionTestCase ();
2833
2934 block.vtx .resize (3 );
3035 block.vtx [0 ] = MakeTransactionRef (tx);
3136 block.nVersion = 42 ;
32- block.hashPrevBlock = InsecureRand256 ();
37+ block.hashPrevBlock = ctx. rand256 ();
3338 block.nBits = 0x207fffff ;
3439
35- tx.vin [0 ].prevout .hash = Txid::FromUint256 (InsecureRand256 ());
40+ tx.vin [0 ].prevout .hash = Txid::FromUint256 (ctx. rand256 ());
3641 tx.vin [0 ].prevout .n = 0 ;
3742 block.vtx [1 ] = MakeTransactionRef (tx);
3843
3944 tx.vin .resize (10 );
4045 for (size_t i = 0 ; i < tx.vin .size (); i++) {
41- tx.vin [i].prevout .hash = Txid::FromUint256 (InsecureRand256 ());
46+ tx.vin [i].prevout .hash = Txid::FromUint256 (ctx. rand256 ());
4247 tx.vin [i].prevout .n = 0 ;
4348 }
4449 block.vtx [2 ] = MakeTransactionRef (tx);
@@ -58,15 +63,16 @@ BOOST_AUTO_TEST_CASE(SimpleRoundTripTest)
5863{
5964 CTxMemPool& pool = *Assert (m_node.mempool );
6065 TestMemPoolEntryHelper entry;
61- CBlock block (BuildBlockTestCase ());
66+ auto rand_ctx (FastRandomContext (uint256{42 }));
67+ CBlock block (BuildBlockTestCase (rand_ctx));
6268
6369 LOCK2 (cs_main, pool.cs );
6470 pool.addUnchecked (entry.FromTx (block.vtx [2 ]));
6571 BOOST_CHECK_EQUAL (pool.get (block.vtx [2 ]->GetHash ()).use_count (), SHARED_TX_OFFSET + 0 );
6672
6773 // Do a simple ShortTxIDs RT
6874 {
69- CBlockHeaderAndShortTxIDs shortIDs{block};
75+ CBlockHeaderAndShortTxIDs shortIDs{block, rand_ctx. rand64 () };
7076
7177 DataStream stream{};
7278 stream << shortIDs;
@@ -75,7 +81,7 @@ BOOST_AUTO_TEST_CASE(SimpleRoundTripTest)
7581 stream >> shortIDs2;
7682
7783 PartiallyDownloadedBlock partialBlock (&pool);
78- BOOST_CHECK (partialBlock.InitData (shortIDs2, extra_txn ) == READ_STATUS_OK);
84+ BOOST_CHECK (partialBlock.InitData (shortIDs2, empty_extra_txn ) == READ_STATUS_OK);
7985 BOOST_CHECK ( partialBlock.IsTxAvailable (0 ));
8086 BOOST_CHECK (!partialBlock.IsTxAvailable (1 ));
8187 BOOST_CHECK ( partialBlock.IsTxAvailable (2 ));
@@ -123,8 +129,8 @@ class TestHeaderAndShortIDs {
123129 stream << orig;
124130 stream >> *this ;
125131 }
126- explicit TestHeaderAndShortIDs (const CBlock& block) :
127- TestHeaderAndShortIDs(CBlockHeaderAndShortTxIDs{block}) {}
132+ explicit TestHeaderAndShortIDs (const CBlock& block, FastRandomContext& ctx ) :
133+ TestHeaderAndShortIDs(CBlockHeaderAndShortTxIDs{block, ctx. rand64 () }) {}
128134
129135 uint64_t GetShortID (const Wtxid& txhash) const {
130136 DataStream stream{};
@@ -141,7 +147,8 @@ BOOST_AUTO_TEST_CASE(NonCoinbasePreforwardRTTest)
141147{
142148 CTxMemPool& pool = *Assert (m_node.mempool );
143149 TestMemPoolEntryHelper entry;
144- CBlock block (BuildBlockTestCase ());
150+ auto rand_ctx (FastRandomContext (uint256{42 }));
151+ CBlock block (BuildBlockTestCase (rand_ctx));
145152
146153 LOCK2 (cs_main, pool.cs );
147154 pool.addUnchecked (entry.FromTx (block.vtx [2 ]));
@@ -151,7 +158,7 @@ BOOST_AUTO_TEST_CASE(NonCoinbasePreforwardRTTest)
151158
152159 // Test with pre-forwarding tx 1, but not coinbase
153160 {
154- TestHeaderAndShortIDs shortIDs (block);
161+ TestHeaderAndShortIDs shortIDs (block, rand_ctx );
155162 shortIDs.prefilledtxn .resize (1 );
156163 shortIDs.prefilledtxn [0 ] = {1 , block.vtx [1 ]};
157164 shortIDs.shorttxids .resize (2 );
@@ -165,7 +172,7 @@ BOOST_AUTO_TEST_CASE(NonCoinbasePreforwardRTTest)
165172 stream >> shortIDs2;
166173
167174 PartiallyDownloadedBlock partialBlock (&pool);
168- BOOST_CHECK (partialBlock.InitData (shortIDs2, extra_txn ) == READ_STATUS_OK);
175+ BOOST_CHECK (partialBlock.InitData (shortIDs2, empty_extra_txn ) == READ_STATUS_OK);
169176 BOOST_CHECK (!partialBlock.IsTxAvailable (0 ));
170177 BOOST_CHECK ( partialBlock.IsTxAvailable (1 ));
171178 BOOST_CHECK ( partialBlock.IsTxAvailable (2 ));
@@ -211,7 +218,8 @@ BOOST_AUTO_TEST_CASE(SufficientPreforwardRTTest)
211218{
212219 CTxMemPool& pool = *Assert (m_node.mempool );
213220 TestMemPoolEntryHelper entry;
214- CBlock block (BuildBlockTestCase ());
221+ auto rand_ctx (FastRandomContext (uint256{42 }));
222+ CBlock block (BuildBlockTestCase (rand_ctx));
215223
216224 LOCK2 (cs_main, pool.cs );
217225 pool.addUnchecked (entry.FromTx (block.vtx [1 ]));
@@ -221,7 +229,7 @@ BOOST_AUTO_TEST_CASE(SufficientPreforwardRTTest)
221229
222230 // Test with pre-forwarding coinbase + tx 2 with tx 1 in mempool
223231 {
224- TestHeaderAndShortIDs shortIDs (block);
232+ TestHeaderAndShortIDs shortIDs (block, rand_ctx );
225233 shortIDs.prefilledtxn .resize (2 );
226234 shortIDs.prefilledtxn [0 ] = {0 , block.vtx [0 ]};
227235 shortIDs.prefilledtxn [1 ] = {1 , block.vtx [2 ]}; // id == 1 as it is 1 after index 1
@@ -235,7 +243,7 @@ BOOST_AUTO_TEST_CASE(SufficientPreforwardRTTest)
235243 stream >> shortIDs2;
236244
237245 PartiallyDownloadedBlock partialBlock (&pool);
238- BOOST_CHECK (partialBlock.InitData (shortIDs2, extra_txn ) == READ_STATUS_OK);
246+ BOOST_CHECK (partialBlock.InitData (shortIDs2, empty_extra_txn ) == READ_STATUS_OK);
239247 BOOST_CHECK ( partialBlock.IsTxAvailable (0 ));
240248 BOOST_CHECK ( partialBlock.IsTxAvailable (1 ));
241249 BOOST_CHECK ( partialBlock.IsTxAvailable (2 ));
@@ -261,17 +269,14 @@ BOOST_AUTO_TEST_CASE(SufficientPreforwardRTTest)
261269BOOST_AUTO_TEST_CASE (EmptyBlockRoundTripTest)
262270{
263271 CTxMemPool& pool = *Assert (m_node.mempool );
264- CMutableTransaction coinbase;
265- coinbase.vin .resize (1 );
266- coinbase.vin [0 ].scriptSig .resize (10 );
267- coinbase.vout .resize (1 );
268- coinbase.vout [0 ].nValue = 42 ;
272+ CMutableTransaction coinbase = BuildTransactionTestCase ();
269273
270274 CBlock block;
275+ auto rand_ctx (FastRandomContext (uint256{42 }));
271276 block.vtx .resize (1 );
272277 block.vtx [0 ] = MakeTransactionRef (std::move (coinbase));
273278 block.nVersion = 42 ;
274- block.hashPrevBlock = InsecureRand256 ();
279+ block.hashPrevBlock = rand_ctx. rand256 ();
275280 block.nBits = 0x207fffff ;
276281
277282 bool mutated;
@@ -281,7 +286,7 @@ BOOST_AUTO_TEST_CASE(EmptyBlockRoundTripTest)
281286
282287 // Test simple header round-trip with only coinbase
283288 {
284- CBlockHeaderAndShortTxIDs shortIDs{block};
289+ CBlockHeaderAndShortTxIDs shortIDs{block, rand_ctx. rand64 () };
285290
286291 DataStream stream{};
287292 stream << shortIDs;
@@ -290,7 +295,7 @@ BOOST_AUTO_TEST_CASE(EmptyBlockRoundTripTest)
290295 stream >> shortIDs2;
291296
292297 PartiallyDownloadedBlock partialBlock (&pool);
293- BOOST_CHECK (partialBlock.InitData (shortIDs2, extra_txn ) == READ_STATUS_OK);
298+ BOOST_CHECK (partialBlock.InitData (shortIDs2, empty_extra_txn ) == READ_STATUS_OK);
294299 BOOST_CHECK (partialBlock.IsTxAvailable (0 ));
295300
296301 CBlock block2;
@@ -302,6 +307,53 @@ BOOST_AUTO_TEST_CASE(EmptyBlockRoundTripTest)
302307 }
303308}
304309
310+ BOOST_AUTO_TEST_CASE (ReceiveWithExtraTransactions) {
311+ CTxMemPool& pool = *Assert (m_node.mempool );
312+ TestMemPoolEntryHelper entry;
313+ auto rand_ctx (FastRandomContext (uint256{42 }));
314+
315+ CMutableTransaction mtx = BuildTransactionTestCase ();
316+ mtx.vin [0 ].prevout .hash = Txid::FromUint256 (rand_ctx.rand256 ());
317+ mtx.vin [0 ].prevout .n = 0 ;
318+ const CTransactionRef non_block_tx = MakeTransactionRef (std::move (mtx));
319+
320+ CBlock block (BuildBlockTestCase (rand_ctx));
321+ std::vector<CTransactionRef> extra_txn;
322+ extra_txn.resize (10 );
323+
324+ LOCK2 (cs_main, pool.cs );
325+ pool.addUnchecked (entry.FromTx (block.vtx [2 ]));
326+ BOOST_CHECK_EQUAL (pool.get (block.vtx [2 ]->GetHash ()).use_count (), SHARED_TX_OFFSET + 0 );
327+ // Ensure the non_block_tx is actually not in the block
328+ for (const auto &block_tx : block.vtx ) {
329+ BOOST_CHECK_NE (block_tx->GetHash (), non_block_tx->GetHash ());
330+ }
331+ // Ensure block.vtx[1] is not in pool
332+ BOOST_CHECK_EQUAL (pool.get (block.vtx [1 ]->GetHash ()), nullptr );
333+
334+ {
335+ const CBlockHeaderAndShortTxIDs cmpctblock{block, rand_ctx.rand64 ()};
336+ PartiallyDownloadedBlock partial_block (&pool);
337+ PartiallyDownloadedBlock partial_block_with_extra (&pool);
338+
339+ BOOST_CHECK (partial_block.InitData (cmpctblock, extra_txn) == READ_STATUS_OK);
340+ BOOST_CHECK ( partial_block.IsTxAvailable (0 ));
341+ BOOST_CHECK (!partial_block.IsTxAvailable (1 ));
342+ BOOST_CHECK ( partial_block.IsTxAvailable (2 ));
343+
344+ // Add an unrelated tx to extra_txn:
345+ extra_txn[0 ] = non_block_tx;
346+ // and a tx from the block that's not in the mempool:
347+ extra_txn[1 ] = block.vtx [1 ];
348+
349+ BOOST_CHECK (partial_block_with_extra.InitData (cmpctblock, extra_txn) == READ_STATUS_OK);
350+ BOOST_CHECK (partial_block_with_extra.IsTxAvailable (0 ));
351+ // This transaction is now available via extra_txn:
352+ BOOST_CHECK (partial_block_with_extra.IsTxAvailable (1 ));
353+ BOOST_CHECK (partial_block_with_extra.IsTxAvailable (2 ));
354+ }
355+ }
356+
305357BOOST_AUTO_TEST_CASE (TransactionsRequestSerializationTest) {
306358 BlockTransactionsRequest req1;
307359 req1.blockhash = InsecureRand256 ();
0 commit comments