Merge rust-bitcoin/rust-bitcoin#1217: Add multithreading for the pmt_tests execution
f924e1451e
Enhance pmt_tests execution time (hrouis) Pull request description: An attempt to enhance pmt_tests execution time. fixes: https://github.com/rust-bitcoin/rust-bitcoin/issues/1214 cargo test result : > test result: ok. 356 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 5.74s ACKs for top commit: Kixunil: ACKf924e1451e
RCasatta: ACKf924e1451e
tcharding: ACKf924e1451e
apoelstra: utACKf924e1451e
Tree-SHA512: d8341778aa7b9e09014d3392962a9bf844fe7870c158d835f667161d6da2e741ba42088c053979fd76154a89996aaa02f8dcb7c1705271d9dff8e10248931459
This commit is contained in:
commit
75949355a4
|
@ -532,81 +532,94 @@ mod tests {
|
||||||
use crate::util::merkleblock::{MerkleBlock, PartialMerkleTree};
|
use crate::util::merkleblock::{MerkleBlock, PartialMerkleTree};
|
||||||
use crate::Block;
|
use crate::Block;
|
||||||
|
|
||||||
#[test]
|
/// accepts `pmt_test_$num`
|
||||||
fn pmt_tests() {
|
fn pmt_test_from_name(name: &str) {
|
||||||
|
pmt_test(name[9..].parse().unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! pmt_tests {
|
||||||
|
($($name:ident),* $(,)?) => {
|
||||||
|
$(
|
||||||
|
#[test]
|
||||||
|
fn $name() {
|
||||||
|
pmt_test_from_name(stringify!($name));
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pmt_tests!(pmt_test_1, pmt_test_4, pmt_test_7, pmt_test_17, pmt_test_56, pmt_test_100,
|
||||||
|
pmt_test_127, pmt_test_256, pmt_test_312, pmt_test_513, pmt_test_1000, pmt_test_4095);
|
||||||
|
|
||||||
|
fn pmt_test(tx_count: usize) {
|
||||||
let mut rng = thread_rng();
|
let mut rng = thread_rng();
|
||||||
let tx_counts = vec![1, 4, 7, 17, 56, 100, 127, 256, 312, 513, 1000, 4095];
|
// Create some fake tx ids
|
||||||
|
let tx_ids = (1..=tx_count)
|
||||||
|
.map(|i| Txid::from_hex(&format!("{:064x}", i)).unwrap())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
for num_tx in tx_counts {
|
// Calculate the merkle root and height
|
||||||
// Create some fake tx ids
|
let hashes = tx_ids.iter().map(|t| t.as_hash());
|
||||||
let txids = (1..num_tx + 1) // change to `1..=num_tx` when min Rust >= 1.26.0
|
let merkle_root_1: TxMerkleNode = bitcoin_merkle_root(hashes).expect("hashes is not empty").into();
|
||||||
.map(|i| Txid::from_hex(&format!("{:064x}", i)).unwrap())
|
let mut height = 1;
|
||||||
.collect::<Vec<_>>();
|
let mut ntx = tx_count;
|
||||||
|
while ntx > 1 {
|
||||||
|
ntx = (ntx + 1) / 2;
|
||||||
|
height += 1;
|
||||||
|
}
|
||||||
|
|
||||||
// Calculate the merkle root and height
|
// Check with random subsets with inclusion chances 1, 1/2, 1/4, ..., 1/128
|
||||||
let hashes = txids.iter().map(|t| t.as_hash());
|
for att in 1..15 {
|
||||||
let merkle_root_1: TxMerkleNode = bitcoin_merkle_root(hashes).expect("hashes is not empty").into();
|
let mut matches = vec![false; tx_count];
|
||||||
let mut height = 1;
|
let mut match_txid1 = vec![];
|
||||||
let mut ntx = num_tx;
|
for j in 0..tx_count {
|
||||||
while ntx > 1 {
|
// Generate `att / 2` random bits
|
||||||
ntx = (ntx + 1) / 2;
|
let rand_bits = match att / 2 {
|
||||||
height += 1;
|
0 => 0,
|
||||||
|
bits => rng.gen::<u64>() >> (64 - bits),
|
||||||
|
};
|
||||||
|
let include = rand_bits == 0;
|
||||||
|
matches[j] = include;
|
||||||
|
|
||||||
|
if include {
|
||||||
|
match_txid1.push(tx_ids[j]);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check with random subsets with inclusion chances 1, 1/2, 1/4, ..., 1/128
|
// Build the partial merkle tree
|
||||||
for att in 1..15 {
|
let pmt1 = PartialMerkleTree::from_txids(&tx_ids, &matches);
|
||||||
let mut matches = vec![false; num_tx];
|
let serialized = serialize(&pmt1);
|
||||||
let mut match_txid1 = vec![];
|
|
||||||
for j in 0..num_tx {
|
|
||||||
// Generate `att / 2` random bits
|
|
||||||
let rand_bits = match att / 2 {
|
|
||||||
0 => 0,
|
|
||||||
bits => rng.gen::<u64>() >> (64 - bits),
|
|
||||||
};
|
|
||||||
let include = rand_bits == 0;
|
|
||||||
matches[j] = include;
|
|
||||||
|
|
||||||
if include {
|
// Verify PartialMerkleTree's size guarantees
|
||||||
match_txid1.push(txids[j]);
|
let n = min(tx_count, 1 + match_txid1.len() * height);
|
||||||
};
|
assert!(serialized.len() <= 10 + (258 * n + 7) / 8);
|
||||||
}
|
|
||||||
|
|
||||||
// Build the partial merkle tree
|
// Deserialize into a tester copy
|
||||||
let pmt1 = PartialMerkleTree::from_txids(&txids, &matches);
|
let pmt2: PartialMerkleTree =
|
||||||
let serialized = serialize(&pmt1);
|
deserialize(&serialized).expect("Could not deserialize own data");
|
||||||
|
|
||||||
// Verify PartialMerkleTree's size guarantees
|
// Extract merkle root and matched txids from copy
|
||||||
let n = min(num_tx, 1 + match_txid1.len() * height);
|
let mut match_txid2: Vec<Txid> = vec![];
|
||||||
assert!(serialized.len() <= 10 + (258 * n + 7) / 8);
|
let mut indexes = vec![];
|
||||||
|
let merkle_root_2 = pmt2
|
||||||
|
.extract_matches(&mut match_txid2, &mut indexes)
|
||||||
|
.expect("Could not extract matches");
|
||||||
|
|
||||||
// Deserialize into a tester copy
|
// Check that it has the same merkle root as the original, and a valid one
|
||||||
let pmt2: PartialMerkleTree =
|
assert_eq!(merkle_root_1, merkle_root_2);
|
||||||
deserialize(&serialized).expect("Could not deserialize own data");
|
assert_ne!(merkle_root_2, TxMerkleNode::all_zeros());
|
||||||
|
|
||||||
// Extract merkle root and matched txids from copy
|
// check that it contains the matched transactions (in the same order!)
|
||||||
let mut match_txid2: Vec<Txid> = vec![];
|
assert_eq!(match_txid1, match_txid2);
|
||||||
let mut indexes = vec![];
|
|
||||||
let merkle_root_2 = pmt2
|
|
||||||
.extract_matches(&mut match_txid2, &mut indexes)
|
|
||||||
.expect("Could not extract matches");
|
|
||||||
|
|
||||||
// Check that it has the same merkle root as the original, and a valid one
|
// check that random bit flips break the authentication
|
||||||
assert_eq!(merkle_root_1, merkle_root_2);
|
for _ in 0..4 {
|
||||||
assert_ne!(merkle_root_2, TxMerkleNode::all_zeros());
|
let mut pmt3: PartialMerkleTree = deserialize(&serialized).unwrap();
|
||||||
|
pmt3.damage(&mut rng);
|
||||||
// check that it contains the matched transactions (in the same order!)
|
let mut match_txid3 = vec![];
|
||||||
assert_eq!(match_txid1, match_txid2);
|
let merkle_root_3 = pmt3
|
||||||
|
.extract_matches(&mut match_txid3, &mut indexes)
|
||||||
// check that random bit flips break the authentication
|
.unwrap();
|
||||||
for _ in 0..4 {
|
assert_ne!(merkle_root_3, merkle_root_1);
|
||||||
let mut pmt3: PartialMerkleTree = deserialize(&serialized).unwrap();
|
|
||||||
pmt3.damage(&mut rng);
|
|
||||||
let mut match_txid3 = vec![];
|
|
||||||
let merkle_root_3 = pmt3
|
|
||||||
.extract_matches(&mut match_txid3, &mut indexes)
|
|
||||||
.unwrap();
|
|
||||||
assert_ne!(merkle_root_3, merkle_root_1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue