mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-08-29 21:41:07 +02:00
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
bf031a517c
(#29752) where the
`extra_txn` vec/circular-buffer was sometimes null-initialized and
not yet filled when dereferenced in `PartiallyDownloadedBlock::InitData`.
This commit is contained in:
@@ -141,7 +141,7 @@ public:
|
|||||||
|
|
||||||
explicit PartiallyDownloadedBlock(CTxMemPool* poolIn) : pool(poolIn) {}
|
explicit PartiallyDownloadedBlock(CTxMemPool* poolIn) : pool(poolIn) {}
|
||||||
|
|
||||||
// extra_txn is a list of extra transactions to look at, in <witness hash, reference> form
|
// extra_txn is a list of extra orphan/conflicted/etc transactions to look at
|
||||||
ReadStatus InitData(const CBlockHeaderAndShortTxIDs& cmpctblock, const std::vector<CTransactionRef>& extra_txn);
|
ReadStatus InitData(const CBlockHeaderAndShortTxIDs& cmpctblock, const std::vector<CTransactionRef>& extra_txn);
|
||||||
bool IsTxAvailable(size_t index) const;
|
bool IsTxAvailable(size_t index) const;
|
||||||
ReadStatus FillBlock(CBlock& block, const std::vector<CTransactionRef>& vtx_missing);
|
ReadStatus FillBlock(CBlock& block, const std::vector<CTransactionRef>& vtx_missing);
|
||||||
|
@@ -18,13 +18,18 @@ const std::vector<CTransactionRef> empty_extra_txn;
|
|||||||
|
|
||||||
BOOST_FIXTURE_TEST_SUITE(blockencodings_tests, RegTestingSetup)
|
BOOST_FIXTURE_TEST_SUITE(blockencodings_tests, RegTestingSetup)
|
||||||
|
|
||||||
static CBlock BuildBlockTestCase() {
|
static CMutableTransaction BuildTransactionTestCase() {
|
||||||
CBlock block;
|
|
||||||
CMutableTransaction tx;
|
CMutableTransaction tx;
|
||||||
tx.vin.resize(1);
|
tx.vin.resize(1);
|
||||||
tx.vin[0].scriptSig.resize(10);
|
tx.vin[0].scriptSig.resize(10);
|
||||||
tx.vout.resize(1);
|
tx.vout.resize(1);
|
||||||
tx.vout[0].nValue = 42;
|
tx.vout[0].nValue = 42;
|
||||||
|
return tx;
|
||||||
|
}
|
||||||
|
|
||||||
|
static CBlock BuildBlockTestCase() {
|
||||||
|
CBlock block;
|
||||||
|
CMutableTransaction tx = BuildTransactionTestCase();
|
||||||
|
|
||||||
block.vtx.resize(3);
|
block.vtx.resize(3);
|
||||||
block.vtx[0] = MakeTransactionRef(tx);
|
block.vtx[0] = MakeTransactionRef(tx);
|
||||||
@@ -261,11 +266,7 @@ BOOST_AUTO_TEST_CASE(SufficientPreforwardRTTest)
|
|||||||
BOOST_AUTO_TEST_CASE(EmptyBlockRoundTripTest)
|
BOOST_AUTO_TEST_CASE(EmptyBlockRoundTripTest)
|
||||||
{
|
{
|
||||||
CTxMemPool& pool = *Assert(m_node.mempool);
|
CTxMemPool& pool = *Assert(m_node.mempool);
|
||||||
CMutableTransaction coinbase;
|
CMutableTransaction coinbase = BuildTransactionTestCase();
|
||||||
coinbase.vin.resize(1);
|
|
||||||
coinbase.vin[0].scriptSig.resize(10);
|
|
||||||
coinbase.vout.resize(1);
|
|
||||||
coinbase.vout[0].nValue = 42;
|
|
||||||
|
|
||||||
CBlock block;
|
CBlock block;
|
||||||
block.vtx.resize(1);
|
block.vtx.resize(1);
|
||||||
@@ -302,6 +303,51 @@ BOOST_AUTO_TEST_CASE(EmptyBlockRoundTripTest)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(ReceiveWithExtraTransactions) {
|
||||||
|
CTxMemPool& pool = *Assert(m_node.mempool);
|
||||||
|
TestMemPoolEntryHelper entry;
|
||||||
|
const CBlock block(BuildBlockTestCase());
|
||||||
|
std::vector<CTransactionRef> extra_txn;
|
||||||
|
extra_txn.resize(10);
|
||||||
|
|
||||||
|
CMutableTransaction mtx = BuildTransactionTestCase();
|
||||||
|
mtx.vin[0].prevout.hash = Txid::FromUint256(InsecureRand256());
|
||||||
|
mtx.vin[0].prevout.n = 0;
|
||||||
|
const CTransactionRef non_block_tx = MakeTransactionRef(std::move(mtx));
|
||||||
|
|
||||||
|
LOCK2(cs_main, pool.cs);
|
||||||
|
pool.addUnchecked(entry.FromTx(block.vtx[2]));
|
||||||
|
BOOST_CHECK_EQUAL(pool.get(block.vtx[2]->GetHash()).use_count(), SHARED_TX_OFFSET + 0);
|
||||||
|
// Ensure the non_block_tx is actually not in the block
|
||||||
|
for (const auto &block_tx : block.vtx) {
|
||||||
|
BOOST_CHECK_NE(block_tx->GetHash(), non_block_tx->GetHash());
|
||||||
|
}
|
||||||
|
// Ensure block.vtx[1] is not in pool
|
||||||
|
BOOST_CHECK_EQUAL(pool.get(block.vtx[1]->GetHash()), nullptr);
|
||||||
|
|
||||||
|
{
|
||||||
|
const CBlockHeaderAndShortTxIDs cmpctblock{block};
|
||||||
|
PartiallyDownloadedBlock partial_block(&pool);
|
||||||
|
PartiallyDownloadedBlock partial_block_with_extra(&pool);
|
||||||
|
|
||||||
|
BOOST_CHECK(partial_block.InitData(cmpctblock, extra_txn) == READ_STATUS_OK);
|
||||||
|
BOOST_CHECK( partial_block.IsTxAvailable(0));
|
||||||
|
BOOST_CHECK(!partial_block.IsTxAvailable(1));
|
||||||
|
BOOST_CHECK( partial_block.IsTxAvailable(2));
|
||||||
|
|
||||||
|
// Add an unrelated tx to extra_txn:
|
||||||
|
extra_txn[0] = non_block_tx;
|
||||||
|
// and a tx from the block that's not in the mempool:
|
||||||
|
extra_txn[1] = block.vtx[1];
|
||||||
|
|
||||||
|
BOOST_CHECK(partial_block_with_extra.InitData(cmpctblock, extra_txn) == READ_STATUS_OK);
|
||||||
|
BOOST_CHECK(partial_block_with_extra.IsTxAvailable(0));
|
||||||
|
// This transaction is now available via extra_txn:
|
||||||
|
BOOST_CHECK(partial_block_with_extra.IsTxAvailable(1));
|
||||||
|
BOOST_CHECK(partial_block_with_extra.IsTxAvailable(2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(TransactionsRequestSerializationTest) {
|
BOOST_AUTO_TEST_CASE(TransactionsRequestSerializationTest) {
|
||||||
BlockTransactionsRequest req1;
|
BlockTransactionsRequest req1;
|
||||||
req1.blockhash = InsecureRand256();
|
req1.blockhash = InsecureRand256();
|
||||||
|
Reference in New Issue
Block a user