Changeset View
Changeset View
Standalone View
Standalone View
src/test/blockencodings_tests.cpp
Show All 28 Lines | static CBlock BuildBlockTestCase() { | ||||
tx.vout[0].nValue = 42; | tx.vout[0].nValue = 42; | ||||
block.vtx.resize(3); | block.vtx.resize(3); | ||||
block.vtx[0] = MakeTransactionRef(tx); | block.vtx[0] = MakeTransactionRef(tx); | ||||
block.nVersion = 42; | block.nVersion = 42; | ||||
block.hashPrevBlock = GetRandHash(); | block.hashPrevBlock = GetRandHash(); | ||||
block.nBits = 0x207fffff; | block.nBits = 0x207fffff; | ||||
tx.vin[0].prevout.hash = GetRandHash(); | tx.vin[0].prevout.unspentid = unspentid_t(GetRandHash()); | ||||
tx.vin[0].prevout.n = 0; | tx.vin[0].prevout.n = 0; | ||||
block.vtx[1] = MakeTransactionRef(tx); | block.vtx[1] = MakeTransactionRef(tx); | ||||
tx.vin.resize(10); | tx.vin.resize(10); | ||||
for (size_t i = 0; i < tx.vin.size(); i++) { | for (size_t i = 0; i < tx.vin.size(); i++) { | ||||
tx.vin[i].prevout.hash = GetRandHash(); | tx.vin[i].prevout.unspentid = unspentid_t(GetRandHash()); | ||||
tx.vin[i].prevout.n = 0; | tx.vin[i].prevout.n = 0; | ||||
} | } | ||||
block.vtx[2] = MakeTransactionRef(tx); | block.vtx[2] = MakeTransactionRef(tx); | ||||
bool mutated; | bool mutated; | ||||
block.hashMerkleRoot = BlockMerkleRoot(block, &mutated); | block.hashMerkleRoot = BlockMerkleRoot(block, &mutated); | ||||
assert(!mutated); | assert(!mutated); | ||||
while (!CheckProofOfWork(block.GetHash(), block.nBits, | while (!CheckProofOfWork(block.GetHash(), block.nBits, | ||||
Params().GetConsensus())) | Params().GetConsensus())) | ||||
++block.nNonce; | ++block.nNonce; | ||||
return block; | return block; | ||||
} | } | ||||
// Number of shared use_counts we expect for a tx we havent touched | // Number of shared use_counts we expect for a tx we havent touched | ||||
// == 2 (mempool + our copy from the GetSharedTx call) | // == 2 (mempool + our copy from the GetSharedTx call) | ||||
#define SHARED_TX_OFFSET 2 | #define SHARED_TX_OFFSET 2 | ||||
BOOST_AUTO_TEST_CASE(SimpleRoundTripTest) { | BOOST_AUTO_TEST_CASE(SimpleRoundTripTest) { | ||||
CTxMemPool pool(CFeeRate(0)); | CTxMemPool pool(CFeeRate(0)); | ||||
TestMemPoolEntryHelper entry; | TestMemPoolEntryHelper entry; | ||||
CBlock block(BuildBlockTestCase()); | CBlock block(BuildBlockTestCase()); | ||||
pool.addUnchecked(block.vtx[2]->GetId(), entry.FromTx(*block.vtx[2])); | pool.addUnchecked(block.vtx[2]->GetHash(), entry.FromTx(*block.vtx[2])); | ||||
BOOST_CHECK_EQUAL( | BOOST_CHECK_EQUAL( | ||||
pool.mapTx.find(block.vtx[2]->GetId())->GetSharedTx().use_count(), | pool.mapTx.find(block.vtx[2]->GetHash())->GetSharedTx().use_count(), | ||||
SHARED_TX_OFFSET + 0); | SHARED_TX_OFFSET + 0); | ||||
// Do a simple ShortTxIDs RT | // Do a simple ShortTxHashes RT | ||||
{ | { | ||||
CBlockHeaderAndShortTxIDs shortIDs(block); | CBlockHeaderAndShortTxHashes shortIDs(block); | ||||
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); | CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); | ||||
stream << shortIDs; | stream << shortIDs; | ||||
CBlockHeaderAndShortTxIDs shortIDs2; | CBlockHeaderAndShortTxHashes shortIDs2; | ||||
stream >> shortIDs2; | stream >> shortIDs2; | ||||
PartiallyDownloadedBlock partialBlock(GetConfig(), &pool); | PartiallyDownloadedBlock partialBlock(GetConfig(), &pool); | ||||
BOOST_CHECK(partialBlock.InitData(shortIDs2, extra_txn) == | BOOST_CHECK(partialBlock.InitData(shortIDs2, extra_txn) == | ||||
READ_STATUS_OK); | READ_STATUS_OK); | ||||
BOOST_CHECK(partialBlock.IsTxAvailable(0)); | BOOST_CHECK(partialBlock.IsTxAvailable(0)); | ||||
BOOST_CHECK(!partialBlock.IsTxAvailable(1)); | BOOST_CHECK(!partialBlock.IsTxAvailable(1)); | ||||
BOOST_CHECK(partialBlock.IsTxAvailable(2)); | BOOST_CHECK(partialBlock.IsTxAvailable(2)); | ||||
BOOST_CHECK_EQUAL( | BOOST_CHECK_EQUAL( | ||||
pool.mapTx.find(block.vtx[2]->GetId())->GetSharedTx().use_count(), | pool.mapTx.find(block.vtx[2]->GetHash())->GetSharedTx().use_count(), | ||||
SHARED_TX_OFFSET + 1); | SHARED_TX_OFFSET + 1); | ||||
size_t poolSize = pool.size(); | size_t poolSize = pool.size(); | ||||
pool.removeRecursive(*block.vtx[2]); | pool.removeRecursive(*block.vtx[2]); | ||||
BOOST_CHECK_EQUAL(pool.size(), poolSize - 1); | BOOST_CHECK_EQUAL(pool.size(), poolSize - 1); | ||||
CBlock block2; | CBlock block2; | ||||
{ | { | ||||
Show All 22 Lines | // Do a simple ShortTxHashes RT | ||||
block3.GetHash().ToString()); | block3.GetHash().ToString()); | ||||
BOOST_CHECK_EQUAL(block.hashMerkleRoot.ToString(), | BOOST_CHECK_EQUAL(block.hashMerkleRoot.ToString(), | ||||
BlockMerkleRoot(block3, &mutated).ToString()); | BlockMerkleRoot(block3, &mutated).ToString()); | ||||
BOOST_CHECK(!mutated); | BOOST_CHECK(!mutated); | ||||
} | } | ||||
} | } | ||||
class TestHeaderAndShortIDs { | class TestHeaderAndShortIDs { | ||||
// Utility to encode custom CBlockHeaderAndShortTxIDs | // Utility to encode custom CBlockHeaderAndShortTxHashes | ||||
public: | public: | ||||
CBlockHeader header; | CBlockHeader header; | ||||
uint64_t nonce; | uint64_t nonce; | ||||
std::vector<uint64_t> shorttxids; | std::vector<uint64_t> shortTxHashes; | ||||
std::vector<PrefilledTransaction> prefilledtxn; | std::vector<PrefilledTransaction> prefilledtxn; | ||||
TestHeaderAndShortIDs(const CBlockHeaderAndShortTxIDs &orig) { | TestHeaderAndShortIDs(const CBlockHeaderAndShortTxHashes &orig) { | ||||
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); | CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); | ||||
stream << orig; | stream << orig; | ||||
stream >> *this; | stream >> *this; | ||||
} | } | ||||
TestHeaderAndShortIDs(const CBlock &block) | TestHeaderAndShortIDs(const CBlock &block) | ||||
: TestHeaderAndShortIDs(CBlockHeaderAndShortTxIDs(block)) {} | : TestHeaderAndShortIDs(CBlockHeaderAndShortTxHashes(block)) {} | ||||
uint64_t GetShortID(const uint256 &txhash) const { | uint64_t GetShortID(const txhash_t &txhash) const { | ||||
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); | CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); | ||||
stream << *this; | stream << *this; | ||||
CBlockHeaderAndShortTxIDs base; | CBlockHeaderAndShortTxHashes base; | ||||
stream >> base; | stream >> base; | ||||
return base.GetShortID(txhash); | return base.GetShortID(txhash); | ||||
} | } | ||||
ADD_SERIALIZE_METHODS; | ADD_SERIALIZE_METHODS; | ||||
template <typename Stream, typename Operation> | template <typename Stream, typename Operation> | ||||
inline void SerializationOp(Stream &s, Operation ser_action) { | inline void SerializationOp(Stream &s, Operation ser_action) { | ||||
READWRITE(header); | READWRITE(header); | ||||
READWRITE(nonce); | READWRITE(nonce); | ||||
size_t shorttxids_size = shorttxids.size(); | size_t shortTxHashes_size = shortTxHashes.size(); | ||||
READWRITE(VARINT(shorttxids_size)); | READWRITE(VARINT(shortTxHashes_size)); | ||||
shorttxids.resize(shorttxids_size); | shortTxHashes.resize(shortTxHashes_size); | ||||
for (size_t i = 0; i < shorttxids.size(); i++) { | for (size_t i = 0; i < shortTxHashes.size(); i++) { | ||||
uint32_t lsb = shorttxids[i] & 0xffffffff; | uint32_t lsb = shortTxHashes[i] & 0xffffffff; | ||||
uint16_t msb = (shorttxids[i] >> 32) & 0xffff; | uint16_t msb = (shortTxHashes[i] >> 32) & 0xffff; | ||||
READWRITE(lsb); | READWRITE(lsb); | ||||
READWRITE(msb); | READWRITE(msb); | ||||
shorttxids[i] = (uint64_t(msb) << 32) | uint64_t(lsb); | shortTxHashes[i] = (uint64_t(msb) << 32) | uint64_t(lsb); | ||||
} | } | ||||
READWRITE(prefilledtxn); | READWRITE(prefilledtxn); | ||||
} | } | ||||
}; | }; | ||||
BOOST_AUTO_TEST_CASE(NonCoinbasePreforwardRTTest) { | BOOST_AUTO_TEST_CASE(NonCoinbasePreforwardRTTest) { | ||||
CTxMemPool pool(CFeeRate(0)); | CTxMemPool pool(CFeeRate(0)); | ||||
TestMemPoolEntryHelper entry; | TestMemPoolEntryHelper entry; | ||||
CBlock block(BuildBlockTestCase()); | CBlock block(BuildBlockTestCase()); | ||||
pool.addUnchecked(block.vtx[2]->GetId(), entry.FromTx(*block.vtx[2])); | pool.addUnchecked(block.vtx[2]->GetHash(), entry.FromTx(*block.vtx[2])); | ||||
BOOST_CHECK_EQUAL( | BOOST_CHECK_EQUAL( | ||||
pool.mapTx.find(block.vtx[2]->GetId())->GetSharedTx().use_count(), | pool.mapTx.find(block.vtx[2]->GetHash())->GetSharedTx().use_count(), | ||||
SHARED_TX_OFFSET + 0); | SHARED_TX_OFFSET + 0); | ||||
uint256 txhash; | txhash_t txhash; | ||||
// Test with pre-forwarding tx 1, but not coinbase | // Test with pre-forwarding tx 1, but not coinbase | ||||
{ | { | ||||
TestHeaderAndShortIDs shortIDs(block); | TestHeaderAndShortIDs shortIDs(block); | ||||
shortIDs.prefilledtxn.resize(1); | shortIDs.prefilledtxn.resize(1); | ||||
shortIDs.prefilledtxn[0] = {1, block.vtx[1]}; | shortIDs.prefilledtxn[0] = {1, block.vtx[1]}; | ||||
shortIDs.shorttxids.resize(2); | shortIDs.shortTxHashes.resize(2); | ||||
shortIDs.shorttxids[0] = shortIDs.GetShortID(block.vtx[0]->GetId()); | shortIDs.shortTxHashes[0] = | ||||
shortIDs.shorttxids[1] = shortIDs.GetShortID(block.vtx[2]->GetId()); | shortIDs.GetShortID(block.vtx[0]->GetHash()); | ||||
shortIDs.shortTxHashes[1] = | |||||
shortIDs.GetShortID(block.vtx[2]->GetHash()); | |||||
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); | CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); | ||||
stream << shortIDs; | stream << shortIDs; | ||||
CBlockHeaderAndShortTxIDs shortIDs2; | CBlockHeaderAndShortTxHashes shortIDs2; | ||||
stream >> shortIDs2; | stream >> shortIDs2; | ||||
PartiallyDownloadedBlock partialBlock(GetConfig(), &pool); | PartiallyDownloadedBlock partialBlock(GetConfig(), &pool); | ||||
BOOST_CHECK(partialBlock.InitData(shortIDs2, extra_txn) == | BOOST_CHECK(partialBlock.InitData(shortIDs2, extra_txn) == | ||||
READ_STATUS_OK); | READ_STATUS_OK); | ||||
BOOST_CHECK(!partialBlock.IsTxAvailable(0)); | BOOST_CHECK(!partialBlock.IsTxAvailable(0)); | ||||
BOOST_CHECK(partialBlock.IsTxAvailable(1)); | BOOST_CHECK(partialBlock.IsTxAvailable(1)); | ||||
BOOST_CHECK(partialBlock.IsTxAvailable(2)); | BOOST_CHECK(partialBlock.IsTxAvailable(2)); | ||||
BOOST_CHECK_EQUAL( | BOOST_CHECK_EQUAL( | ||||
pool.mapTx.find(block.vtx[2]->GetId())->GetSharedTx().use_count(), | pool.mapTx.find(block.vtx[2]->GetHash())->GetSharedTx().use_count(), | ||||
SHARED_TX_OFFSET + 1); | SHARED_TX_OFFSET + 1); | ||||
CBlock block2; | CBlock block2; | ||||
{ | { | ||||
// No transactions. | // No transactions. | ||||
PartiallyDownloadedBlock tmp = partialBlock; | PartiallyDownloadedBlock tmp = partialBlock; | ||||
BOOST_CHECK(partialBlock.FillBlock(block2, {}) == | BOOST_CHECK(partialBlock.FillBlock(block2, {}) == | ||||
READ_STATUS_INVALID); | READ_STATUS_INVALID); | ||||
Show All 16 Lines | // Test with pre-forwarding tx 1, but not coinbase | ||||
BOOST_CHECK(partialBlock.FillBlock(block3, {block.vtx[0]}) == | BOOST_CHECK(partialBlock.FillBlock(block3, {block.vtx[0]}) == | ||||
READ_STATUS_OK); | READ_STATUS_OK); | ||||
BOOST_CHECK_EQUAL(block.GetHash().ToString(), | BOOST_CHECK_EQUAL(block.GetHash().ToString(), | ||||
block3.GetHash().ToString()); | block3.GetHash().ToString()); | ||||
BOOST_CHECK_EQUAL(block.hashMerkleRoot.ToString(), | BOOST_CHECK_EQUAL(block.hashMerkleRoot.ToString(), | ||||
BlockMerkleRoot(block3, &mutated).ToString()); | BlockMerkleRoot(block3, &mutated).ToString()); | ||||
BOOST_CHECK(!mutated); | BOOST_CHECK(!mutated); | ||||
txhash = block.vtx[2]->GetId(); | txhash = block.vtx[2]->GetHash(); | ||||
block.vtx.clear(); | block.vtx.clear(); | ||||
block2.vtx.clear(); | block2.vtx.clear(); | ||||
block3.vtx.clear(); | block3.vtx.clear(); | ||||
// + 1 because of partialBlockCopy. | // + 1 because of partialBlockCopy. | ||||
BOOST_CHECK_EQUAL(pool.mapTx.find(txhash)->GetSharedTx().use_count(), | BOOST_CHECK_EQUAL(pool.mapTx.find(txhash)->GetSharedTx().use_count(), | ||||
SHARED_TX_OFFSET + 1); | SHARED_TX_OFFSET + 1); | ||||
} | } | ||||
BOOST_CHECK_EQUAL(pool.mapTx.find(txhash)->GetSharedTx().use_count(), | BOOST_CHECK_EQUAL(pool.mapTx.find(txhash)->GetSharedTx().use_count(), | ||||
SHARED_TX_OFFSET + 0); | SHARED_TX_OFFSET + 0); | ||||
} | } | ||||
BOOST_AUTO_TEST_CASE(SufficientPreforwardRTTest) { | BOOST_AUTO_TEST_CASE(SufficientPreforwardRTTest) { | ||||
CTxMemPool pool(CFeeRate(0)); | CTxMemPool pool(CFeeRate(0)); | ||||
TestMemPoolEntryHelper entry; | TestMemPoolEntryHelper entry; | ||||
CBlock block(BuildBlockTestCase()); | CBlock block(BuildBlockTestCase()); | ||||
pool.addUnchecked(block.vtx[1]->GetId(), entry.FromTx(*block.vtx[1])); | pool.addUnchecked(block.vtx[1]->GetHash(), entry.FromTx(*block.vtx[1])); | ||||
BOOST_CHECK_EQUAL( | BOOST_CHECK_EQUAL( | ||||
pool.mapTx.find(block.vtx[1]->GetId())->GetSharedTx().use_count(), | pool.mapTx.find(block.vtx[1]->GetHash())->GetSharedTx().use_count(), | ||||
SHARED_TX_OFFSET + 0); | SHARED_TX_OFFSET + 0); | ||||
uint256 txhash; | txhash_t txhash; | ||||
// Test with pre-forwarding coinbase + tx 2 with tx 1 in mempool | // Test with pre-forwarding coinbase + tx 2 with tx 1 in mempool | ||||
{ | { | ||||
TestHeaderAndShortIDs shortIDs(block); | TestHeaderAndShortIDs shortIDs(block); | ||||
shortIDs.prefilledtxn.resize(2); | shortIDs.prefilledtxn.resize(2); | ||||
shortIDs.prefilledtxn[0] = {0, block.vtx[0]}; | shortIDs.prefilledtxn[0] = {0, block.vtx[0]}; | ||||
// id == 1 as it is 1 after index 1 | // id == 1 as it is 1 after index 1 | ||||
shortIDs.prefilledtxn[1] = {1, block.vtx[2]}; | shortIDs.prefilledtxn[1] = {1, block.vtx[2]}; | ||||
shortIDs.shorttxids.resize(1); | shortIDs.shortTxHashes.resize(1); | ||||
shortIDs.shorttxids[0] = shortIDs.GetShortID(block.vtx[1]->GetId()); | shortIDs.shortTxHashes[0] = | ||||
shortIDs.GetShortID(block.vtx[1]->GetHash()); | |||||
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); | CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); | ||||
stream << shortIDs; | stream << shortIDs; | ||||
CBlockHeaderAndShortTxIDs shortIDs2; | CBlockHeaderAndShortTxHashes shortIDs2; | ||||
stream >> shortIDs2; | stream >> shortIDs2; | ||||
PartiallyDownloadedBlock partialBlock(GetConfig(), &pool); | PartiallyDownloadedBlock partialBlock(GetConfig(), &pool); | ||||
BOOST_CHECK(partialBlock.InitData(shortIDs2, extra_txn) == | BOOST_CHECK(partialBlock.InitData(shortIDs2, extra_txn) == | ||||
READ_STATUS_OK); | READ_STATUS_OK); | ||||
BOOST_CHECK(partialBlock.IsTxAvailable(0)); | BOOST_CHECK(partialBlock.IsTxAvailable(0)); | ||||
BOOST_CHECK(partialBlock.IsTxAvailable(1)); | BOOST_CHECK(partialBlock.IsTxAvailable(1)); | ||||
BOOST_CHECK(partialBlock.IsTxAvailable(2)); | BOOST_CHECK(partialBlock.IsTxAvailable(2)); | ||||
BOOST_CHECK_EQUAL( | BOOST_CHECK_EQUAL( | ||||
pool.mapTx.find(block.vtx[1]->GetId())->GetSharedTx().use_count(), | pool.mapTx.find(block.vtx[1]->GetHash())->GetSharedTx().use_count(), | ||||
SHARED_TX_OFFSET + 1); | SHARED_TX_OFFSET + 1); | ||||
CBlock block2; | CBlock block2; | ||||
PartiallyDownloadedBlock partialBlockCopy = partialBlock; | PartiallyDownloadedBlock partialBlockCopy = partialBlock; | ||||
BOOST_CHECK(partialBlock.FillBlock(block2, {}) == READ_STATUS_OK); | BOOST_CHECK(partialBlock.FillBlock(block2, {}) == READ_STATUS_OK); | ||||
BOOST_CHECK_EQUAL(block.GetHash().ToString(), | BOOST_CHECK_EQUAL(block.GetHash().ToString(), | ||||
block2.GetHash().ToString()); | block2.GetHash().ToString()); | ||||
bool mutated; | bool mutated; | ||||
BOOST_CHECK_EQUAL(block.hashMerkleRoot.ToString(), | BOOST_CHECK_EQUAL(block.hashMerkleRoot.ToString(), | ||||
BlockMerkleRoot(block2, &mutated).ToString()); | BlockMerkleRoot(block2, &mutated).ToString()); | ||||
BOOST_CHECK(!mutated); | BOOST_CHECK(!mutated); | ||||
txhash = block.vtx[1]->GetId(); | txhash = block.vtx[1]->GetHash(); | ||||
block.vtx.clear(); | block.vtx.clear(); | ||||
block2.vtx.clear(); | block2.vtx.clear(); | ||||
// + 1 because of partialBlockCopy. | // + 1 because of partialBlockCopy. | ||||
BOOST_CHECK_EQUAL(pool.mapTx.find(txhash)->GetSharedTx().use_count(), | BOOST_CHECK_EQUAL(pool.mapTx.find(txhash)->GetSharedTx().use_count(), | ||||
SHARED_TX_OFFSET + 1); | SHARED_TX_OFFSET + 1); | ||||
} | } | ||||
BOOST_CHECK_EQUAL(pool.mapTx.find(txhash)->GetSharedTx().use_count(), | BOOST_CHECK_EQUAL(pool.mapTx.find(txhash)->GetSharedTx().use_count(), | ||||
Show All 19 Lines | BOOST_AUTO_TEST_CASE(EmptyBlockRoundTripTest) { | ||||
block.hashMerkleRoot = BlockMerkleRoot(block, &mutated); | block.hashMerkleRoot = BlockMerkleRoot(block, &mutated); | ||||
assert(!mutated); | assert(!mutated); | ||||
while (!CheckProofOfWork(block.GetHash(), block.nBits, | while (!CheckProofOfWork(block.GetHash(), block.nBits, | ||||
Params().GetConsensus())) | Params().GetConsensus())) | ||||
++block.nNonce; | ++block.nNonce; | ||||
// Test simple header round-trip with only coinbase | // Test simple header round-trip with only coinbase | ||||
{ | { | ||||
CBlockHeaderAndShortTxIDs shortIDs(block); | CBlockHeaderAndShortTxHashes shortIDs(block); | ||||
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); | CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); | ||||
stream << shortIDs; | stream << shortIDs; | ||||
CBlockHeaderAndShortTxIDs shortIDs2; | CBlockHeaderAndShortTxHashes shortIDs2; | ||||
stream >> shortIDs2; | stream >> shortIDs2; | ||||
PartiallyDownloadedBlock partialBlock(GetConfig(), &pool); | PartiallyDownloadedBlock partialBlock(GetConfig(), &pool); | ||||
BOOST_CHECK(partialBlock.InitData(shortIDs2, extra_txn) == | BOOST_CHECK(partialBlock.InitData(shortIDs2, extra_txn) == | ||||
READ_STATUS_OK); | READ_STATUS_OK); | ||||
BOOST_CHECK(partialBlock.IsTxAvailable(0)); | BOOST_CHECK(partialBlock.IsTxAvailable(0)); | ||||
CBlock block2; | CBlock block2; | ||||
Show All 35 Lines |