aboutsummaryrefslogtreecommitdiff
path: root/src/test/pmt_tests.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/pmt_tests.cpp')
-rw-r--r--src/test/pmt_tests.cpp98
1 files changed, 98 insertions, 0 deletions
diff --git a/src/test/pmt_tests.cpp b/src/test/pmt_tests.cpp
new file mode 100644
index 0000000000..cf09421617
--- /dev/null
+++ b/src/test/pmt_tests.cpp
@@ -0,0 +1,98 @@
+#include <boost/test/unit_test.hpp>
+
+#include "uint256.h"
+#include "main.h"
+
+using namespace std;
+
+class CPartialMerkleTreeTester : public CPartialMerkleTree
+{
+public:
+ // flip one bit in one of the hashes - this should break the authentication
+ void Damage() {
+ unsigned int n = rand() % vHash.size();
+ int bit = rand() % 256;
+ uint256 &hash = vHash[n];
+ hash ^= ((uint256)1 << bit);
+ }
+};
+
+BOOST_AUTO_TEST_SUITE(pmt_tests)
+
+BOOST_AUTO_TEST_CASE(pmt_test1)
+{
+ static const unsigned int nTxCounts[] = {1, 4, 7, 17, 56, 100, 127, 256, 312, 513, 1000, 4095};
+
+ for (int n = 0; n < 12; n++) {
+ unsigned int nTx = nTxCounts[n];
+
+ // build a block with some dummy transactions
+ CBlock block;
+ for (unsigned int j=0; j<nTx; j++) {
+ CTransaction tx;
+ tx.nLockTime = rand(); // actual transaction data doesn't matter; just make the nLockTime's unique
+ block.vtx.push_back(tx);
+ }
+
+ // calculate actual merkle root and height
+ uint256 merkleRoot1 = block.BuildMerkleTree();
+ std::vector<uint256> vTxid(nTx, 0);
+ for (unsigned int j=0; j<nTx; j++)
+ vTxid[j] = block.vtx[j].GetHash();
+ int nHeight = 1, nTx_ = nTx;
+ while (nTx_ > 1) {
+ nTx_ = (nTx_+1)/2;
+ nHeight++;
+ }
+
+ // check with random subsets with inclusion chances 1, 1/2, 1/4, ..., 1/128
+ for (int att = 1; att < 15; att++) {
+ // build random subset of txid's
+ std::vector<bool> vMatch(nTx, false);
+ std::vector<uint256> vMatchTxid1;
+ for (unsigned int j=0; j<nTx; j++) {
+ bool fInclude = (rand() & ((1 << (att/2)) - 1)) == 0;
+ vMatch[j] = fInclude;
+ if (fInclude)
+ vMatchTxid1.push_back(vTxid[j]);
+ }
+
+ // build the partial merkle tree
+ CPartialMerkleTree pmt1(vTxid, vMatch);
+
+ // serialize
+ CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
+ ss << pmt1;
+
+ // verify CPartialMerkleTree's size guarantees
+ unsigned int n = std::min<unsigned int>(nTx, 1 + vMatchTxid1.size()*nHeight);
+ BOOST_CHECK(ss.size() <= 10 + (258*n+7)/8);
+
+ // deserialize into a tester copy
+ CPartialMerkleTreeTester pmt2;
+ ss >> pmt2;
+
+ // extract merkle root and matched txids from copy
+ std::vector<uint256> vMatchTxid2;
+ uint256 merkleRoot2 = pmt2.ExtractMatches(vMatchTxid2);
+
+ // check that it has the same merkle root as the original, and a valid one
+ BOOST_CHECK(merkleRoot1 == merkleRoot2);
+ BOOST_CHECK(merkleRoot2 != 0);
+
+ // check that it contains the matched transactions (in the same order!)
+ BOOST_CHECK(vMatchTxid1 == vMatchTxid2);
+
+ // check that random bit flips break the authentication
+ for (int j=0; j<4; j++) {
+ CPartialMerkleTreeTester pmt3(pmt2);
+ pmt3.Damage();
+ std::vector<uint256> vMatchTxid3;
+ uint256 merkleRoot3 = pmt3.ExtractMatches(vMatchTxid3);
+ BOOST_CHECK(merkleRoot3 != merkleRoot1);
+ }
+ }
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()