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]));
66 BOOST_CHECK_EQUAL(pool
.mapTx
.find(block
.vtx
[2]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET
+ 0);
68 // Do a simple ShortTxIDs RT
70 CBlockHeaderAndShortTxIDs
shortIDs(block
, true);
72 CDataStream
stream(SER_NETWORK
, PROTOCOL_VERSION
);
75 CBlockHeaderAndShortTxIDs shortIDs2
;
78 PartiallyDownloadedBlock
partialBlock(&pool
);
79 BOOST_CHECK(partialBlock
.InitData(shortIDs2
, extra_txn
) == READ_STATUS_OK
);
80 BOOST_CHECK( partialBlock
.IsTxAvailable(0));
81 BOOST_CHECK(!partialBlock
.IsTxAvailable(1));
82 BOOST_CHECK( partialBlock
.IsTxAvailable(2));
84 BOOST_CHECK_EQUAL(pool
.mapTx
.find(block
.vtx
[2]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET
+ 1);
86 size_t poolSize
= pool
.size();
87 pool
.removeRecursive(*block
.vtx
[2]);
88 BOOST_CHECK_EQUAL(pool
.size(), poolSize
- 1);
92 PartiallyDownloadedBlock tmp
= partialBlock
;
93 BOOST_CHECK(partialBlock
.FillBlock(block2
, {}) == READ_STATUS_INVALID
); // No transactions
99 PartiallyDownloadedBlock tmp
= partialBlock
;
100 partialBlock
.FillBlock(block2
, {block
.vtx
[2]}); // Current implementation doesn't check txn here, but don't require that
104 BOOST_CHECK(block
.hashMerkleRoot
!= BlockMerkleRoot(block2
, &mutated
));
107 BOOST_CHECK(partialBlock
.FillBlock(block3
, {block
.vtx
[1]}) == READ_STATUS_OK
);
108 BOOST_CHECK_EQUAL(block
.GetHash().ToString(), block3
.GetHash().ToString());
109 BOOST_CHECK_EQUAL(block
.hashMerkleRoot
.ToString(), BlockMerkleRoot(block3
, &mutated
).ToString());
110 BOOST_CHECK(!mutated
);
114 class TestHeaderAndShortIDs
{
115 // Utility to encode custom CBlockHeaderAndShortTxIDs
119 std::vector
<uint64_t> shorttxids
;
120 std::vector
<PrefilledTransaction
> prefilledtxn
;
122 explicit TestHeaderAndShortIDs(const CBlockHeaderAndShortTxIDs
& orig
) {
123 CDataStream
stream(SER_NETWORK
, PROTOCOL_VERSION
);
127 explicit TestHeaderAndShortIDs(const CBlock
& block
) :
128 TestHeaderAndShortIDs(CBlockHeaderAndShortTxIDs(block
, true)) {}
130 uint64_t GetShortID(const uint256
& txhash
) const {
131 CDataStream
stream(SER_NETWORK
, PROTOCOL_VERSION
);
133 CBlockHeaderAndShortTxIDs base
;
135 return base
.GetShortID(txhash
);
138 ADD_SERIALIZE_METHODS
;
140 template <typename Stream
, typename Operation
>
141 inline void SerializationOp(Stream
& s
, Operation ser_action
) {
144 size_t shorttxids_size
= shorttxids
.size();
145 READWRITE(VARINT(shorttxids_size
));
146 shorttxids
.resize(shorttxids_size
);
147 for (size_t i
= 0; i
< shorttxids
.size(); i
++) {
148 uint32_t lsb
= shorttxids
[i
] & 0xffffffff;
149 uint16_t msb
= (shorttxids
[i
] >> 32) & 0xffff;
152 shorttxids
[i
] = (uint64_t(msb
) << 32) | uint64_t(lsb
);
154 READWRITE(prefilledtxn
);
158 BOOST_AUTO_TEST_CASE(NonCoinbasePreforwardRTTest
)
161 TestMemPoolEntryHelper entry
;
162 CBlock
block(BuildBlockTestCase());
164 pool
.addUnchecked(block
.vtx
[2]->GetHash(), entry
.FromTx(*block
.vtx
[2]));
166 BOOST_CHECK_EQUAL(pool
.mapTx
.find(block
.vtx
[2]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET
+ 0);
170 // Test with pre-forwarding tx 1, but not coinbase
172 TestHeaderAndShortIDs
shortIDs(block
);
173 shortIDs
.prefilledtxn
.resize(1);
174 shortIDs
.prefilledtxn
[0] = {1, block
.vtx
[1]};
175 shortIDs
.shorttxids
.resize(2);
176 shortIDs
.shorttxids
[0] = shortIDs
.GetShortID(block
.vtx
[0]->GetHash());
177 shortIDs
.shorttxids
[1] = shortIDs
.GetShortID(block
.vtx
[2]->GetHash());
179 CDataStream
stream(SER_NETWORK
, PROTOCOL_VERSION
);
182 CBlockHeaderAndShortTxIDs shortIDs2
;
185 PartiallyDownloadedBlock
partialBlock(&pool
);
186 BOOST_CHECK(partialBlock
.InitData(shortIDs2
, extra_txn
) == READ_STATUS_OK
);
187 BOOST_CHECK(!partialBlock
.IsTxAvailable(0));
188 BOOST_CHECK( partialBlock
.IsTxAvailable(1));
189 BOOST_CHECK( partialBlock
.IsTxAvailable(2));
191 BOOST_CHECK_EQUAL(pool
.mapTx
.find(block
.vtx
[2]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET
+ 1);
195 PartiallyDownloadedBlock tmp
= partialBlock
;
196 BOOST_CHECK(partialBlock
.FillBlock(block2
, {}) == READ_STATUS_INVALID
); // No transactions
202 PartiallyDownloadedBlock tmp
= partialBlock
;
203 partialBlock
.FillBlock(block2
, {block
.vtx
[1]}); // Current implementation doesn't check txn here, but don't require that
207 BOOST_CHECK(block
.hashMerkleRoot
!= BlockMerkleRoot(block2
, &mutated
));
210 PartiallyDownloadedBlock partialBlockCopy
= partialBlock
;
211 BOOST_CHECK(partialBlock
.FillBlock(block3
, {block
.vtx
[0]}) == READ_STATUS_OK
);
212 BOOST_CHECK_EQUAL(block
.GetHash().ToString(), block3
.GetHash().ToString());
213 BOOST_CHECK_EQUAL(block
.hashMerkleRoot
.ToString(), BlockMerkleRoot(block3
, &mutated
).ToString());
214 BOOST_CHECK(!mutated
);
216 txhash
= block
.vtx
[2]->GetHash();
220 BOOST_CHECK_EQUAL(pool
.mapTx
.find(txhash
)->GetSharedTx().use_count(), SHARED_TX_OFFSET
+ 1); // + 1 because of partialBlockCopy.
222 BOOST_CHECK_EQUAL(pool
.mapTx
.find(txhash
)->GetSharedTx().use_count(), SHARED_TX_OFFSET
+ 0);
225 BOOST_AUTO_TEST_CASE(SufficientPreforwardRTTest
)
228 TestMemPoolEntryHelper entry
;
229 CBlock
block(BuildBlockTestCase());
231 pool
.addUnchecked(block
.vtx
[1]->GetHash(), entry
.FromTx(*block
.vtx
[1]));
233 BOOST_CHECK_EQUAL(pool
.mapTx
.find(block
.vtx
[1]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET
+ 0);
237 // Test with pre-forwarding coinbase + tx 2 with tx 1 in mempool
239 TestHeaderAndShortIDs
shortIDs(block
);
240 shortIDs
.prefilledtxn
.resize(2);
241 shortIDs
.prefilledtxn
[0] = {0, block
.vtx
[0]};
242 shortIDs
.prefilledtxn
[1] = {1, block
.vtx
[2]}; // id == 1 as it is 1 after index 1
243 shortIDs
.shorttxids
.resize(1);
244 shortIDs
.shorttxids
[0] = shortIDs
.GetShortID(block
.vtx
[1]->GetHash());
246 CDataStream
stream(SER_NETWORK
, PROTOCOL_VERSION
);
249 CBlockHeaderAndShortTxIDs shortIDs2
;
252 PartiallyDownloadedBlock
partialBlock(&pool
);
253 BOOST_CHECK(partialBlock
.InitData(shortIDs2
, extra_txn
) == READ_STATUS_OK
);
254 BOOST_CHECK( partialBlock
.IsTxAvailable(0));
255 BOOST_CHECK( partialBlock
.IsTxAvailable(1));
256 BOOST_CHECK( partialBlock
.IsTxAvailable(2));
258 BOOST_CHECK_EQUAL(pool
.mapTx
.find(block
.vtx
[1]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET
+ 1);
261 PartiallyDownloadedBlock partialBlockCopy
= partialBlock
;
262 BOOST_CHECK(partialBlock
.FillBlock(block2
, {}) == READ_STATUS_OK
);
263 BOOST_CHECK_EQUAL(block
.GetHash().ToString(), block2
.GetHash().ToString());
265 BOOST_CHECK_EQUAL(block
.hashMerkleRoot
.ToString(), BlockMerkleRoot(block2
, &mutated
).ToString());
266 BOOST_CHECK(!mutated
);
268 txhash
= block
.vtx
[1]->GetHash();
271 BOOST_CHECK_EQUAL(pool
.mapTx
.find(txhash
)->GetSharedTx().use_count(), SHARED_TX_OFFSET
+ 1); // + 1 because of partialBlockCopy.
273 BOOST_CHECK_EQUAL(pool
.mapTx
.find(txhash
)->GetSharedTx().use_count(), SHARED_TX_OFFSET
+ 0);
276 BOOST_AUTO_TEST_CASE(EmptyBlockRoundTripTest
)
279 CMutableTransaction coinbase
;
280 coinbase
.vin
.resize(1);
281 coinbase
.vin
[0].scriptSig
.resize(10);
282 coinbase
.vout
.resize(1);
283 coinbase
.vout
[0].nValue
= 42;
287 block
.vtx
[0] = MakeTransactionRef(std::move(coinbase
));
289 block
.hashPrevBlock
= InsecureRand256();
290 block
.nBits
= 0x207fffff;
293 block
.hashMerkleRoot
= BlockMerkleRoot(block
, &mutated
);
295 while (!CheckProofOfWork(block
.GetHash(), block
.nBits
, Params().GetConsensus())) ++block
.nNonce
;
297 // Test simple header round-trip with only coinbase
299 CBlockHeaderAndShortTxIDs
shortIDs(block
, false);
301 CDataStream
stream(SER_NETWORK
, PROTOCOL_VERSION
);
304 CBlockHeaderAndShortTxIDs shortIDs2
;
307 PartiallyDownloadedBlock
partialBlock(&pool
);
308 BOOST_CHECK(partialBlock
.InitData(shortIDs2
, extra_txn
) == READ_STATUS_OK
);
309 BOOST_CHECK(partialBlock
.IsTxAvailable(0));
312 std::vector
<CTransactionRef
> vtx_missing
;
313 BOOST_CHECK(partialBlock
.FillBlock(block2
, vtx_missing
) == READ_STATUS_OK
);
314 BOOST_CHECK_EQUAL(block
.GetHash().ToString(), block2
.GetHash().ToString());
315 BOOST_CHECK_EQUAL(block
.hashMerkleRoot
.ToString(), BlockMerkleRoot(block2
, &mutated
).ToString());
316 BOOST_CHECK(!mutated
);
320 BOOST_AUTO_TEST_CASE(TransactionsRequestSerializationTest
) {
321 BlockTransactionsRequest req1
;
322 req1
.blockhash
= InsecureRand256();
323 req1
.indexes
.resize(4);
329 CDataStream
stream(SER_NETWORK
, PROTOCOL_VERSION
);
332 BlockTransactionsRequest req2
;
335 BOOST_CHECK_EQUAL(req1
.blockhash
.ToString(), req2
.blockhash
.ToString());
336 BOOST_CHECK_EQUAL(req1
.indexes
.size(), req2
.indexes
.size());
337 BOOST_CHECK_EQUAL(req1
.indexes
[0], req2
.indexes
[0]);
338 BOOST_CHECK_EQUAL(req1
.indexes
[1], req2
.indexes
[1]);
339 BOOST_CHECK_EQUAL(req1
.indexes
[2], req2
.indexes
[2]);
340 BOOST_CHECK_EQUAL(req1
.indexes
[3], req2
.indexes
[3]);
343 BOOST_AUTO_TEST_SUITE_END()