diff --git a/Cargo.lock b/Cargo.lock index 74f91f864..67af7728b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -361,6 +361,7 @@ dependencies = [ name = "chia-consensus" version = "0.18.0" dependencies = [ + "blocking-threadpool", "chia-bls 0.18.0", "chia-protocol", "chia-puzzle-types", diff --git a/crates/chia-consensus/Cargo.toml b/crates/chia-consensus/Cargo.toml index 430593007..1da1a1fca 100644 --- a/crates/chia-consensus/Cargo.toml +++ b/crates/chia-consensus/Cargo.toml @@ -41,6 +41,7 @@ rstest = { workspace = true } text-diff = { workspace = true } criterion = { workspace = true } rand = { workspace = true, features = [ "small_rng" ] } +blocking-threadpool = { workspace = true } [lib] bench = false diff --git a/crates/chia-consensus/src/gen/build_compressed_block.rs b/crates/chia-consensus/src/gen/build_compressed_block.rs new file mode 100644 index 000000000..34bd12b7e --- /dev/null +++ b/crates/chia-consensus/src/gen/build_compressed_block.rs @@ -0,0 +1,418 @@ +use crate::consensus_constants::ConsensusConstants; +use chia_bls::Signature; +use chia_protocol::SpendBundle; +use clvmr::allocator::{Allocator, NodePtr}; +use clvmr::serde::{node_from_bytes_backrefs, Serializer}; +use std::io; + +#[cfg(feature = "py-bindings")] +use pyo3::prelude::*; + +/// Maximum number of mempool items that can be skipped (not considered) during +/// the creation of a block bundle. An item is skipped if it won't fit in the +/// block we're trying to create. +const MAX_SKIPPED_ITEMS: u32 = 6; + +/// Typical cost of a standard XCH spend. It's used as a heuristic to help +/// determine how close to the block size limit we're willing to go. +const MIN_COST_THRESHOLD: u64 = 6_000_000; + +/// Returned from add_spend_bundle(), indicating whether more bundles can be +/// added or not. +#[derive(PartialEq)] +pub enum BuildBlockResult { + /// More spend bundles can be added + KeepGoing, + /// No more spend bundles can be added. We're too close to the limit + Done, +} + +/// This takes a list of spends, highest priority first, and returns a +/// block generator with as many spends as possible, that fit within the +/// specified maximum block cost. The priority of spends is typically the +/// fee-per-cost (higher is better). The cost of the generated block is computed +/// incrementally, based on the (compressed) size in bytes, the execution cost +/// and conditions cost of each spend. The compressed size is not trivially +/// predicted. Spends are added to the generator, and compressed, one at a time +/// until we reach the target cost limit. +#[cfg_attr(feature = "py-bindings", pyclass)] +pub struct BlockBuilder { + allocator: Allocator, + signature: Signature, + sentinel: NodePtr, + + // the cost of the block we've built up so far, not including the byte-cost. + // That's seprated out into the byte_cost member. + block_cost: u64, + + // the byte cost, so for, of what's in the Serializer + byte_cost: u64, + + // the number of spend bundles we've failed to add. Once this grows too + // large, we give up + num_skipped: u32, + + // the serializer for the generator CLVM + ser: Serializer, +} + +fn result(num_skipped: u32) -> BuildBlockResult { + if num_skipped > MAX_SKIPPED_ITEMS { + BuildBlockResult::Done + } else { + BuildBlockResult::KeepGoing + } +} + +impl BlockBuilder { + pub fn new() -> io::Result { + let mut a = Allocator::new(); + + // the sentinel just needs to be a unique NodePtr. Since atoms may be + // de-duplicated (for small integers), we create a pair. + let sentinel = a.new_pair(NodePtr::NIL, NodePtr::NIL)?; + + // the generator we produce is just a quoted list. Nothing fancy. + // Its format is as follows: + // (q . ( ( ( parent-id puzzle-reveal amount solution ) ... ) ) ) + + // the list of spends is the first (and only) item in an outer list + let spend_list = a.new_pair(sentinel, a.nil())?; + let quoted_list = a.new_pair(a.one(), spend_list)?; + + let mut ser = Serializer::new(Some(sentinel)); + ser.add(&a, quoted_list)?; + + Ok(Self { + allocator: a, + signature: Signature::default(), + sentinel, + // This is the cost of executing a quote. we quote the list of + // spends + block_cost: 20, + byte_cost: 0, + num_skipped: 0, + ser, + }) + } + + /// add a spend bundle to the generator. The cost must be *only* the CLVM + /// execution cost + the cost of the conditions. It must not include the byte cost + /// of the bundle. The byte cost is unpredictible as the generator is being + /// compressed. The true byte cost is computed by this function. + /// returns true if this bundle could be added to the generator, false otherwise + pub fn add_spend_bundle( + &mut self, + bundle: &SpendBundle, + cost: u64, + constants: &ConsensusConstants, + ) -> io::Result<(bool, BuildBlockResult)> { + // if we're very close to a full block, we're done. It's very unlikely + // any transaction will be smallar than MIN_COST_THRESHOLD + if self.byte_cost + self.block_cost + MIN_COST_THRESHOLD > constants.max_block_cost_clvm { + self.num_skipped += 1; + return Ok((false, BuildBlockResult::Done)); + } + + if self.byte_cost + self.block_cost + cost > constants.max_block_cost_clvm { + self.num_skipped += 1; + return Ok((false, result(self.num_skipped))); + } + + let a = &mut self.allocator; + + let mut spend_list = self.sentinel; + for spend in &bundle.coin_spends { + // solution + let solution = node_from_bytes_backrefs(a, spend.solution.as_ref())?; + let item = a.new_pair(solution, NodePtr::NIL)?; + // amount + let amount = a.new_number(spend.coin.amount.into())?; + let item = a.new_pair(amount, item)?; + // puzzle reveal + let puzzle = node_from_bytes_backrefs(a, spend.puzzle_reveal.as_ref())?; + let item = a.new_pair(puzzle, item)?; + // parent-id + let parent_id = a.new_atom(&spend.coin.parent_coin_info)?; + let item = a.new_pair(parent_id, item)?; + + spend_list = a.new_pair(item, spend_list)?; + } + + let (done, state) = self.ser.add(a, spend_list)?; + assert!(!done); + + // closing the lists at the end needs 2 extra bytes + self.byte_cost = (self.ser.size() + 2) * constants.cost_per_byte; + if self.byte_cost + self.block_cost + cost > constants.max_block_cost_clvm { + // undo the last add() call + self.ser.restore(state); + self.byte_cost = (self.ser.size() + 2) * constants.cost_per_byte; + self.num_skipped += 1; + return Ok((false, result(self.num_skipped))); + } + self.block_cost += cost; + self.signature.aggregate(&bundle.aggregated_signature); + + // if we're very close to a full block, we're done. It's very unlikely + // any transaction will be smallar than MIN_COST_THRESHOLD + let result = if self.byte_cost + self.block_cost + MIN_COST_THRESHOLD + > constants.max_block_cost_clvm + { + BuildBlockResult::Done + } else { + BuildBlockResult::KeepGoing + }; + Ok((true, result)) + } + + pub fn finalize( + mut self, + constants: &ConsensusConstants, + ) -> io::Result<(Vec, Signature, u64)> { + let (done, _) = self.ser.add(&self.allocator, self.allocator.nil())?; + assert!(done); + + // add the size cost before returning it + self.block_cost += self.ser.size() * constants.cost_per_byte; + + assert!(self.block_cost <= constants.max_block_cost_clvm); + Ok((self.ser.into_inner(), self.signature, self.block_cost)) + } +} + +#[cfg(feature = "py-bindings")] +#[pymethods] +impl BlockBuilder { + #[new] + pub fn py_new() -> PyResult { + Ok(Self::new()?) + } + + /// the first bool indicates whether the bundles was added. + /// the second bool indicates whether we're done + #[pyo3(name = "add_spend_bundle")] + pub fn py_add_spend_bundle( + &mut self, + bundle: &SpendBundle, + cost: u64, + constants: &ConsensusConstants, + ) -> PyResult<(bool, bool)> { + let (added, result) = self.add_spend_bundle(bundle, cost, constants)?; + let done = match result { + BuildBlockResult::Done => true, + BuildBlockResult::KeepGoing => false, + }; + Ok((added, done)) + } + + /// generate the block generator + #[pyo3(name = "finalize")] + pub fn py_finalize( + &mut self, + constants: &ConsensusConstants, + ) -> PyResult<(Vec, Signature, u64)> { + let mut temp = BlockBuilder::new()?; + std::mem::swap(self, &mut temp); + let (generator, sig, cost) = temp.finalize(constants)?; + Ok((generator, sig, cost)) + } +} + +// this test is expensive and takes forever in debug builds +#[cfg(not(debug_assertions))] +#[cfg(test)] +mod tests { + use super::*; + use crate::consensus_constants::TEST_CONSTANTS; + use crate::gen::flags::MEMPOOL_MODE; + use crate::gen::owned_conditions::OwnedSpendBundleConditions; + use crate::gen::run_block_generator::run_block_generator2; + use crate::gen::solution_generator::calculate_generator_length; + use crate::spendbundle_conditions::run_spendbundle; + use chia_protocol::Coin; + use chia_traits::Streamable; + use rand::rngs::StdRng; + use rand::{prelude::SliceRandom, SeedableRng}; + use std::collections::HashSet; + use std::fs; + use std::time::Instant; + + #[test] + fn test_build_block() { + let mut all_bundles = vec![]; + println!("loading spend bundles from disk"); + let mut seen_spends = HashSet::new(); + for entry in fs::read_dir("../../test-bundles").expect("listing test-bundles directory") { + let file = entry.expect("list dir").path(); + if file.extension().map(|s| s.to_str()) != Some(Some("bundle")) { + continue; + } + // only use 32 byte hex encoded filenames + if file.file_stem().map(|s| s.len()) != Some(64_usize) { + continue; + } + let buf = fs::read(file.clone()).expect("read bundle file"); + let bundle = SpendBundle::from_bytes(buf.as_slice()).expect("parsing SpendBundle"); + + let mut a = Allocator::new(); + let conds = run_spendbundle( + &mut a, + &bundle, + 11_000_000_000, + 7_000_000, + 0, + &TEST_CONSTANTS, + ) + .expect("run_spendbundle") + .0; + + if conds + .spends + .iter() + .any(|s| seen_spends.contains(&*s.coin_id)) + { + // We can't have conflicting spend bundles, since we combine + // them randomly. In this case two spend bundles spend the same + // coin + panic!( + "conflict in {}", + file.file_name().unwrap().to_str().unwrap() + ); + } + if conds.spends.iter().any(|s| { + s.create_coin.iter().any(|c| { + seen_spends.contains(&Coin::new(*s.coin_id, c.puzzle_hash, c.amount).coin_id()) + }) + }) { + // We can't have conflicting spend bundles, since we combine + // them randomly. In this case one spend bundle spends the coin + // created by another. This is probably OK in most cases, but + // not in the general case. We have restrictions on ephemeral + // spends (they cannot have relative time-lock conditions). + // Since the combination is random, we may end up with an + // invalid block. + panic!( + "conflict in {}", + file.file_name().unwrap().to_str().unwrap() + ); + } + for spend in &conds.spends { + seen_spends.insert(*spend.coin_id); + for coin in &spend.create_coin { + seen_spends + .insert(Coin::new(*spend.coin_id, coin.puzzle_hash, coin.amount).coin_id()); + } + } + + // cost is supposed to not include byte-cost, so we have to subtract + // it here + let cost = conds.cost + - (calculate_generator_length(&bundle.coin_spends) as u64 - 2) + * TEST_CONSTANTS.cost_per_byte; + + let mut conds = OwnedSpendBundleConditions::from(&a, conds); + // when running a block in consensus mode, we don't bother + // establishing whether a spend is eligible for dedup or not. + // So, to compare with the generator output later, we need to clear + // this field + for s in &mut conds.spends { + s.flags = 0; + // when parsing conditions, create coin conditions are stored in + // a hash set to cheaply check for double spends. This means the + // order of this collection is not deterministic. In order to + // compare to the generator output later, we need to sort both. + s.create_coin.sort(); + } + all_bundles.push(Box::new((bundle, cost, conds))); + } + all_bundles.sort_by_key(|x| x.1); + /* + let mut last_cost = 0; + for entry in &all_bundles { + let (cond, cost, _) = entry.as_ref(); + if *cost != last_cost { + println!("\n== {cost}"); + last_cost = *cost; + } + print!("{}.bundle ", cond.name()); + } + println!("\n"); + */ + println!("loaded {} spend bundles", all_bundles.len()); + + let num_cores: usize = std::thread::available_parallelism().unwrap().into(); + let pool = blocking_threadpool::Builder::new() + .num_threads(num_cores) + .queue_len(num_cores + 1) + .build(); + + for seed in 0..30 { + let mut bundles = all_bundles.clone(); + let mut rng = StdRng::seed_from_u64(seed); + pool.execute(move || { + bundles.shuffle(&mut rng); + + let start = Instant::now(); + let mut builder = BlockBuilder::new().expect("BlockBuilder"); + let mut skipped = 0; + let mut num_tx = 0; + let mut max_call_time = 0.0f32; + let mut spends = vec![]; + for entry in &bundles { + let (bundle, cost, conds) = entry.as_ref(); + let start_call = Instant::now(); + let (added, result) = builder + .add_spend_bundle(bundle, *cost, &TEST_CONSTANTS) + .expect("add_spend_bundle"); + max_call_time = f32::max(max_call_time, start_call.elapsed().as_secs_f32()); + if !added { + skipped += 1 + } else { + num_tx += 1; + spends.extend(conds.spends.iter()); + } + if result == BuildBlockResult::Done { + break; + } + } + let (generator, signature, cost) = + builder.finalize(&TEST_CONSTANTS).expect("finalize()"); + + println!( + "idx: {seed:3} built block in {:>5.2} seconds, cost: {cost:11} skipped: {skipped:2} longest-call: {max_call_time:>5.2}s TX: {num_tx}", + start.elapsed().as_secs_f32() + ); + + //fs::write(format!("../../{seed}.generator"), generator.as_slice()) + // .expect("write generator"); + + let mut a = Allocator::new(); + let conds = run_block_generator2::<&[u8], _>( + &mut a, + generator.as_slice(), + [], + TEST_CONSTANTS.max_block_cost_clvm, + MEMPOOL_MODE, + &signature, + None, + &TEST_CONSTANTS, + ) + .expect("run_block_generator2"); + assert_eq!(conds.cost, cost); + let mut conds = OwnedSpendBundleConditions::from(&a, conds); + + assert_eq!(conds.spends.len(), spends.len()); + conds.spends.sort_by_key(|s| s.coin_id); + spends.sort_by_key(|s| s.coin_id); + for (mut gen, tx) in conds.spends.into_iter().zip(spends) { + gen.create_coin.sort(); + assert_eq!(&gen, tx); + } + }); + assert_eq!(pool.panic_count(), 0); + } + pool.join(); + assert_eq!(pool.panic_count(), 0); + } +} diff --git a/crates/chia-consensus/src/gen/mod.rs b/crates/chia-consensus/src/gen/mod.rs index 666c2bc38..4712770d1 100644 --- a/crates/chia-consensus/src/gen/mod.rs +++ b/crates/chia-consensus/src/gen/mod.rs @@ -1,4 +1,5 @@ pub mod additions_and_removals; +pub mod build_compressed_block; mod coin_id; mod condition_sanitizers; pub mod conditions; diff --git a/test-bundles/037e680ae8fe9cfdac4ff2257d07f70c602da7e9b9066b31521d442eee83a001.bundle b/test-bundles/037e680ae8fe9cfdac4ff2257d07f70c602da7e9b9066b31521d442eee83a001.bundle new file mode 100644 index 000000000..48c3dde9b Binary files /dev/null and b/test-bundles/037e680ae8fe9cfdac4ff2257d07f70c602da7e9b9066b31521d442eee83a001.bundle differ diff --git a/test-bundles/0c796f9910b2fb30c9e23c8cb609d012571e3e4e8604125807ed8540f730d04a.bundle b/test-bundles/0c796f9910b2fb30c9e23c8cb609d012571e3e4e8604125807ed8540f730d04a.bundle new file mode 100644 index 000000000..72f4a0f69 Binary files /dev/null and b/test-bundles/0c796f9910b2fb30c9e23c8cb609d012571e3e4e8604125807ed8540f730d04a.bundle differ diff --git a/test-bundles/0de72afdbf8d049d1d597d9031f044a00376a0c0d7555c7d0a124550c731c151.bundle b/test-bundles/0de72afdbf8d049d1d597d9031f044a00376a0c0d7555c7d0a124550c731c151.bundle new file mode 100644 index 000000000..581d4b5e2 Binary files /dev/null and b/test-bundles/0de72afdbf8d049d1d597d9031f044a00376a0c0d7555c7d0a124550c731c151.bundle differ diff --git a/test-bundles/0f70d1176cc38ffa71044be0e777f4e849273a06b58dbb68e790795bb62e7aa4.bundle b/test-bundles/0f70d1176cc38ffa71044be0e777f4e849273a06b58dbb68e790795bb62e7aa4.bundle new file mode 100644 index 000000000..325f6610b Binary files /dev/null and b/test-bundles/0f70d1176cc38ffa71044be0e777f4e849273a06b58dbb68e790795bb62e7aa4.bundle differ diff --git a/test-bundles/10bb3987874ddb17478659ed61022f41c03f7cd9efd9a4977bc73cf61a334ac6.bundle b/test-bundles/10bb3987874ddb17478659ed61022f41c03f7cd9efd9a4977bc73cf61a334ac6.bundle new file mode 100644 index 000000000..c04207156 Binary files /dev/null and b/test-bundles/10bb3987874ddb17478659ed61022f41c03f7cd9efd9a4977bc73cf61a334ac6.bundle differ diff --git a/test-bundles/12e8f00e9d0cefd6c9b6ca6579879c562bc0fb30263c959379893e16f0a7ee74.bundle b/test-bundles/12e8f00e9d0cefd6c9b6ca6579879c562bc0fb30263c959379893e16f0a7ee74.bundle new file mode 100644 index 000000000..b703b5be4 Binary files /dev/null and b/test-bundles/12e8f00e9d0cefd6c9b6ca6579879c562bc0fb30263c959379893e16f0a7ee74.bundle differ diff --git a/test-bundles/16f0778b505d9dd8e38348c4c4ad9a704a78a21dcc79e3940d14e1b53cf63a41.bundle b/test-bundles/16f0778b505d9dd8e38348c4c4ad9a704a78a21dcc79e3940d14e1b53cf63a41.bundle new file mode 100644 index 000000000..6627600ad Binary files /dev/null and b/test-bundles/16f0778b505d9dd8e38348c4c4ad9a704a78a21dcc79e3940d14e1b53cf63a41.bundle differ diff --git a/test-bundles/1925f147c8e99ed9166a85e1757c96332b0be95eee91e97a73bc925918f3dd3e.bundle b/test-bundles/1925f147c8e99ed9166a85e1757c96332b0be95eee91e97a73bc925918f3dd3e.bundle new file mode 100644 index 000000000..765842448 Binary files /dev/null and b/test-bundles/1925f147c8e99ed9166a85e1757c96332b0be95eee91e97a73bc925918f3dd3e.bundle differ diff --git a/test-bundles/1cd979f21a52b810ea82d097d5e2b221d78e62969be90b0197c5f38407636ce7.bundle b/test-bundles/1cd979f21a52b810ea82d097d5e2b221d78e62969be90b0197c5f38407636ce7.bundle new file mode 100644 index 000000000..f07120765 Binary files /dev/null and b/test-bundles/1cd979f21a52b810ea82d097d5e2b221d78e62969be90b0197c5f38407636ce7.bundle differ diff --git a/test-bundles/21990dc23d091c20dec57d9ee8c4ae58fde803c5e1c2338f1aa1f3fd74f5f95a.bundle b/test-bundles/21990dc23d091c20dec57d9ee8c4ae58fde803c5e1c2338f1aa1f3fd74f5f95a.bundle new file mode 100644 index 000000000..80943074a Binary files /dev/null and b/test-bundles/21990dc23d091c20dec57d9ee8c4ae58fde803c5e1c2338f1aa1f3fd74f5f95a.bundle differ diff --git a/test-bundles/268c426be3b370d2226a11fb8286005f2313813f22f593a5de426d5fd2b44cf0.bundle b/test-bundles/268c426be3b370d2226a11fb8286005f2313813f22f593a5de426d5fd2b44cf0.bundle new file mode 100644 index 000000000..c2eb87bc5 Binary files /dev/null and b/test-bundles/268c426be3b370d2226a11fb8286005f2313813f22f593a5de426d5fd2b44cf0.bundle differ diff --git a/test-bundles/2a219fefaed38bd24672596038fe69958abe092ba8d3701f4073aad3e9fe1076.bundle b/test-bundles/2a219fefaed38bd24672596038fe69958abe092ba8d3701f4073aad3e9fe1076.bundle new file mode 100644 index 000000000..c00bec4ea Binary files /dev/null and b/test-bundles/2a219fefaed38bd24672596038fe69958abe092ba8d3701f4073aad3e9fe1076.bundle differ diff --git a/test-bundles/2d2ad9eb0be3b6cda65183b525fb24a02eca9eba654d146a16b7e007dbb6191c.bundle b/test-bundles/2d2ad9eb0be3b6cda65183b525fb24a02eca9eba654d146a16b7e007dbb6191c.bundle new file mode 100644 index 000000000..913173cb1 Binary files /dev/null and b/test-bundles/2d2ad9eb0be3b6cda65183b525fb24a02eca9eba654d146a16b7e007dbb6191c.bundle differ diff --git a/test-bundles/2d55585299f9b8ec442967818b2c8c54d9efbf84ffc23d2300136e29cf593067.bundle b/test-bundles/2d55585299f9b8ec442967818b2c8c54d9efbf84ffc23d2300136e29cf593067.bundle new file mode 100644 index 000000000..961661752 Binary files /dev/null and b/test-bundles/2d55585299f9b8ec442967818b2c8c54d9efbf84ffc23d2300136e29cf593067.bundle differ diff --git a/test-bundles/2d8e85be24a72f02fc26283fe14fad1a76ea77e55f1641f0701e8bdfe34a6f16.bundle b/test-bundles/2d8e85be24a72f02fc26283fe14fad1a76ea77e55f1641f0701e8bdfe34a6f16.bundle new file mode 100644 index 000000000..01aafef51 Binary files /dev/null and b/test-bundles/2d8e85be24a72f02fc26283fe14fad1a76ea77e55f1641f0701e8bdfe34a6f16.bundle differ diff --git a/test-bundles/2e03daa850e6c6c0a7e003f9ec22034a314a2b37caf65e1947b5236f19946338.bundle b/test-bundles/2e03daa850e6c6c0a7e003f9ec22034a314a2b37caf65e1947b5236f19946338.bundle new file mode 100644 index 000000000..476e9d38b Binary files /dev/null and b/test-bundles/2e03daa850e6c6c0a7e003f9ec22034a314a2b37caf65e1947b5236f19946338.bundle differ diff --git a/test-bundles/31f8bd13279eb68ea387272d923c69ff5361d0f799926dc2de465a3fdac9e6e7.bundle b/test-bundles/31f8bd13279eb68ea387272d923c69ff5361d0f799926dc2de465a3fdac9e6e7.bundle new file mode 100644 index 000000000..c7f301b9b Binary files /dev/null and b/test-bundles/31f8bd13279eb68ea387272d923c69ff5361d0f799926dc2de465a3fdac9e6e7.bundle differ diff --git a/test-bundles/37c5716665ac5fb008a8a6d460b4b541a9a1d8e987a2eacceef2ebcaa12c09c6.bundle b/test-bundles/37c5716665ac5fb008a8a6d460b4b541a9a1d8e987a2eacceef2ebcaa12c09c6.bundle new file mode 100644 index 000000000..ed92859fe Binary files /dev/null and b/test-bundles/37c5716665ac5fb008a8a6d460b4b541a9a1d8e987a2eacceef2ebcaa12c09c6.bundle differ diff --git a/test-bundles/386a21482642db13e5c011dc4399aabd4378e2d387fceed0826276d15b86a465.bundle b/test-bundles/386a21482642db13e5c011dc4399aabd4378e2d387fceed0826276d15b86a465.bundle new file mode 100644 index 000000000..2e39247af Binary files /dev/null and b/test-bundles/386a21482642db13e5c011dc4399aabd4378e2d387fceed0826276d15b86a465.bundle differ diff --git a/test-bundles/38a6b2090adfa0666d1d49e411a05d5f3cb44202e6fffc5340a9060037837e7c.bundle b/test-bundles/38a6b2090adfa0666d1d49e411a05d5f3cb44202e6fffc5340a9060037837e7c.bundle new file mode 100644 index 000000000..771cb72ae Binary files /dev/null and b/test-bundles/38a6b2090adfa0666d1d49e411a05d5f3cb44202e6fffc5340a9060037837e7c.bundle differ diff --git a/test-bundles/3cc81d20eb2e3e9feefd5eb58a2203c8efab5939e6ab3ec1da80c8dfd9f121a6.bundle b/test-bundles/3cc81d20eb2e3e9feefd5eb58a2203c8efab5939e6ab3ec1da80c8dfd9f121a6.bundle new file mode 100644 index 000000000..6482b7f85 Binary files /dev/null and b/test-bundles/3cc81d20eb2e3e9feefd5eb58a2203c8efab5939e6ab3ec1da80c8dfd9f121a6.bundle differ diff --git a/test-bundles/3e8361ba27ab425a7cab334adc27d64783ae332bba716e8cc5eae2cd480d7d42.bundle b/test-bundles/3e8361ba27ab425a7cab334adc27d64783ae332bba716e8cc5eae2cd480d7d42.bundle new file mode 100644 index 000000000..fb0014c75 Binary files /dev/null and b/test-bundles/3e8361ba27ab425a7cab334adc27d64783ae332bba716e8cc5eae2cd480d7d42.bundle differ diff --git a/test-bundles/43d1514054adee33fcc666af405d5c918434ac52923adb3be686c0d0bbaba50c.bundle b/test-bundles/43d1514054adee33fcc666af405d5c918434ac52923adb3be686c0d0bbaba50c.bundle new file mode 100644 index 000000000..ee580017b Binary files /dev/null and b/test-bundles/43d1514054adee33fcc666af405d5c918434ac52923adb3be686c0d0bbaba50c.bundle differ diff --git a/test-bundles/45208fa020a00509bfe4d07e8b3e01f846443df292d4b43327bb93600060a774.bundle b/test-bundles/45208fa020a00509bfe4d07e8b3e01f846443df292d4b43327bb93600060a774.bundle new file mode 100644 index 000000000..a0bffe31c Binary files /dev/null and b/test-bundles/45208fa020a00509bfe4d07e8b3e01f846443df292d4b43327bb93600060a774.bundle differ diff --git a/test-bundles/46b904e55559a386f1b5e98033feab0b2986c9dbf59e340cf24fe2d5e055739b.bundle b/test-bundles/46b904e55559a386f1b5e98033feab0b2986c9dbf59e340cf24fe2d5e055739b.bundle new file mode 100644 index 000000000..986f6a713 Binary files /dev/null and b/test-bundles/46b904e55559a386f1b5e98033feab0b2986c9dbf59e340cf24fe2d5e055739b.bundle differ diff --git a/test-bundles/46daf158d4117972c5b66a180316d5f2abfc02bb68539cb63ccedf2caf6e4c8e.bundle b/test-bundles/46daf158d4117972c5b66a180316d5f2abfc02bb68539cb63ccedf2caf6e4c8e.bundle new file mode 100644 index 000000000..5a8cf44e8 Binary files /dev/null and b/test-bundles/46daf158d4117972c5b66a180316d5f2abfc02bb68539cb63ccedf2caf6e4c8e.bundle differ diff --git a/test-bundles/472749423dd9238234a77acae729ed58d25660bb3b54291e950c2bd7fb0aa29f.bundle b/test-bundles/472749423dd9238234a77acae729ed58d25660bb3b54291e950c2bd7fb0aa29f.bundle new file mode 100644 index 000000000..ec47e056d Binary files /dev/null and b/test-bundles/472749423dd9238234a77acae729ed58d25660bb3b54291e950c2bd7fb0aa29f.bundle differ diff --git a/test-bundles/485f1ad283991bbf26eedbe05678499db17160e5e52701d2f27b367ce6f97136.bundle b/test-bundles/485f1ad283991bbf26eedbe05678499db17160e5e52701d2f27b367ce6f97136.bundle new file mode 100644 index 000000000..b989b5a6e Binary files /dev/null and b/test-bundles/485f1ad283991bbf26eedbe05678499db17160e5e52701d2f27b367ce6f97136.bundle differ diff --git a/test-bundles/48d9587d396fb1847dc04fff9df7892bb536944d345f73d33f443710c7bcd464.bundle b/test-bundles/48d9587d396fb1847dc04fff9df7892bb536944d345f73d33f443710c7bcd464.bundle new file mode 100644 index 000000000..3396b2023 Binary files /dev/null and b/test-bundles/48d9587d396fb1847dc04fff9df7892bb536944d345f73d33f443710c7bcd464.bundle differ diff --git a/test-bundles/4c966796ed1bab48a71ada8b89942322dc40695c957a629442a3973766beba6e.bundle b/test-bundles/4c966796ed1bab48a71ada8b89942322dc40695c957a629442a3973766beba6e.bundle new file mode 100644 index 000000000..8307137ef Binary files /dev/null and b/test-bundles/4c966796ed1bab48a71ada8b89942322dc40695c957a629442a3973766beba6e.bundle differ diff --git a/test-bundles/5d01fb2058f6e4dceee4d5db8bff37e80a994656940b71f1b644cd99dc16941c.bundle b/test-bundles/5d01fb2058f6e4dceee4d5db8bff37e80a994656940b71f1b644cd99dc16941c.bundle new file mode 100644 index 000000000..5c21fb151 Binary files /dev/null and b/test-bundles/5d01fb2058f6e4dceee4d5db8bff37e80a994656940b71f1b644cd99dc16941c.bundle differ diff --git a/test-bundles/5f1d8f039c5c0d270a6dbaa76c0ab8644102fc2fc6b608598b496757b93fd956.bundle b/test-bundles/5f1d8f039c5c0d270a6dbaa76c0ab8644102fc2fc6b608598b496757b93fd956.bundle new file mode 100644 index 000000000..b262aac84 Binary files /dev/null and b/test-bundles/5f1d8f039c5c0d270a6dbaa76c0ab8644102fc2fc6b608598b496757b93fd956.bundle differ diff --git a/test-bundles/629a309e5a9b50c41b0d8a76b5c92b089ae07fa4d9062a43ff274a212b967bea.bundle b/test-bundles/629a309e5a9b50c41b0d8a76b5c92b089ae07fa4d9062a43ff274a212b967bea.bundle new file mode 100644 index 000000000..8d43a652f Binary files /dev/null and b/test-bundles/629a309e5a9b50c41b0d8a76b5c92b089ae07fa4d9062a43ff274a212b967bea.bundle differ diff --git a/test-bundles/647e5b7e1b05ce752de28a2e636799b9b9b5fefaa966dc50871f6a6c5344fffc.bundle b/test-bundles/647e5b7e1b05ce752de28a2e636799b9b9b5fefaa966dc50871f6a6c5344fffc.bundle new file mode 100644 index 000000000..c930edd06 Binary files /dev/null and b/test-bundles/647e5b7e1b05ce752de28a2e636799b9b9b5fefaa966dc50871f6a6c5344fffc.bundle differ diff --git a/test-bundles/67a24e5ae201ddeb5b8e050611e866b93674f5979ab363f18736fc3d40439ebb.bundle b/test-bundles/67a24e5ae201ddeb5b8e050611e866b93674f5979ab363f18736fc3d40439ebb.bundle new file mode 100644 index 000000000..eef1c8ef0 Binary files /dev/null and b/test-bundles/67a24e5ae201ddeb5b8e050611e866b93674f5979ab363f18736fc3d40439ebb.bundle differ diff --git a/test-bundles/6a961d7f704fcbf47590b8f3caade94ff2e6a0b6f9787619c5cd7e23c895abf6.bundle b/test-bundles/6a961d7f704fcbf47590b8f3caade94ff2e6a0b6f9787619c5cd7e23c895abf6.bundle new file mode 100644 index 000000000..6f37067a3 Binary files /dev/null and b/test-bundles/6a961d7f704fcbf47590b8f3caade94ff2e6a0b6f9787619c5cd7e23c895abf6.bundle differ diff --git a/test-bundles/6bf510b642abebd30d0b92253d8784c3bef6e3cf6d10b36d1b974631b1f80f0f.bundle b/test-bundles/6bf510b642abebd30d0b92253d8784c3bef6e3cf6d10b36d1b974631b1f80f0f.bundle new file mode 100644 index 000000000..25d419145 Binary files /dev/null and b/test-bundles/6bf510b642abebd30d0b92253d8784c3bef6e3cf6d10b36d1b974631b1f80f0f.bundle differ diff --git a/test-bundles/7687ca119948030f01991176e2ebbc718ae6854120dc0d11794877988569a58a.bundle b/test-bundles/7687ca119948030f01991176e2ebbc718ae6854120dc0d11794877988569a58a.bundle new file mode 100644 index 000000000..d1d32ad32 Binary files /dev/null and b/test-bundles/7687ca119948030f01991176e2ebbc718ae6854120dc0d11794877988569a58a.bundle differ diff --git a/test-bundles/76b0716e35795da02d945a22b87bf60f30a4a43c418e302bd6bae16fd6cffa1a.bundle b/test-bundles/76b0716e35795da02d945a22b87bf60f30a4a43c418e302bd6bae16fd6cffa1a.bundle new file mode 100644 index 000000000..6a85061c6 Binary files /dev/null and b/test-bundles/76b0716e35795da02d945a22b87bf60f30a4a43c418e302bd6bae16fd6cffa1a.bundle differ diff --git a/test-bundles/7885406ea7ce65161b53ae23f721b09f6c8a142162615fed4d5f28ff1e86770c.bundle b/test-bundles/7885406ea7ce65161b53ae23f721b09f6c8a142162615fed4d5f28ff1e86770c.bundle new file mode 100644 index 000000000..38888a615 Binary files /dev/null and b/test-bundles/7885406ea7ce65161b53ae23f721b09f6c8a142162615fed4d5f28ff1e86770c.bundle differ diff --git a/test-bundles/7e83fb4723c1641d2a500427beba2521f343121d8b45350a158900405d7cf1c3.bundle b/test-bundles/7e83fb4723c1641d2a500427beba2521f343121d8b45350a158900405d7cf1c3.bundle new file mode 100644 index 000000000..431300c71 Binary files /dev/null and b/test-bundles/7e83fb4723c1641d2a500427beba2521f343121d8b45350a158900405d7cf1c3.bundle differ diff --git a/test-bundles/80c84c693534ff845ef7cb7f086960d4ba1fe98a481720860447b1eb166daf32.bundle b/test-bundles/80c84c693534ff845ef7cb7f086960d4ba1fe98a481720860447b1eb166daf32.bundle new file mode 100644 index 000000000..cf03e1075 Binary files /dev/null and b/test-bundles/80c84c693534ff845ef7cb7f086960d4ba1fe98a481720860447b1eb166daf32.bundle differ diff --git a/test-bundles/83bc1054429289b03073769f05e1733f57758b7c3d63639d08bdf34294e6c6e8.bundle b/test-bundles/83bc1054429289b03073769f05e1733f57758b7c3d63639d08bdf34294e6c6e8.bundle new file mode 100644 index 000000000..62f7d0b4d Binary files /dev/null and b/test-bundles/83bc1054429289b03073769f05e1733f57758b7c3d63639d08bdf34294e6c6e8.bundle differ diff --git a/test-bundles/8ca52e211116d645d802df74dde8d3adba326f3579ed7ed170c95ef7b6def3a4.bundle b/test-bundles/8ca52e211116d645d802df74dde8d3adba326f3579ed7ed170c95ef7b6def3a4.bundle new file mode 100644 index 000000000..1c5fb733b Binary files /dev/null and b/test-bundles/8ca52e211116d645d802df74dde8d3adba326f3579ed7ed170c95ef7b6def3a4.bundle differ diff --git a/test-bundles/8cc1e0f8b36345318573ec90d643d9fc8cec1314672db477542b99e1f56ebb19.bundle b/test-bundles/8cc1e0f8b36345318573ec90d643d9fc8cec1314672db477542b99e1f56ebb19.bundle new file mode 100644 index 000000000..e97c4d83f Binary files /dev/null and b/test-bundles/8cc1e0f8b36345318573ec90d643d9fc8cec1314672db477542b99e1f56ebb19.bundle differ diff --git a/test-bundles/90556b4beb95a0bd33123f6d8eb638d443da9b9e1311c4c5e17e00dd7cb7077f.bundle b/test-bundles/90556b4beb95a0bd33123f6d8eb638d443da9b9e1311c4c5e17e00dd7cb7077f.bundle new file mode 100644 index 000000000..6c792975c Binary files /dev/null and b/test-bundles/90556b4beb95a0bd33123f6d8eb638d443da9b9e1311c4c5e17e00dd7cb7077f.bundle differ diff --git a/test-bundles/91378e247412c989e2e9f469a2acc20b3c63fdd2e0a02252634393dddb9048b3.bundle b/test-bundles/91378e247412c989e2e9f469a2acc20b3c63fdd2e0a02252634393dddb9048b3.bundle new file mode 100644 index 000000000..a96c3ea9f Binary files /dev/null and b/test-bundles/91378e247412c989e2e9f469a2acc20b3c63fdd2e0a02252634393dddb9048b3.bundle differ diff --git a/test-bundles/91933e4b35155fc3efb768f374679b0f3f449d57365a138aca6759a339cf8fe7.bundle b/test-bundles/91933e4b35155fc3efb768f374679b0f3f449d57365a138aca6759a339cf8fe7.bundle new file mode 100644 index 000000000..b0bc1faa7 Binary files /dev/null and b/test-bundles/91933e4b35155fc3efb768f374679b0f3f449d57365a138aca6759a339cf8fe7.bundle differ diff --git a/test-bundles/96dbb40af966696f82707c1e2a2b96b77f634ec21fcbc42f58ee372652107a51.bundle b/test-bundles/96dbb40af966696f82707c1e2a2b96b77f634ec21fcbc42f58ee372652107a51.bundle new file mode 100644 index 000000000..caa4e8d79 Binary files /dev/null and b/test-bundles/96dbb40af966696f82707c1e2a2b96b77f634ec21fcbc42f58ee372652107a51.bundle differ diff --git a/test-bundles/9983252d51abff56851b4848f78767852c3a901cb73b5ddc52b1ce904210183a.bundle b/test-bundles/9983252d51abff56851b4848f78767852c3a901cb73b5ddc52b1ce904210183a.bundle new file mode 100644 index 000000000..ae816b7cc Binary files /dev/null and b/test-bundles/9983252d51abff56851b4848f78767852c3a901cb73b5ddc52b1ce904210183a.bundle differ diff --git a/test-bundles/9b076fee375eb94b9b6cc2b8c2bfd0622cd9bfd7d7aabf586d0c418641b8ec4c.bundle b/test-bundles/9b076fee375eb94b9b6cc2b8c2bfd0622cd9bfd7d7aabf586d0c418641b8ec4c.bundle new file mode 100644 index 000000000..d2020a32c Binary files /dev/null and b/test-bundles/9b076fee375eb94b9b6cc2b8c2bfd0622cd9bfd7d7aabf586d0c418641b8ec4c.bundle differ diff --git a/test-bundles/9c8d0a2032a80d41bba2ec226d8b315ee2f7d66602f7da65b534831de39c54fe.bundle b/test-bundles/9c8d0a2032a80d41bba2ec226d8b315ee2f7d66602f7da65b534831de39c54fe.bundle new file mode 100644 index 000000000..cf63d304a Binary files /dev/null and b/test-bundles/9c8d0a2032a80d41bba2ec226d8b315ee2f7d66602f7da65b534831de39c54fe.bundle differ diff --git a/test-bundles/9d39ab5b0d8eaf58c372d614021f2685502b114a05804ca7556c85db084a9113.bundle b/test-bundles/9d39ab5b0d8eaf58c372d614021f2685502b114a05804ca7556c85db084a9113.bundle new file mode 100644 index 000000000..75b278c02 Binary files /dev/null and b/test-bundles/9d39ab5b0d8eaf58c372d614021f2685502b114a05804ca7556c85db084a9113.bundle differ diff --git a/test-bundles/9fd62d48c3eb44bc5a53362c6bccf1cabeb6f6ef3ea1b63562490c44ecbb55da.bundle b/test-bundles/9fd62d48c3eb44bc5a53362c6bccf1cabeb6f6ef3ea1b63562490c44ecbb55da.bundle new file mode 100644 index 000000000..efbd87d84 Binary files /dev/null and b/test-bundles/9fd62d48c3eb44bc5a53362c6bccf1cabeb6f6ef3ea1b63562490c44ecbb55da.bundle differ diff --git a/test-bundles/a3dfcdf2d9e9222e29c524b3f6db3310b51c7f0d90810aa17a0dab5b6c51c36c.bundle b/test-bundles/a3dfcdf2d9e9222e29c524b3f6db3310b51c7f0d90810aa17a0dab5b6c51c36c.bundle new file mode 100644 index 000000000..856be8fca Binary files /dev/null and b/test-bundles/a3dfcdf2d9e9222e29c524b3f6db3310b51c7f0d90810aa17a0dab5b6c51c36c.bundle differ diff --git a/test-bundles/a67f0af6ad07eddbd496b03f6a56f731aa82cc1fd92783a0ef4ba78d5ef154dc.bundle b/test-bundles/a67f0af6ad07eddbd496b03f6a56f731aa82cc1fd92783a0ef4ba78d5ef154dc.bundle new file mode 100644 index 000000000..d971955cf Binary files /dev/null and b/test-bundles/a67f0af6ad07eddbd496b03f6a56f731aa82cc1fd92783a0ef4ba78d5ef154dc.bundle differ diff --git a/test-bundles/acf3d90eb51968732a1191ffd407cb96e0eabddb919a67983c01095095f63d67.bundle b/test-bundles/acf3d90eb51968732a1191ffd407cb96e0eabddb919a67983c01095095f63d67.bundle new file mode 100644 index 000000000..fb088053a Binary files /dev/null and b/test-bundles/acf3d90eb51968732a1191ffd407cb96e0eabddb919a67983c01095095f63d67.bundle differ diff --git a/test-bundles/ad4e414d2493f3ad30a1f27869114e228e302104676e5548a3ba7d37a76e5e5d.bundle b/test-bundles/ad4e414d2493f3ad30a1f27869114e228e302104676e5548a3ba7d37a76e5e5d.bundle new file mode 100644 index 000000000..79114aa4b Binary files /dev/null and b/test-bundles/ad4e414d2493f3ad30a1f27869114e228e302104676e5548a3ba7d37a76e5e5d.bundle differ diff --git a/test-bundles/aef956080dc128528b411587bce2dd2f3e38a803252750f675a4841484040db1.bundle b/test-bundles/aef956080dc128528b411587bce2dd2f3e38a803252750f675a4841484040db1.bundle new file mode 100644 index 000000000..141829dfc Binary files /dev/null and b/test-bundles/aef956080dc128528b411587bce2dd2f3e38a803252750f675a4841484040db1.bundle differ diff --git a/test-bundles/b045a645abfe390ccdee5ad4c0bc058c635f4c3d25a1ccc5bcb4cb436a1d154c.bundle b/test-bundles/b045a645abfe390ccdee5ad4c0bc058c635f4c3d25a1ccc5bcb4cb436a1d154c.bundle new file mode 100644 index 000000000..c8eec295e Binary files /dev/null and b/test-bundles/b045a645abfe390ccdee5ad4c0bc058c635f4c3d25a1ccc5bcb4cb436a1d154c.bundle differ diff --git a/test-bundles/b2452cbee1aba0a5ac45f3e91ed519dbad279645b65483c51ca39996a7590cba.bundle b/test-bundles/b2452cbee1aba0a5ac45f3e91ed519dbad279645b65483c51ca39996a7590cba.bundle new file mode 100644 index 000000000..fac4b7d4d Binary files /dev/null and b/test-bundles/b2452cbee1aba0a5ac45f3e91ed519dbad279645b65483c51ca39996a7590cba.bundle differ diff --git a/test-bundles/bc34f43cbb9bbd0fc6f1029164ee85c68b97860aaacb56f2fa1fbb36f6259893.bundle b/test-bundles/bc34f43cbb9bbd0fc6f1029164ee85c68b97860aaacb56f2fa1fbb36f6259893.bundle new file mode 100644 index 000000000..aed093dfb Binary files /dev/null and b/test-bundles/bc34f43cbb9bbd0fc6f1029164ee85c68b97860aaacb56f2fa1fbb36f6259893.bundle differ diff --git a/test-bundles/bc4852de4a69a8d3426f7524a98e618908c40ded2947dea21f990057c5893d72.bundle b/test-bundles/bc4852de4a69a8d3426f7524a98e618908c40ded2947dea21f990057c5893d72.bundle new file mode 100644 index 000000000..670fc46ed Binary files /dev/null and b/test-bundles/bc4852de4a69a8d3426f7524a98e618908c40ded2947dea21f990057c5893d72.bundle differ diff --git a/test-bundles/bc7920dd8ac5865d228a1f9f9fb06f60c4c1226aec6462bbd83661669b663890.bundle b/test-bundles/bc7920dd8ac5865d228a1f9f9fb06f60c4c1226aec6462bbd83661669b663890.bundle new file mode 100644 index 000000000..036b54b6f Binary files /dev/null and b/test-bundles/bc7920dd8ac5865d228a1f9f9fb06f60c4c1226aec6462bbd83661669b663890.bundle differ diff --git a/test-bundles/be52228bf596f24106cebece425bf69c8f9d794d34d49b61435eb0216649298c.bundle b/test-bundles/be52228bf596f24106cebece425bf69c8f9d794d34d49b61435eb0216649298c.bundle new file mode 100644 index 000000000..a16843a54 Binary files /dev/null and b/test-bundles/be52228bf596f24106cebece425bf69c8f9d794d34d49b61435eb0216649298c.bundle differ diff --git a/test-bundles/bfba39278a69996008fe093f11bf136d6f81e873d6d309029fef79faf2a92fce.bundle b/test-bundles/bfba39278a69996008fe093f11bf136d6f81e873d6d309029fef79faf2a92fce.bundle new file mode 100644 index 000000000..66c673207 Binary files /dev/null and b/test-bundles/bfba39278a69996008fe093f11bf136d6f81e873d6d309029fef79faf2a92fce.bundle differ diff --git a/test-bundles/c00b13ec1eb80e79bef103de384cb1d30f766d5563d1be9a437671b3f753cec4.bundle b/test-bundles/c00b13ec1eb80e79bef103de384cb1d30f766d5563d1be9a437671b3f753cec4.bundle new file mode 100644 index 000000000..5412e5296 Binary files /dev/null and b/test-bundles/c00b13ec1eb80e79bef103de384cb1d30f766d5563d1be9a437671b3f753cec4.bundle differ diff --git a/test-bundles/c0a646b803f4c652e9d11e31f6b63f2a91c9b5a21f37f1484e88d4342ee4a68a.bundle b/test-bundles/c0a646b803f4c652e9d11e31f6b63f2a91c9b5a21f37f1484e88d4342ee4a68a.bundle new file mode 100644 index 000000000..1180ab3cd Binary files /dev/null and b/test-bundles/c0a646b803f4c652e9d11e31f6b63f2a91c9b5a21f37f1484e88d4342ee4a68a.bundle differ diff --git a/test-bundles/c154226f0d70943b49ea8da4c17b1ea62286951631cba2bbb9c4609ab8c33ea1.bundle b/test-bundles/c154226f0d70943b49ea8da4c17b1ea62286951631cba2bbb9c4609ab8c33ea1.bundle new file mode 100644 index 000000000..1a13646ad Binary files /dev/null and b/test-bundles/c154226f0d70943b49ea8da4c17b1ea62286951631cba2bbb9c4609ab8c33ea1.bundle differ diff --git a/test-bundles/d0c028ea6dbfa8f38e61b7f55ef4a7d8a2f436ff4069bb7178944962a8c02c44.bundle b/test-bundles/d0c028ea6dbfa8f38e61b7f55ef4a7d8a2f436ff4069bb7178944962a8c02c44.bundle new file mode 100644 index 000000000..a0e5ecc6a Binary files /dev/null and b/test-bundles/d0c028ea6dbfa8f38e61b7f55ef4a7d8a2f436ff4069bb7178944962a8c02c44.bundle differ diff --git a/test-bundles/d299c5b1d9068d5e0987f0e675ca0893bb48cfa51e1776eadc9f4fa073c5637e.bundle b/test-bundles/d299c5b1d9068d5e0987f0e675ca0893bb48cfa51e1776eadc9f4fa073c5637e.bundle new file mode 100644 index 000000000..a13a2ff22 Binary files /dev/null and b/test-bundles/d299c5b1d9068d5e0987f0e675ca0893bb48cfa51e1776eadc9f4fa073c5637e.bundle differ diff --git a/test-bundles/d3c07592627b1932f4ff5b6f703a4572e6edd1ee7a1e27dc62ee0c63fc7b4a07.bundle b/test-bundles/d3c07592627b1932f4ff5b6f703a4572e6edd1ee7a1e27dc62ee0c63fc7b4a07.bundle new file mode 100644 index 000000000..0403bdfc3 Binary files /dev/null and b/test-bundles/d3c07592627b1932f4ff5b6f703a4572e6edd1ee7a1e27dc62ee0c63fc7b4a07.bundle differ diff --git a/test-bundles/d5e423ef262b1b9bd1196a79ee2d469c74ba1c7124028c602ff0b3501b25d652.bundle b/test-bundles/d5e423ef262b1b9bd1196a79ee2d469c74ba1c7124028c602ff0b3501b25d652.bundle new file mode 100644 index 000000000..c3ff0eaf5 Binary files /dev/null and b/test-bundles/d5e423ef262b1b9bd1196a79ee2d469c74ba1c7124028c602ff0b3501b25d652.bundle differ diff --git a/test-bundles/d662ac4f196bebeae888b811ab9abc597d0fbeee9dea04bb7bf992cb3c36f9a8.bundle b/test-bundles/d662ac4f196bebeae888b811ab9abc597d0fbeee9dea04bb7bf992cb3c36f9a8.bundle new file mode 100644 index 000000000..b50e20cd5 Binary files /dev/null and b/test-bundles/d662ac4f196bebeae888b811ab9abc597d0fbeee9dea04bb7bf992cb3c36f9a8.bundle differ diff --git a/test-bundles/da2fa398155951d4faaf11ebc091c082a374e0611e58ae4ecd92d509e44eeda7.bundle b/test-bundles/da2fa398155951d4faaf11ebc091c082a374e0611e58ae4ecd92d509e44eeda7.bundle new file mode 100644 index 000000000..946a4cff3 Binary files /dev/null and b/test-bundles/da2fa398155951d4faaf11ebc091c082a374e0611e58ae4ecd92d509e44eeda7.bundle differ diff --git a/test-bundles/db351f9e1d86979358f516d10481ec8f877fb7e90cffe4a391f452534a533778.bundle b/test-bundles/db351f9e1d86979358f516d10481ec8f877fb7e90cffe4a391f452534a533778.bundle new file mode 100644 index 000000000..caccd95d1 Binary files /dev/null and b/test-bundles/db351f9e1d86979358f516d10481ec8f877fb7e90cffe4a391f452534a533778.bundle differ diff --git a/test-bundles/dcfceb0863b2b6bdb2fbd694a7980482ef0ee1f89796f64a52fca20c29b66402.bundle b/test-bundles/dcfceb0863b2b6bdb2fbd694a7980482ef0ee1f89796f64a52fca20c29b66402.bundle new file mode 100644 index 000000000..b31db7c79 Binary files /dev/null and b/test-bundles/dcfceb0863b2b6bdb2fbd694a7980482ef0ee1f89796f64a52fca20c29b66402.bundle differ diff --git a/test-bundles/e3109f42a1645cf0e6297287362e11506687295a8cc406cce5e060c5faf0b137.bundle b/test-bundles/e3109f42a1645cf0e6297287362e11506687295a8cc406cce5e060c5faf0b137.bundle new file mode 100644 index 000000000..7d6922d83 Binary files /dev/null and b/test-bundles/e3109f42a1645cf0e6297287362e11506687295a8cc406cce5e060c5faf0b137.bundle differ diff --git a/test-bundles/e510bf5542753bf200f1c78f3b5f10eed2cd33aa9a7bb2e085eb5824c020e1bd.bundle b/test-bundles/e510bf5542753bf200f1c78f3b5f10eed2cd33aa9a7bb2e085eb5824c020e1bd.bundle new file mode 100644 index 000000000..569668640 Binary files /dev/null and b/test-bundles/e510bf5542753bf200f1c78f3b5f10eed2cd33aa9a7bb2e085eb5824c020e1bd.bundle differ diff --git a/test-bundles/ea1741fd2291dd7e9ccd27b80777759fb406f5cdcf191c64ae0430033409d5f2.bundle b/test-bundles/ea1741fd2291dd7e9ccd27b80777759fb406f5cdcf191c64ae0430033409d5f2.bundle new file mode 100644 index 000000000..1869a2390 Binary files /dev/null and b/test-bundles/ea1741fd2291dd7e9ccd27b80777759fb406f5cdcf191c64ae0430033409d5f2.bundle differ diff --git a/test-bundles/eb33dd74ca01c65025922947c734a10974602c44a4140034c048c280d9465920.bundle b/test-bundles/eb33dd74ca01c65025922947c734a10974602c44a4140034c048c280d9465920.bundle new file mode 100644 index 000000000..53f084e3f Binary files /dev/null and b/test-bundles/eb33dd74ca01c65025922947c734a10974602c44a4140034c048c280d9465920.bundle differ diff --git a/test-bundles/eed539eac205c7f4f07bfe072eccb9cfc784ee082f616c66b5a4eda7e630a5bf.bundle b/test-bundles/eed539eac205c7f4f07bfe072eccb9cfc784ee082f616c66b5a4eda7e630a5bf.bundle new file mode 100644 index 000000000..79311c3e5 Binary files /dev/null and b/test-bundles/eed539eac205c7f4f07bfe072eccb9cfc784ee082f616c66b5a4eda7e630a5bf.bundle differ diff --git a/test-bundles/f0b970676fadd05f2959c4f162f538c29b540b697f2997b6f59648d968751c2a.bundle b/test-bundles/f0b970676fadd05f2959c4f162f538c29b540b697f2997b6f59648d968751c2a.bundle new file mode 100644 index 000000000..c13ecfbc7 Binary files /dev/null and b/test-bundles/f0b970676fadd05f2959c4f162f538c29b540b697f2997b6f59648d968751c2a.bundle differ diff --git a/test-bundles/f387210887d5c4859f0a468021ba7e9a269ddd13dfb260af5b94ecb03d3c710c.bundle b/test-bundles/f387210887d5c4859f0a468021ba7e9a269ddd13dfb260af5b94ecb03d3c710c.bundle new file mode 100644 index 000000000..9da6382aa Binary files /dev/null and b/test-bundles/f387210887d5c4859f0a468021ba7e9a269ddd13dfb260af5b94ecb03d3c710c.bundle differ diff --git a/test-bundles/f720b0c8a94262f4e73b726fb23399b2093a650be2e5f75e7346f139428f1592.bundle b/test-bundles/f720b0c8a94262f4e73b726fb23399b2093a650be2e5f75e7346f139428f1592.bundle new file mode 100644 index 000000000..2944a2444 Binary files /dev/null and b/test-bundles/f720b0c8a94262f4e73b726fb23399b2093a650be2e5f75e7346f139428f1592.bundle differ diff --git a/test-bundles/f9531ff43c0c72840a0360981fa7fe10a19d5111f8a58f3da2517c8ca20a719c.bundle b/test-bundles/f9531ff43c0c72840a0360981fa7fe10a19d5111f8a58f3da2517c8ca20a719c.bundle new file mode 100644 index 000000000..5177f6756 Binary files /dev/null and b/test-bundles/f9531ff43c0c72840a0360981fa7fe10a19d5111f8a58f3da2517c8ca20a719c.bundle differ diff --git a/test-bundles/fa5a5324230f73fbb8ddc66fbc6fbcb40fbdd7cf9a7859b6617fe6e24061130d.bundle b/test-bundles/fa5a5324230f73fbb8ddc66fbc6fbcb40fbdd7cf9a7859b6617fe6e24061130d.bundle new file mode 100644 index 000000000..7939efc7d Binary files /dev/null and b/test-bundles/fa5a5324230f73fbb8ddc66fbc6fbcb40fbdd7cf9a7859b6617fe6e24061130d.bundle differ diff --git a/test-bundles/fc1b9bdb810f07898dfc0ce576c2200653440b3b59364dc41ee7fd0ba39093a7.bundle b/test-bundles/fc1b9bdb810f07898dfc0ce576c2200653440b3b59364dc41ee7fd0ba39093a7.bundle new file mode 100644 index 000000000..db8b4f7a9 Binary files /dev/null and b/test-bundles/fc1b9bdb810f07898dfc0ce576c2200653440b3b59364dc41ee7fd0ba39093a7.bundle differ diff --git a/test-bundles/fe12e75c190315870e1ae6226ef244d89bac9d54aae32d718fdd3f0deaaa0418.bundle b/test-bundles/fe12e75c190315870e1ae6226ef244d89bac9d54aae32d718fdd3f0deaaa0418.bundle new file mode 100644 index 000000000..b889ff53f Binary files /dev/null and b/test-bundles/fe12e75c190315870e1ae6226ef244d89bac9d54aae32d718fdd3f0deaaa0418.bundle differ diff --git a/test-bundles/fec00832cacfc586541f70bc762d856038f5af9f007509e21393c63edeafbef8.bundle b/test-bundles/fec00832cacfc586541f70bc762d856038f5af9f007509e21393c63edeafbef8.bundle new file mode 100644 index 000000000..0115924ad Binary files /dev/null and b/test-bundles/fec00832cacfc586541f70bc762d856038f5af9f007509e21393c63edeafbef8.bundle differ diff --git a/tests/test_block_builder.py b/tests/test_block_builder.py new file mode 100644 index 000000000..44a5242db --- /dev/null +++ b/tests/test_block_builder.py @@ -0,0 +1,75 @@ +from chia_rs import ( + BlockBuilder, + validate_clvm_and_signature, + SpendBundle, + run_block_generator, + run_block_generator2, + MEMPOOL_MODE, +) +from chia_rs.sized_ints import uint64 +from run_gen import DEFAULT_CONSTANTS +from os import listdir +from os.path import join +import time +import random + + +def test_block_builder() -> None: + + all_bundles = [] + start = time.monotonic() + for name in listdir("test-bundles"): + if not name.endswith(".bundle"): + continue + if len(name) != 64 + 7: + continue + with open(join("test-bundles", name), "rb") as f: + sb = SpendBundle.from_bytes(f.read()) + conds, bls_cache, duration = validate_clvm_and_signature( + sb, 11000000000, DEFAULT_CONSTANTS, 5000000 + ) + cost = uint64(conds.execution_cost + conds.condition_cost) + + # print(f"{name} {conds.execution_cost} {conds.condition_cost}") + all_bundles.append((sb, cost)) + + # the total cost should be greater than the execution + condition + # cost + assert conds.cost > cost + end = time.monotonic() + print(f"loaded {len(all_bundles)} spend bundles in {end-start:0.2f}s") + all_bundles.sort(key=lambda x: x[1]) + + for seed in range(50): + rng = random.Random(seed) + random.shuffle(all_bundles) + + start = time.monotonic() + builder = BlockBuilder() + skipped = 0 + for sb, cost in all_bundles: + added, done = builder.add_spend_bundle(sb, cost, DEFAULT_CONSTANTS) + if not added: + skipped += 1 + if done: + break + + generator, signature, generator_cost = builder.finalize(DEFAULT_CONSTANTS) + + end = time.monotonic() + gen_time = end - start + + start = time.monotonic() + err, conds2 = run_block_generator2( + generator, [], 11200000000, MEMPOOL_MODE, signature, None, DEFAULT_CONSTANTS + ) + end = time.monotonic() + run_time = end - start + + print( + f"idx: {seed:3} gen-time: {gen_time:0.2f}s cost: {generator_cost:11} skipped: {skipped:2} run-time: {run_time:0.2f}" + ) + + assert err is None + assert conds2 is not None + assert conds2.cost == generator_cost diff --git a/wheel/generate_type_stubs.py b/wheel/generate_type_stubs.py index 48ec6a9c6..0939244fc 100644 --- a/wheel/generate_type_stubs.py +++ b/wheel/generate_type_stubs.py @@ -394,6 +394,11 @@ def derive_child_sk_unhardened(sk: PrivateKey, index: int) -> PrivateKey: ... @staticmethod def derive_child_pk_unhardened(pk: G1Element, index: int) -> G1Element: ... +@final +class BlockBuilder: + def add_spend_bundle(self, bundle: SpendBundle, cost: uint64, constants: ConsensusConstants) -> tuple[bool, bool]: ... + def finalize(self, constants: ConsensusConstants) -> tuple[bytes, G2Element, uint64]: ... + @final class MerkleSet: def get_root(self) -> bytes32: ... diff --git a/wheel/python/chia_rs/chia_rs.pyi b/wheel/python/chia_rs/chia_rs.pyi index af0306b92..6a2ab1aed 100644 --- a/wheel/python/chia_rs/chia_rs.pyi +++ b/wheel/python/chia_rs/chia_rs.pyi @@ -123,6 +123,11 @@ class AugSchemeMPL: @staticmethod def derive_child_pk_unhardened(pk: G1Element, index: int) -> G1Element: ... +@final +class BlockBuilder: + def add_spend_bundle(self, bundle: SpendBundle, cost: uint64, constants: ConsensusConstants) -> tuple[bool, bool]: ... + def finalize(self, constants: ConsensusConstants) -> tuple[bytes, G2Element, uint64]: ... + @final class MerkleSet: def get_root(self) -> bytes32: ... diff --git a/wheel/src/api.rs b/wheel/src/api.rs index 70b2c5916..e4a671869 100644 --- a/wheel/src/api.rs +++ b/wheel/src/api.rs @@ -3,6 +3,7 @@ use crate::run_generator::{ }; use chia_consensus::allocator::make_allocator; use chia_consensus::consensus_constants::ConsensusConstants; +use chia_consensus::gen::build_compressed_block::BlockBuilder; use chia_consensus::gen::flags::{ DONT_VALIDATE_SIGNATURE, MEMPOOL_MODE, NO_UNKNOWN_CONDS, STRICT_ARGS_COUNT, }; @@ -448,6 +449,7 @@ pub fn chia_rs(_py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> { m.add_function(wrap_pyfunction!(supports_fast_forward, m)?)?; m.add_function(wrap_pyfunction!(fast_forward_singleton, m)?)?; m.add_class::()?; + m.add_class::()?; m.add( "ELIGIBLE_FOR_DEDUP", chia_consensus::gen::conditions::ELIGIBLE_FOR_DEDUP,