diff --git a/CHANGELOG.md b/CHANGELOG.md index eff2539ef..3892b7fd1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ - Introduced `AccountComponentTemplate` with TOML serialization and templating (#1015, #1027). - Introduce `AccountIdError` and make account ID byte representations (`u128`, `[u8; 15]`) consistent (#1055). - Refactor `AccountId` and `AccountIdPrefix` into version wrappers (#1058). +- Remove multi-threaded account seed generation due to single-threaded generation being faster (#1061). ## 0.6.2 (2024-11-20) diff --git a/Cargo.lock b/Cargo.lock index 3b21047b2..39a1e1830 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -39,6 +39,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "aligned-vec" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e0966165eaf052580bd70eb1b32cb3d6245774c0104d1b2793e9650bf83b52a" +dependencies = [ + "equator", +] + [[package]] name = "alloc-no-stdlib" version = "2.0.4" @@ -631,6 +640,8 @@ dependencies = [ "num-traits", "once_cell", "oorandom", + "plotters", + "rayon", "regex", "serde", "serde_derive", @@ -723,6 +734,15 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" +[[package]] +name = "debugid" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d" +dependencies = [ + "uuid", +] + [[package]] name = "derivative" version = "2.2.0" @@ -807,6 +827,26 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "equator" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c35da53b5a021d2484a7cc49b2ac7f2d840f8236a286f84202369bd338d761ea" +dependencies = [ + "equator-macro", +] + +[[package]] +name = "equator-macro" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bf679796c0322556351f287a51b49e48f7c4986e727b5dd78c972d30e2e16cc" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.94", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -843,6 +883,18 @@ dependencies = [ "version_check", ] +[[package]] +name = "findshlibs" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40b9e59cd0f7e0806cca4be089683ecb6434e602038df21fe6bf6711b2f07f64" +dependencies = [ + "cc", + "lazy_static", + "libc", + "winapi", +] + [[package]] name = "fixedbitset" version = "0.4.2" @@ -1477,6 +1529,24 @@ dependencies = [ "hashbrown 0.15.2", ] +[[package]] +name = "inferno" +version = "0.11.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "321f0f839cd44a4686e9504b0a62b4d69a50b62072144c71c68f5873c167b8d9" +dependencies = [ + "ahash", + "indexmap 2.7.0", + "is-terminal", + "itoa", + "log", + "num-format", + "once_cell", + "quick-xml", + "rgb", + "str_stack", +] + [[package]] name = "inlinable_string" version = "0.1.15" @@ -1760,6 +1830,15 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +[[package]] +name = "memmap2" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f" +dependencies = [ + "libc", +] + [[package]] name = "memoffset" version = "0.6.5" @@ -1931,6 +2010,7 @@ dependencies = [ "miden-objects", "miden-processor", "miden-verifier", + "pprof", "rand", "rand_xoshiro", "rstest", @@ -2173,6 +2253,17 @@ dependencies = [ "memoffset", ] +[[package]] +name = "nix" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "libc", +] + [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -2227,6 +2318,16 @@ dependencies = [ "syn 2.0.94", ] +[[package]] +name = "num-format" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a652d9771a63711fd3c3deb670acfbe5c30a4072e664d7a3bf5a9e1056ac72c3" +dependencies = [ + "arrayvec", + "itoa", +] + [[package]] name = "num-integer" version = "0.1.46" @@ -2684,7 +2785,7 @@ dependencies = [ "libc", "log", "lru", - "nix", + "nix 0.24.3", "once_cell", "openssl-probe", "parking_lot", @@ -2865,6 +2966,57 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" +[[package]] +name = "plotters" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" + +[[package]] +name = "plotters-svg" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" +dependencies = [ + "plotters-backend", +] + +[[package]] +name = "pprof" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebbe2f8898beba44815fdc9e5a4ae9c929e21c5dc29b0c774a15555f7f58d6d0" +dependencies = [ + "aligned-vec", + "backtrace", + "cfg-if", + "criterion", + "findshlibs", + "inferno", + "libc", + "log", + "nix 0.26.4", + "once_cell", + "parking_lot", + "smallvec", + "symbolic-demangle", + "tempfile", + "thiserror 1.0.69", +] + [[package]] name = "ppv-lite86" version = "0.2.20" @@ -3058,6 +3210,15 @@ dependencies = [ "thiserror 1.0.69", ] +[[package]] +name = "quick-xml" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f50b1c63b38611e7d4d7f68b82d3ad0cc71a2ad2e7f61fc10f1328d917c93cd" +dependencies = [ + "memchr", +] + [[package]] name = "quote" version = "1.0.38" @@ -3236,6 +3397,15 @@ dependencies = [ "winreg", ] +[[package]] +name = "rgb" +version = "0.8.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f86ae463694029097b846d8f99fd5536740602ae00022c0c50c5600720b2f71" +dependencies = [ + "bytemuck", +] + [[package]] name = "rmp" version = "0.8.14" @@ -3641,6 +3811,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +[[package]] +name = "str_stack" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9091b6114800a5f2141aee1d1b9d6ca3592ac062dc5decb3764ec5895a47b4eb" + [[package]] name = "string_cache" version = "0.8.7" @@ -3724,6 +3900,28 @@ version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7401a30af6cb5818bb64852270bb722533397edcfc7344954a38f420819ece2" +[[package]] +name = "symbolic-common" +version = "12.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf08b42a6f9469bd8584daee39a1352c8133ccabc5151ccccb15896ef047d99a" +dependencies = [ + "debugid", + "memmap2", + "stable_deref_trait", + "uuid", +] + +[[package]] +name = "symbolic-demangle" +version = "12.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f73b5a5bd4da72720c45756a2d11edf110116b87f998bda59b97be8c2c7cf1" +dependencies = [ + "rustc-demangle", + "symbolic-common", +] + [[package]] name = "syn" version = "1.0.109" diff --git a/bin/tx-prover/Cargo.toml b/bin/tx-prover/Cargo.toml index 650862eb9..d8cf19cc8 100644 --- a/bin/tx-prover/Cargo.toml +++ b/bin/tx-prover/Cargo.toml @@ -24,7 +24,7 @@ async = ["miden-tx/async"] default = ["std"] std = ["miden-objects/std", "miden-tx/std", "dep:tokio", "dep:tonic-web", "dep:tokio-stream", "dep:axum", "dep:tracing", "dep:tracing-subscriber", "tonic/transport"] testing = ["miden-objects/testing", "miden-lib/testing", "miden-tx/testing"] -concurrent = ["miden-lib/concurrent", "miden-objects/concurrent", "miden-tx/concurrent", "std"] +concurrent = ["miden-tx/concurrent", "std"] [target.'cfg(all(target_arch = "wasm32", target_os = "unknown"))'.dependencies] tonic-web-wasm-client = { version = "0.6", default-features = false } diff --git a/miden-lib/Cargo.toml b/miden-lib/Cargo.toml index 06fded0be..dd5461cec 100644 --- a/miden-lib/Cargo.toml +++ b/miden-lib/Cargo.toml @@ -15,10 +15,8 @@ edition.workspace = true [lib] [features] -concurrent = ["miden-objects/concurrent", "std"] default = ["std"] std = ["assembly/std", "miden-objects/std", "miden-stdlib/std", "vm-processor/std"] -# the testing feature is required to enable the account creation pow patch testing = ["miden-objects/testing"] with-debug-info = ["miden-stdlib/with-debug-info"] diff --git a/miden-tx/Cargo.toml b/miden-tx/Cargo.toml index 998e59e6e..80eca0326 100644 --- a/miden-tx/Cargo.toml +++ b/miden-tx/Cargo.toml @@ -18,7 +18,7 @@ path = "tests/integration/main.rs" [features] async = ["winter-maybe-async/async"] -concurrent = ["miden-lib/concurrent", "miden-objects/concurrent", "miden-prover/concurrent", "std"] +concurrent = ["miden-prover/concurrent", "std"] default = ["std"] std = ["miden-lib/std", "miden-objects/std", "miden-prover/std", "miden-verifier/std", "vm-processor/std"] testing = ["miden-objects/testing", "miden-lib/testing", "vm-processor/testing", "dep:rand_chacha"] diff --git a/objects/Cargo.toml b/objects/Cargo.toml index c243420af..ebc5191c3 100644 --- a/objects/Cargo.toml +++ b/objects/Cargo.toml @@ -20,7 +20,6 @@ harness = false bench = false [features] -concurrent = ["std"] default = ["std"] std = ["assembly/std", "miden-crypto/std", "miden-verifier/std", "vm-core/std", "vm-processor/std", "dep:toml", "dep:serde"] testing = ["dep:winter-rand-utils", "dep:rand", "dep:rand_xoshiro"] @@ -44,6 +43,7 @@ winter-rand-utils = { version = "0.10", optional = true } getrandom = { version = "0.2", features = ["js"] } [dev-dependencies] +pprof = { version = "0.14.0", default-features = false, features = ["criterion", "flamegraph"] } anyhow = { version = "1.0.93", default-features = false, features = ["std", "backtrace"]} assert_matches = { workspace = true } criterion = { version = "0.5", default-features = false, features = ["html_reports"] } diff --git a/objects/benches/account_seed.rs b/objects/benches/account_seed.rs index b836f7185..4c5e7c5f5 100644 --- a/objects/benches/account_seed.rs +++ b/objects/benches/account_seed.rs @@ -11,6 +11,15 @@ use rand::{Rng, SeedableRng}; /// computation. /// /// Passing --features concurrent will use the multi-threaded account seed computation. +/// +/// To produce a flamegraph, run with the `--profile-time` argument. +/// +/// ```sh +/// cargo bench -p miden-objects --no-default-features -- --profile-time 10 +/// ``` +/// +/// The flamegraph will be saved as `target/criterion/grind-seed/Grind regular on-chain account +/// seed/profile/flamegraph.svg`. fn grind_account_seed(c: &mut Criterion) { let mut group = c.benchmark_group("grind-seed"); // Increase measurement time (= target time) from the default 5s as suggested by criterion @@ -38,24 +47,19 @@ fn grind_account_seed(c: &mut Criterion) { }) }); - // Reinitialize the RNG. - let mut rng = rand_xoshiro::Xoshiro256PlusPlus::from_seed(init_seed); - group.bench_function("Grind fungible faucet on-chain account seed", |bench| { - bench.iter(|| { - AccountId::compute_account_seed( - rng.gen(), - AccountType::FungibleFaucet, - AccountStorageMode::Public, - AccountIdVersion::Version0, - Digest::default(), - Digest::default(), - Digest::default(), - ) - }) - }); - group.finish(); } -criterion_group!(account_seed, grind_account_seed); +fn with_pprof_profiler() -> Criterion { + Criterion::default().with_profiler(pprof::criterion::PProfProfiler::new( + 1_000_000, + pprof::criterion::Output::Flamegraph(None), + )) +} + +criterion_group! { + name = account_seed; + config = with_pprof_profiler(); + targets = grind_account_seed +} criterion_main!(account_seed); diff --git a/objects/src/accounts/account_id/seed.rs b/objects/src/accounts/account_id/seed.rs index ca5ccd4cd..2e6295ee0 100644 --- a/objects/src/accounts/account_id/seed.rs +++ b/objects/src/accounts/account_id/seed.rs @@ -1,12 +1,4 @@ use alloc::vec::Vec; -#[cfg(feature = "concurrent")] -use std::{ - sync::{ - mpsc::{self, Sender}, - Arc, RwLock, - }, - thread::{self, spawn}, -}; use vm_core::{Felt, Word}; use vm_processor::Digest; @@ -21,125 +13,14 @@ use crate::{ }, AccountError, }; -// SEED GENERATORS -// -------------------------------------------------------------------------------------------- /// Finds and returns a seed suitable for creating an account ID for the specified account type -/// using the provided initial seed as a starting point. Using multi-threading. -#[cfg(feature = "concurrent")] -pub fn compute_account_seed( - init_seed: [u8; 32], - account_type: AccountType, - storage_mode: AccountStorageMode, - version: AccountIdVersion, - code_commitment: Digest, - storage_commitment: Digest, - anchor_block_hash: Digest, -) -> Result { - let thread_count = thread::available_parallelism().map_or(1, |v| v.get()); - - let (send, recv) = mpsc::channel(); - let stop = Arc::new(RwLock::new(false)); - - for count in 0..thread_count { - let send = send.clone(); - let stop = Arc::clone(&stop); - let mut init_seed = init_seed; - init_seed[0] = init_seed[0].wrapping_add(count as u8); - spawn(move || { - compute_account_seed_inner( - send, - stop, - init_seed, - account_type, - storage_mode, - version, - code_commitment, - storage_commitment, - anchor_block_hash, - ) - }); - } - - #[allow(unused_variables)] - let (digest, seed) = recv.recv().unwrap(); - - // Safety: this is the only writer for this lock, it should never be poisoned - *stop.write().unwrap() = true; - - #[cfg(feature = "log")] - ::log::info!( - "Using account seed [digest={}, seed={}]", - log::digest_hex(digest), - log::word_hex(seed), - ); - - Ok(seed) -} - -#[cfg(feature = "concurrent")] -#[allow(clippy::too_many_arguments)] -fn compute_account_seed_inner( - send: Sender<(Digest, Word)>, - stop: Arc>, - init_seed: [u8; 32], - account_type: AccountType, - storage_mode: AccountStorageMode, - version: AccountIdVersion, - code_commitment: Digest, - storage_commitment: Digest, - anchor_block_hash: Digest, -) { - let init_seed: Vec<[u8; 8]> = - init_seed.chunks(8).map(|chunk| chunk.try_into().unwrap()).collect(); - let mut current_seed: Word = [ - Felt::new(u64::from_le_bytes(init_seed[0])), - Felt::new(u64::from_le_bytes(init_seed[1])), - Felt::new(u64::from_le_bytes(init_seed[2])), - Felt::new(u64::from_le_bytes(init_seed[3])), - ]; - let mut current_digest = - compute_digest(current_seed, code_commitment, storage_commitment, anchor_block_hash); - - #[cfg(feature = "log")] - let mut log = log::Log::start(current_digest, current_seed, account_type, storage_mode); - - // loop until we have a seed that satisfies the specified account type. - let mut count = 0; - loop { - #[cfg(feature = "log")] - log.iteration(current_digest, current_seed); - - // regularly check if another thread found a digest - count += 1; - if count % 500_000 == 0 && *stop.read().unwrap() { - return; - } - - let prefix = current_digest.as_elements()[0]; - if let Ok((computed_account_type, computed_storage_mode, computed_version)) = - validate_prefix(prefix) - { - if computed_account_type == account_type - && computed_storage_mode == storage_mode - && computed_version == version - { - #[cfg(feature = "log")] - log.done(current_digest, current_seed); - - let _ = send.send((current_digest, current_seed)); - return; - }; - } - - current_seed = current_digest.into(); - current_digest = - compute_digest(current_seed, code_commitment, storage_commitment, anchor_block_hash); - } -} - -#[cfg(not(feature = "concurrent"))] -pub fn compute_account_seed( +/// using the provided initial seed as a starting point. +/// +/// This currently always uses a single thread. This method used to either use a single- or +/// multi-threaded implementation based on a compile-time feature flag. The multi-threaded +/// implementation was removed in commit dab6159318832fc537bb35abf251870a9129ac8c in PR 1061. +pub(super) fn compute_account_seed( init_seed: [u8; 32], account_type: AccountType, storage_mode: AccountStorageMode, @@ -159,10 +40,7 @@ pub fn compute_account_seed( ) } -/// Finds and returns a seed suitable for creating an account ID for the specified account type -/// using the provided initial seed as a starting point. Using a single thread. -#[cfg(not(feature = "concurrent"))] -pub fn compute_account_seed_single( +fn compute_account_seed_single( init_seed: [u8; 32], account_type: AccountType, storage_mode: AccountStorageMode, diff --git a/objects/src/assets/mod.rs b/objects/src/assets/mod.rs index cc7cd7875..3608c1a67 100644 --- a/objects/src/assets/mod.rs +++ b/objects/src/assets/mod.rs @@ -242,9 +242,9 @@ fn is_not_a_non_fungible_asset(asset: Word) -> bool { Ok(prefix) => { matches!(prefix.account_type(), AccountType::FungibleFaucet) }, - Err(err) => { + Err(_err) => { #[cfg(debug_assertions)] - panic!("invalid account ID prefix passed to is_not_a_non_fungible_asset: {err}"); + panic!("invalid account ID prefix passed to is_not_a_non_fungible_asset: {_err}"); #[cfg(not(debug_assertions))] false },