1 // Copyright (c) 2011-2016 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 #include "blockencodings.h"
6 #include "consensus/merkle.h"
7 #include "chainparams.h"
10 #include "test/test_bitcoin.h"
12 #include <boost/test/unit_test.hpp>
14 std::vector
<std::pair
<uint256
, CTransactionRef
>> extra_txn
;
16 struct RegtestingSetup
: public TestingSetup
{
17 RegtestingSetup() : TestingSetup(CBaseChainParams::REGTEST
) {}
20 BOOST_FIXTURE_TEST_SUITE(blockencodings_tests
, RegtestingSetup
)
22 static CBlock
BuildBlockTestCase() {
24 CMutableTransaction tx
;
26 tx
.vin
[0].scriptSig
.resize(10);
28 tx
.vout
[0].nValue
= 42;
31 block
.vtx
[0] = MakeTransactionRef(tx
);
33 block
.hashPrevBlock
= InsecureRand256();
34 block
.nBits
= 0x207fffff;
36 tx
.vin
[0].prevout
.hash
= InsecureRand256();
37 tx
.vin
[0].prevout
.n
= 0;
38 block
.vtx
[1] = MakeTransactionRef(tx
);
41 for (size_t i
= 0; i
< tx
.vin
.size(); i
++) {
42 tx
.vin
[i
].prevout
.hash
= InsecureRand256();
43 tx
.vin
[i
].prevout
.n
= 0;
45 block
.vtx
[2] = MakeTransactionRef(tx
);
48 block
.hashMerkleRoot
= BlockMerkleRoot(block
, &mutated
);
50 while (!CheckProofOfWork(block
.GetHash(), block
.nBits
, Params().GetConsensus())) ++block
.nNonce
;
54 // Number of shared use_counts we expect for a tx we haven't touched
55 // == 2 (mempool + our copy from the GetSharedTx call)
56 #define SHARED_TX_OFFSET 2
58 BOOST_AUTO_TEST_CASE(SimpleRoundTripTest
)
61 TestMemPoolEntryHelper entry
;
62 CBlock
block(BuildBlockTestCase());
64 pool
.addUnchecked(block
.vtx
[2]->GetHash(), entry
.FromTx(*block
.vtx
[2]));
65 BOOST_CHECK_EQUAL(pool
.mapTx
.find(block
.vtx
[2]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET
+ 0);
67 // Do a simple ShortTxIDs RT
69 CBlockHeaderAndShortTxIDs
shortIDs(block
, true);
71 CDataStream
stream(SER_NETWORK
, PROTOCOL_VERSION
);
74 CBlockHeaderAndShortTxIDs shortIDs2
;
77 PartiallyDownloadedBlock
partialBlock(&pool
);
78 BOOST_CHECK(partialBlock
.InitData(shortIDs2
, extra_txn
) == READ_STATUS_OK
);
79 BOOST_CHECK( partialBlock
.IsTxAvailable(0));
80 BOOST_CHECK(!partialBlock
.IsTxAvailable(1));
81 BOOST_CHECK( partialBlock
.IsTxAvailable(2));
83 BOOST_CHECK_EQUAL(pool
.mapTx
.find(block
.vtx
[2]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET
+ 1);
85 size_t poolSize
= pool
.size();
86 pool
.removeRecursive(*block
.vtx
[2]);
87 BOOST_CHECK_EQUAL(pool
.size(), poolSize
- 1);
91 PartiallyDownloadedBlock tmp
= partialBlock
;
92 BOOST_CHECK(partialBlock
.FillBlock(block2
, {}) == READ_STATUS_INVALID
); // No transactions
98 PartiallyDownloadedBlock tmp
= partialBlock
;
99 partialBlock
.FillBlock(block2
, {block
.vtx
[2]}); // Current implementation doesn't check txn here, but don't require that
103 BOOST_CHECK(block
.hashMerkleRoot
!= BlockMerkleRoot(block2
, &mutated
));
106 BOOST_CHECK(partialBlock
.FillBlock(block3
, {block
.vtx
[1]}) == READ_STATUS_OK
);
107 BOOST_CHECK_EQUAL(block
.GetHash().ToString(), block3
.GetHash().ToString());
108 BOOST_CHECK_EQUAL(block
.hashMerkleRoot
.ToString(), BlockMerkleRoot(block3
, &mutated
).ToString());
109 BOOST_CHECK(!mutated
);
113 class TestHeaderAndShortIDs
{
114 // Utility to encode custom CBlockHeaderAndShortTxIDs
118 std::vector
<uint64_t> shorttxids
;
119 std::vector
<PrefilledTransaction
> prefilledtxn
;
121 explicit TestHeaderAndShortIDs(const CBlockHeaderAndShortTxIDs
& orig
) {
122 CDataStream
stream(SER_NETWORK
, PROTOCOL_VERSION
);
126 explicit TestHeaderAndShortIDs(const CBlock
& block
) :
127 TestHeaderAndShortIDs(CBlockHeaderAndShortTxIDs(block
, true)) {}
129 uint64_t GetShortID(const uint256
& txhash
) const {
130 CDataStream
stream(SER_NETWORK
, PROTOCOL_VERSION
);
132 CBlockHeaderAndShortTxIDs base
;
134 return base
.GetShortID(txhash
);
137 ADD_SERIALIZE_METHODS
;
139 template <typename Stream
, typename Operation
>
140 inline void SerializationOp(Stream
& s
, Operation ser_action
) {
143 size_t shorttxids_size
= shorttxids
.size();
144 READWRITE(VARINT(shorttxids_size
));
145 shorttxids
.resize(shorttxids_size
);
146 for (size_t i
= 0; i
< shorttxids
.size(); i
++) {
147 uint32_t lsb
= shorttxids
[i
] & 0xffffffff;
148 uint16_t msb
= (shorttxids
[i
] >> 32) & 0xffff;
151 shorttxids
[i
] = (uint64_t(msb
) << 32) | uint64_t(lsb
);
153 READWRITE(prefilledtxn
);
157 BOOST_AUTO_TEST_CASE(NonCoinbasePreforwardRTTest
)
160 TestMemPoolEntryHelper entry
;
161 CBlock
block(BuildBlockTestCase());
163 pool
.addUnchecked(block
.vtx
[2]->GetHash(), entry
.FromTx(*block
.vtx
[2]));
164 BOOST_CHECK_EQUAL(pool
.mapTx
.find(block
.vtx
[2]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET
+ 0);
168 // Test with pre-forwarding tx 1, but not coinbase
170 TestHeaderAndShortIDs
shortIDs(block
);
171 shortIDs
.prefilledtxn
.resize(1);
172 shortIDs
.prefilledtxn
[0] = {1, block
.vtx
[1]};
173 shortIDs
.shorttxids
.resize(2);
174 shortIDs
.shorttxids
[0] = shortIDs
.GetShortID(block
.vtx
[0]->GetHash());
175 shortIDs
.shorttxids
[1] = shortIDs
.GetShortID(block
.vtx
[2]->GetHash());
177 CDataStream
stream(SER_NETWORK
, PROTOCOL_VERSION
);
180 CBlockHeaderAndShortTxIDs shortIDs2
;
183 PartiallyDownloadedBlock
partialBlock(&pool
);
184 BOOST_CHECK(partialBlock
.InitData(shortIDs2
, extra_txn
) == READ_STATUS_OK
);
185 BOOST_CHECK(!partialBlock
.IsTxAvailable(0));
186 BOOST_CHECK( partialBlock
.IsTxAvailable(1));
187 BOOST_CHECK( partialBlock
.IsTxAvailable(2));
189 BOOST_CHECK_EQUAL(pool
.mapTx
.find(block
.vtx
[2]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET
+ 1);
193 PartiallyDownloadedBlock tmp
= partialBlock
;
194 BOOST_CHECK(partialBlock
.FillBlock(block2
, {}) == READ_STATUS_INVALID
); // No transactions
200 PartiallyDownloadedBlock tmp
= partialBlock
;
201 partialBlock
.FillBlock(block2
, {block
.vtx
[1]}); // Current implementation doesn't check txn here, but don't require that
205 BOOST_CHECK(block
.hashMerkleRoot
!= BlockMerkleRoot(block2
, &mutated
));
208 PartiallyDownloadedBlock partialBlockCopy
= partialBlock
;
209 BOOST_CHECK(partialBlock
.FillBlock(block3
, {block
.vtx
[0]}) == READ_STATUS_OK
);
210 BOOST_CHECK_EQUAL(block
.GetHash().ToString(), block3
.GetHash().ToString());
211 BOOST_CHECK_EQUAL(block
.hashMerkleRoot
.ToString(), BlockMerkleRoot(block3
, &mutated
).ToString());
212 BOOST_CHECK(!mutated
);
214 txhash
= block
.vtx
[2]->GetHash();
218 BOOST_CHECK_EQUAL(pool
.mapTx
.find(txhash
)->GetSharedTx().use_count(), SHARED_TX_OFFSET
+ 1); // + 1 because of partialBlockCopy.
220 BOOST_CHECK_EQUAL(pool
.mapTx
.find(txhash
)->GetSharedTx().use_count(), SHARED_TX_OFFSET
+ 0);
223 BOOST_AUTO_TEST_CASE(SufficientPreforwardRTTest
)
226 TestMemPoolEntryHelper entry
;
227 CBlock
block(BuildBlockTestCase());
229 pool
.addUnchecked(block
.vtx
[1]->GetHash(), entry
.FromTx(*block
.vtx
[1]));
230 BOOST_CHECK_EQUAL(pool
.mapTx
.find(block
.vtx
[1]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET
+ 0);
234 // Test with pre-forwarding coinbase + tx 2 with tx 1 in mempool
236 TestHeaderAndShortIDs
shortIDs(block
);
237 shortIDs
.prefilledtxn
.resize(2);
238 shortIDs
.prefilledtxn
[0] = {0, block
.vtx
[0]};
239 shortIDs
.prefilledtxn
[1] = {1, block
.vtx
[2]}; // id == 1 as it is 1 after index 1
240 shortIDs
.shorttxids
.resize(1);
241 shortIDs
.shorttxids
[0] = shortIDs
.GetShortID(block
.vtx
[1]->GetHash());
243 CDataStream
stream(SER_NETWORK
, PROTOCOL_VERSION
);
246 CBlockHeaderAndShortTxIDs shortIDs2
;
249 PartiallyDownloadedBlock
partialBlock(&pool
);
250 BOOST_CHECK(partialBlock
.InitData(shortIDs2
, extra_txn
) == READ_STATUS_OK
);
251 BOOST_CHECK( partialBlock
.IsTxAvailable(0));
252 BOOST_CHECK( partialBlock
.IsTxAvailable(1));
253 BOOST_CHECK( partialBlock
.IsTxAvailable(2));
255 BOOST_CHECK_EQUAL(pool
.mapTx
.find(block
.vtx
[1]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET
+ 1);
258 PartiallyDownloadedBlock partialBlockCopy
= partialBlock
;
259 BOOST_CHECK(partialBlock
.FillBlock(block2
, {}) == READ_STATUS_OK
);
260 BOOST_CHECK_EQUAL(block
.GetHash().ToString(), block2
.GetHash().ToString());
262 BOOST_CHECK_EQUAL(block
.hashMerkleRoot
.ToString(), BlockMerkleRoot(block2
, &mutated
).ToString());
263 BOOST_CHECK(!mutated
);
265 txhash
= block
.vtx
[1]->GetHash();
268 BOOST_CHECK_EQUAL(pool
.mapTx
.find(txhash
)->GetSharedTx().use_count(), SHARED_TX_OFFSET
+ 1); // + 1 because of partialBlockCopy.
270 BOOST_CHECK_EQUAL(pool
.mapTx
.find(txhash
)->GetSharedTx().use_count(), SHARED_TX_OFFSET
+ 0);
273 BOOST_AUTO_TEST_CASE(EmptyBlockRoundTripTest
)
276 CMutableTransaction coinbase
;
277 coinbase
.vin
.resize(1);
278 coinbase
.vin
[0].scriptSig
.resize(10);
279 coinbase
.vout
.resize(1);
280 coinbase
.vout
[0].nValue
= 42;
284 block
.vtx
[0] = MakeTransactionRef(std::move(coinbase
));
286 block
.hashPrevBlock
= InsecureRand256();
287 block
.nBits
= 0x207fffff;
290 block
.hashMerkleRoot
= BlockMerkleRoot(block
, &mutated
);
292 while (!CheckProofOfWork(block
.GetHash(), block
.nBits
, Params().GetConsensus())) ++block
.nNonce
;
294 // Test simple header round-trip with only coinbase
296 CBlockHeaderAndShortTxIDs
shortIDs(block
, false);
298 CDataStream
stream(SER_NETWORK
, PROTOCOL_VERSION
);
301 CBlockHeaderAndShortTxIDs shortIDs2
;
304 PartiallyDownloadedBlock
partialBlock(&pool
);
305 BOOST_CHECK(partialBlock
.InitData(shortIDs2
, extra_txn
) == READ_STATUS_OK
);
306 BOOST_CHECK(partialBlock
.IsTxAvailable(0));
309 std::vector
<CTransactionRef
> vtx_missing
;
310 BOOST_CHECK(partialBlock
.FillBlock(block2
, vtx_missing
) == READ_STATUS_OK
);
311 BOOST_CHECK_EQUAL(block
.GetHash().ToString(), block2
.GetHash().ToString());
312 BOOST_CHECK_EQUAL(block
.hashMerkleRoot
.ToString(), BlockMerkleRoot(block2
, &mutated
).ToString());
313 BOOST_CHECK(!mutated
);
317 BOOST_AUTO_TEST_CASE(TransactionsRequestSerializationTest
) {
318 BlockTransactionsRequest req1
;
319 req1
.blockhash
= InsecureRand256();
320 req1
.indexes
.resize(4);
326 CDataStream
stream(SER_NETWORK
, PROTOCOL_VERSION
);
329 BlockTransactionsRequest req2
;
332 BOOST_CHECK_EQUAL(req1
.blockhash
.ToString(), req2
.blockhash
.ToString());
333 BOOST_CHECK_EQUAL(req1
.indexes
.size(), req2
.indexes
.size());
334 BOOST_CHECK_EQUAL(req1
.indexes
[0], req2
.indexes
[0]);
335 BOOST_CHECK_EQUAL(req1
.indexes
[1], req2
.indexes
[1]);
336 BOOST_CHECK_EQUAL(req1
.indexes
[2], req2
.indexes
[2]);
337 BOOST_CHECK_EQUAL(req1
.indexes
[3], req2
.indexes
[3]);
340 BOOST_AUTO_TEST_SUITE_END()