Skip to content

Commit e3b2222

Browse files
committed
Add some blockencodings tests
1 parent f4f8f14 commit e3b2222

File tree

2 files changed

+316
-0
lines changed

2 files changed

+316
-0
lines changed

src/Makefile.test.include

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ BITCOIN_TESTS =\
4545
test/base58_tests.cpp \
4646
test/base64_tests.cpp \
4747
test/bip32_tests.cpp \
48+
test/blockencodings_tests.cpp \
4849
test/bloom_tests.cpp \
4950
test/Checkpoints_tests.cpp \
5051
test/coins_tests.cpp \

src/test/blockencodings_tests.cpp

Lines changed: 315 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,315 @@
1+
// Copyright (c) 2011-2015 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.
4+
5+
#include "blockencodings.h"
6+
#include "consensus/merkle.h"
7+
#include "chainparams.h"
8+
#include "random.h"
9+
10+
#include "test/test_bitcoin.h"
11+
12+
#include <boost/test/unit_test.hpp>
13+
14+
struct RegtestingSetup : public TestingSetup {
15+
RegtestingSetup() : TestingSetup(CBaseChainParams::REGTEST) {}
16+
};
17+
18+
BOOST_FIXTURE_TEST_SUITE(blockencodings_tests, RegtestingSetup)
19+
20+
static CBlock BuildBlockTestCase() {
21+
CBlock block;
22+
CMutableTransaction tx;
23+
tx.vin.resize(1);
24+
tx.vin[0].scriptSig.resize(10);
25+
tx.vout.resize(1);
26+
tx.vout[0].nValue = 42;
27+
28+
block.vtx.resize(3);
29+
block.vtx[0] = tx;
30+
block.nVersion = 42;
31+
block.hashPrevBlock = GetRandHash();
32+
block.nBits = 0x207fffff;
33+
34+
tx.vin[0].prevout.hash = GetRandHash();
35+
tx.vin[0].prevout.n = 0;
36+
block.vtx[1] = tx;
37+
38+
tx.vin.resize(10);
39+
for (size_t i = 0; i < tx.vin.size(); i++) {
40+
tx.vin[i].prevout.hash = GetRandHash();
41+
tx.vin[i].prevout.n = 0;
42+
}
43+
block.vtx[2] = tx;
44+
45+
bool mutated;
46+
block.hashMerkleRoot = BlockMerkleRoot(block, &mutated);
47+
assert(!mutated);
48+
while (!CheckProofOfWork(block.GetHash(), block.nBits, Params().GetConsensus())) ++block.nNonce;
49+
return block;
50+
}
51+
52+
// Number of shared use_counts we expect for a tx we havent touched
53+
// == 2 (mempool + our copy from the GetSharedTx call)
54+
#define SHARED_TX_OFFSET 2
55+
56+
BOOST_AUTO_TEST_CASE(SimpleRoundTripTest)
57+
{
58+
CTxMemPool pool(CFeeRate(0));
59+
TestMemPoolEntryHelper entry;
60+
CBlock block(BuildBlockTestCase());
61+
62+
pool.addUnchecked(block.vtx[2].GetHash(), entry.FromTx(block.vtx[2]));
63+
BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[2].GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0);
64+
65+
// Do a simple ShortTxIDs RT
66+
{
67+
CBlockHeaderAndShortTxIDs shortIDs(block);
68+
69+
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
70+
stream << shortIDs;
71+
72+
CBlockHeaderAndShortTxIDs shortIDs2;
73+
stream >> shortIDs2;
74+
75+
PartiallyDownloadedBlock partialBlock(&pool);
76+
BOOST_CHECK(partialBlock.InitData(shortIDs2) == READ_STATUS_OK);
77+
BOOST_CHECK( partialBlock.IsTxAvailable(0));
78+
BOOST_CHECK(!partialBlock.IsTxAvailable(1));
79+
BOOST_CHECK( partialBlock.IsTxAvailable(2));
80+
81+
BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[2].GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1);
82+
83+
std::list<CTransaction> removed;
84+
pool.removeRecursive(block.vtx[2], removed);
85+
BOOST_CHECK_EQUAL(removed.size(), 1);
86+
87+
CBlock block2;
88+
std::vector<CTransaction> vtx_missing;
89+
BOOST_CHECK(partialBlock.FillBlock(block2, vtx_missing) == READ_STATUS_INVALID); // No transactions
90+
91+
vtx_missing.push_back(block.vtx[2]); // Wrong transaction
92+
partialBlock.FillBlock(block2, vtx_missing); // Current implementation doesn't check txn here, but don't require that
93+
bool mutated;
94+
BOOST_CHECK(block.hashMerkleRoot != BlockMerkleRoot(block2, &mutated));
95+
96+
vtx_missing[0] = block.vtx[1];
97+
CBlock block3;
98+
BOOST_CHECK(partialBlock.FillBlock(block3, vtx_missing) == READ_STATUS_OK);
99+
BOOST_CHECK_EQUAL(block.GetHash().ToString(), block3.GetHash().ToString());
100+
BOOST_CHECK_EQUAL(block.hashMerkleRoot.ToString(), BlockMerkleRoot(block3, &mutated).ToString());
101+
BOOST_CHECK(!mutated);
102+
}
103+
}
104+
105+
class TestHeaderAndShortIDs {
106+
// Utility to encode custom CBlockHeaderAndShortTxIDs
107+
public:
108+
CBlockHeader header;
109+
uint64_t nonce;
110+
std::vector<uint64_t> shorttxids;
111+
std::vector<PrefilledTransaction> prefilledtxn;
112+
113+
TestHeaderAndShortIDs(const CBlockHeaderAndShortTxIDs& orig) {
114+
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
115+
stream << orig;
116+
stream >> *this;
117+
}
118+
TestHeaderAndShortIDs(const CBlock& block) :
119+
TestHeaderAndShortIDs(CBlockHeaderAndShortTxIDs(block)) {}
120+
121+
uint64_t GetShortID(const uint256& txhash) const {
122+
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
123+
stream << *this;
124+
CBlockHeaderAndShortTxIDs base;
125+
stream >> base;
126+
return base.GetShortID(txhash);
127+
}
128+
129+
ADD_SERIALIZE_METHODS;
130+
131+
template <typename Stream, typename Operation>
132+
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
133+
READWRITE(header);
134+
READWRITE(nonce);
135+
size_t shorttxids_size = shorttxids.size();
136+
READWRITE(VARINT(shorttxids_size));
137+
shorttxids.resize(shorttxids_size);
138+
for (size_t i = 0; i < shorttxids.size(); i++) {
139+
uint32_t lsb = shorttxids[i] & 0xffffffff;
140+
uint16_t msb = (shorttxids[i] >> 32) & 0xffff;
141+
READWRITE(lsb);
142+
READWRITE(msb);
143+
shorttxids[i] = (uint64_t(msb) << 32) | uint64_t(lsb);
144+
}
145+
READWRITE(prefilledtxn);
146+
}
147+
};
148+
149+
BOOST_AUTO_TEST_CASE(NonCoinbasePreforwardRTTest)
150+
{
151+
CTxMemPool pool(CFeeRate(0));
152+
TestMemPoolEntryHelper entry;
153+
CBlock block(BuildBlockTestCase());
154+
155+
pool.addUnchecked(block.vtx[2].GetHash(), entry.FromTx(block.vtx[2]));
156+
BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[2].GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0);
157+
158+
// Test with pre-forwarding tx 1, but not coinbase
159+
{
160+
TestHeaderAndShortIDs shortIDs(block);
161+
shortIDs.prefilledtxn.resize(1);
162+
shortIDs.prefilledtxn[0] = {1, block.vtx[1]};
163+
shortIDs.shorttxids.resize(2);
164+
shortIDs.shorttxids[0] = shortIDs.GetShortID(block.vtx[0].GetHash());
165+
shortIDs.shorttxids[1] = shortIDs.GetShortID(block.vtx[2].GetHash());
166+
167+
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
168+
stream << shortIDs;
169+
170+
CBlockHeaderAndShortTxIDs shortIDs2;
171+
stream >> shortIDs2;
172+
173+
PartiallyDownloadedBlock partialBlock(&pool);
174+
BOOST_CHECK(partialBlock.InitData(shortIDs2) == READ_STATUS_OK);
175+
BOOST_CHECK(!partialBlock.IsTxAvailable(0));
176+
BOOST_CHECK( partialBlock.IsTxAvailable(1));
177+
BOOST_CHECK( partialBlock.IsTxAvailable(2));
178+
179+
BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[2].GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1);
180+
181+
CBlock block2;
182+
std::vector<CTransaction> vtx_missing;
183+
BOOST_CHECK(partialBlock.FillBlock(block2, vtx_missing) == READ_STATUS_INVALID); // No transactions
184+
185+
vtx_missing.push_back(block.vtx[1]); // Wrong transaction
186+
partialBlock.FillBlock(block2, vtx_missing); // Current implementation doesn't check txn here, but don't require that
187+
bool mutated;
188+
BOOST_CHECK(block.hashMerkleRoot != BlockMerkleRoot(block2, &mutated));
189+
190+
vtx_missing[0] = block.vtx[0];
191+
CBlock block3;
192+
BOOST_CHECK(partialBlock.FillBlock(block3, vtx_missing) == READ_STATUS_OK);
193+
BOOST_CHECK_EQUAL(block.GetHash().ToString(), block3.GetHash().ToString());
194+
BOOST_CHECK_EQUAL(block.hashMerkleRoot.ToString(), BlockMerkleRoot(block3, &mutated).ToString());
195+
BOOST_CHECK(!mutated);
196+
197+
BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[2].GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1);
198+
}
199+
BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[2].GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0);
200+
}
201+
202+
BOOST_AUTO_TEST_CASE(SufficientPreforwardRTTest)
203+
{
204+
CTxMemPool pool(CFeeRate(0));
205+
TestMemPoolEntryHelper entry;
206+
CBlock block(BuildBlockTestCase());
207+
208+
pool.addUnchecked(block.vtx[1].GetHash(), entry.FromTx(block.vtx[1]));
209+
BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[1].GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0);
210+
211+
// Test with pre-forwarding coinbase + tx 2 with tx 1 in mempool
212+
{
213+
TestHeaderAndShortIDs shortIDs(block);
214+
shortIDs.prefilledtxn.resize(2);
215+
shortIDs.prefilledtxn[0] = {0, block.vtx[0]};
216+
shortIDs.prefilledtxn[1] = {1, block.vtx[2]}; // id == 1 as it is 1 after index 1
217+
shortIDs.shorttxids.resize(1);
218+
shortIDs.shorttxids[0] = shortIDs.GetShortID(block.vtx[1].GetHash());
219+
220+
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
221+
stream << shortIDs;
222+
223+
CBlockHeaderAndShortTxIDs shortIDs2;
224+
stream >> shortIDs2;
225+
226+
PartiallyDownloadedBlock partialBlock(&pool);
227+
BOOST_CHECK(partialBlock.InitData(shortIDs2) == READ_STATUS_OK);
228+
BOOST_CHECK( partialBlock.IsTxAvailable(0));
229+
BOOST_CHECK( partialBlock.IsTxAvailable(1));
230+
BOOST_CHECK( partialBlock.IsTxAvailable(2));
231+
232+
BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[1].GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1);
233+
234+
CBlock block2;
235+
std::vector<CTransaction> vtx_missing;
236+
BOOST_CHECK(partialBlock.FillBlock(block2, vtx_missing) == READ_STATUS_OK);
237+
BOOST_CHECK_EQUAL(block.GetHash().ToString(), block2.GetHash().ToString());
238+
bool mutated;
239+
BOOST_CHECK_EQUAL(block.hashMerkleRoot.ToString(), BlockMerkleRoot(block2, &mutated).ToString());
240+
BOOST_CHECK(!mutated);
241+
242+
BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[1].GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1);
243+
}
244+
BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[1].GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0);
245+
}
246+
247+
BOOST_AUTO_TEST_CASE(EmptyBlockRoundTripTest)
248+
{
249+
CTxMemPool pool(CFeeRate(0));
250+
CMutableTransaction coinbase;
251+
coinbase.vin.resize(1);
252+
coinbase.vin[0].scriptSig.resize(10);
253+
coinbase.vout.resize(1);
254+
coinbase.vout[0].nValue = 42;
255+
256+
CBlock block;
257+
block.vtx.resize(1);
258+
block.vtx[0] = coinbase;
259+
block.nVersion = 42;
260+
block.hashPrevBlock = GetRandHash();
261+
block.nBits = 0x207fffff;
262+
263+
bool mutated;
264+
block.hashMerkleRoot = BlockMerkleRoot(block, &mutated);
265+
assert(!mutated);
266+
while (!CheckProofOfWork(block.GetHash(), block.nBits, Params().GetConsensus())) ++block.nNonce;
267+
268+
// Test simple header round-trip with only coinbase
269+
{
270+
CBlockHeaderAndShortTxIDs shortIDs(block);
271+
272+
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
273+
stream << shortIDs;
274+
275+
CBlockHeaderAndShortTxIDs shortIDs2;
276+
stream >> shortIDs2;
277+
278+
PartiallyDownloadedBlock partialBlock(&pool);
279+
BOOST_CHECK(partialBlock.InitData(shortIDs2) == READ_STATUS_OK);
280+
BOOST_CHECK(partialBlock.IsTxAvailable(0));
281+
282+
CBlock block2;
283+
std::vector<CTransaction> vtx_missing;
284+
BOOST_CHECK(partialBlock.FillBlock(block2, vtx_missing) == READ_STATUS_OK);
285+
BOOST_CHECK_EQUAL(block.GetHash().ToString(), block2.GetHash().ToString());
286+
bool mutated;
287+
BOOST_CHECK_EQUAL(block.hashMerkleRoot.ToString(), BlockMerkleRoot(block2, &mutated).ToString());
288+
BOOST_CHECK(!mutated);
289+
}
290+
}
291+
292+
BOOST_AUTO_TEST_CASE(TransactionsRequestSerializationTest) {
293+
BlockTransactionsRequest req1;
294+
req1.blockhash = GetRandHash();
295+
req1.indexes.resize(4);
296+
req1.indexes[0] = 0;
297+
req1.indexes[1] = 1;
298+
req1.indexes[2] = 3;
299+
req1.indexes[3] = 4;
300+
301+
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
302+
stream << req1;
303+
304+
BlockTransactionsRequest req2;
305+
stream >> req2;
306+
307+
BOOST_CHECK_EQUAL(req1.blockhash.ToString(), req2.blockhash.ToString());
308+
BOOST_CHECK_EQUAL(req1.indexes.size(), req2.indexes.size());
309+
BOOST_CHECK_EQUAL(req1.indexes[0], req2.indexes[0]);
310+
BOOST_CHECK_EQUAL(req1.indexes[1], req2.indexes[1]);
311+
BOOST_CHECK_EQUAL(req1.indexes[2], req2.indexes[2]);
312+
BOOST_CHECK_EQUAL(req1.indexes[3], req2.indexes[3]);
313+
}
314+
315+
BOOST_AUTO_TEST_SUITE_END()

0 commit comments

Comments
 (0)