Changeset View
Changeset View
Standalone View
Standalone View
src/test/pmt_tests.cpp
Show First 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | for (int i = 0; i < 12; i++) { | ||||
// actual transaction data doesn't matter; just make the nLockTime's | // actual transaction data doesn't matter; just make the nLockTime's | ||||
// unique | // unique | ||||
tx.nLockTime = j; | tx.nLockTime = j; | ||||
block.vtx.push_back(MakeTransactionRef(std::move(tx))); | block.vtx.push_back(MakeTransactionRef(std::move(tx))); | ||||
} | } | ||||
// calculate actual merkle root and height | // calculate actual merkle root and height | ||||
uint256 merkleRoot1 = BlockMerkleRoot(block); | uint256 merkleRoot1 = BlockMerkleRoot(block); | ||||
std::vector<uint256> vTxid(nTx, uint256()); | std::vector<uint256> vTxhash(nTx, uint256()); | ||||
for (unsigned int j = 0; j < nTx; j++) | for (unsigned int j = 0; j < nTx; j++) | ||||
vTxid[j] = block.vtx[j]->GetId(); | vTxhash[j] = block.vtx[j]->GetHash(); | ||||
int nHeight = 1, nTx_ = nTx; | int nHeight = 1, nTx_ = nTx; | ||||
while (nTx_ > 1) { | while (nTx_ > 1) { | ||||
nTx_ = (nTx_ + 1) / 2; | nTx_ = (nTx_ + 1) / 2; | ||||
nHeight++; | nHeight++; | ||||
} | } | ||||
// check with random subsets with inclusion chances 1, 1/2, 1/4, ..., | // check with random subsets with inclusion chances 1, 1/2, 1/4, ..., | ||||
// 1/128 | // 1/128 | ||||
for (int att = 1; att < 15; att++) { | for (int att = 1; att < 15; att++) { | ||||
// build random subset of txid's | // build random subset of txhashes | ||||
std::vector<bool> vMatch(nTx, false); | std::vector<bool> vMatch(nTx, false); | ||||
std::vector<uint256> vMatchTxid1; | std::vector<uint256> vMatchTxhash1; | ||||
for (unsigned int j = 0; j < nTx; j++) { | for (unsigned int j = 0; j < nTx; j++) { | ||||
bool fInclude = (insecure_rand() & ((1 << (att / 2)) - 1)) == 0; | bool fInclude = (insecure_rand() & ((1 << (att / 2)) - 1)) == 0; | ||||
vMatch[j] = fInclude; | vMatch[j] = fInclude; | ||||
if (fInclude) vMatchTxid1.push_back(vTxid[j]); | if (fInclude) vMatchTxhash1.push_back(vTxhash[j]); | ||||
} | } | ||||
// build the partial merkle tree | // build the partial merkle tree | ||||
CPartialMerkleTree pmt1(vTxid, vMatch); | CPartialMerkleTree pmt1(vTxhash, vMatch); | ||||
// serialize | // serialize | ||||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); | CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); | ||||
ss << pmt1; | ss << pmt1; | ||||
// verify CPartialMerkleTree's size guarantees | // verify CPartialMerkleTree's size guarantees | ||||
unsigned int n = | unsigned int n = | ||||
std::min<unsigned int>(nTx, 1 + vMatchTxid1.size() * nHeight); | std::min<unsigned int>(nTx, 1 + vMatchTxhash1.size() * nHeight); | ||||
BOOST_CHECK(ss.size() <= 10 + (258 * n + 7) / 8); | BOOST_CHECK(ss.size() <= 10 + (258 * n + 7) / 8); | ||||
// deserialize into a tester copy | // deserialize into a tester copy | ||||
CPartialMerkleTreeTester pmt2; | CPartialMerkleTreeTester pmt2; | ||||
ss >> pmt2; | ss >> pmt2; | ||||
// extract merkle root and matched txids from copy | // extract merkle root and matched txhashes from copy | ||||
std::vector<uint256> vMatchTxid2; | std::vector<uint256> vMatchTxhash2; | ||||
std::vector<unsigned int> vIndex; | std::vector<unsigned int> vIndex; | ||||
uint256 merkleRoot2 = pmt2.ExtractMatches(vMatchTxid2, vIndex); | uint256 merkleRoot2 = pmt2.ExtractMatches(vMatchTxhash2, vIndex); | ||||
// check that it has the same merkle root as the original, and a | // check that it has the same merkle root as the original, and a | ||||
// valid one | // valid one | ||||
BOOST_CHECK(merkleRoot1 == merkleRoot2); | BOOST_CHECK(merkleRoot1 == merkleRoot2); | ||||
BOOST_CHECK(!merkleRoot2.IsNull()); | BOOST_CHECK(!merkleRoot2.IsNull()); | ||||
// check that it contains the matched transactions (in the same | // check that it contains the matched transactions (in the same | ||||
// order!) | // order!) | ||||
BOOST_CHECK(vMatchTxid1 == vMatchTxid2); | BOOST_CHECK(vMatchTxhash1 == vMatchTxhash2); | ||||
// check that random bit flips break the authentication | // check that random bit flips break the authentication | ||||
for (int j = 0; j < 4; j++) { | for (int j = 0; j < 4; j++) { | ||||
CPartialMerkleTreeTester pmt3(pmt2); | CPartialMerkleTreeTester pmt3(pmt2); | ||||
pmt3.Damage(); | pmt3.Damage(); | ||||
std::vector<uint256> vMatchTxid3; | std::vector<uint256> vMatchTxhash3; | ||||
uint256 merkleRoot3 = pmt3.ExtractMatches(vMatchTxid3, vIndex); | uint256 merkleRoot3 = | ||||
pmt3.ExtractMatches(vMatchTxhash3, vIndex); | |||||
BOOST_CHECK(merkleRoot3 != merkleRoot1); | BOOST_CHECK(merkleRoot3 != merkleRoot1); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } | ||||
BOOST_AUTO_TEST_CASE(pmt_malleability) { | BOOST_AUTO_TEST_CASE(pmt_malleability) { | ||||
std::vector<uint256> vTxid = { | std::vector<uint256> vTxhash = { | ||||
ArithToUint256(1), ArithToUint256(2), ArithToUint256(3), | ArithToUint256(1), ArithToUint256(2), ArithToUint256(3), | ||||
ArithToUint256(4), ArithToUint256(5), ArithToUint256(6), | ArithToUint256(4), ArithToUint256(5), ArithToUint256(6), | ||||
ArithToUint256(7), ArithToUint256(8), ArithToUint256(9), | ArithToUint256(7), ArithToUint256(8), ArithToUint256(9), | ||||
ArithToUint256(10), ArithToUint256(9), ArithToUint256(10)}; | ArithToUint256(10), ArithToUint256(9), ArithToUint256(10)}; | ||||
std::vector<bool> vMatch = {false, false, false, false, false, false, | std::vector<bool> vMatch = {false, false, false, false, false, false, | ||||
false, false, false, true, true, false}; | false, false, false, true, true, false}; | ||||
CPartialMerkleTree tree(vTxid, vMatch); | CPartialMerkleTree tree(vTxhash, vMatch); | ||||
std::vector<unsigned int> vIndex; | std::vector<unsigned int> vIndex; | ||||
BOOST_CHECK(tree.ExtractMatches(vTxid, vIndex).IsNull()); | BOOST_CHECK(tree.ExtractMatches(vTxhash, vIndex).IsNull()); | ||||
} | } | ||||
BOOST_AUTO_TEST_SUITE_END() | BOOST_AUTO_TEST_SUITE_END() |