diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3003cef..5e1ecc3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -50,5 +50,5 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - uses: dtolnay/rust-toolchain@nightly - - run: RUSTFLAGS='--cfg=bench' cargo +nightly bench --all-features + - uses: dtolnay/rust-toolchain@stable + - run: cargo bench --all-features diff --git a/Cargo.toml b/Cargo.toml index 6fcfc44..8515f4c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,7 +31,13 @@ hex_lit = { version = "0.1", features = ["rust_v_1_46"] } bitcoin = { version = "0.32.0", features = ["rand"] } bitcoin-test-data = "0.2.0" tempfile = "3.4.0" +criterion = "0.3" [package.metadata.docs.rs] all-features = true rustdoc-args = ["--cfg", "docsrs"] + +[[bench]] +name = "benches" +harness = false +required-features = ["bitcoin_hashes", "bitcoin", "sha2"] diff --git a/README.md b/README.md index fb8d8ae..74f98e7 100644 --- a/README.md +++ b/README.md @@ -120,31 +120,45 @@ cargo test ## Bench +[Criterion](https://bheisler.github.io/criterion.rs/book/) is used for benching mainly because we are not required to use nightly, and it is also nicer. + +```sh +cargo bench --all-features +``` + +To have compact results, similar to standard libtests launch with: + ```sh -RUSTFLAGS='--cfg=bench' cargo +nightly bench --all-features +cargo bench --bench benches --all-features -- --output-format bencher ``` ```sh -test bsl::block::bench::block_deserialize ... bench: 289,421 ns/iter (+/- 46,179) -test bsl::block::bench::block_deserialize_bitcoin ... bench: 2,719,666 ns/iter (+/- 459,186) -test bsl::block::bench::block_sum_outputs ... bench: 288,248 ns/iter (+/- 39,013) -test bsl::block::bench::block_sum_outputs_bitcoin ... bench: 2,607,791 ns/iter (+/- 321,212) -test bsl::block::bench::find_tx ... bench: 1,012,297 ns/iter (+/- 6,278) -test bsl::block::bench::find_tx_bitcoin ... bench: 8,632,416 ns/iter (+/- 89,751) -test bsl::block::bench::hash_block_txs ... bench: 8,406,341 ns/iter (+/- 938,119) -test bsl::block::bench::hash_block_txs_bitcoin ... bench: 11,843,590 ns/iter (+/- 1,052,109) -test bsl::block::bench::hash_block_txs_sha2 ... bench: 7,891,956 ns/iter (+/- 1,047,439) -test bsl::block_header::bench::block_hash ... bench: 1,399 ns/iter (+/- 205) -test bsl::block_header::bench::block_hash_bitcoin ... bench: 1,510 ns/iter (+/- 222) -test bsl::transaction::bench::tx_deserialize ... bench: 38 ns/iter (+/- 8) -test bsl::transaction::bench::tx_deserialize_bitcoin ... bench: 219 ns/iter (+/- 30) -test bsl::transaction::bench::txid ... bench: 2,185 ns/iter (+/- 166) -test bsl::transaction::bench::txid_bitcoin ... bench: 2,416 ns/iter (+/- 213) -test bsl::transaction::bench::txid_sha2 ... bench: 2,085 ns/iter (+/- 216) +test tx_deserialize/slices ... bench: 29 ns/iter (+/- 0) +test tx_deserialize/bitcoin ... bench: 211 ns/iter (+/- 0) + +test tx_id/slices_bitcoin_hashes ... bench: 183 ns/iter (+/- 0) +test tx_id/slices_sha2 ... bench: 158 ns/iter (+/- 0) +test tx_id/bitcoin ... bench: 234 ns/iter (+/- 1) + +test block_deserialize/slices ... bench: 230872 ns/iter (+/- 1686) +test block_deserialize/bitcoin ... bench: 1462784 ns/iter (+/- 115792) + +test block_sum_outputs/slices ... bench: 235757 ns/iter (+/- 1318) +test block_sum_outputs/bitcoin ... bench: 1459730 ns/iter (+/- 95817) + +test hash_block_txs/slices ... bench: 881940 ns/iter (+/- 4961) +test hash_block_txs/slices_sha2 ... bench: 789365 ns/iter (+/- 932) +test hash_block_txs/bitcoin ... bench: 2301561 ns/iter (+/- 15406) + +test find_tx/slices ... bench: 406519 ns/iter (+/- 1423) +test find_tx/bitcoin ... bench: 1826147 ns/iter (+/- 122216) + +test block_hash/slices ... bench: 112 ns/iter (+/- 0) +test block_hash/bitcoin ... bench: 146 ns/iter (+/- 2) ``` -* benches ending with `_bitcoin` use `rust-bitcoin` -* benches ending with `_sha2` use `sha2` lib instead of `bitcoin_hashes` +* benches variants with `/bitcoin` use `rust-bitcoin` +* benches ending with `/slices_sha2` use this lib and `sha2` lib instead of `bitcoin_hashes` ### Comparison against rust-bitcoin diff --git a/benches/benches.rs b/benches/benches.rs new file mode 100644 index 0000000..ef466ed --- /dev/null +++ b/benches/benches.rs @@ -0,0 +1,229 @@ +use bitcoin::consensus::deserialize; +use bitcoin_hashes::sha256d; +use bitcoin_slices::bsl::{Block, BlockHeader, FindTransaction, Transaction, TxOut}; +use bitcoin_slices::{Parse, Visit, Visitor}; +use bitcoin_test_data::blocks::mainnet_702861; +use core::ops::ControlFlow; +use criterion::{black_box, criterion_group, criterion_main, Criterion}; +use hex_lit::hex; +use std::str::FromStr; + +const BENCH_TX: [u8; 193] = hex!("0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000"); +const GENESIS_BLOCK_HEADER: [u8; 80] = hex!("0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a29ab5f49ffff001d1dac2b7c"); + +criterion_group!( + benches, + tx_deserialize, + tx_id, + block_deserialize, + block_sum_outputs, + hash_block_txs, + find_tx, + block_hash +); +criterion_main!(benches); + +pub fn tx_deserialize(c: &mut Criterion) { + c.benchmark_group("tx_deserialize") + .throughput(criterion::Throughput::Bytes(BENCH_TX.len() as u64)) + .bench_function("slices", |b| { + b.iter(|| { + let tx = Transaction::parse(&BENCH_TX[..]).unwrap().parsed_owned(); + black_box(&tx); + }) + }) + .bench_function("bitcoin", |b| { + b.iter(|| { + let tx: bitcoin::Transaction = deserialize(&BENCH_TX).unwrap(); + black_box(&tx); + }) + }); +} + +pub fn tx_id(c: &mut Criterion) { + c.benchmark_group("tx_id") + .throughput(criterion::Throughput::Bytes(BENCH_TX.len() as u64)) + .bench_function("slices_bitcoin_hashes", |b| { + let tx = Transaction::parse(&BENCH_TX[..]).unwrap().parsed_owned(); + b.iter(|| { + black_box(tx.txid()); + }) + }) + .bench_function("slices_sha2", |b| { + let tx = Transaction::parse(&BENCH_TX[..]).unwrap().parsed_owned(); + b.iter(|| { + black_box(tx.txid_sha2()); + }) + }) + .bench_function("bitcoin", |b| { + let tx: bitcoin::Transaction = deserialize(&BENCH_TX[..]).unwrap(); + b.iter(|| { + black_box(tx.compute_txid()); + }) + }); +} + +pub fn block_deserialize(c: &mut Criterion) { + c.benchmark_group("block_deserialize") + .throughput(criterion::Throughput::Bytes(mainnet_702861().len() as u64)) + .bench_function("slices", |b| { + b.iter(|| { + let block = Block::parse(mainnet_702861()).unwrap(); + black_box(&block); + }) + }) + .bench_function("bitcoin", |b| { + b.iter(|| { + let block: bitcoin::Block = deserialize(mainnet_702861()).unwrap(); + black_box(&block); + }) + }); +} + +pub fn block_sum_outputs(c: &mut Criterion) { + c.benchmark_group("block_sum_outputs") + .throughput(criterion::Throughput::Bytes(mainnet_702861().len() as u64)) + .bench_function("slices", |b| { + b.iter(|| { + struct Sum(u64); + impl Visitor for Sum { + fn visit_tx_out(&mut self, _vout: usize, tx_out: &TxOut) -> ControlFlow<()> { + self.0 += tx_out.value(); + ControlFlow::Continue(()) + } + } + let mut sum = Sum(0); + let block = Block::visit(mainnet_702861(), &mut sum).unwrap(); + assert_eq!(sum.0, 2883682728990); + black_box(&block); + }) + }) + .bench_function("bitcoin", |b| { + b.iter(|| { + let block: bitcoin::Block = deserialize(mainnet_702861()).unwrap(); + let sum: u64 = block + .txdata + .iter() + .flat_map(|t| t.output.iter()) + .fold(0, |acc, e| acc + e.value.to_sat()); + assert_eq!(sum, 2883682728990); + + black_box(&block); + }) + }); +} + +pub fn hash_block_txs(c: &mut Criterion) { + c.benchmark_group("hash_block_txs") + .throughput(criterion::Throughput::Bytes(mainnet_702861().len() as u64)) + .bench_function("slices", |b| { + b.iter(|| { + struct VisitTx(Vec); + let mut v = VisitTx(vec![]); + impl Visitor for VisitTx { + fn visit_block_begin(&mut self, total_transactions: usize) { + self.0.reserve(total_transactions); + } + fn visit_transaction(&mut self, tx: &Transaction) -> ControlFlow<()> { + self.0.push(tx.txid()); + ControlFlow::Continue(()) + } + } + + let block = Block::visit(mainnet_702861(), &mut v).unwrap(); + + assert_eq!(v.0.len(), 2500); + + black_box((&block, v)); + }) + }) + .bench_function("slices_sha2", |b| { + b.iter(|| { + struct VisitTx( + Vec>, + ); + let mut v = VisitTx(vec![]); + impl Visitor for VisitTx { + fn visit_block_begin(&mut self, total_transactions: usize) { + self.0.reserve(total_transactions); + } + fn visit_transaction(&mut self, tx: &Transaction) -> ControlFlow<()> { + self.0.push(tx.txid_sha2()); + ControlFlow::Continue(()) + } + } + + let block = Block::visit(mainnet_702861(), &mut v).unwrap(); + + assert_eq!(v.0.len(), 2500); + + black_box((&block, v)); + }) + }) + .bench_function("bitcoin", |b| { + b.iter(|| { + let block: bitcoin::Block = deserialize(mainnet_702861()).unwrap(); + let mut tx_hashes = Vec::with_capacity(block.txdata.len()); + + for tx in block.txdata.iter() { + tx_hashes.push(tx.compute_txid()) + } + assert_eq!(tx_hashes.len(), 2500); + black_box((&block, tx_hashes)); + }) + }); +} + +const TXID: &str = "416a5f96cb63e7649f6f272e7f82a43a97bcf6cfc46184c733344de96ff1e433"; +pub fn find_tx(c: &mut Criterion) { + c.benchmark_group("find_tx") + .throughput(criterion::Throughput::Bytes(mainnet_702861().len() as u64)) + .bench_function("slices", |b| { + let txid = bitcoin::Txid::from_str(TXID).unwrap(); + b.iter(|| { + let mut visitor = FindTransaction::new(txid.clone()); + let _ = Block::visit(&mainnet_702861(), &mut visitor); + let tx = visitor.tx_found().unwrap(); + assert_eq!(tx.compute_txid(), txid); + core::hint::black_box(tx); + }) + }) + .bench_function("bitcoin", |b| { + let txid = bitcoin::Txid::from_str(TXID).unwrap(); + + b.iter(|| { + let block: bitcoin::Block = deserialize(mainnet_702861()).unwrap(); + let mut tx = None; + for current in block.txdata { + if current.compute_txid() == txid { + tx = Some(current); + break; + } + } + let tx = tx.unwrap(); + assert_eq!(tx.compute_txid(), txid); + core::hint::black_box(&tx); + }) + }); +} + +pub fn block_hash(c: &mut Criterion) { + c.benchmark_group("block_hash") + .bench_function("slices", |b| { + let block_header = BlockHeader::parse(&GENESIS_BLOCK_HEADER) + .unwrap() + .parsed_owned(); + b.iter(|| { + let hash = block_header.block_hash(); + black_box(&hash); + }) + }) + .bench_function("bitcoin", |b| { + let block_header: bitcoin::blockdata::block::Header = + deserialize(&GENESIS_BLOCK_HEADER).unwrap(); + b.iter(|| { + let hash = block_header.block_hash(); + black_box(&hash); + }) + }); +} diff --git a/fuzz/fuzz_targets/block.rs b/fuzz/fuzz_targets/block.rs index fcb434f..651f349 100644 --- a/fuzz/fuzz_targets/block.rs +++ b/fuzz/fuzz_targets/block.rs @@ -7,3 +7,16 @@ fuzz_target!(|data: &[u8]| { let p = Block::parse(data); check(data, p); }); + +/// Some checks on a succesfull parse +pub fn check>( + data: &[u8], + p: Result, bitcoin_slices::Error>, +) { + if let Ok(p) = p { + let consumed = p.consumed(); + assert_eq!(p.parsed().as_ref().len(), consumed); + assert_eq!(&data[..consumed], p.parsed().as_ref()); + assert_eq!(&data[consumed..], p.remaining()); + } +} diff --git a/fuzz/fuzz_targets/block_header.rs b/fuzz/fuzz_targets/block_header.rs index 2bc474c..22871c6 100644 --- a/fuzz/fuzz_targets/block_header.rs +++ b/fuzz/fuzz_targets/block_header.rs @@ -7,3 +7,16 @@ fuzz_target!(|data: &[u8]| { let p = BlockHeader::parse(data); check(data, p); }); + +/// Some checks on a succesfull parse +pub fn check>( + data: &[u8], + p: Result, bitcoin_slices::Error>, +) { + if let Ok(p) = p { + let consumed = p.consumed(); + assert_eq!(p.parsed().as_ref().len(), consumed); + assert_eq!(&data[..consumed], p.parsed().as_ref()); + assert_eq!(&data[consumed..], p.remaining()); + } +} diff --git a/fuzz/fuzz_targets/len.rs b/fuzz/fuzz_targets/len.rs index 95a3e34..b126a81 100644 --- a/fuzz/fuzz_targets/len.rs +++ b/fuzz/fuzz_targets/len.rs @@ -7,3 +7,16 @@ fuzz_target!(|data: &[u8]| { let p = Len::parse(data); check(data, p); }); + +/// Some checks on a succesfull parse +pub fn check>( + data: &[u8], + p: Result, bitcoin_slices::Error>, +) { + if let Ok(p) = p { + let consumed = p.consumed(); + assert_eq!(p.parsed().as_ref().len(), consumed); + assert_eq!(&data[..consumed], p.parsed().as_ref()); + assert_eq!(&data[consumed..], p.remaining()); + } +} diff --git a/fuzz/fuzz_targets/out_point.rs b/fuzz/fuzz_targets/out_point.rs index 16a4cd8..3ef48be 100644 --- a/fuzz/fuzz_targets/out_point.rs +++ b/fuzz/fuzz_targets/out_point.rs @@ -7,3 +7,16 @@ fuzz_target!(|data: &[u8]| { let p = OutPoint::parse(data); check(data, p); }); + +/// Some checks on a succesfull parse +pub fn check>( + data: &[u8], + p: Result, bitcoin_slices::Error>, +) { + if let Ok(p) = p { + let consumed = p.consumed(); + assert_eq!(p.parsed().as_ref().len(), consumed); + assert_eq!(&data[..consumed], p.parsed().as_ref()); + assert_eq!(&data[consumed..], p.remaining()); + } +} diff --git a/fuzz/fuzz_targets/script.rs b/fuzz/fuzz_targets/script.rs index 6748aeb..5c4be7f 100644 --- a/fuzz/fuzz_targets/script.rs +++ b/fuzz/fuzz_targets/script.rs @@ -7,3 +7,16 @@ fuzz_target!(|data: &[u8]| { let p = Script::parse(data); check(data, p); }); + +/// Some checks on a succesfull parse +pub fn check>( + data: &[u8], + p: Result, bitcoin_slices::Error>, +) { + if let Ok(p) = p { + let consumed = p.consumed(); + assert_eq!(p.parsed().as_ref().len(), consumed); + assert_eq!(&data[..consumed], p.parsed().as_ref()); + assert_eq!(&data[consumed..], p.remaining()); + } +} diff --git a/fuzz/fuzz_targets/transaction.rs b/fuzz/fuzz_targets/transaction.rs index 096dbf3..b7e998b 100644 --- a/fuzz/fuzz_targets/transaction.rs +++ b/fuzz/fuzz_targets/transaction.rs @@ -7,3 +7,16 @@ fuzz_target!(|data: &[u8]| { let p = Transaction::parse(data); check(data, p); }); + +/// Some checks on a succesfull parse +pub fn check>( + data: &[u8], + p: Result, bitcoin_slices::Error>, +) { + if let Ok(p) = p { + let consumed = p.consumed(); + assert_eq!(p.parsed().as_ref().len(), consumed); + assert_eq!(&data[..consumed], p.parsed().as_ref()); + assert_eq!(&data[consumed..], p.remaining()); + } +} diff --git a/fuzz/fuzz_targets/tx_in.rs b/fuzz/fuzz_targets/tx_in.rs index a05efe6..583b6c7 100644 --- a/fuzz/fuzz_targets/tx_in.rs +++ b/fuzz/fuzz_targets/tx_in.rs @@ -7,3 +7,16 @@ fuzz_target!(|data: &[u8]| { let p = TxIn::parse(data); check(data, p); }); + +/// Some checks on a succesfull parse +pub fn check>( + data: &[u8], + p: Result, bitcoin_slices::Error>, +) { + if let Ok(p) = p { + let consumed = p.consumed(); + assert_eq!(p.parsed().as_ref().len(), consumed); + assert_eq!(&data[..consumed], p.parsed().as_ref()); + assert_eq!(&data[consumed..], p.remaining()); + } +} diff --git a/fuzz/fuzz_targets/tx_ins.rs b/fuzz/fuzz_targets/tx_ins.rs index 4f51e9d..52853da 100644 --- a/fuzz/fuzz_targets/tx_ins.rs +++ b/fuzz/fuzz_targets/tx_ins.rs @@ -7,3 +7,16 @@ fuzz_target!(|data: &[u8]| { let p = TxIns::parse(data); check(data, p); }); + +/// Some checks on a succesfull parse +pub fn check>( + data: &[u8], + p: Result, bitcoin_slices::Error>, +) { + if let Ok(p) = p { + let consumed = p.consumed(); + assert_eq!(p.parsed().as_ref().len(), consumed); + assert_eq!(&data[..consumed], p.parsed().as_ref()); + assert_eq!(&data[consumed..], p.remaining()); + } +} diff --git a/fuzz/fuzz_targets/tx_out.rs b/fuzz/fuzz_targets/tx_out.rs index 343a1ab..0e0f0af 100644 --- a/fuzz/fuzz_targets/tx_out.rs +++ b/fuzz/fuzz_targets/tx_out.rs @@ -7,3 +7,16 @@ fuzz_target!(|data: &[u8]| { let p = TxOut::parse(data); check(data, p); }); + +/// Some checks on a succesfull parse +pub fn check>( + data: &[u8], + p: Result, bitcoin_slices::Error>, +) { + if let Ok(p) = p { + let consumed = p.consumed(); + assert_eq!(p.parsed().as_ref().len(), consumed); + assert_eq!(&data[..consumed], p.parsed().as_ref()); + assert_eq!(&data[consumed..], p.remaining()); + } +} diff --git a/fuzz/fuzz_targets/tx_outs.rs b/fuzz/fuzz_targets/tx_outs.rs index bbdbdcc..0fc2d64 100644 --- a/fuzz/fuzz_targets/tx_outs.rs +++ b/fuzz/fuzz_targets/tx_outs.rs @@ -7,3 +7,16 @@ fuzz_target!(|data: &[u8]| { let p = TxOuts::parse(data); check(data, p); }); + +/// Some checks on a succesfull parse +pub fn check>( + data: &[u8], + p: Result, bitcoin_slices::Error>, +) { + if let Ok(p) = p { + let consumed = p.consumed(); + assert_eq!(p.parsed().as_ref().len(), consumed); + assert_eq!(&data[..consumed], p.parsed().as_ref()); + assert_eq!(&data[consumed..], p.remaining()); + } +} diff --git a/fuzz/fuzz_targets/witness.rs b/fuzz/fuzz_targets/witness.rs index a5cea1b..5e89523 100644 --- a/fuzz/fuzz_targets/witness.rs +++ b/fuzz/fuzz_targets/witness.rs @@ -7,3 +7,16 @@ fuzz_target!(|data: &[u8]| { let p = Witness::parse(data); check(data, p); }); + +/// Some checks on a succesfull parse +pub fn check>( + data: &[u8], + p: Result, bitcoin_slices::Error>, +) { + if let Ok(p) = p { + let consumed = p.consumed(); + assert_eq!(p.parsed().as_ref().len(), consumed); + assert_eq!(&data[..consumed], p.parsed().as_ref()); + assert_eq!(&data[consumed..], p.remaining()); + } +} diff --git a/fuzz/fuzz_targets/witnesses.rs b/fuzz/fuzz_targets/witnesses.rs index 755e9ab..6260d4f 100644 --- a/fuzz/fuzz_targets/witnesses.rs +++ b/fuzz/fuzz_targets/witnesses.rs @@ -9,3 +9,16 @@ fuzz_target!(|data: &[u8]| { check(&data[1..], p); } }); + +/// Some checks on a succesfull parse +pub fn check>( + data: &[u8], + p: Result, bitcoin_slices::Error>, +) { + if let Ok(p) = p { + let consumed = p.consumed(); + assert_eq!(p.parsed().as_ref().len(), consumed); + assert_eq!(&data[..consumed], p.parsed().as_ref()); + assert_eq!(&data[consumed..], p.remaining()); + } +} diff --git a/src/bsl/block.rs b/src/bsl/block.rs index a7326b0..f4e7b9f 100644 --- a/src/bsl/block.rs +++ b/src/bsl/block.rs @@ -166,180 +166,3 @@ mod test { assert_eq!(std::mem::size_of::>(), 1); } } - -#[cfg(bench)] -mod bench { - use core::ops::ControlFlow; - - use crate::bsl::{Block, TxOut}; - use crate::{Parse, Visit, Visitor}; - use bitcoin::consensus::deserialize; - use bitcoin_test_data::blocks::mainnet_702861; - use test::{black_box, Bencher}; - - #[bench] - pub fn block_deserialize(bh: &mut Bencher) { - bh.iter(|| { - let block = Block::parse(mainnet_702861()).unwrap(); - black_box(&block); - }); - bh.bytes = mainnet_702861().len() as u64; - } - - #[bench] - pub fn block_deserialize_bitcoin(bh: &mut Bencher) { - bh.iter(|| { - let block: bitcoin::Block = deserialize(mainnet_702861()).unwrap(); - black_box(&block); - }); - bh.bytes = mainnet_702861().len() as u64; - } - - #[bench] - pub fn block_sum_outputs(bh: &mut Bencher) { - bh.iter(|| { - struct Sum(u64); - impl Visitor for Sum { - fn visit_tx_out(&mut self, _vout: usize, tx_out: &TxOut) -> ControlFlow<()> { - self.0 += tx_out.value(); - ControlFlow::Continue(()) - } - } - let mut sum = Sum(0); - let block = Block::visit(mainnet_702861(), &mut sum).unwrap(); - assert_eq!(sum.0, 2883682728990); - black_box(&block); - }); - } - - #[bench] - pub fn block_sum_outputs_bitcoin(bh: &mut Bencher) { - bh.iter(|| { - let block: bitcoin::Block = deserialize(mainnet_702861()).unwrap(); - let sum: u64 = block - .txdata - .iter() - .flat_map(|t| t.output.iter()) - .fold(0, |acc, e| acc + e.value.to_sat()); - assert_eq!(sum, 2883682728990); - - black_box(&block); - }); - } - - #[cfg(feature = "bitcoin_hashes")] - #[bench] - pub fn hash_block_txs(bh: &mut Bencher) { - use core::ops::ControlFlow; - - use bitcoin::hashes::sha256d; - - bh.iter(|| { - struct VisitTx(Vec); - let mut v = VisitTx(vec![]); - impl crate::Visitor for VisitTx { - fn visit_block_begin(&mut self, total_transactions: usize) { - self.0.reserve(total_transactions); - } - fn visit_transaction(&mut self, tx: &crate::bsl::Transaction) -> ControlFlow<()> { - self.0.push(tx.txid()); - ControlFlow::Continue(()) - } - } - - let block = Block::visit(mainnet_702861(), &mut v).unwrap(); - - assert_eq!(v.0.len(), 2500); - - black_box((&block, v)); - }); - } - - #[cfg(feature = "sha2")] - #[bench] - pub fn hash_block_txs_sha2(bh: &mut Bencher) { - use core::ops::ControlFlow; - - bh.iter(|| { - struct VisitTx( - Vec< - crate::sha2::digest::generic_array::GenericArray< - u8, - crate::sha2::digest::typenum::U32, - >, - >, - ); - let mut v = VisitTx(vec![]); - impl crate::Visitor for VisitTx { - fn visit_block_begin(&mut self, total_transactions: usize) { - self.0.reserve(total_transactions); - } - fn visit_transaction(&mut self, tx: &crate::bsl::Transaction) -> ControlFlow<()> { - self.0.push(tx.txid_sha2()); - ControlFlow::Continue(()) - } - } - - let block = Block::visit(mainnet_702861(), &mut v).unwrap(); - - assert_eq!(v.0.len(), 2500); - - black_box((&block, v)); - }); - } - - #[bench] - pub fn hash_block_txs_bitcoin(bh: &mut Bencher) { - bh.iter(|| { - let block: bitcoin::Block = deserialize(mainnet_702861()).unwrap(); - let mut tx_hashes = Vec::with_capacity(block.txdata.len()); - - for tx in block.txdata.iter() { - tx_hashes.push(tx.compute_txid()) - } - assert_eq!(tx_hashes.len(), 2500); - black_box((&block, tx_hashes)); - }); - } - - #[cfg(all(feature = "bitcoin", feature = "sha2"))] - #[bench] - pub fn find_tx(bh: &mut Bencher) { - use std::str::FromStr; - let txid = bitcoin::Txid::from_str( - "416a5f96cb63e7649f6f272e7f82a43a97bcf6cfc46184c733344de96ff1e433", - ) - .unwrap(); - - bh.iter(|| { - let mut visitor = crate::bsl::FindTransaction::new(txid.clone()); - let _ = Block::visit(&mainnet_702861(), &mut visitor); - let tx = visitor.tx_found().unwrap(); - assert_eq!(tx.compute_txid(), txid); - core::hint::black_box(tx); - }); - } - - #[cfg(feature = "bitcoin")] - #[bench] - pub fn find_tx_bitcoin(bh: &mut Bencher) { - use std::str::FromStr; - let txid = bitcoin::Txid::from_str( - "416a5f96cb63e7649f6f272e7f82a43a97bcf6cfc46184c733344de96ff1e433", - ) - .unwrap(); - bh.iter(|| { - let block: bitcoin::Block = deserialize(mainnet_702861()).unwrap(); - let mut tx = None; - for current in block.txdata { - if current.compute_txid() == txid { - tx = Some(current); - break; - } - } - let tx = tx.unwrap(); - assert_eq!(tx.txid(), txid); - core::hint::black_box(&tx); - }); - } -} diff --git a/src/bsl/block_header.rs b/src/bsl/block_header.rs index ec3130e..b70dd34 100644 --- a/src/bsl/block_header.rs +++ b/src/bsl/block_header.rs @@ -164,36 +164,3 @@ mod test { assert_eq!(&block.block_hash_sha2()[..], &reverse(expected)[..]); } } - -#[cfg(bench)] -mod bench { - - #[cfg(feature = "bitcoin_hashes")] - #[bench] - pub fn block_hash(bh: &mut test::Bencher) { - use crate::bsl::BlockHeader; - use crate::Parse; - let block_header = BlockHeader::parse(&crate::test_common::GENESIS_BLOCK_HEADER) - .unwrap() - .parsed_owned(); - - bh.iter(|| { - let hash = block_header.block_hash(); - test::black_box(&hash); - }); - } - - #[cfg(feature = "bitcoin")] - #[bench] - pub fn block_hash_bitcoin(bh: &mut test::Bencher) { - use bitcoin::consensus::deserialize; - - let block_header: bitcoin::blockdata::block::Header = - deserialize(&crate::test_common::GENESIS_BLOCK_HEADER).unwrap(); - - bh.iter(|| { - let hash = block_header.block_hash(); - test::black_box(&hash); - }); - } -} diff --git a/src/bsl/transaction.rs b/src/bsl/transaction.rs index 100a1fa..72a68fb 100644 --- a/src/bsl/transaction.rs +++ b/src/bsl/transaction.rs @@ -299,58 +299,3 @@ mod test { check_weight(&segwit_tx); } } - -#[cfg(bench)] -mod bench { - use crate::bsl::Transaction; - use crate::Parse; - use bitcoin::consensus::deserialize; - use hex_lit::hex; - use test::{black_box, Bencher}; - - const BENCH_TX: [u8; 193] = hex!("0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000"); - - #[bench] - pub fn tx_deserialize(bh: &mut Bencher) { - bh.iter(|| { - let tx = Transaction::parse(&BENCH_TX[..]).unwrap().parsed_owned(); - black_box(&tx); - }); - bh.bytes = BENCH_TX.len() as u64; - } - - #[bench] - pub fn tx_deserialize_bitcoin(bh: &mut Bencher) { - bh.iter(|| { - let tx: bitcoin::Transaction = deserialize(&BENCH_TX).unwrap(); - black_box(&tx); - }); - bh.bytes = BENCH_TX.len() as u64; - } - - #[cfg(feature = "bitcoin_hashes")] - #[bench] - pub fn txid(bh: &mut Bencher) { - let tx = Transaction::parse(&BENCH_TX[..]).unwrap().parsed_owned(); - bh.iter(|| { - black_box(&tx.txid()); - }); - } - - #[cfg(feature = "sha2")] - #[bench] - pub fn txid_sha2(bh: &mut Bencher) { - let tx = Transaction::parse(&BENCH_TX[..]).unwrap().parsed_owned(); - bh.iter(|| { - black_box(&tx.txid_sha2()); - }); - } - - #[bench] - pub fn txid_bitcoin(bh: &mut Bencher) { - let tx: bitcoin::Transaction = deserialize(&BENCH_TX[..]).unwrap(); - bh.iter(|| { - black_box(&tx.compute_txid()); - }); - } -} diff --git a/src/lib.rs b/src/lib.rs index b81d596..a21bc3e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,13 +1,9 @@ #![cfg_attr(docsrs, feature(doc_auto_cfg))] #![deny(missing_docs)] -#![cfg_attr(bench, feature(test))] #![cfg_attr(not(test), no_std)] #![warn(missing_docs)] #![doc = include_str!("../README.md")] -#[cfg(bench)] -extern crate test; - pub mod bsl; mod error; pub mod number; @@ -45,7 +41,7 @@ pub use redb; #[cfg(feature = "bitcoin")] pub use bitcoin; -#[cfg(any(test, bench))] +#[cfg(test)] pub mod test_common { use hex_lit::hex; @@ -67,19 +63,3 @@ pub mod test_common { ret } } - -/// Common functions used in fuzzing -#[cfg(fuzzing)] -pub mod fuzzing { - use crate::{Error, ParseResult}; - - /// Some checks on a succesfull parse - pub fn check>(data: &[u8], p: Result, Error>) { - if let Ok(p) = p { - let consumed = p.consumed(); - assert_eq!(p.parsed().as_ref().len(), consumed); - assert_eq!(&data[..consumed], p.parsed().as_ref()); - assert_eq!(&data[consumed..], p.remaining()); - } - } -}