From ecab1599679e25e97ed94f251c27928b08b2458e Mon Sep 17 00:00:00 2001 From: Marti Date: Sat, 31 Jan 2026 19:17:54 +0000 Subject: [PATCH 01/14] feat: load genesis accounts from acc files --- Cargo.lock | 1 + bin/node/src/commands/store.rs | 4 +- crates/store/Cargo.toml | 1 + crates/store/src/genesis/config/errors.rs | 8 + crates/store/src/genesis/config/mod.rs | 211 +++++++++++++++---- crates/store/src/genesis/config/tests.rs | 237 +++++++++++++++++++++- 6 files changed, 423 insertions(+), 39 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c338dda5f..65d8804d0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2925,6 +2925,7 @@ dependencies = [ "rand_chacha 0.9.0", "regex", "serde", + "tempfile", "termtree", "thiserror 2.0.18", "tokio", diff --git a/bin/node/src/commands/store.rs b/bin/node/src/commands/store.rs index 9dd311368..2e70fd6e1 100644 --- a/bin/node/src/commands/store.rs +++ b/bin/node/src/commands/store.rs @@ -192,7 +192,9 @@ impl StoreCommand { let config = genesis_config .map(|file_path| { let toml_str = fs_err::read_to_string(file_path)?; - GenesisConfig::read_toml(toml_str.as_str()).with_context(|| { + // Get the directory containing the config file for resolving relative paths + let config_dir = file_path.parent().unwrap_or_else(|| Path::new(".")); + GenesisConfig::read_toml(toml_str.as_str(), config_dir).with_context(|| { format!("failed to parse genesis config from file {}", file_path.display()) }) }) diff --git a/crates/store/Cargo.toml b/crates/store/Cargo.toml index dd06567ea..28d910ddb 100644 --- a/crates/store/Cargo.toml +++ b/crates/store/Cargo.toml @@ -54,6 +54,7 @@ miden-protocol = { default-features = true, features = ["testing"], works miden-standards = { features = ["testing"], workspace = true } rand = { workspace = true } regex = { version = "1.11" } +tempfile = "3.24.0" termtree = { version = "0.5" } [features] diff --git a/crates/store/src/genesis/config/errors.rs b/crates/store/src/genesis/config/errors.rs index b39495c87..d82ef899c 100644 --- a/crates/store/src/genesis/config/errors.rs +++ b/crates/store/src/genesis/config/errors.rs @@ -1,3 +1,5 @@ +use std::path::PathBuf; + use miden_protocol::account::AccountId; use miden_protocol::errors::{ AccountDeltaError, @@ -17,6 +19,12 @@ use crate::genesis::config::TokenSymbolStr; pub enum GenesisConfigError { #[error(transparent)] Toml(#[from] toml::de::Error), + #[error("failed to read config file at {path}: {reason}")] + ConfigFileRead { path: PathBuf, reason: String }, + #[error("failed to read account file at {path}: {reason}")] + AccountFileRead { path: PathBuf, reason: String }, + #[error("native faucet from file {path} is not a fungible faucet")] + NativeFaucetNotFungible { path: PathBuf }, #[error("account translation from config to state failed")] Account(#[from] AccountError), #[error("asset translation from config to state failed")] diff --git a/crates/store/src/genesis/config/mod.rs b/crates/store/src/genesis/config/mod.rs index e7abe8b58..14bdc1b08 100644 --- a/crates/store/src/genesis/config/mod.rs +++ b/crates/store/src/genesis/config/mod.rs @@ -1,6 +1,7 @@ //! Describe a subset of the genesis manifest in easily human readable format use std::cmp::Ordering; +use std::path::Path; use std::str::FromStr; use indexmap::IndexMap; @@ -42,22 +43,64 @@ use self::errors::GenesisConfigError; #[cfg(test)] mod tests; +// TOML PARSING STRUCTS (INTERMEDIATE) +// ================================================================================================ + +/// Intermediate struct for TOML parsing - native faucet can be params or file path +#[derive(Debug, Clone, serde::Deserialize)] +#[serde(untagged)] +enum NativeFaucetToml { + /// Build from parameters (dev/testing) + Parameters { + symbol: TokenSymbolStr, + decimals: u8, + max_supply: u64, + }, + /// Load from pre-built account file (production/multisig) + File { path: std::path::PathBuf }, +} + +/// Intermediate struct for TOML parsing - arbitrary account from file +#[derive(Debug, Clone, serde::Deserialize)] +#[serde(deny_unknown_fields)] +struct AccountToml { + /// Path to .mac file (relative to genesis config directory) + path: std::path::PathBuf, +} + +/// Intermediate struct for full TOML parsing +#[derive(Debug, Clone, serde::Deserialize)] +struct GenesisConfigToml { + version: u32, + timestamp: u32, + native_faucet: NativeFaucetToml, + fee_parameters: FeeParameterConfig, + #[serde(default)] + wallet: Vec, + #[serde(default)] + fungible_faucet: Vec, + #[serde(default)] + account: Vec, +} + // GENESIS CONFIG // ================================================================================================ /// Specify a set of faucets and wallets with assets for easier test deployments. /// /// Notice: Any faucet must be declared _before_ it's use in a wallet/regular account. -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +/// +/// This struct holds the parsed configuration. Accounts referenced via file paths +/// are loaded during [`read_toml`] and stored directly as [`Account`] objects. +#[derive(Debug, Clone)] pub struct GenesisConfig { version: u32, timestamp: u32, native_faucet: NativeFaucet, fee_parameters: FeeParameterConfig, - #[serde(default)] wallet: Vec, - #[serde(default)] fungible_faucet: Vec, + accounts: Vec, } impl Default for GenesisConfig { @@ -73,24 +116,78 @@ impl Default for GenesisConfig { ) .expect("Timestamp should fit into u32"), wallet: vec![], - native_faucet: NativeFaucet { + native_faucet: NativeFaucet::Parameters { max_supply: 100_000_000_000_000_000u64, decimals: 6u8, symbol: miden.clone(), }, fee_parameters: FeeParameterConfig { verification_base_fee: 0 }, fungible_faucet: vec![], + accounts: vec![], } } } impl GenesisConfig { - /// Read the genesis accounts from a toml formatted string + /// Read the genesis accounts from a toml formatted string. + /// + /// The `config_dir` parameter is used to resolve relative paths for account files + /// referenced in the configuration (e.g., `[[account]]` entries with `path` fields). /// /// Notice: It will generate the specified case during [`fn into_state`]. - pub fn read_toml(toml_str: &str) -> Result { - let me = toml::from_str::(toml_str)?; - Ok(me) + pub fn read_toml(toml_str: &str, config_dir: &Path) -> Result { + // Parse TOML into intermediate struct + let toml_config: GenesisConfigToml = toml::from_str(toml_str)?; + + // Handle native faucet (params or file) + let native_faucet = match toml_config.native_faucet { + NativeFaucetToml::Parameters { symbol, decimals, max_supply } => { + NativeFaucet::Parameters { symbol, decimals, max_supply } + }, + NativeFaucetToml::File { path } => { + let full_path = config_dir.join(&path); + let account_file = AccountFile::read(&full_path).map_err(|e| { + GenesisConfigError::AccountFileRead { + path: full_path.clone(), + reason: e.to_string(), + } + })?; + let account = account_file.account; + + // Validate it's a fungible faucet + if account.id().account_type() != AccountType::FungibleFaucet { + return Err(GenesisConfigError::NativeFaucetNotFungible { path: full_path }); + } + + NativeFaucet::Account { account } + }, + }; + + // Load all account files + let accounts = toml_config + .account + .into_iter() + .map(|acc| { + let full_path = config_dir.join(&acc.path); + let account_file = AccountFile::read(&full_path).map_err(|e| { + GenesisConfigError::AccountFileRead { + path: full_path.clone(), + reason: e.to_string(), + } + })?; + Ok(account_file.account) + }) + .collect::, GenesisConfigError>>()?; + + Ok(Self { + version: toml_config.version, + timestamp: toml_config.timestamp, + native_faucet, + fee_parameters: toml_config.fee_parameters, + wallet: toml_config.wallet, + fungible_faucet: toml_config.fungible_faucet, + accounts, + }) } /// Convert the in memory representation into the new genesis state @@ -108,10 +205,10 @@ impl GenesisConfig { fee_parameters, fungible_faucet: fungible_faucet_configs, wallet: wallet_configs, - .. + accounts: file_loaded_accounts, } = self; - let symbol = native_faucet.symbol.clone(); + let symbol = native_faucet.symbol(); let mut wallet_accounts = Vec::::new(); // Every asset sitting in a wallet, has to reference a faucet for that asset @@ -121,10 +218,26 @@ impl GenesisConfig { // accounts/sign transactions let mut secrets = Vec::new(); - // First setup all the faucets - for fungible_faucet_config in std::iter::once(native_faucet.to_faucet_config()) - .chain(fungible_faucet_configs.into_iter()) - { + // Handle native faucet: use pre-loaded account if available, otherwise build from params + let native_faucet_account = match native_faucet { + NativeFaucet::Parameters { .. } => { + let (faucet_account, secret_key) = + native_faucet.to_faucet_config().build_account()?; + faucet_accounts.insert(symbol.clone(), faucet_account.clone()); + secrets.push(( + format!("faucet_{symbol}.mac", symbol = symbol.to_string().to_lowercase()), + faucet_account.id(), + secret_key, + )); + faucet_account + }, + NativeFaucet::Account { account } => account, + }; + let native_faucet_account_id = native_faucet_account.id(); + faucet_accounts.insert(symbol.clone(), native_faucet_account); + + // Setup additional fungible faucets from parameters + for fungible_faucet_config in fungible_faucet_configs.into_iter() { let symbol = fungible_faucet_config.symbol.clone(); let (faucet_account, secret_key) = fungible_faucet_config.build_account()?; @@ -141,11 +254,6 @@ impl GenesisConfig { // we know the remaining supply in the faucets. } - let native_faucet_account_id = faucet_accounts - .get(&symbol) - .expect("Parsing guarantees the existence of a native faucet.") - .id(); - let fee_parameters = FeeParameters::new(native_faucet_account_id, fee_parameters.verification_base_fee)?; @@ -264,6 +372,9 @@ impl GenesisConfig { // Ensure the faucets always precede the wallets referencing them all_accounts.extend(wallet_accounts); + // Append file-loaded accounts as-is + all_accounts.extend(file_loaded_accounts); + Ok(( GenesisState { fee_parameters, @@ -281,28 +392,46 @@ impl GenesisConfig { // ================================================================================================ /// Declare the native fungible asset -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] -#[serde(deny_unknown_fields)] -pub struct NativeFaucet { - /// Token symbol to use for fees. - symbol: TokenSymbolStr, - - decimals: u8, - /// Max supply in full token units - /// - /// It will be converted internally to the smallest representable unit, - /// using based `10.powi(decimals)` as a multiplier. - max_supply: u64, +#[derive(Debug, Clone)] +enum NativeFaucet { + Parameters { + symbol: TokenSymbolStr, + decimals: u8, + max_supply: u64, + }, + Account { + account: Account, + }, } impl NativeFaucet { fn to_faucet_config(&self) -> FungibleFaucetConfig { - let NativeFaucet { symbol, decimals, max_supply, .. } = self; - FungibleFaucetConfig { - symbol: symbol.clone(), - decimals: *decimals, - max_supply: *max_supply, - storage_mode: StorageMode::Public, + match self { + NativeFaucet::Parameters { symbol, decimals, max_supply } => FungibleFaucetConfig { + symbol: symbol.clone(), + decimals: *decimals, + max_supply: *max_supply, + storage_mode: StorageMode::Public, + }, + NativeFaucet::Account { .. } => { + panic!( + "conversion to fungible faucet config should not happen when an account file is provided" + ); + }, + } + } +} + +impl NativeFaucet { + fn symbol(&self) -> TokenSymbolStr { + match self { + NativeFaucet::Parameters { symbol, .. } => symbol.clone(), + NativeFaucet::Account { account } => { + // this is safe since we validate the account type when reading the genesis config + let faucet = BasicFungibleFaucet::try_from(account) + .expect("native faucet account should be a fungible faucet"); + TokenSymbolStr::from(faucet.symbol()) + }, } } } @@ -548,6 +677,14 @@ impl From for TokenSymbol { } } +impl From for TokenSymbolStr { + fn from(symbol: TokenSymbol) -> Self { + // TokenSymbol guarantees valid format, so to_string should not fail + let raw = symbol.to_string().expect("TokenSymbol should always produce valid string"); + Self { raw, encoded: symbol } + } +} + impl Ord for TokenSymbolStr { fn cmp(&self, other: &Self) -> Ordering { self.raw.cmp(&other.raw) diff --git a/crates/store/src/genesis/config/tests.rs b/crates/store/src/genesis/config/tests.rs index 23e2daa43..69cf43499 100644 --- a/crates/store/src/genesis/config/tests.rs +++ b/crates/store/src/genesis/config/tests.rs @@ -1,3 +1,5 @@ +use std::path::Path; + use assert_matches::assert_matches; use miden_protocol::ONE; use miden_protocol::crypto::dsa::ecdsa_k256_keccak::SecretKey; @@ -10,7 +12,8 @@ type TestResult = Result<(), Box>; #[miden_node_test_macro::enable_logging] fn parsing_yields_expected_default_values() -> TestResult { let s = include_str!("./samples/01-simple.toml"); - let gcfg = GenesisConfig::read_toml(s)?; + // Use current directory since this sample doesn't reference any account files + let gcfg = GenesisConfig::read_toml(s, Path::new("."))?; let (state, _secrets) = gcfg.into_state(SecretKey::new())?; let _ = state; // faucets always precede wallet accounts @@ -67,3 +70,235 @@ fn genesis_accounts_have_nonce_one() -> TestResult { let _block = state.into_block()?; Ok(()) } + +#[test] +fn parsing_account_from_file() -> TestResult { + use miden_protocol::account::{AccountFile, AccountStorageMode, AccountType}; + use miden_standards::AuthScheme; + use miden_standards::account::wallets::create_basic_wallet; + use tempfile::tempdir; + + // Create a temporary directory for our test files + let temp_dir = tempdir()?; + let config_dir = temp_dir.path(); + + // Create a test wallet account and save it to a .mac file + let init_seed: [u8; 32] = rand::random(); + let mut rng = rand_chacha::ChaCha20Rng::from_seed(rand::random()); + let secret_key = miden_protocol::crypto::dsa::falcon512_rpo::SecretKey::with_rng( + &mut miden_node_utils::crypto::get_rpo_random_coin(&mut rng), + ); + let auth = AuthScheme::Falcon512Rpo { pub_key: secret_key.public_key().into() }; + + let test_account = create_basic_wallet( + init_seed, + auth, + AccountType::RegularAccountUpdatableCode, + AccountStorageMode::Public, + )?; + + let account_id = test_account.id(); + + // Save to file + let account_file_path = config_dir.join("test_account.mac"); + let account_file = AccountFile::new(test_account, vec![]); + account_file.write(&account_file_path)?; + + // Create a genesis config TOML that references the account file + let toml_content = format!( + r#" +timestamp = 1717344256 +version = 1 + +[native_faucet] +decimals = 6 +max_supply = 100_000_000 +symbol = "TEST" + +[fee_parameters] +verification_base_fee = 0 + +[[account]] +path = "test_account.mac" +"# + ); + + // Parse the config + let gcfg = GenesisConfig::read_toml(&toml_content, config_dir)?; + + // Convert to state and verify the account is included + let (state, _secrets) = gcfg.into_state(SecretKey::new())?; + assert!(state.accounts.iter().find(|a| a.id() == account_id).is_some()); + + Ok(()) +} + +#[test] +fn parsing_native_faucet_from_file() -> TestResult { + use miden_protocol::account::{AccountBuilder, AccountFile, AccountStorageMode, AccountType}; + use miden_standards::account::auth::AuthFalcon512Rpo; + use tempfile::tempdir; + + // Create a temporary directory for our test files + let temp_dir = tempdir()?; + let config_dir = temp_dir.path(); + + // Create a faucet account and save it to a .mac file + let init_seed: [u8; 32] = rand::random(); + let mut rng = rand_chacha::ChaCha20Rng::from_seed(rand::random()); + let secret_key = miden_protocol::crypto::dsa::falcon512_rpo::SecretKey::with_rng( + &mut miden_node_utils::crypto::get_rpo_random_coin(&mut rng), + ); + let auth = AuthFalcon512Rpo::new(secret_key.public_key().into()); + + let faucet_component = + BasicFungibleFaucet::new(TokenSymbol::new("NFAU").unwrap(), 6, Felt::new(1_000_000_000))?; + + let faucet_account = AccountBuilder::new(init_seed) + .account_type(AccountType::FungibleFaucet) + .storage_mode(AccountStorageMode::Public) + .with_auth_component(auth) + .with_component(faucet_component) + .build()?; + + let faucet_id = faucet_account.id(); + + // Save to file + let faucet_file_path = config_dir.join("native_faucet.mac"); + let account_file = AccountFile::new(faucet_account, vec![]); + account_file.write(&faucet_file_path)?; + + // Create a genesis config TOML that references the faucet file + let toml_content = r#" +timestamp = 1717344256 +version = 1 + +[native_faucet] +path = "native_faucet.mac" + +[fee_parameters] +verification_base_fee = 0 +"#; + + // Parse the config + let gcfg = GenesisConfig::read_toml(toml_content, config_dir)?; + + // Convert to state and verify the native faucet is included + let (state, secrets) = gcfg.into_state(SecretKey::new())?; + assert!(state.accounts.iter().find(|a| a.id() == faucet_id).is_some()); + + // No secrets should be generated for file-loaded native faucet + assert!(secrets.secrets.is_empty()); + + Ok(()) +} + +#[test] +fn native_faucet_from_file_must_be_faucet_type() -> TestResult { + use miden_protocol::account::{AccountFile, AccountStorageMode, AccountType}; + use miden_standards::AuthScheme; + use miden_standards::account::wallets::create_basic_wallet; + use tempfile::tempdir; + + // Create a temporary directory for our test files + let temp_dir = tempdir()?; + let config_dir = temp_dir.path(); + + // Create a regular wallet account (not a faucet) and try to use it as native faucet + let init_seed: [u8; 32] = rand::random(); + let mut rng = rand_chacha::ChaCha20Rng::from_seed(rand::random()); + let secret_key = miden_protocol::crypto::dsa::falcon512_rpo::SecretKey::with_rng( + &mut miden_node_utils::crypto::get_rpo_random_coin(&mut rng), + ); + let auth = AuthScheme::Falcon512Rpo { pub_key: secret_key.public_key().into() }; + + let regular_account = create_basic_wallet( + init_seed, + auth, + AccountType::RegularAccountImmutableCode, + AccountStorageMode::Public, + )?; + + // Save to file + let account_file_path = config_dir.join("not_a_faucet.mac"); + let account_file = AccountFile::new(regular_account, vec![]); + account_file.write(&account_file_path)?; + + // Create a genesis config TOML that tries to use a non-faucet as native faucet + let toml_content = r#" +timestamp = 1717344256 +version = 1 + +[native_faucet] +path = "not_a_faucet.mac" + +[fee_parameters] +verification_base_fee = 0 +"#; + + // Parse should fail with NativeFaucetNotFungible error + let result = GenesisConfig::read_toml(toml_content, config_dir); + assert!(result.is_err()); + let err = result.unwrap_err(); + assert!( + matches!(err, GenesisConfigError::NativeFaucetNotFungible { .. }), + "Expected NativeFaucetNotFungible error, got: {:?}", + err + ); + + Ok(()) +} + +#[test] +fn missing_account_file_returns_error() { + // Create a genesis config TOML that references a non-existent file + let toml_content = r#" +timestamp = 1717344256 +version = 1 + +[native_faucet] +decimals = 6 +max_supply = 100_000_000 +symbol = "TEST" + +[fee_parameters] +verification_base_fee = 0 + +[[account]] +path = "does_not_exist.mac" +"#; + + // Use temp dir as config dir + let temp_dir = tempfile::tempdir().unwrap(); + let result = GenesisConfig::read_toml(toml_content, temp_dir.path()); + assert!(result.is_err()); + let err = result.unwrap_err(); + assert!( + matches!(err, GenesisConfigError::AccountFileRead { .. }), + "Expected AccountFileRead error, got: {:?}", + err + ); +} + +#[test] +fn missing_native_faucet_not_allowed() -> TestResult { + let toml_content = r#" +timestamp = 1717344256 +version = 1 + +[fee_parameters] +verification_base_fee = 0 +"#; + + let result = GenesisConfig::read_toml(toml_content, Path::new(".")); + assert!(result.is_err()); + let err = result.unwrap_err(); + assert_matches!(err, GenesisConfigError::Toml(toml_err) => { + let msg = toml_err.message(); + assert!( + msg.contains("missing field `native_faucet`"), + "Expected error message to mention 'native_faucet', got: {msg}" + ); + }); + Ok(()) +} From 3e27b147cfd0658d90b43e810f6dac3dd3faed69 Mon Sep 17 00:00:00 2001 From: Marti Date: Sat, 31 Jan 2026 19:56:15 +0000 Subject: [PATCH 02/14] chore: move toml reading logic to genesisconfig struct --- bin/node/src/commands/store.rs | 5 +-- crates/store/src/genesis/config/mod.rs | 21 +++++++++++-- crates/store/src/genesis/config/tests.rs | 40 +++++++++++++++++------- 3 files changed, 47 insertions(+), 19 deletions(-) diff --git a/bin/node/src/commands/store.rs b/bin/node/src/commands/store.rs index 2e70fd6e1..3bc875337 100644 --- a/bin/node/src/commands/store.rs +++ b/bin/node/src/commands/store.rs @@ -191,10 +191,7 @@ impl StoreCommand { // Parse genesis config (or default if not given). let config = genesis_config .map(|file_path| { - let toml_str = fs_err::read_to_string(file_path)?; - // Get the directory containing the config file for resolving relative paths - let config_dir = file_path.parent().unwrap_or_else(|| Path::new(".")); - GenesisConfig::read_toml(toml_str.as_str(), config_dir).with_context(|| { + GenesisConfig::read_toml_file(file_path).with_context(|| { format!("failed to parse genesis config from file {}", file_path.display()) }) }) diff --git a/crates/store/src/genesis/config/mod.rs b/crates/store/src/genesis/config/mod.rs index 14bdc1b08..8fa667596 100644 --- a/crates/store/src/genesis/config/mod.rs +++ b/crates/store/src/genesis/config/mod.rs @@ -129,13 +129,28 @@ impl Default for GenesisConfig { } impl GenesisConfig { - /// Read the genesis accounts from a toml formatted string. + /// Read the genesis config from a TOML file. /// - /// The `config_dir` parameter is used to resolve relative paths for account files + /// The parent directory of `path` is used to resolve relative paths for account files /// referenced in the configuration (e.g., `[[account]]` entries with `path` fields). /// /// Notice: It will generate the specified case during [`fn into_state`]. - pub fn read_toml(toml_str: &str, config_dir: &Path) -> Result { + pub fn read_toml_file(path: &Path) -> Result { + let toml_str = std::fs::read_to_string(path).map_err(|e| { + GenesisConfigError::ConfigFileRead { + path: path.to_path_buf(), + reason: e.to_string(), + } + })?; + let config_dir = path.parent().unwrap_or_else(|| Path::new(".")); + Self::read_toml(&toml_str, config_dir) + } + + /// Read the genesis accounts from a TOML formatted string. + /// + /// The `config_dir` parameter is used to resolve relative paths for account files + /// referenced in the configuration (e.g., `[[account]]` entries with `path` fields). + fn read_toml(toml_str: &str, config_dir: &Path) -> Result { // Parse TOML into intermediate struct let toml_config: GenesisConfigToml = toml::from_str(toml_str)?; diff --git a/crates/store/src/genesis/config/tests.rs b/crates/store/src/genesis/config/tests.rs index 69cf43499..cf9e47050 100644 --- a/crates/store/src/genesis/config/tests.rs +++ b/crates/store/src/genesis/config/tests.rs @@ -1,3 +1,4 @@ +use std::io::Write; use std::path::Path; use assert_matches::assert_matches; @@ -8,12 +9,23 @@ use super::*; type TestResult = Result<(), Box>; +/// Helper to write TOML content to a file and return the path +fn write_toml_file(dir: &Path, content: &str) -> std::path::PathBuf { + let path = dir.join("genesis.toml"); + let mut file = std::fs::File::create(&path).unwrap(); + file.write_all(content.as_bytes()).unwrap(); + path +} + #[test] #[miden_node_test_macro::enable_logging] fn parsing_yields_expected_default_values() -> TestResult { - let s = include_str!("./samples/01-simple.toml"); - // Use current directory since this sample doesn't reference any account files - let gcfg = GenesisConfig::read_toml(s, Path::new("."))?; + // Copy sample file to temp dir since read_toml_file needs a real file path + let temp_dir = tempfile::tempdir()?; + let sample_content = include_str!("./samples/01-simple.toml"); + let config_path = write_toml_file(temp_dir.path(), sample_content); + + let gcfg = GenesisConfig::read_toml_file(&config_path)?; let (state, _secrets) = gcfg.into_state(SecretKey::new())?; let _ = state; // faucets always precede wallet accounts @@ -105,8 +117,7 @@ fn parsing_account_from_file() -> TestResult { account_file.write(&account_file_path)?; // Create a genesis config TOML that references the account file - let toml_content = format!( - r#" + let toml_content = r#" timestamp = 1717344256 version = 1 @@ -120,11 +131,11 @@ verification_base_fee = 0 [[account]] path = "test_account.mac" -"# - ); +"#; + let config_path = write_toml_file(config_dir, toml_content); // Parse the config - let gcfg = GenesisConfig::read_toml(&toml_content, config_dir)?; + let gcfg = GenesisConfig::read_toml_file(&config_path)?; // Convert to state and verify the account is included let (state, _secrets) = gcfg.into_state(SecretKey::new())?; @@ -179,9 +190,10 @@ path = "native_faucet.mac" [fee_parameters] verification_base_fee = 0 "#; + let config_path = write_toml_file(config_dir, toml_content); // Parse the config - let gcfg = GenesisConfig::read_toml(toml_content, config_dir)?; + let gcfg = GenesisConfig::read_toml_file(&config_path)?; // Convert to state and verify the native faucet is included let (state, secrets) = gcfg.into_state(SecretKey::new())?; @@ -235,9 +247,10 @@ path = "not_a_faucet.mac" [fee_parameters] verification_base_fee = 0 "#; + let config_path = write_toml_file(config_dir, toml_content); // Parse should fail with NativeFaucetNotFungible error - let result = GenesisConfig::read_toml(toml_content, config_dir); + let result = GenesisConfig::read_toml_file(&config_path); assert!(result.is_err()); let err = result.unwrap_err(); assert!( @@ -270,7 +283,8 @@ path = "does_not_exist.mac" // Use temp dir as config dir let temp_dir = tempfile::tempdir().unwrap(); - let result = GenesisConfig::read_toml(toml_content, temp_dir.path()); + let config_path = write_toml_file(temp_dir.path(), toml_content); + let result = GenesisConfig::read_toml_file(&config_path); assert!(result.is_err()); let err = result.unwrap_err(); assert!( @@ -290,7 +304,9 @@ version = 1 verification_base_fee = 0 "#; - let result = GenesisConfig::read_toml(toml_content, Path::new(".")); + let temp_dir = tempfile::tempdir()?; + let config_path = write_toml_file(temp_dir.path(), toml_content); + let result = GenesisConfig::read_toml_file(&config_path); assert!(result.is_err()); let err = result.unwrap_err(); assert_matches!(err, GenesisConfigError::Toml(toml_err) => { From 94c6916b322f71762d4c46601170eb60e37301bb Mon Sep 17 00:00:00 2001 From: Marti Date: Sat, 31 Jan 2026 20:34:40 +0000 Subject: [PATCH 03/14] feat: sample config with agglayer accounts --- Cargo.lock | 1 + crates/store/Cargo.toml | 6 +- crates/store/build.rs | 76 ++++++++++++++++++ .../config/samples/02-with-account-files.toml | 36 +++++++++ .../agglayer_faucet_eth.mac | Bin 0 -> 20624 bytes .../agglayer_faucet_usdc.mac | Bin 0 -> 20624 bytes .../samples/02-with-account-files/bridge.mac | Bin 0 -> 20449 bytes crates/store/src/genesis/config/tests.rs | 71 ++++++++++++++++ 8 files changed, 189 insertions(+), 1 deletion(-) create mode 100644 crates/store/src/genesis/config/samples/02-with-account-files.toml create mode 100644 crates/store/src/genesis/config/samples/02-with-account-files/agglayer_faucet_eth.mac create mode 100644 crates/store/src/genesis/config/samples/02-with-account-files/agglayer_faucet_usdc.mac create mode 100644 crates/store/src/genesis/config/samples/02-with-account-files/bridge.mac diff --git a/Cargo.lock b/Cargo.lock index 65d8804d0..7704dbdd6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2913,6 +2913,7 @@ dependencies = [ "fs-err", "hex", "indexmap 2.13.0", + "miden-agglayer", "miden-crypto", "miden-node-proto", "miden-node-proto-build", diff --git a/crates/store/Cargo.toml b/crates/store/Cargo.toml index 28d910ddb..ddadcfd26 100644 --- a/crates/store/Cargo.toml +++ b/crates/store/Cargo.toml @@ -54,9 +54,13 @@ miden-protocol = { default-features = true, features = ["testing"], works miden-standards = { features = ["testing"], workspace = true } rand = { workspace = true } regex = { version = "1.11" } -tempfile = "3.24.0" +tempfile = "3.24.0" termtree = { version = "0.5" } +[build-dependencies] +miden-agglayer = { branch = "next", features = ["testing"], git = "https://github.com/0xMiden/miden-base" } +miden-protocol = { features = ["std"], workspace = true } + [features] default = ["rocksdb"] rocksdb = ["miden-crypto/rocksdb"] diff --git a/crates/store/build.rs b/crates/store/build.rs index d08f3fd0e..7215db991 100644 --- a/crates/store/build.rs +++ b/crates/store/build.rs @@ -1,9 +1,85 @@ // This build.rs is required to trigger the `diesel_migrations::embed_migrations!` proc-macro in // `store/src/db/migrations.rs` to include the latest version of the migrations into the binary, see . + +use std::path::PathBuf; + +use miden_agglayer::{create_existing_agglayer_faucet, create_existing_bridge_account}; +use miden_protocol::account::AccountFile; +use miden_protocol::{Felt, Word}; fn main() { println!("cargo:rerun-if-changed=./src/db/migrations"); // If we do one re-write, the default rules are disabled, // hence we need to trigger explicitly on `Cargo.toml`. // println!("cargo:rerun-if-changed=Cargo.toml"); + + // Generate sample AggLayer account files for genesis config samples. + generate_agglayer_sample_accounts(); +} + +/// Generates sample AggLayer account files for the `02-with-account-files` genesis config sample. +/// +/// Creates: +/// - `bridge.mac` - AggLayer bridge account +/// - `agglayer_faucet_eth.mac` - AggLayer faucet for wrapped ETH +/// - `agglayer_faucet_usdc.mac` - AggLayer faucet for wrapped USDC +fn generate_agglayer_sample_accounts() { + // Use CARGO_MANIFEST_DIR to get the absolute path to the crate root + let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set"); + let samples_dir: PathBuf = + [&manifest_dir, "src", "genesis", "config", "samples", "02-with-account-files"] + .iter() + .collect(); + + // Create the directory if it doesn't exist + std::fs::create_dir_all(&samples_dir).expect("Failed to create samples directory"); + + // Use deterministic seeds for reproducible builds + // WARNING: DO NOT USE THIS IN PRODUCTION + let bridge_seed: Word = Word::new([Felt::new(1u64); 4]); + let eth_faucet_seed: Word = Word::new([Felt::new(2u64); 4]); + let usdc_faucet_seed: Word = Word::new([Felt::new(3u64); 4]); + + // Create the bridge account first (faucets need to reference it) + // Use "existing" variant so accounts have nonce > 0 (required for genesis) + let bridge_account = create_existing_bridge_account(bridge_seed); + let bridge_account_id = bridge_account.id(); + + // Create AggLayer faucets using "existing" variant + // ETH: 18 decimals, max supply of 1 billion tokens + let eth_faucet = create_existing_agglayer_faucet( + eth_faucet_seed, + "ETH", + 18, + Felt::new(1_000_000_000), + bridge_account_id, + ); + + // USDC: 6 decimals, max supply of 10 billion tokens + let usdc_faucet = create_existing_agglayer_faucet( + usdc_faucet_seed, + "USDC", + 6, + Felt::new(10_000_000_000), + bridge_account_id, + ); + + // Save account files (without secret keys since these use NoAuth) + let bridge_file = AccountFile::new(bridge_account, vec![]); + let eth_faucet_file = AccountFile::new(eth_faucet, vec![]); + let usdc_faucet_file = AccountFile::new(usdc_faucet, vec![]); + + // Write files + bridge_file.write(samples_dir.join("bridge.mac")).expect("Failed to write bridge.mac"); + eth_faucet_file + .write(samples_dir.join("agglayer_faucet_eth.mac")) + .expect("Failed to write agglayer_faucet_eth.mac"); + usdc_faucet_file + .write(samples_dir.join("agglayer_faucet_usdc.mac")) + .expect("Failed to write agglayer_faucet_usdc.mac"); + + // Track these files for rebuild + println!("cargo:rerun-if-changed={}", samples_dir.join("bridge.mac").display()); + println!("cargo:rerun-if-changed={}", samples_dir.join("agglayer_faucet_eth.mac").display()); + println!("cargo:rerun-if-changed={}", samples_dir.join("agglayer_faucet_usdc.mac").display()); } diff --git a/crates/store/src/genesis/config/samples/02-with-account-files.toml b/crates/store/src/genesis/config/samples/02-with-account-files.toml new file mode 100644 index 000000000..c5d59896b --- /dev/null +++ b/crates/store/src/genesis/config/samples/02-with-account-files.toml @@ -0,0 +1,36 @@ +# Genesis configuration example with AggLayer account files +# +# This example demonstrates how to include pre-built accounts from .mac files +# in the genesis block. The account files are generated by the build script +# using deterministic seeds for reproducibility. +# They demonstrate interdependencies between accounts: +# - bridge.mac: AggLayer bridge account for cross-chain asset transfers +# - agglayer_faucet_eth.mac: AggLayer faucet for wrapped ETH, depends on the bridge account. +# - agglayer_faucet_usdc.mac: AggLayer faucet for wrapped USDC, depends on the bridge account. +# +# Paths are relative to the directory containing this configuration file. + +timestamp = 1717344256 +version = 1 + +[fee_parameters] +verification_base_fee = 0 + +# Native faucet for the chain's native token (e.g., MIDEN) +# This uses parameters to build a standard fungible faucet +[native_faucet] +decimals = 6 +max_supply = 100_000_000_000 +symbol = "MIDEN" + +# AggLayer bridge account for bridging assets to/from AggLayer +[[account]] +path = "02-with-account-files/bridge.mac" + +# AggLayer ETH faucet for wrapped ETH tokens +[[account]] +path = "02-with-account-files/agglayer_faucet_eth.mac" + +# AggLayer USDC faucet for wrapped USDC tokens +[[account]] +path = "02-with-account-files/agglayer_faucet_usdc.mac" diff --git a/crates/store/src/genesis/config/samples/02-with-account-files/agglayer_faucet_eth.mac b/crates/store/src/genesis/config/samples/02-with-account-files/agglayer_faucet_eth.mac new file mode 100644 index 0000000000000000000000000000000000000000..d132c18f71d8ad3a7234081d35b40bb1e0649553 GIT binary patch literal 20624 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 Dea!6b literal 0 HcmV?d00001 diff --git a/crates/store/src/genesis/config/samples/02-with-account-files/agglayer_faucet_usdc.mac b/crates/store/src/genesis/config/samples/02-with-account-files/agglayer_faucet_usdc.mac new file mode 100644 index 0000000000000000000000000000000000000000..715806fc939b197f202ea164d88d82e0398be6ea GIT binary patch literal 20624 zcmc(H2|QHm|No4^7($YeV(d$n*~gG2Z4{A`YSI`CO<^QXhVA*6Aeii#E{i=-|tk-~&~+!!a7$Ry#C=#Cp*T;h}CBZM;H zU+?|tioL=@yi6DyA(TeMgNcOLC~;V{NYI`MxDq3h3EQpJYm8I^3#tk$tl^nI*z@Z* zVkBNjRmvmLF_StFxeyvgdPw~An+gzfZz>bID}vbnBgc0QV8)75+O{1kO3hF z!deKq5b_}0*CnZ_5G_fzB!Z>wPX|p|ho(4q9l}p4wlrlmTW!TfLsa5hVAFfue4!ZmUAwxVk#xRIRy%tpk5^@Oo=g9qD2IK9%z5SaM7S z|M~H#3wt)$tMWO6tKJ_UD5M+kojbC_R|t^NUuBHu040OKq$%^=J97I^#Zy!PfuPCH z_F>r)a(ZU*XD*zP?R%}eKh_2r6r7aI7~bmMY8qZ@#4cR`EG;alx@(km2l%dg3_7Mp z#%jjj2Qpn(SBGD!NZ*maqF{S^;2 zFEwbUjtJ;2bfOADPmQnM9!)S;Ky4l|5`j;Kb4O47i}Hqf)hlQQ3RXkG8ed?GS7YJM9{EUL*A3t0@xW ze}N*POg8Hj9c=k+a8(}Dd68`9$btj=ueSUmMt>LUU`x>BvoDbd8|n{K^T!UF^tjSKCXF#JtYC2FmXy7L!WP-L%XWHKxwT;)sgDr(` zpeT_eO-H4(cpxhLB>_Ymg$hljQ`_DY>hgzwrb8+nn){@sZXq!k?X66N+sw`A-d#

wavn8ik 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 I$q(ZH175T2(*OVf literal 0 HcmV?d00001 diff --git a/crates/store/src/genesis/config/samples/02-with-account-files/bridge.mac b/crates/store/src/genesis/config/samples/02-with-account-files/bridge.mac new file mode 100644 index 0000000000000000000000000000000000000000..4d159c18646041f1f94774187808dde965272e80 GIT binary patch literal 20449 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 literal 0 HcmV?d00001 diff --git a/crates/store/src/genesis/config/tests.rs b/crates/store/src/genesis/config/tests.rs index cf9e47050..6df0f1314 100644 --- a/crates/store/src/genesis/config/tests.rs +++ b/crates/store/src/genesis/config/tests.rs @@ -318,3 +318,74 @@ verification_base_fee = 0 }); Ok(()) } + +#[test] +#[miden_node_test_macro::enable_logging] +fn parsing_agglayer_sample_with_account_files() -> TestResult { + use miden_protocol::account::AccountType; + + // Use the actual sample file path since it references relative .mac files + let sample_path = Path::new(env!("CARGO_MANIFEST_DIR")) + .join("src/genesis/config/samples/02-with-account-files.toml"); + + let gcfg = GenesisConfig::read_toml_file(&sample_path)?; + let (state, secrets) = gcfg.into_state(SecretKey::new())?; + + // Should have 4 accounts: + // 1. Native faucet (MIDEN) - built from parameters + // 2. Bridge account (bridge.mac) - loaded from file + // 3. ETH faucet (agglayer_faucet_eth.mac) - loaded from file + // 4. USDC faucet (agglayer_faucet_usdc.mac) - loaded from file + assert_eq!(state.accounts.len(), 4, "Expected 4 accounts in genesis state"); + + // Verify account types + let native_faucet = &state.accounts[0]; + let bridge_account = &state.accounts[1]; + let eth_faucet = &state.accounts[2]; + let usdc_faucet = &state.accounts[3]; + + // Native faucet should be a fungible faucet (built from parameters) + assert_eq!( + native_faucet.id().account_type(), + AccountType::FungibleFaucet, + "Native faucet should be a FungibleFaucet" + ); + + // Verify native faucet symbol + { + let faucet = BasicFungibleFaucet::try_from(native_faucet.clone()).unwrap(); + assert_eq!(faucet.symbol(), TokenSymbol::new("MIDEN").unwrap()); + } + + // Bridge account is a regular account (not a faucet) + assert!( + bridge_account.is_regular_account(), + "Bridge account should be a regular account" + ); + + // ETH faucet should be a fungible faucet (AggLayer faucet loaded from file) + assert_eq!( + eth_faucet.id().account_type(), + AccountType::FungibleFaucet, + "ETH faucet should be a FungibleFaucet" + ); + + // USDC faucet should be a fungible faucet (AggLayer faucet loaded from file) + assert_eq!( + usdc_faucet.id().account_type(), + AccountType::FungibleFaucet, + "USDC faucet should be a FungibleFaucet" + ); + + // Only the native faucet generates a secret (built from parameters) + assert_eq!( + secrets.secrets.len(), + 1, + "Only native faucet should generate a secret" + ); + + // Verify the genesis state can be converted to a block + let _block = state.into_block()?; + + Ok(()) +} From 2a62f1e0a3df70b78d4b53ae19cfa033a58d1d72 Mon Sep 17 00:00:00 2001 From: Marti Date: Sun, 1 Feb 2026 09:42:55 +0000 Subject: [PATCH 04/14] chore: make tempfile a workspace dep --- Cargo.toml | 1 + crates/block-producer/Cargo.toml | 2 +- crates/rpc/Cargo.toml | 2 +- crates/store/Cargo.toml | 3 ++- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 839d354f1..38761e92e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -82,6 +82,7 @@ rand = { version = "0.9" } rand_chacha = { version = "0.9" } rstest = { version = "0.26" } serde = { features = ["derive"], version = "1" } +tempfile = { version = "3" } thiserror = { default-features = false, version = "2.0" } tokio = { features = ["rt-multi-thread"], version = "1.46" } tokio-stream = { version = "0.1" } diff --git a/crates/block-producer/Cargo.toml b/crates/block-producer/Cargo.toml index e5e5511ad..c6d6a5945 100644 --- a/crates/block-producer/Cargo.toml +++ b/crates/block-producer/Cargo.toml @@ -53,6 +53,6 @@ pretty_assertions = "1.4" rand_chacha = { default-features = false, version = "0.9" } rstest = { workspace = true } serial_test = "3.2" -tempfile = { version = "3.20" } +tempfile = { workspace = true } tokio = { features = ["test-util"], workspace = true } winterfell = { version = "0.13" } diff --git a/crates/rpc/Cargo.toml b/crates/rpc/Cargo.toml index 30ec4dcb8..654c7e29b 100644 --- a/crates/rpc/Cargo.toml +++ b/crates/rpc/Cargo.toml @@ -44,4 +44,4 @@ miden-protocol = { default-features = true, features = ["testing"], workspace miden-standards = { workspace = true } reqwest = { version = "0.12" } rstest = { workspace = true } -tempfile = { version = "3.20" } +tempfile = { workspace = true } diff --git a/crates/store/Cargo.toml b/crates/store/Cargo.toml index ddadcfd26..733b3833b 100644 --- a/crates/store/Cargo.toml +++ b/crates/store/Cargo.toml @@ -54,10 +54,11 @@ miden-protocol = { default-features = true, features = ["testing"], works miden-standards = { features = ["testing"], workspace = true } rand = { workspace = true } regex = { version = "1.11" } -tempfile = "3.24.0" +tempfile = { workspace = true } termtree = { version = "0.5" } [build-dependencies] +fs-err = { workspace = true } miden-agglayer = { branch = "next", features = ["testing"], git = "https://github.com/0xMiden/miden-base" } miden-protocol = { features = ["std"], workspace = true } From 04a4606b56bdf0fdaf6287b75b132312f3c53fc6 Mon Sep 17 00:00:00 2001 From: Marti Date: Sun, 1 Feb 2026 09:47:44 +0000 Subject: [PATCH 05/14] clippy --- crates/store/build.rs | 27 ++++++++++++++++-------- crates/store/src/genesis/config/mod.rs | 17 +++++++-------- crates/store/src/genesis/config/tests.rs | 20 ++++++------------ 3 files changed, 33 insertions(+), 31 deletions(-) diff --git a/crates/store/build.rs b/crates/store/build.rs index 7215db991..fdcb42757 100644 --- a/crates/store/build.rs +++ b/crates/store/build.rs @@ -6,6 +6,7 @@ use std::path::PathBuf; use miden_agglayer::{create_existing_agglayer_faucet, create_existing_bridge_account}; use miden_protocol::account::AccountFile; use miden_protocol::{Felt, Word}; + fn main() { println!("cargo:rerun-if-changed=./src/db/migrations"); // If we do one re-write, the default rules are disabled, @@ -13,16 +14,16 @@ fn main() { // println!("cargo:rerun-if-changed=Cargo.toml"); - // Generate sample AggLayer account files for genesis config samples. + // Generate sample agglayer account files for genesis config samples. generate_agglayer_sample_accounts(); } -/// Generates sample AggLayer account files for the `02-with-account-files` genesis config sample. +/// Generates sample agglayer account files for the `02-with-account-files` genesis config sample. /// /// Creates: -/// - `bridge.mac` - AggLayer bridge account -/// - `agglayer_faucet_eth.mac` - AggLayer faucet for wrapped ETH -/// - `agglayer_faucet_usdc.mac` - AggLayer faucet for wrapped USDC +/// - `bridge.mac` - agglayer bridge account +/// - `agglayer_faucet_eth.mac` - agglayer faucet for wrapped ETH +/// - `agglayer_faucet_usdc.mac` - agglayer faucet for wrapped USDC fn generate_agglayer_sample_accounts() { // Use CARGO_MANIFEST_DIR to get the absolute path to the crate root let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set"); @@ -32,7 +33,7 @@ fn generate_agglayer_sample_accounts() { .collect(); // Create the directory if it doesn't exist - std::fs::create_dir_all(&samples_dir).expect("Failed to create samples directory"); + fs_err::create_dir_all(&samples_dir).expect("Failed to create samples directory"); // Use deterministic seeds for reproducible builds // WARNING: DO NOT USE THIS IN PRODUCTION @@ -70,7 +71,9 @@ fn generate_agglayer_sample_accounts() { let usdc_faucet_file = AccountFile::new(usdc_faucet, vec![]); // Write files - bridge_file.write(samples_dir.join("bridge.mac")).expect("Failed to write bridge.mac"); + bridge_file + .write(samples_dir.join("bridge.mac")) + .expect("Failed to write bridge.mac"); eth_faucet_file .write(samples_dir.join("agglayer_faucet_eth.mac")) .expect("Failed to write agglayer_faucet_eth.mac"); @@ -80,6 +83,12 @@ fn generate_agglayer_sample_accounts() { // Track these files for rebuild println!("cargo:rerun-if-changed={}", samples_dir.join("bridge.mac").display()); - println!("cargo:rerun-if-changed={}", samples_dir.join("agglayer_faucet_eth.mac").display()); - println!("cargo:rerun-if-changed={}", samples_dir.join("agglayer_faucet_usdc.mac").display()); + println!( + "cargo:rerun-if-changed={}", + samples_dir.join("agglayer_faucet_eth.mac").display() + ); + println!( + "cargo:rerun-if-changed={}", + samples_dir.join("agglayer_faucet_usdc.mac").display() + ); } diff --git a/crates/store/src/genesis/config/mod.rs b/crates/store/src/genesis/config/mod.rs index 8fa667596..ba60f968c 100644 --- a/crates/store/src/genesis/config/mod.rs +++ b/crates/store/src/genesis/config/mod.rs @@ -136,12 +136,11 @@ impl GenesisConfig { /// /// Notice: It will generate the specified case during [`fn into_state`]. pub fn read_toml_file(path: &Path) -> Result { - let toml_str = std::fs::read_to_string(path).map_err(|e| { - GenesisConfigError::ConfigFileRead { + let toml_str = + fs_err::read_to_string(path).map_err(|e| GenesisConfigError::ConfigFileRead { path: path.to_path_buf(), reason: e.to_string(), - } - })?; + })?; let config_dir = path.parent().unwrap_or_else(|| Path::new(".")); Self::read_toml(&toml_str, config_dir) } @@ -174,7 +173,7 @@ impl GenesisConfig { return Err(GenesisConfigError::NativeFaucetNotFungible { path: full_path }); } - NativeFaucet::Account { account } + NativeFaucet::Account { account: Box::new(account) } }, }; @@ -246,13 +245,13 @@ impl GenesisConfig { )); faucet_account }, - NativeFaucet::Account { account } => account, + NativeFaucet::Account { account } => *account, }; let native_faucet_account_id = native_faucet_account.id(); faucet_accounts.insert(symbol.clone(), native_faucet_account); // Setup additional fungible faucets from parameters - for fungible_faucet_config in fungible_faucet_configs.into_iter() { + for fungible_faucet_config in fungible_faucet_configs { let symbol = fungible_faucet_config.symbol.clone(); let (faucet_account, secret_key) = fungible_faucet_config.build_account()?; @@ -415,7 +414,7 @@ enum NativeFaucet { max_supply: u64, }, Account { - account: Account, + account: Box, }, } @@ -443,7 +442,7 @@ impl NativeFaucet { NativeFaucet::Parameters { symbol, .. } => symbol.clone(), NativeFaucet::Account { account } => { // this is safe since we validate the account type when reading the genesis config - let faucet = BasicFungibleFaucet::try_from(account) + let faucet = BasicFungibleFaucet::try_from(account.as_ref()) .expect("native faucet account should be a fungible faucet"); TokenSymbolStr::from(faucet.symbol()) }, diff --git a/crates/store/src/genesis/config/tests.rs b/crates/store/src/genesis/config/tests.rs index 6df0f1314..07e380ebc 100644 --- a/crates/store/src/genesis/config/tests.rs +++ b/crates/store/src/genesis/config/tests.rs @@ -139,7 +139,7 @@ path = "test_account.mac" // Convert to state and verify the account is included let (state, _secrets) = gcfg.into_state(SecretKey::new())?; - assert!(state.accounts.iter().find(|a| a.id() == account_id).is_some()); + assert!(state.accounts.iter().any(|a| a.id() == account_id)); Ok(()) } @@ -197,7 +197,7 @@ verification_base_fee = 0 // Convert to state and verify the native faucet is included let (state, secrets) = gcfg.into_state(SecretKey::new())?; - assert!(state.accounts.iter().find(|a| a.id() == faucet_id).is_some()); + assert!(state.accounts.iter().any(|a| a.id() == faucet_id)); // No secrets should be generated for file-loaded native faucet assert!(secrets.secrets.is_empty()); @@ -255,8 +255,7 @@ verification_base_fee = 0 let err = result.unwrap_err(); assert!( matches!(err, GenesisConfigError::NativeFaucetNotFungible { .. }), - "Expected NativeFaucetNotFungible error, got: {:?}", - err + "Expected NativeFaucetNotFungible error, got: {err:?}" ); Ok(()) @@ -289,20 +288,19 @@ path = "does_not_exist.mac" let err = result.unwrap_err(); assert!( matches!(err, GenesisConfigError::AccountFileRead { .. }), - "Expected AccountFileRead error, got: {:?}", - err + "Expected AccountFileRead error, got: {err:?}" ); } #[test] fn missing_native_faucet_not_allowed() -> TestResult { - let toml_content = r#" + let toml_content = r" timestamp = 1717344256 version = 1 [fee_parameters] verification_base_fee = 0 -"#; +"; let temp_dir = tempfile::tempdir()?; let config_path = write_toml_file(temp_dir.path(), toml_content); @@ -378,11 +376,7 @@ fn parsing_agglayer_sample_with_account_files() -> TestResult { ); // Only the native faucet generates a secret (built from parameters) - assert_eq!( - secrets.secrets.len(), - 1, - "Only native faucet should generate a secret" - ); + assert_eq!(secrets.secrets.len(), 1, "Only native faucet should generate a secret"); // Verify the genesis state can be converted to a block let _block = state.into_block()?; From a89b4c98f7b45214f4092e22d774e35df4759646 Mon Sep 17 00:00:00 2001 From: Marti Date: Sun, 1 Feb 2026 10:05:28 +0000 Subject: [PATCH 06/14] regen account files --- .../agglayer_faucet_eth.mac | Bin 20624 -> 20624 bytes .../agglayer_faucet_usdc.mac | Bin 20624 -> 20624 bytes .../samples/02-with-account-files/bridge.mac | Bin 20449 -> 20449 bytes 3 files changed, 0 insertions(+), 0 deletions(-) diff --git a/crates/store/src/genesis/config/samples/02-with-account-files/agglayer_faucet_eth.mac b/crates/store/src/genesis/config/samples/02-with-account-files/agglayer_faucet_eth.mac index d132c18f71d8ad3a7234081d35b40bb1e0649553..7b7ce32807bc84efae40a58ea75ae4e8a81607fd 100644 GIT binary patch delta 187 zcmbQRka5C7#tpUl0%@ixX68nwY39iWhGwY-mXmw+w_pfv4m1d6#1Ngl#c(Hv;O1JR zZWaNvw6tV%12eoP+?g;$CkGmcZ{BNng#|-q^FrtMJOFJ2 BH;(`S delta 187 zcmbQRka5C7#tpUl0!gWoP+?g;$CkGmcZ{BNng#|-q^FrtMJOFJ2 BH;(`S delta 187 zcmbQRka5C7#tpUl0!gW*#trB61ky}X%*>5U)6A0%49!vvEGOU7+kzpud69lFBZlZ?R>Pebf}777 vcC!eWrKKgC8<-iUrllCAC8i{8&NNeJ#Z*#trB61d>uy%}gy46HQYM%uPebf}777 ucC!c=8K$He8>b{DCs_blX2zQ{&D2>j)h@7hXTlWyZu^=AQ}mP5dmaGFUpyQD From fa7df9f7ea4ade7801c4a4004d103ea7537054b2 Mon Sep 17 00:00:00 2001 From: Marti Date: Sun, 1 Feb 2026 20:27:28 +0000 Subject: [PATCH 07/14] Revert "regen account files" This reverts commit a89b4c98f7b45214f4092e22d774e35df4759646. --- .../agglayer_faucet_eth.mac | Bin 20624 -> 20624 bytes .../agglayer_faucet_usdc.mac | Bin 20624 -> 20624 bytes .../samples/02-with-account-files/bridge.mac | Bin 20449 -> 20449 bytes 3 files changed, 0 insertions(+), 0 deletions(-) diff --git a/crates/store/src/genesis/config/samples/02-with-account-files/agglayer_faucet_eth.mac b/crates/store/src/genesis/config/samples/02-with-account-files/agglayer_faucet_eth.mac index 7b7ce32807bc84efae40a58ea75ae4e8a81607fd..d132c18f71d8ad3a7234081d35b40bb1e0649553 100644 GIT binary patch delta 187 zcmbQRka5C7#tpUl0!gWoP+?g;$CkGmcZ{BNng#|-q^FrtMJOFJ2 BH;(`S diff --git a/crates/store/src/genesis/config/samples/02-with-account-files/agglayer_faucet_usdc.mac b/crates/store/src/genesis/config/samples/02-with-account-files/agglayer_faucet_usdc.mac index 0737d48d558ea78a22e12c928d66ed0799eccdc6..715806fc939b197f202ea164d88d82e0398be6ea 100644 GIT binary patch delta 187 zcmbQRka5C7#tpUl0!gWoP+?g;$CkGmcZ{BNng#|-q^FrtMJOFJ2 BH;(`S diff --git a/crates/store/src/genesis/config/samples/02-with-account-files/bridge.mac b/crates/store/src/genesis/config/samples/02-with-account-files/bridge.mac index cfb3bce9588d7a503ea99daac5a4fd7174c20afc..4d159c18646041f1f94774187808dde965272e80 100644 GIT binary patch delta 183 zcmaDjpYh>*#trB61d>uy%}gy46HQYM%uPebf}777 ucC!c=8K$He8>b{DCs_blX2zQ{&D2>j)h@7hXTlWyZu^=AQ}mP5dmaGFUpyQD delta 183 zcmaDjpYh>*#trB61ky}X%*>5U)6A0%49!vvEGOU7+kzpud69lFBZlZ?R>Pebf}777 vcC!eWrKKgC8<-iUrllCAC8i{8&NNeJ#Z Date: Mon, 9 Feb 2026 13:15:10 +0000 Subject: [PATCH 08/14] changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4aefc8673..393dcaa8b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ - Refactored NTX Builder startup and introduced `NtxBuilderConfig` with configurable parameters ([#1610](https://github.com/0xMiden/miden-node/pull/1610)). - Refactored NTX Builder actor state into `AccountDeltaTracker` and `NotePool` for clarity, and added tracing instrumentation to event broadcasting ([#1611](https://github.com/0xMiden/miden-node/pull/1611)). - Add #[track_caller] to tracing/logging helpers ([#1651](https://github.com/0xMiden/miden-node/pull/1651)). +- Added support for generic account loading at genesis ([#1624](https://github.com/0xMiden/miden-node/pull/1624)). ## v0.13.5 (TBD) From 0b426074d8a5b5a143f15af73663b2a073943d63 Mon Sep 17 00:00:00 2001 From: Marti Date: Mon, 9 Feb 2026 13:15:50 +0000 Subject: [PATCH 09/14] lints --- crates/store/Cargo.toml | 6 +++--- crates/store/build.rs | 2 +- .../agglayer_faucet_eth.mac | Bin 20624 -> 20624 bytes .../agglayer_faucet_usdc.mac | Bin 20624 -> 20624 bytes .../samples/02-with-account-files/bridge.mac | Bin 20449 -> 20449 bytes 5 files changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/store/Cargo.toml b/crates/store/Cargo.toml index 314c60e8a..c8ee4b093 100644 --- a/crates/store/Cargo.toml +++ b/crates/store/Cargo.toml @@ -50,10 +50,10 @@ tracing = { workspace = true } url = { workspace = true } [build-dependencies] -fs-err = { workspace = true } -miden-agglayer = { branch = "next", features = ["testing"], git = "https://github.com/0xMiden/miden-base" } +fs-err = { workspace = true } +miden-agglayer = { branch = "next", features = ["testing"], git = "https://github.com/0xMiden/miden-base" } miden-node-rocksdb-cxx-linkage-fix = { workspace = true } -miden-protocol = { features = ["std"], workspace = true } +miden-protocol = { features = ["std"], workspace = true } [dev-dependencies] assert_matches = { workspace = true } diff --git a/crates/store/build.rs b/crates/store/build.rs index 7c1b0c23d..2f32b7dfc 100644 --- a/crates/store/build.rs +++ b/crates/store/build.rs @@ -92,4 +92,4 @@ fn generate_agglayer_sample_accounts() { "cargo:rerun-if-changed={}", samples_dir.join("agglayer_faucet_usdc.mac").display() ); -} \ No newline at end of file +} diff --git a/crates/store/src/genesis/config/samples/02-with-account-files/agglayer_faucet_eth.mac b/crates/store/src/genesis/config/samples/02-with-account-files/agglayer_faucet_eth.mac index a8fa76298961fb29a18001a7ec4caba5e5f01225..5bfcbc224db83fa953091238bfb0f8d29cdd6cc9 100644 GIT binary patch delta 187 zcmbQRka5C7#tpUl0+y+X7D+~yW~OF|si|oeiIaQvw_pfv4m1d6#1Ngl#c(Hv;O1JR zZWe(gW8)-Cixgw?M58oQQvoP+?g;$CkGmcZ{BNng#|-q^FrtMJOGzj BI>7({ delta 187 zcmbQRka5C7#tpUl0){3=Nv0MCM#*ML24-m~7L$ARw_pfv4m1d6#1Ngl#c(Hv;O1JR zZWe*mltirW66Wfxm}>oP+?g;$CkGmcZ{BNng#|-q^FrtMJOC4l BHp&11 diff --git a/crates/store/src/genesis/config/samples/02-with-account-files/agglayer_faucet_usdc.mac b/crates/store/src/genesis/config/samples/02-with-account-files/agglayer_faucet_usdc.mac index 6a657cd4fc90897a2fdc01eb388262d9584ced6f..849ff4681fa789da6e2d0892d2b3cb2ca86fc6a8 100644 GIT binary patch delta 187 zcmbQRka5C7#tpUl0+y+X7D+~yW~OF|si|oeiIaQvw_pfv4m1d6#1Ngl#c(Hv;O1JR zZWe(gW8)-Cixgw?M58oQQvoP+?g;$CkGmcZ{BNng#|-q^FrtMJOGzj BI>7({ delta 187 zcmbQRka5C7#tpUl0){3=Nv0MCM#*ML24-m~7L$ARw_pfv4m1d6#1Ngl#c(Hv;O1JR zZWe*mltirW66Wfxm}>oP+?g;$CkGmcZ{BNng#|-q^FrtMJOC4l BHp&11 diff --git a/crates/store/src/genesis/config/samples/02-with-account-files/bridge.mac b/crates/store/src/genesis/config/samples/02-with-account-files/bridge.mac index f310306b002d243b72fccbcd80ed8e8d7ec2fd20..5e77754ac05459459a7d8941f06e0454f3fe2dcb 100644 GIT binary patch delta 183 zcmaDjpYh>*#trB61T0e%Es~5Z%}mV_Q&ZC{5+~o&+kzpud69lFBZlZ?R>Pebf}777 vcC!d185<{ATBI18CmN-hni`mG&NNeJ#Z*#trB61Po1#l1wcOjFQcg49wC}EGFO6+kzpud69lFBZlZ?R>Pebf}777 vcC!eirX-rBB$*l;8>bi>B%3E~&NNeJ#Z Date: Mon, 9 Feb 2026 13:26:31 +0000 Subject: [PATCH 10/14] chore: MissingFaucetDefinition error msg includes "account file" option --- crates/store/src/genesis/config/errors.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/store/src/genesis/config/errors.rs b/crates/store/src/genesis/config/errors.rs index d82ef899c..c7a07f1c7 100644 --- a/crates/store/src/genesis/config/errors.rs +++ b/crates/store/src/genesis/config/errors.rs @@ -31,7 +31,9 @@ pub enum GenesisConfigError { Asset(#[from] AssetError), #[error("adding assets to account failed")] AccountDelta(#[from] AccountDeltaError), - #[error("the defined asset {symbol:?} has no corresponding faucet")] + #[error( + "the defined asset {symbol:?} has no corresponding faucet, or the faucet was provided as an account file" + )] MissingFaucetDefinition { symbol: TokenSymbolStr }, #[error("account with id {account_id} was referenced but is not part of given genesis state")] MissingGenesisAccount { account_id: AccountId }, From debc11a605ea90c15779b872089b1f7528284cc9 Mon Sep 17 00:00:00 2001 From: Marti Date: Mon, 9 Feb 2026 13:27:04 +0000 Subject: [PATCH 11/14] chore: nits --- crates/store/src/genesis/config/mod.rs | 3 --- crates/store/src/genesis/config/tests.rs | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/crates/store/src/genesis/config/mod.rs b/crates/store/src/genesis/config/mod.rs index ba60f968c..1277037b3 100644 --- a/crates/store/src/genesis/config/mod.rs +++ b/crates/store/src/genesis/config/mod.rs @@ -89,9 +89,6 @@ struct GenesisConfigToml { /// Specify a set of faucets and wallets with assets for easier test deployments. /// /// Notice: Any faucet must be declared _before_ it's use in a wallet/regular account. -/// -/// This struct holds the parsed configuration. Accounts referenced via file paths -/// are loaded during [`read_toml`] and stored directly as [`Account`] objects. #[derive(Debug, Clone)] pub struct GenesisConfig { version: u32, diff --git a/crates/store/src/genesis/config/tests.rs b/crates/store/src/genesis/config/tests.rs index 07e380ebc..8d9848efc 100644 --- a/crates/store/src/genesis/config/tests.rs +++ b/crates/store/src/genesis/config/tests.rs @@ -163,7 +163,7 @@ fn parsing_native_faucet_from_file() -> TestResult { let auth = AuthFalcon512Rpo::new(secret_key.public_key().into()); let faucet_component = - BasicFungibleFaucet::new(TokenSymbol::new("NFAU").unwrap(), 6, Felt::new(1_000_000_000))?; + BasicFungibleFaucet::new(TokenSymbol::new("MIDEN").unwrap(), 6, Felt::new(1_000_000_000))?; let faucet_account = AccountBuilder::new(init_seed) .account_type(AccountType::FungibleFaucet) From 784c5faa8e114e2ad88b31d6d1355e3f49e3e354 Mon Sep 17 00:00:00 2001 From: Marti Date: Mon, 9 Feb 2026 13:30:51 +0000 Subject: [PATCH 12/14] chore: should not rebuild when .mac changes --- crates/store/build.rs | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/crates/store/build.rs b/crates/store/build.rs index 2f32b7dfc..d0f9d4d59 100644 --- a/crates/store/build.rs +++ b/crates/store/build.rs @@ -81,15 +81,4 @@ fn generate_agglayer_sample_accounts() { usdc_faucet_file .write(samples_dir.join("agglayer_faucet_usdc.mac")) .expect("Failed to write agglayer_faucet_usdc.mac"); - - // Track these files for rebuild - println!("cargo:rerun-if-changed={}", samples_dir.join("bridge.mac").display()); - println!( - "cargo:rerun-if-changed={}", - samples_dir.join("agglayer_faucet_eth.mac").display() - ); - println!( - "cargo:rerun-if-changed={}", - samples_dir.join("agglayer_faucet_usdc.mac").display() - ); } From c96f01f9303986b7e77001f30e10bbe5cc452be7 Mon Sep 17 00:00:00 2001 From: Marti Date: Mon, 9 Feb 2026 13:37:33 +0000 Subject: [PATCH 13/14] regen account files --- .../agglayer_faucet_eth.mac | Bin 20624 -> 20624 bytes .../agglayer_faucet_usdc.mac | Bin 20624 -> 20624 bytes .../samples/02-with-account-files/bridge.mac | Bin 20449 -> 20449 bytes 3 files changed, 0 insertions(+), 0 deletions(-) diff --git a/crates/store/src/genesis/config/samples/02-with-account-files/agglayer_faucet_eth.mac b/crates/store/src/genesis/config/samples/02-with-account-files/agglayer_faucet_eth.mac index 5bfcbc224db83fa953091238bfb0f8d29cdd6cc9..a8fa76298961fb29a18001a7ec4caba5e5f01225 100644 GIT binary patch delta 187 zcmbQRka5C7#tpUl0){3=Nv0MCM#*ML24-m~7L$ARw_pfv4m1d6#1Ngl#c(Hv;O1JR zZWe*mltirW66Wfxm}>oP+?g;$CkGmcZ{BNng#|-q^FrtMJOC4l BHp&11 delta 187 zcmbQRka5C7#tpUl0+y+X7D+~yW~OF|si|oeiIaQvw_pfv4m1d6#1Ngl#c(Hv;O1JR zZWe(gW8)-Cixgw?M58oQQvoP+?g;$CkGmcZ{BNng#|-q^FrtMJOGzj BI>7({ diff --git a/crates/store/src/genesis/config/samples/02-with-account-files/agglayer_faucet_usdc.mac b/crates/store/src/genesis/config/samples/02-with-account-files/agglayer_faucet_usdc.mac index 849ff4681fa789da6e2d0892d2b3cb2ca86fc6a8..6a657cd4fc90897a2fdc01eb388262d9584ced6f 100644 GIT binary patch delta 187 zcmbQRka5C7#tpUl0){3=Nv0MCM#*ML24-m~7L$ARw_pfv4m1d6#1Ngl#c(Hv;O1JR zZWe*mltirW66Wfxm}>oP+?g;$CkGmcZ{BNng#|-q^FrtMJOC4l BHp&11 delta 187 zcmbQRka5C7#tpUl0+y+X7D+~yW~OF|si|oeiIaQvw_pfv4m1d6#1Ngl#c(Hv;O1JR zZWe(gW8)-Cixgw?M58oQQvoP+?g;$CkGmcZ{BNng#|-q^FrtMJOGzj BI>7({ diff --git a/crates/store/src/genesis/config/samples/02-with-account-files/bridge.mac b/crates/store/src/genesis/config/samples/02-with-account-files/bridge.mac index 5e77754ac05459459a7d8941f06e0454f3fe2dcb..f310306b002d243b72fccbcd80ed8e8d7ec2fd20 100644 GIT binary patch delta 183 zcmaDjpYh>*#trB61Po1#l1wcOjFQcg49wC}EGFO6+kzpud69lFBZlZ?R>Pebf}777 vcC!eirX-rBB$*l;8>bi>B%3E~&NNeJ#Z*#trB61T0e%Es~5Z%}mV_Q&ZC{5+~o&+kzpud69lFBZlZ?R>Pebf}777 vcC!d185<{ATBI18CmN-hni`mG&NNeJ#Z Date: Mon, 9 Feb 2026 14:47:51 +0000 Subject: [PATCH 14/14] feat: ensure reproducible account file generation --- crates/store/build.rs | 24 +++++++++++++++++- .../agglayer_faucet_eth.mac | Bin 20624 -> 8521 bytes .../agglayer_faucet_usdc.mac | Bin 20624 -> 8521 bytes .../samples/02-with-account-files/bridge.mac | Bin 20449 -> 8346 bytes 4 files changed, 23 insertions(+), 1 deletion(-) diff --git a/crates/store/build.rs b/crates/store/build.rs index d0f9d4d59..bf19fbcb4 100644 --- a/crates/store/build.rs +++ b/crates/store/build.rs @@ -2,9 +2,10 @@ // `store/src/db/migrations.rs` to include the latest version of the migrations into the binary, see . use std::path::PathBuf; +use std::sync::Arc; use miden_agglayer::{create_existing_agglayer_faucet, create_existing_bridge_account}; -use miden_protocol::account::AccountFile; +use miden_protocol::account::{Account, AccountCode, AccountFile}; use miden_protocol::{Felt, Word}; fn main() { @@ -66,6 +67,11 @@ fn generate_agglayer_sample_accounts() { bridge_account_id, ); + // Strip source location decorators from account code to ensure deterministic output. + let bridge_account = strip_code_decorators(bridge_account); + let eth_faucet = strip_code_decorators(eth_faucet); + let usdc_faucet = strip_code_decorators(usdc_faucet); + // Save account files (without secret keys since these use NoAuth) let bridge_file = AccountFile::new(bridge_account, vec![]); let eth_faucet_file = AccountFile::new(eth_faucet, vec![]); @@ -82,3 +88,19 @@ fn generate_agglayer_sample_accounts() { .write(samples_dir.join("agglayer_faucet_usdc.mac")) .expect("Failed to write agglayer_faucet_usdc.mac"); } + +/// Strips source location decorators from an account's code MAST forest. +/// +/// This is necessary because the MAST forest embeds absolute file paths from the Cargo build +/// directory, which include a hash that differs between `cargo check` and `cargo build`. Stripping +/// decorators ensures the serialized `.mac` files are identical regardless of which cargo command +/// is used (CI or local builds or tests). +fn strip_code_decorators(account: Account) -> Account { + let (id, vault, storage, code, nonce, seed) = account.into_parts(); + + let mut mast = code.mast(); + Arc::make_mut(&mut mast).strip_decorators(); + let code = AccountCode::from_parts(mast, code.procedures().to_vec()); + + Account::new_unchecked(id, vault, storage, code, nonce, seed) +} diff --git a/crates/store/src/genesis/config/samples/02-with-account-files/agglayer_faucet_eth.mac b/crates/store/src/genesis/config/samples/02-with-account-files/agglayer_faucet_eth.mac index a8fa76298961fb29a18001a7ec4caba5e5f01225..ed79a49b1b58f01a656883fcee580301361de395 100644 GIT binary patch delta 155 zcmWN~p-ut-6ac{8n`5|HNN%z*2V;yeH86`CL4u9|CZokd#!UhSXP{_dBM}MAWMIy0 zGB7Lzqrrr;7)T`Ge&BjTlWOmm@n1P}Z=Wmj5GUO`dGfg{H%PMxc%yL6@L)}04k zPx=OiMxMPGd-LwY)XbM}Kj!`|EUhHMUdV>Sa1zc!BV31@&<>s0+Vng9&*c7V;^NU7 D>s}*C delta 12300 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 diff --git a/crates/store/src/genesis/config/samples/02-with-account-files/agglayer_faucet_usdc.mac b/crates/store/src/genesis/config/samples/02-with-account-files/agglayer_faucet_usdc.mac index 6a657cd4fc90897a2fdc01eb388262d9584ced6f..13c71956cdfa0560245f6ffdbe691be347d136d2 100644 GIT binary patch delta 155 zcmWN~p-ut-6ac{8n`5|HNN%z*2V;yeH86`CL4u9|CZokd#!UhSXP{_dBM}MAWMIy0 zGB7Lzqrrr;7)T`Ge&BjTlWOmm@n1P}Z=Wmj5GUO`dGfg{H%PMxc%yL6@L)}04k zPx=OiMxMPGd-LwY)XbM}Kj!`|EUhHMUdV>Sa1zc!BV31@&<>s0+Vng9&*c7V;^NU7 D>s}*C delta 12300 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 diff --git a/crates/store/src/genesis/config/samples/02-with-account-files/bridge.mac b/crates/store/src/genesis/config/samples/02-with-account-files/bridge.mac index f310306b002d243b72fccbcd80ed8e8d7ec2fd20..57b462715064d7dee0fdecaa8a5559bae2386d15 100644 GIT binary patch delta 155 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