2022-12-24 23:49:50 +00:00
|
|
|
// Copyright (c) 2011-2022 The Bitcoin Core developers
|
2016-04-25 15:51:08 -07:00
|
|
|
// Distributed under the MIT software license, see the accompanying
|
|
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
|
2017-11-10 13:57:53 +13:00
|
|
|
#include <blockencodings.h>
|
|
|
|
#include <chainparams.h>
|
2019-09-24 11:23:19 -04:00
|
|
|
#include <consensus/merkle.h>
|
2018-05-13 23:39:53 -07:00
|
|
|
#include <pow.h>
|
2019-06-24 17:22:28 +02:00
|
|
|
#include <streams.h>
|
2023-01-22 09:57:19 -08:00
|
|
|
#include <test/util/random.h>
|
2022-10-10 14:27:31 +02:00
|
|
|
#include <test/util/txmempool.h>
|
2016-04-25 15:51:08 -07:00
|
|
|
|
2019-11-05 15:18:59 -05:00
|
|
|
#include <test/util/setup_common.h>
|
2016-04-25 15:51:08 -07:00
|
|
|
|
|
|
|
#include <boost/test/unit_test.hpp>
|
|
|
|
|
2016-12-04 20:44:37 -08:00
|
|
|
std::vector<std::pair<uint256, CTransactionRef>> extra_txn;
|
|
|
|
|
2019-09-24 11:23:19 -04:00
|
|
|
BOOST_FIXTURE_TEST_SUITE(blockencodings_tests, RegTestingSetup)
|
2016-04-25 15:51:08 -07:00
|
|
|
|
|
|
|
static CBlock BuildBlockTestCase() {
|
|
|
|
CBlock block;
|
|
|
|
CMutableTransaction tx;
|
|
|
|
tx.vin.resize(1);
|
|
|
|
tx.vin[0].scriptSig.resize(10);
|
|
|
|
tx.vout.resize(1);
|
|
|
|
tx.vout[0].nValue = 42;
|
|
|
|
|
|
|
|
block.vtx.resize(3);
|
2016-11-10 17:34:17 -08:00
|
|
|
block.vtx[0] = MakeTransactionRef(tx);
|
2016-04-25 15:51:08 -07:00
|
|
|
block.nVersion = 42;
|
2017-06-07 12:03:17 -07:00
|
|
|
block.hashPrevBlock = InsecureRand256();
|
2016-04-25 15:51:08 -07:00
|
|
|
block.nBits = 0x207fffff;
|
|
|
|
|
2023-10-11 14:53:04 +01:00
|
|
|
tx.vin[0].prevout.hash = Txid::FromUint256(InsecureRand256());
|
2016-04-25 15:51:08 -07:00
|
|
|
tx.vin[0].prevout.n = 0;
|
2016-11-10 17:34:17 -08:00
|
|
|
block.vtx[1] = MakeTransactionRef(tx);
|
2016-04-25 15:51:08 -07:00
|
|
|
|
|
|
|
tx.vin.resize(10);
|
|
|
|
for (size_t i = 0; i < tx.vin.size(); i++) {
|
2023-10-11 14:53:04 +01:00
|
|
|
tx.vin[i].prevout.hash = Txid::FromUint256(InsecureRand256());
|
2016-04-25 15:51:08 -07:00
|
|
|
tx.vin[i].prevout.n = 0;
|
|
|
|
}
|
2016-11-10 17:34:17 -08:00
|
|
|
block.vtx[2] = MakeTransactionRef(tx);
|
2016-04-25 15:51:08 -07:00
|
|
|
|
|
|
|
bool mutated;
|
|
|
|
block.hashMerkleRoot = BlockMerkleRoot(block, &mutated);
|
|
|
|
assert(!mutated);
|
|
|
|
while (!CheckProofOfWork(block.GetHash(), block.nBits, Params().GetConsensus())) ++block.nNonce;
|
|
|
|
return block;
|
|
|
|
}
|
|
|
|
|
2017-08-16 00:24:39 +02:00
|
|
|
// Number of shared use_counts we expect for a tx we haven't touched
|
2023-09-01 21:36:54 +02:00
|
|
|
// (block + mempool entry + mempool txns_randomized + our copy from the GetSharedTx call)
|
2023-08-25 17:01:51 +01:00
|
|
|
constexpr long SHARED_TX_OFFSET{4};
|
2016-04-25 15:51:08 -07:00
|
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE(SimpleRoundTripTest)
|
|
|
|
{
|
2022-03-21 21:42:40 -04:00
|
|
|
CTxMemPool& pool = *Assert(m_node.mempool);
|
2016-04-25 15:51:08 -07:00
|
|
|
TestMemPoolEntryHelper entry;
|
|
|
|
CBlock block(BuildBlockTestCase());
|
|
|
|
|
2018-12-17 14:27:43 -05:00
|
|
|
LOCK2(cs_main, pool.cs);
|
2018-07-30 09:11:13 -04:00
|
|
|
pool.addUnchecked(entry.FromTx(block.vtx[2]));
|
2023-08-30 15:40:49 +01:00
|
|
|
BOOST_CHECK_EQUAL(pool.get(block.vtx[2]->GetHash()).use_count(), SHARED_TX_OFFSET + 0);
|
2016-04-25 15:51:08 -07:00
|
|
|
|
|
|
|
// Do a simple ShortTxIDs RT
|
|
|
|
{
|
2022-05-16 18:21:15 +01:00
|
|
|
CBlockHeaderAndShortTxIDs shortIDs{block};
|
2016-04-25 15:51:08 -07:00
|
|
|
|
2023-11-19 14:58:00 +01:00
|
|
|
DataStream stream{};
|
2016-04-25 15:51:08 -07:00
|
|
|
stream << shortIDs;
|
|
|
|
|
|
|
|
CBlockHeaderAndShortTxIDs shortIDs2;
|
|
|
|
stream >> shortIDs2;
|
|
|
|
|
|
|
|
PartiallyDownloadedBlock partialBlock(&pool);
|
2016-12-04 20:44:37 -08:00
|
|
|
BOOST_CHECK(partialBlock.InitData(shortIDs2, extra_txn) == READ_STATUS_OK);
|
2016-04-25 15:51:08 -07:00
|
|
|
BOOST_CHECK( partialBlock.IsTxAvailable(0));
|
|
|
|
BOOST_CHECK(!partialBlock.IsTxAvailable(1));
|
|
|
|
BOOST_CHECK( partialBlock.IsTxAvailable(2));
|
|
|
|
|
2023-08-30 15:40:49 +01:00
|
|
|
BOOST_CHECK_EQUAL(pool.get(block.vtx[2]->GetHash()).use_count(), SHARED_TX_OFFSET + 1);
|
2016-04-25 15:51:08 -07:00
|
|
|
|
2016-11-29 17:51:26 -05:00
|
|
|
size_t poolSize = pool.size();
|
2019-07-22 07:42:01 -04:00
|
|
|
pool.removeRecursive(*block.vtx[2], MemPoolRemovalReason::REPLACED);
|
2016-11-29 17:51:26 -05:00
|
|
|
BOOST_CHECK_EQUAL(pool.size(), poolSize - 1);
|
2016-04-25 15:51:08 -07:00
|
|
|
|
|
|
|
CBlock block2;
|
2016-11-11 13:01:27 -08:00
|
|
|
{
|
|
|
|
PartiallyDownloadedBlock tmp = partialBlock;
|
|
|
|
BOOST_CHECK(partialBlock.FillBlock(block2, {}) == READ_STATUS_INVALID); // No transactions
|
|
|
|
partialBlock = tmp;
|
|
|
|
}
|
2016-04-25 15:51:08 -07:00
|
|
|
|
2016-11-11 13:01:27 -08:00
|
|
|
// Wrong transaction
|
|
|
|
{
|
|
|
|
PartiallyDownloadedBlock tmp = partialBlock;
|
|
|
|
partialBlock.FillBlock(block2, {block.vtx[2]}); // Current implementation doesn't check txn here, but don't require that
|
|
|
|
partialBlock = tmp;
|
|
|
|
}
|
2016-04-25 15:51:08 -07:00
|
|
|
bool mutated;
|
|
|
|
BOOST_CHECK(block.hashMerkleRoot != BlockMerkleRoot(block2, &mutated));
|
|
|
|
|
|
|
|
CBlock block3;
|
2016-11-11 13:01:27 -08:00
|
|
|
BOOST_CHECK(partialBlock.FillBlock(block3, {block.vtx[1]}) == READ_STATUS_OK);
|
2016-04-25 15:51:08 -07:00
|
|
|
BOOST_CHECK_EQUAL(block.GetHash().ToString(), block3.GetHash().ToString());
|
|
|
|
BOOST_CHECK_EQUAL(block.hashMerkleRoot.ToString(), BlockMerkleRoot(block3, &mutated).ToString());
|
|
|
|
BOOST_CHECK(!mutated);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class TestHeaderAndShortIDs {
|
|
|
|
// Utility to encode custom CBlockHeaderAndShortTxIDs
|
|
|
|
public:
|
|
|
|
CBlockHeader header;
|
|
|
|
uint64_t nonce;
|
|
|
|
std::vector<uint64_t> shorttxids;
|
|
|
|
std::vector<PrefilledTransaction> prefilledtxn;
|
|
|
|
|
2017-08-01 12:22:41 +02:00
|
|
|
explicit TestHeaderAndShortIDs(const CBlockHeaderAndShortTxIDs& orig) {
|
2023-11-19 14:58:00 +01:00
|
|
|
DataStream stream{};
|
2016-04-25 15:51:08 -07:00
|
|
|
stream << orig;
|
|
|
|
stream >> *this;
|
|
|
|
}
|
2017-08-01 12:22:41 +02:00
|
|
|
explicit TestHeaderAndShortIDs(const CBlock& block) :
|
2022-05-16 18:21:15 +01:00
|
|
|
TestHeaderAndShortIDs(CBlockHeaderAndShortTxIDs{block}) {}
|
2016-04-25 15:51:08 -07:00
|
|
|
|
|
|
|
uint64_t GetShortID(const uint256& txhash) const {
|
2023-11-19 14:58:00 +01:00
|
|
|
DataStream stream{};
|
2016-04-25 15:51:08 -07:00
|
|
|
stream << *this;
|
|
|
|
CBlockHeaderAndShortTxIDs base;
|
|
|
|
stream >> base;
|
|
|
|
return base.GetShortID(txhash);
|
|
|
|
}
|
|
|
|
|
2020-03-11 09:35:39 -07:00
|
|
|
SERIALIZE_METHODS(TestHeaderAndShortIDs, obj) { READWRITE(obj.header, obj.nonce, Using<VectorFormatter<CustomUintFormatter<CBlockHeaderAndShortTxIDs::SHORTTXIDS_LENGTH>>>(obj.shorttxids), obj.prefilledtxn); }
|
2016-04-25 15:51:08 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE(NonCoinbasePreforwardRTTest)
|
|
|
|
{
|
2022-03-21 21:42:40 -04:00
|
|
|
CTxMemPool& pool = *Assert(m_node.mempool);
|
2016-04-25 15:51:08 -07:00
|
|
|
TestMemPoolEntryHelper entry;
|
|
|
|
CBlock block(BuildBlockTestCase());
|
|
|
|
|
2018-12-17 14:27:43 -05:00
|
|
|
LOCK2(cs_main, pool.cs);
|
2018-07-30 09:11:13 -04:00
|
|
|
pool.addUnchecked(entry.FromTx(block.vtx[2]));
|
2023-08-30 15:40:49 +01:00
|
|
|
BOOST_CHECK_EQUAL(pool.get(block.vtx[2]->GetHash()).use_count(), SHARED_TX_OFFSET + 0);
|
2016-11-10 17:26:00 -08:00
|
|
|
|
|
|
|
uint256 txhash;
|
2016-04-25 15:51:08 -07:00
|
|
|
|
|
|
|
// Test with pre-forwarding tx 1, but not coinbase
|
|
|
|
{
|
|
|
|
TestHeaderAndShortIDs shortIDs(block);
|
|
|
|
shortIDs.prefilledtxn.resize(1);
|
|
|
|
shortIDs.prefilledtxn[0] = {1, block.vtx[1]};
|
|
|
|
shortIDs.shorttxids.resize(2);
|
2016-11-10 17:26:00 -08:00
|
|
|
shortIDs.shorttxids[0] = shortIDs.GetShortID(block.vtx[0]->GetHash());
|
|
|
|
shortIDs.shorttxids[1] = shortIDs.GetShortID(block.vtx[2]->GetHash());
|
2016-04-25 15:51:08 -07:00
|
|
|
|
2023-11-19 14:58:00 +01:00
|
|
|
DataStream stream{};
|
2016-04-25 15:51:08 -07:00
|
|
|
stream << shortIDs;
|
|
|
|
|
|
|
|
CBlockHeaderAndShortTxIDs shortIDs2;
|
|
|
|
stream >> shortIDs2;
|
|
|
|
|
|
|
|
PartiallyDownloadedBlock partialBlock(&pool);
|
2016-12-04 20:44:37 -08:00
|
|
|
BOOST_CHECK(partialBlock.InitData(shortIDs2, extra_txn) == READ_STATUS_OK);
|
2016-04-25 15:51:08 -07:00
|
|
|
BOOST_CHECK(!partialBlock.IsTxAvailable(0));
|
|
|
|
BOOST_CHECK( partialBlock.IsTxAvailable(1));
|
|
|
|
BOOST_CHECK( partialBlock.IsTxAvailable(2));
|
|
|
|
|
2023-08-30 15:40:49 +01:00
|
|
|
BOOST_CHECK_EQUAL(pool.get(block.vtx[2]->GetHash()).use_count(), SHARED_TX_OFFSET + 1); // +1 because of partialBlock
|
2016-04-25 15:51:08 -07:00
|
|
|
|
|
|
|
CBlock block2;
|
2016-11-11 13:01:27 -08:00
|
|
|
{
|
|
|
|
PartiallyDownloadedBlock tmp = partialBlock;
|
|
|
|
BOOST_CHECK(partialBlock.FillBlock(block2, {}) == READ_STATUS_INVALID); // No transactions
|
|
|
|
partialBlock = tmp;
|
|
|
|
}
|
2016-04-25 15:51:08 -07:00
|
|
|
|
2016-11-11 13:01:27 -08:00
|
|
|
// Wrong transaction
|
|
|
|
{
|
|
|
|
PartiallyDownloadedBlock tmp = partialBlock;
|
|
|
|
partialBlock.FillBlock(block2, {block.vtx[1]}); // Current implementation doesn't check txn here, but don't require that
|
|
|
|
partialBlock = tmp;
|
|
|
|
}
|
2023-08-30 15:40:49 +01:00
|
|
|
BOOST_CHECK_EQUAL(pool.get(block.vtx[2]->GetHash()).use_count(), SHARED_TX_OFFSET + 2); // +2 because of partialBlock and block2
|
2016-04-25 15:51:08 -07:00
|
|
|
bool mutated;
|
|
|
|
BOOST_CHECK(block.hashMerkleRoot != BlockMerkleRoot(block2, &mutated));
|
|
|
|
|
|
|
|
CBlock block3;
|
2016-11-11 13:01:27 -08:00
|
|
|
PartiallyDownloadedBlock partialBlockCopy = partialBlock;
|
|
|
|
BOOST_CHECK(partialBlock.FillBlock(block3, {block.vtx[0]}) == READ_STATUS_OK);
|
2016-04-25 15:51:08 -07:00
|
|
|
BOOST_CHECK_EQUAL(block.GetHash().ToString(), block3.GetHash().ToString());
|
|
|
|
BOOST_CHECK_EQUAL(block.hashMerkleRoot.ToString(), BlockMerkleRoot(block3, &mutated).ToString());
|
|
|
|
BOOST_CHECK(!mutated);
|
|
|
|
|
2023-08-30 15:40:49 +01:00
|
|
|
BOOST_CHECK_EQUAL(pool.get(block.vtx[2]->GetHash()).use_count(), SHARED_TX_OFFSET + 3); // +2 because of partialBlock and block2 and block3
|
2018-04-11 13:51:28 -04:00
|
|
|
|
2016-11-10 17:26:00 -08:00
|
|
|
txhash = block.vtx[2]->GetHash();
|
|
|
|
block.vtx.clear();
|
|
|
|
block2.vtx.clear();
|
|
|
|
block3.vtx.clear();
|
2023-08-30 15:40:49 +01:00
|
|
|
BOOST_CHECK_EQUAL(pool.get(txhash).use_count(), SHARED_TX_OFFSET + 1 - 1); // + 1 because of partialBlock; -1 because of block.
|
2016-04-25 15:51:08 -07:00
|
|
|
}
|
2023-08-30 15:40:49 +01:00
|
|
|
BOOST_CHECK_EQUAL(pool.get(txhash).use_count(), SHARED_TX_OFFSET - 1); // -1 because of block
|
2016-04-25 15:51:08 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE(SufficientPreforwardRTTest)
|
|
|
|
{
|
2022-03-21 21:42:40 -04:00
|
|
|
CTxMemPool& pool = *Assert(m_node.mempool);
|
2016-04-25 15:51:08 -07:00
|
|
|
TestMemPoolEntryHelper entry;
|
|
|
|
CBlock block(BuildBlockTestCase());
|
|
|
|
|
2018-12-17 14:27:43 -05:00
|
|
|
LOCK2(cs_main, pool.cs);
|
2018-07-30 09:11:13 -04:00
|
|
|
pool.addUnchecked(entry.FromTx(block.vtx[1]));
|
2023-08-30 15:40:49 +01:00
|
|
|
BOOST_CHECK_EQUAL(pool.get(block.vtx[1]->GetHash()).use_count(), SHARED_TX_OFFSET + 0);
|
2016-11-10 17:26:00 -08:00
|
|
|
|
|
|
|
uint256 txhash;
|
2016-04-25 15:51:08 -07:00
|
|
|
|
|
|
|
// Test with pre-forwarding coinbase + tx 2 with tx 1 in mempool
|
|
|
|
{
|
|
|
|
TestHeaderAndShortIDs shortIDs(block);
|
|
|
|
shortIDs.prefilledtxn.resize(2);
|
|
|
|
shortIDs.prefilledtxn[0] = {0, block.vtx[0]};
|
|
|
|
shortIDs.prefilledtxn[1] = {1, block.vtx[2]}; // id == 1 as it is 1 after index 1
|
|
|
|
shortIDs.shorttxids.resize(1);
|
2016-11-10 17:26:00 -08:00
|
|
|
shortIDs.shorttxids[0] = shortIDs.GetShortID(block.vtx[1]->GetHash());
|
2016-04-25 15:51:08 -07:00
|
|
|
|
2023-11-19 14:58:00 +01:00
|
|
|
DataStream stream{};
|
2016-04-25 15:51:08 -07:00
|
|
|
stream << shortIDs;
|
|
|
|
|
|
|
|
CBlockHeaderAndShortTxIDs shortIDs2;
|
|
|
|
stream >> shortIDs2;
|
|
|
|
|
|
|
|
PartiallyDownloadedBlock partialBlock(&pool);
|
2016-12-04 20:44:37 -08:00
|
|
|
BOOST_CHECK(partialBlock.InitData(shortIDs2, extra_txn) == READ_STATUS_OK);
|
2016-04-25 15:51:08 -07:00
|
|
|
BOOST_CHECK( partialBlock.IsTxAvailable(0));
|
|
|
|
BOOST_CHECK( partialBlock.IsTxAvailable(1));
|
|
|
|
BOOST_CHECK( partialBlock.IsTxAvailable(2));
|
|
|
|
|
2023-08-30 15:40:49 +01:00
|
|
|
BOOST_CHECK_EQUAL(pool.get(block.vtx[1]->GetHash()).use_count(), SHARED_TX_OFFSET + 1);
|
2016-04-25 15:51:08 -07:00
|
|
|
|
|
|
|
CBlock block2;
|
2016-11-11 13:01:27 -08:00
|
|
|
PartiallyDownloadedBlock partialBlockCopy = partialBlock;
|
|
|
|
BOOST_CHECK(partialBlock.FillBlock(block2, {}) == READ_STATUS_OK);
|
2016-04-25 15:51:08 -07:00
|
|
|
BOOST_CHECK_EQUAL(block.GetHash().ToString(), block2.GetHash().ToString());
|
|
|
|
bool mutated;
|
|
|
|
BOOST_CHECK_EQUAL(block.hashMerkleRoot.ToString(), BlockMerkleRoot(block2, &mutated).ToString());
|
|
|
|
BOOST_CHECK(!mutated);
|
|
|
|
|
2016-11-10 17:26:00 -08:00
|
|
|
txhash = block.vtx[1]->GetHash();
|
|
|
|
block.vtx.clear();
|
|
|
|
block2.vtx.clear();
|
2023-08-30 15:40:49 +01:00
|
|
|
BOOST_CHECK_EQUAL(pool.get(txhash).use_count(), SHARED_TX_OFFSET + 1 - 1); // + 1 because of partialBlock; -1 because of block.
|
2016-04-25 15:51:08 -07:00
|
|
|
}
|
2023-08-30 15:40:49 +01:00
|
|
|
BOOST_CHECK_EQUAL(pool.get(txhash).use_count(), SHARED_TX_OFFSET - 1); // -1 because of block
|
2016-04-25 15:51:08 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE(EmptyBlockRoundTripTest)
|
|
|
|
{
|
2022-03-21 21:42:40 -04:00
|
|
|
CTxMemPool& pool = *Assert(m_node.mempool);
|
2016-04-25 15:51:08 -07:00
|
|
|
CMutableTransaction coinbase;
|
|
|
|
coinbase.vin.resize(1);
|
|
|
|
coinbase.vin[0].scriptSig.resize(10);
|
|
|
|
coinbase.vout.resize(1);
|
|
|
|
coinbase.vout[0].nValue = 42;
|
|
|
|
|
|
|
|
CBlock block;
|
|
|
|
block.vtx.resize(1);
|
2016-11-10 17:34:17 -08:00
|
|
|
block.vtx[0] = MakeTransactionRef(std::move(coinbase));
|
2016-04-25 15:51:08 -07:00
|
|
|
block.nVersion = 42;
|
2017-06-07 12:03:17 -07:00
|
|
|
block.hashPrevBlock = InsecureRand256();
|
2016-04-25 15:51:08 -07:00
|
|
|
block.nBits = 0x207fffff;
|
|
|
|
|
|
|
|
bool mutated;
|
|
|
|
block.hashMerkleRoot = BlockMerkleRoot(block, &mutated);
|
|
|
|
assert(!mutated);
|
|
|
|
while (!CheckProofOfWork(block.GetHash(), block.nBits, Params().GetConsensus())) ++block.nNonce;
|
|
|
|
|
|
|
|
// Test simple header round-trip with only coinbase
|
|
|
|
{
|
2022-05-16 18:21:15 +01:00
|
|
|
CBlockHeaderAndShortTxIDs shortIDs{block};
|
2016-04-25 15:51:08 -07:00
|
|
|
|
2023-11-19 14:58:00 +01:00
|
|
|
DataStream stream{};
|
2016-04-25 15:51:08 -07:00
|
|
|
stream << shortIDs;
|
|
|
|
|
|
|
|
CBlockHeaderAndShortTxIDs shortIDs2;
|
|
|
|
stream >> shortIDs2;
|
|
|
|
|
|
|
|
PartiallyDownloadedBlock partialBlock(&pool);
|
2016-12-04 20:44:37 -08:00
|
|
|
BOOST_CHECK(partialBlock.InitData(shortIDs2, extra_txn) == READ_STATUS_OK);
|
2016-04-25 15:51:08 -07:00
|
|
|
BOOST_CHECK(partialBlock.IsTxAvailable(0));
|
|
|
|
|
|
|
|
CBlock block2;
|
2016-11-10 17:34:17 -08:00
|
|
|
std::vector<CTransactionRef> vtx_missing;
|
2016-04-25 15:51:08 -07:00
|
|
|
BOOST_CHECK(partialBlock.FillBlock(block2, vtx_missing) == READ_STATUS_OK);
|
|
|
|
BOOST_CHECK_EQUAL(block.GetHash().ToString(), block2.GetHash().ToString());
|
|
|
|
BOOST_CHECK_EQUAL(block.hashMerkleRoot.ToString(), BlockMerkleRoot(block2, &mutated).ToString());
|
|
|
|
BOOST_CHECK(!mutated);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE(TransactionsRequestSerializationTest) {
|
|
|
|
BlockTransactionsRequest req1;
|
2017-06-07 12:03:17 -07:00
|
|
|
req1.blockhash = InsecureRand256();
|
2016-04-25 15:51:08 -07:00
|
|
|
req1.indexes.resize(4);
|
|
|
|
req1.indexes[0] = 0;
|
|
|
|
req1.indexes[1] = 1;
|
|
|
|
req1.indexes[2] = 3;
|
|
|
|
req1.indexes[3] = 4;
|
|
|
|
|
2023-01-03 13:21:44 +01:00
|
|
|
DataStream stream{};
|
2016-04-25 15:51:08 -07:00
|
|
|
stream << req1;
|
|
|
|
|
|
|
|
BlockTransactionsRequest req2;
|
|
|
|
stream >> req2;
|
|
|
|
|
|
|
|
BOOST_CHECK_EQUAL(req1.blockhash.ToString(), req2.blockhash.ToString());
|
|
|
|
BOOST_CHECK_EQUAL(req1.indexes.size(), req2.indexes.size());
|
|
|
|
BOOST_CHECK_EQUAL(req1.indexes[0], req2.indexes[0]);
|
|
|
|
BOOST_CHECK_EQUAL(req1.indexes[1], req2.indexes[1]);
|
|
|
|
BOOST_CHECK_EQUAL(req1.indexes[2], req2.indexes[2]);
|
|
|
|
BOOST_CHECK_EQUAL(req1.indexes[3], req2.indexes[3]);
|
|
|
|
}
|
|
|
|
|
2018-11-07 12:36:23 -08:00
|
|
|
BOOST_AUTO_TEST_CASE(TransactionsRequestDeserializationMaxTest) {
|
|
|
|
// Check that the highest legal index is decoded correctly
|
|
|
|
BlockTransactionsRequest req0;
|
|
|
|
req0.blockhash = InsecureRand256();
|
|
|
|
req0.indexes.resize(1);
|
|
|
|
req0.indexes[0] = 0xffff;
|
2023-01-03 13:21:44 +01:00
|
|
|
DataStream stream{};
|
2018-11-07 12:36:23 -08:00
|
|
|
stream << req0;
|
|
|
|
|
|
|
|
BlockTransactionsRequest req1;
|
|
|
|
stream >> req1;
|
|
|
|
BOOST_CHECK_EQUAL(req0.indexes.size(), req1.indexes.size());
|
|
|
|
BOOST_CHECK_EQUAL(req0.indexes[0], req1.indexes[0]);
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE(TransactionsRequestDeserializationOverflowTest) {
|
|
|
|
// Any set of index deltas that starts with N values that sum to (0x10000 - N)
|
|
|
|
// causes the edge-case overflow that was originally not checked for. Such
|
|
|
|
// a request cannot be created by serializing a real BlockTransactionsRequest
|
|
|
|
// due to the overflow, so here we'll serialize from raw deltas.
|
|
|
|
BlockTransactionsRequest req0;
|
|
|
|
req0.blockhash = InsecureRand256();
|
|
|
|
req0.indexes.resize(3);
|
|
|
|
req0.indexes[0] = 0x7000;
|
|
|
|
req0.indexes[1] = 0x10000 - 0x7000 - 2;
|
|
|
|
req0.indexes[2] = 0;
|
2023-01-03 13:21:44 +01:00
|
|
|
DataStream stream{};
|
2018-11-07 12:36:23 -08:00
|
|
|
stream << req0.blockhash;
|
|
|
|
WriteCompactSize(stream, req0.indexes.size());
|
|
|
|
WriteCompactSize(stream, req0.indexes[0]);
|
|
|
|
WriteCompactSize(stream, req0.indexes[1]);
|
|
|
|
WriteCompactSize(stream, req0.indexes[2]);
|
|
|
|
|
|
|
|
BlockTransactionsRequest req1;
|
|
|
|
try {
|
|
|
|
stream >> req1;
|
|
|
|
// before patch: deserialize above succeeds and this check fails, demonstrating the overflow
|
|
|
|
BOOST_CHECK(req1.indexes[1] < req1.indexes[2]);
|
|
|
|
// this shouldn't be reachable before or after patch
|
|
|
|
BOOST_CHECK(0);
|
|
|
|
} catch(std::ios_base::failure &) {
|
|
|
|
// deserialize should fail
|
2019-03-29 15:22:48 +01:00
|
|
|
BOOST_CHECK(true); // Needed to suppress "Test case [...] did not check any assertions"
|
2018-11-07 12:36:23 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-25 15:51:08 -07:00
|
|
|
BOOST_AUTO_TEST_SUITE_END()
|