Skip to content

Commit 4c99301

Browse files
committed
test: Add ReceiveWithExtraTransactions Compact Block receive test.
This new test uses the `vExtraTxnForCompact` (`extra_txn`) vector of optional orphan/conflicted/etc. transactions to provide a transaction in a compact block that was not otherwise present in our mempool. This also covers an improbable nullptr deref bug addressed in bf031a5 (#29752) where the `extra_txn` vec/circular-buffer was sometimes null-initialized and not yet filled when dereferenced in `PartiallyDownloadedBlock::InitData`.
1 parent 4621e7c commit 4c99301

File tree

2 files changed

+54
-8
lines changed

2 files changed

+54
-8
lines changed

src/blockencodings.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ class PartiallyDownloadedBlock {
141141

142142
explicit PartiallyDownloadedBlock(CTxMemPool* poolIn) : pool(poolIn) {}
143143

144-
// extra_txn is a list of extra transactions to look at, in <witness hash, reference> form
144+
// extra_txn is a list of extra orphan/conflicted/etc transactions to look at
145145
ReadStatus InitData(const CBlockHeaderAndShortTxIDs& cmpctblock, const std::vector<CTransactionRef>& extra_txn);
146146
bool IsTxAvailable(size_t index) const;
147147
ReadStatus FillBlock(CBlock& block, const std::vector<CTransactionRef>& vtx_missing);

src/test/blockencodings_tests.cpp

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,18 @@ const std::vector<CTransactionRef> empty_extra_txn;
1818

1919
BOOST_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() {
31+
CBlock block;
32+
CMutableTransaction tx = BuildTransactionTestCase();
2833

2934
block.vtx.resize(3);
3035
block.vtx[0] = MakeTransactionRef(tx);
@@ -261,11 +266,7 @@ BOOST_AUTO_TEST_CASE(SufficientPreforwardRTTest)
261266
BOOST_AUTO_TEST_CASE(EmptyBlockRoundTripTest)
262267
{
263268
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;
269+
CMutableTransaction coinbase = BuildTransactionTestCase();
269270

270271
CBlock block;
271272
block.vtx.resize(1);
@@ -302,6 +303,51 @@ BOOST_AUTO_TEST_CASE(EmptyBlockRoundTripTest)
302303
}
303304
}
304305

306+
BOOST_AUTO_TEST_CASE(ReceiveWithExtraTransactions) {
307+
CTxMemPool& pool = *Assert(m_node.mempool);
308+
TestMemPoolEntryHelper entry;
309+
const CBlock block(BuildBlockTestCase());
310+
std::vector<CTransactionRef> extra_txn;
311+
extra_txn.resize(10);
312+
313+
CMutableTransaction mtx = BuildTransactionTestCase();
314+
mtx.vin[0].prevout.hash = Txid::FromUint256(InsecureRand256());
315+
mtx.vin[0].prevout.n = 0;
316+
const CTransactionRef non_block_tx = MakeTransactionRef(std::move(mtx));
317+
318+
LOCK2(cs_main, pool.cs);
319+
pool.addUnchecked(entry.FromTx(block.vtx[2]));
320+
BOOST_CHECK_EQUAL(pool.get(block.vtx[2]->GetHash()).use_count(), SHARED_TX_OFFSET + 0);
321+
// Ensure the non_block_tx is actually not in the block
322+
for (const auto &block_tx : block.vtx) {
323+
BOOST_CHECK_NE(block_tx->GetHash(), non_block_tx->GetHash());
324+
}
325+
// Ensure block.vtx[1] is not in pool
326+
BOOST_CHECK_EQUAL(pool.get(block.vtx[1]->GetHash()), nullptr);
327+
328+
{
329+
const CBlockHeaderAndShortTxIDs cmpctblock{block};
330+
PartiallyDownloadedBlock partial_block(&pool);
331+
PartiallyDownloadedBlock partial_block_with_extra(&pool);
332+
333+
BOOST_CHECK(partial_block.InitData(cmpctblock, extra_txn) == READ_STATUS_OK);
334+
BOOST_CHECK( partial_block.IsTxAvailable(0));
335+
BOOST_CHECK(!partial_block.IsTxAvailable(1));
336+
BOOST_CHECK( partial_block.IsTxAvailable(2));
337+
338+
// Add an unrelated tx to extra_txn:
339+
extra_txn[0] = non_block_tx;
340+
// and a tx from the block that's not in the mempool:
341+
extra_txn[1] = block.vtx[1];
342+
343+
BOOST_CHECK(partial_block_with_extra.InitData(cmpctblock, extra_txn) == READ_STATUS_OK);
344+
BOOST_CHECK(partial_block_with_extra.IsTxAvailable(0));
345+
// This transaction is now available via extra_txn:
346+
BOOST_CHECK(partial_block_with_extra.IsTxAvailable(1));
347+
BOOST_CHECK(partial_block_with_extra.IsTxAvailable(2));
348+
}
349+
}
350+
305351
BOOST_AUTO_TEST_CASE(TransactionsRequestSerializationTest) {
306352
BlockTransactionsRequest req1;
307353
req1.blockhash = InsecureRand256();

0 commit comments

Comments
 (0)