From 51503366d6a9c4ddaa41e1d7aaa5f158330e0118 Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Thu, 12 Mar 2026 10:16:20 +0100 Subject: [PATCH 1/2] feat: enforce component name and code path consistency --- crates/miden-agglayer/build.rs | 12 ++- crates/miden-agglayer/src/lib.rs | 13 ++- .../miden-protocol/src/account/builder/mod.rs | 12 ++- crates/miden-protocol/src/account/code/mod.rs | 14 +++- .../src/account/component/mod.rs | 79 +++++++++++++++---- crates/miden-protocol/src/account/mod.rs | 7 +- crates/miden-protocol/src/errors/mod.rs | 4 + .../src/testing/account_code.rs | 6 +- .../src/testing/add_component.rs | 9 ++- .../src/testing/noop_auth_component.rs | 12 ++- .../src/account/metadata/mod.rs | 5 +- .../account_component/conditional_auth.rs | 8 +- .../testing/account_component/incr_nonce.rs | 8 +- .../mock_account_component.rs | 7 +- .../mock_faucet_component.rs | 6 +- .../src/testing/mock_account_code.rs | 5 +- .../src/kernel_tests/tx/test_account.rs | 6 +- .../src/kernel_tests/tx/test_auth.rs | 2 +- .../src/kernel_tests/tx/test_fpi.rs | 8 +- 19 files changed, 168 insertions(+), 55 deletions(-) diff --git a/crates/miden-agglayer/build.rs b/crates/miden-agglayer/build.rs index 436447346f..24bdbc7de1 100644 --- a/crates/miden-agglayer/build.rs +++ b/crates/miden-agglayer/build.rs @@ -22,6 +22,7 @@ const ASM_NOTE_SCRIPTS_DIR: &str = "note_scripts"; const ASM_AGGLAYER_DIR: &str = "agglayer"; const ASM_AGGLAYER_BRIDGE_DIR: &str = "agglayer/bridge"; const ASM_COMPONENTS_DIR: &str = "components"; +const AGGLAYER_COMPONENTS_NAMESPACE: &str = "agglayer::components"; const AGGLAYER_ERRORS_FILE: &str = "src/errors/agglayer.rs"; const AGGLAYER_ERRORS_ARRAY_NAME: &str = "AGGLAYER_ERRORS"; @@ -178,7 +179,16 @@ fn compile_account_components( let component_source_code = fs::read_to_string(&masm_file_path) .expect("reading the component's MASM source code should succeed"); - let named_source = NamedSource::new(component_name.clone(), component_source_code); + let relative_path = masm_file_path + .strip_prefix(source_dir) + .expect("masm file should be inside source dir"); + let mut library_path = AGGLAYER_COMPONENTS_NAMESPACE.to_owned(); + for component in relative_path.with_extension("").components() { + let part = component.as_os_str().to_str().expect("valid UTF-8"); + library_path.push_str("::"); + library_path.push_str(part); + } + let named_source = NamedSource::new(library_path, component_source_code); let component_library = assembler .clone() diff --git a/crates/miden-agglayer/src/lib.rs b/crates/miden-agglayer/src/lib.rs index b8870a89ef..229cdb7c7d 100644 --- a/crates/miden-agglayer/src/lib.rs +++ b/crates/miden-agglayer/src/lib.rs @@ -98,7 +98,7 @@ fn agglayer_faucet_component_library() -> Library { /// Creates an AggLayer Bridge component with the specified storage slots. fn bridge_component(storage_slots: Vec) -> AccountComponent { let library = agglayer_bridge_component_library(); - let metadata = AccountComponentMetadata::new("agglayer::bridge", AccountType::all()) + let metadata = AccountComponentMetadata::new(AggLayerBridge::NAME, AccountType::all()) .with_description("Bridge component for AggLayer"); AccountComponent::new(library, storage_slots, metadata) @@ -172,6 +172,9 @@ pub struct AggLayerBridge { } impl AggLayerBridge { + /// The name of the component. + pub const NAME: &str = "agglayer::components::bridge"; + /// Creates a new AggLayer bridge component with the standard configuration. pub fn new(bridge_admin_id: AccountId, ger_manager_id: AccountId) -> Self { Self { bridge_admin_id, ger_manager_id } @@ -244,8 +247,9 @@ impl From for AccountComponent { /// validates CLAIM notes against a bridge MMR account before minting assets. fn agglayer_faucet_component(storage_slots: Vec) -> AccountComponent { let library = agglayer_faucet_component_library(); - let metadata = AccountComponentMetadata::new("agglayer::faucet", [AccountType::FungibleFaucet]) - .with_description("AggLayer faucet component with bridge validation"); + let metadata = + AccountComponentMetadata::new(AggLayerFaucet::NAME, [AccountType::FungibleFaucet]) + .with_description("AggLayer faucet component with bridge validation"); AccountComponent::new(library, storage_slots, metadata).expect( "agglayer_faucet component should satisfy the requirements of a valid account component", @@ -328,6 +332,9 @@ pub struct AggLayerFaucet { } impl AggLayerFaucet { + /// The name of the component. + pub const NAME: &str = "agglayer::components::faucet"; + /// Creates a new AggLayer faucet component from the given configuration. /// /// # Errors diff --git a/crates/miden-protocol/src/account/builder/mod.rs b/crates/miden-protocol/src/account/builder/mod.rs index 7a0e7bec6e..b1cc7e2db2 100644 --- a/crates/miden-protocol/src/account/builder/mod.rs +++ b/crates/miden-protocol/src/account/builder/mod.rs @@ -292,6 +292,7 @@ mod tests { use std::sync::LazyLock; use assert_matches::assert_matches; + use miden_assembly::diagnostics::NamedSource; use miden_assembly::{Assembler, Library}; use miden_core::mast::MastNodeExt; @@ -300,6 +301,9 @@ mod tests { use crate::account::{AccountProcedureRoot, StorageSlot, StorageSlotName}; use crate::testing::noop_auth_component::NoopAuthComponent; + const CUSTOM_COMPONENT1_NAME: &str = "test::custom_component1"; + const CUSTOM_COMPONENT2_NAME: &str = "test::custom_component2"; + const CUSTOM_CODE1: &str = " pub proc foo push.2.2 add eq.4 @@ -313,12 +317,12 @@ mod tests { static CUSTOM_LIBRARY1: LazyLock = LazyLock::new(|| { Assembler::default() - .assemble_library([CUSTOM_CODE1]) + .assemble_library([NamedSource::new(CUSTOM_COMPONENT1_NAME, CUSTOM_CODE1)]) .expect("code should be valid") }); static CUSTOM_LIBRARY2: LazyLock = LazyLock::new(|| { Assembler::default() - .assemble_library([CUSTOM_CODE2]) + .assemble_library([NamedSource::new(CUSTOM_COMPONENT2_NAME, CUSTOM_CODE2)]) .expect("code should be valid") }); @@ -344,7 +348,7 @@ mod tests { value[0] = Felt::new(custom.slot0); let metadata = - AccountComponentMetadata::new("test::custom_component1", AccountType::all()); + AccountComponentMetadata::new(CUSTOM_COMPONENT1_NAME, AccountType::all()); AccountComponent::new( CUSTOM_LIBRARY1.clone(), vec![StorageSlot::with_value(CUSTOM_COMPONENT1_SLOT_NAME.clone(), value)], @@ -366,7 +370,7 @@ mod tests { value1[3] = Felt::new(custom.slot1); let metadata = - AccountComponentMetadata::new("test::custom_component2", AccountType::all()); + AccountComponentMetadata::new(CUSTOM_COMPONENT2_NAME, AccountType::all()); AccountComponent::new( CUSTOM_LIBRARY2.clone(), vec![ diff --git a/crates/miden-protocol/src/account/code/mod.rs b/crates/miden-protocol/src/account/code/mod.rs index c8825b9f3c..3ade245537 100644 --- a/crates/miden-protocol/src/account/code/mod.rs +++ b/crates/miden-protocol/src/account/code/mod.rs @@ -410,6 +410,7 @@ mod tests { use assert_matches::assert_matches; use miden_assembly::Assembler; + use miden_assembly::diagnostics::NamedSource; use super::{AccountCode, Deserializable, Serializable}; use crate::account::code::build_procedure_commitment; @@ -447,8 +448,10 @@ mod tests { #[test] fn test_account_code_no_auth_component() { - let library = Assembler::default().assemble_library([CODE]).unwrap(); - let metadata = AccountComponentMetadata::new("test::no_auth", AccountType::all()); + let name = "test::no_auth"; + let library = + Assembler::default().assemble_library([NamedSource::new(name, CODE)]).unwrap(); + let metadata = AccountComponentMetadata::new(name, AccountType::all()); let component = AccountComponent::new(library, vec![], metadata).unwrap(); let err = @@ -485,8 +488,11 @@ mod tests { end "; - let library = Assembler::default().assemble_library([code_with_multiple_auth]).unwrap(); - let metadata = AccountComponentMetadata::new("test::multiple_auth", AccountType::all()); + let name = "test::multiple_auth"; + let library = Assembler::default() + .assemble_library([NamedSource::new(name, code_with_multiple_auth)]) + .unwrap(); + let metadata = AccountComponentMetadata::new(name, AccountType::all()); let component = AccountComponent::new(library, vec![], metadata).unwrap(); let err = diff --git a/crates/miden-protocol/src/account/component/mod.rs b/crates/miden-protocol/src/account/component/mod.rs index b9da72c1f5..f31b45e4e8 100644 --- a/crates/miden-protocol/src/account/component/mod.rs +++ b/crates/miden-protocol/src/account/component/mod.rs @@ -64,6 +64,8 @@ impl AccountComponent { /// /// Returns an error if: /// - The number of given [`StorageSlot`]s exceeds 255. + /// - The metadata name is not a valid path. + /// - The metadata name is not a prefix (at a `::` boundary) of any library export path. pub fn new( code: impl Into, storage_slots: Vec, @@ -73,11 +75,28 @@ impl AccountComponent { u8::try_from(storage_slots.len()) .map_err(|_| AccountError::StorageTooManySlots(storage_slots.len() as u64))?; - Ok(Self { - code: code.into(), - storage_slots, - metadata, - }) + let code: AccountComponentCode = code.into(); + let canonical_name = Path::validate(metadata.name()) + .map_err(|err| { + AccountError::other_with_source("account component name is not a valid path", err) + })? + .canonicalize() + .expect("Path::validate should ensure valid path"); + + for export in code.as_library().exports() { + // Contrary to starts_with_exactly, this ignores whether paths start with `::` or not. + // That allows a component's name to start without `::` even if the library's path + // starts with `::`. + let is_prefix = export.path().starts_with(canonical_name.as_path()); + if !is_prefix { + return Err(AccountError::AccountComponentNameMismatch { + name: metadata.name().into(), + export_path: export.path().as_str().into(), + }); + } + } + + Ok(Self { code, storage_slots, metadata }) } /// Creates an [`AccountComponent`] from a [`Package`] using [`InitStorageData`]. @@ -235,7 +254,9 @@ mod tests { use alloc::string::ToString; use alloc::sync::Arc; + use assert_matches::assert_matches; use miden_assembly::Assembler; + use miden_assembly::diagnostics::NamedSource; use miden_mast_package::{ MastArtifact, Package, @@ -252,16 +273,16 @@ mod tests { #[test] fn test_extract_metadata_from_package() { + let name = "test_component"; // Create a simple library for testing - let library = Assembler::default().assemble_library([CODE]).unwrap(); + let library = + Assembler::default().assemble_library([NamedSource::new(name, CODE)]).unwrap(); // Test with metadata - let metadata = AccountComponentMetadata::new( - "test_component", - [AccountType::RegularAccountImmutableCode], - ) - .with_description("A test component") - .with_version(Version::new(1, 0, 0)); + let metadata = + AccountComponentMetadata::new(name, [AccountType::RegularAccountImmutableCode]) + .with_description("A test component") + .with_version(Version::new(1, 0, 0)); let metadata_bytes = metadata.to_bytes(); let package_with_metadata = Package { @@ -279,7 +300,7 @@ mod tests { let extracted_metadata = AccountComponentMetadata::try_from(&package_with_metadata).unwrap(); - assert_eq!(extracted_metadata.name(), "test_component"); + assert_eq!(extracted_metadata.name(), name); assert!( extracted_metadata .supported_types() @@ -305,12 +326,14 @@ mod tests { #[test] fn test_from_library_with_init_data() { + let name = "test_component"; // Create a simple library for testing - let library = Assembler::default().assemble_library([CODE]).unwrap(); + let library = + Assembler::default().assemble_library([NamedSource::new(name, CODE)]).unwrap(); let component_code = AccountComponentCode::from(library.clone()); // Create metadata for the component - let metadata = AccountComponentMetadata::new("test_component", AccountType::regular()) + let metadata = AccountComponentMetadata::new(name, AccountType::regular()) .with_description("A test component") .with_version(Version::new(1, 0, 0)); @@ -342,4 +365,30 @@ mod tests { let error_msg = result.unwrap_err().to_string(); assert!(error_msg.contains("package does not contain account component metadata")); } + + #[test] + fn test_name_mismatch_returns_error() { + let correct_name = "correct::namespace"; + let wrong_name = "wrong::name"; + + // Create a library under the "correct::namespace" path. + let library = Assembler::default() + .assemble_library([NamedSource::new(correct_name, CODE)]) + .unwrap(); + + // Use a metadata name that does NOT match the library path. + let metadata = AccountComponentMetadata::new(wrong_name, AccountType::all()); + + let result = AccountComponent::new(library, vec![], metadata); + assert_matches!( + result, + Err(AccountError::AccountComponentNameMismatch { name, export_path }) => { + assert_eq!(name.as_ref(), wrong_name); + assert!( + export_path.contains(correct_name), + "export_path `{export_path}` should contain `{correct_name}`" + ); + } + ); + } } diff --git a/crates/miden-protocol/src/account/mod.rs b/crates/miden-protocol/src/account/mod.rs index 0396dbac43..286ea6a1a3 100644 --- a/crates/miden-protocol/src/account/mod.rs +++ b/crates/miden-protocol/src/account/mod.rs @@ -553,6 +553,7 @@ mod tests { use assert_matches::assert_matches; use miden_assembly::Assembler; + use miden_assembly::diagnostics::NamedSource; use miden_crypto::utils::{Deserializable, Serializable}; use miden_crypto::{Felt, Word}; @@ -799,12 +800,14 @@ mod tests { /// account type returns an error. #[test] fn test_account_unsupported_component_type() { + let name = "test::component1"; let code1 = "pub proc foo add end"; - let library1 = Assembler::default().assemble_library([code1]).unwrap(); + let library1 = + Assembler::default().assemble_library([NamedSource::new(name, code1)]).unwrap(); // This component support all account types except the regular account with updatable code. let metadata = AccountComponentMetadata::new( - "test::component1", + name, [ AccountType::FungibleFaucet, AccountType::NonFungibleFaucet, diff --git a/crates/miden-protocol/src/errors/mod.rs b/crates/miden-protocol/src/errors/mod.rs index 04ebc56285..d5079f150d 100644 --- a/crates/miden-protocol/src/errors/mod.rs +++ b/crates/miden-protocol/src/errors/mod.rs @@ -122,6 +122,10 @@ pub enum AccountError { AccountComponentAssemblyError(Report), #[error("failed to merge components into one account code mast forest")] AccountComponentMastForestMergeError(#[source] MastForestError), + #[error( + "account component metadata name `{name}` is not a prefix of library export path `{export_path}`" + )] + AccountComponentNameMismatch { name: Box, export_path: Box }, #[error("account component contains multiple authentication procedures")] AccountComponentMultipleAuthProcedures, #[error("failed to update asset vault")] diff --git a/crates/miden-protocol/src/testing/account_code.rs b/crates/miden-protocol/src/testing/account_code.rs index ea98aeb1cf..67681114da 100644 --- a/crates/miden-protocol/src/testing/account_code.rs +++ b/crates/miden-protocol/src/testing/account_code.rs @@ -2,6 +2,7 @@ // ================================================================================================ use miden_assembly::Assembler; +use miden_assembly::diagnostics::NamedSource; use crate::account::component::AccountComponentMetadata; use crate::account::{AccountCode, AccountComponent, AccountType}; @@ -20,10 +21,11 @@ pub const CODE: &str = " impl AccountCode { /// Creates a mock [AccountCode] with default assembler and mock code pub fn mock() -> AccountCode { + let name = "miden::testing::mock"; let library = Assembler::default() - .assemble_library([CODE]) + .assemble_library([NamedSource::new(name, CODE)]) .expect("mock account component should assemble"); - let metadata = AccountComponentMetadata::new("miden::testing::mock", AccountType::all()); + let metadata = AccountComponentMetadata::new(name, AccountType::all()); let component = AccountComponent::new(library, vec![], metadata).unwrap(); Self::from_components( diff --git a/crates/miden-protocol/src/testing/add_component.rs b/crates/miden-protocol/src/testing/add_component.rs index 98dd2b8629..f44fa1f9da 100644 --- a/crates/miden-protocol/src/testing/add_component.rs +++ b/crates/miden-protocol/src/testing/add_component.rs @@ -1,5 +1,6 @@ use crate::account::component::AccountComponentMetadata; use crate::account::{AccountComponent, AccountType}; +use crate::assembly::diagnostics::NamedSource; use crate::assembly::{Assembler, Library}; use crate::utils::sync::LazyLock; @@ -14,7 +15,7 @@ const ADD_CODE: &str = " static ADD_LIBRARY: LazyLock = LazyLock::new(|| { Assembler::default() - .assemble_library([ADD_CODE]) + .assemble_library([NamedSource::new(AddComponent::NAME, ADD_CODE)]) .expect("add code should be valid") }); @@ -23,9 +24,13 @@ static ADD_LIBRARY: LazyLock = LazyLock::new(|| { /// The component defines an `add5` procedure that adds 5 to its input. pub struct AddComponent; +impl AddComponent { + pub const NAME: &str = "miden::testing::add"; +} + impl From for AccountComponent { fn from(_: AddComponent) -> Self { - let metadata = AccountComponentMetadata::new("miden::testing::add", AccountType::all()) + let metadata = AccountComponentMetadata::new(AddComponent::NAME, AccountType::all()) .with_description("Add component for testing"); AccountComponent::new(ADD_LIBRARY.clone(), vec![], metadata) diff --git a/crates/miden-protocol/src/testing/noop_auth_component.rs b/crates/miden-protocol/src/testing/noop_auth_component.rs index 5a7880e7f8..7304f38767 100644 --- a/crates/miden-protocol/src/testing/noop_auth_component.rs +++ b/crates/miden-protocol/src/testing/noop_auth_component.rs @@ -1,5 +1,6 @@ use crate::account::component::AccountComponentMetadata; use crate::account::{AccountComponent, AccountType}; +use crate::assembly::diagnostics::NamedSource; use crate::assembly::{Assembler, Library}; use crate::utils::sync::LazyLock; @@ -15,7 +16,7 @@ const NOOP_AUTH_CODE: &str = " static NOOP_AUTH_LIBRARY: LazyLock = LazyLock::new(|| { Assembler::default() - .assemble_library([NOOP_AUTH_CODE]) + .assemble_library([NamedSource::new(NoopAuthComponent::NAME, NOOP_AUTH_CODE)]) .expect("noop auth code should be valid") }); @@ -24,11 +25,14 @@ static NOOP_AUTH_LIBRARY: LazyLock = LazyLock::new(|| { /// The component defines an `auth_noop` procedure that does nothing (always succeeds). pub struct NoopAuthComponent; +impl NoopAuthComponent { + pub const NAME: &str = "miden::testing::noop_auth"; +} + impl From for AccountComponent { fn from(_: NoopAuthComponent) -> Self { - let metadata = - AccountComponentMetadata::new("miden::testing::noop_auth", AccountType::all()) - .with_description("No-op auth component for testing"); + let metadata = AccountComponentMetadata::new(NoopAuthComponent::NAME, AccountType::all()) + .with_description("No-op auth component for testing"); AccountComponent::new(NOOP_AUTH_LIBRARY.clone(), vec![], metadata) .expect("component should be valid") diff --git a/crates/miden-standards/src/account/metadata/mod.rs b/crates/miden-standards/src/account/metadata/mod.rs index d0fc25288a..e0a61af8bf 100644 --- a/crates/miden-standards/src/account/metadata/mod.rs +++ b/crates/miden-standards/src/account/metadata/mod.rs @@ -37,6 +37,9 @@ pub struct AccountSchemaCommitment { } impl AccountSchemaCommitment { + /// The name of the component. + pub const NAME: &str = "miden::standards::components::metadata::schema_commitment"; + /// Creates a new [`AccountSchemaCommitment`] component from storage schemas. /// /// The input schemas are merged into a single schema before the final commitment is computed. @@ -66,7 +69,7 @@ impl AccountSchemaCommitment { impl From for AccountComponent { fn from(schema_commitment: AccountSchemaCommitment) -> Self { let metadata = - AccountComponentMetadata::new("miden::metadata::schema_commitment", AccountType::all()) + AccountComponentMetadata::new(AccountSchemaCommitment::NAME, AccountType::all()) .with_description("Component exposing the account storage schema commitment"); AccountComponent::new( diff --git a/crates/miden-standards/src/testing/account_component/conditional_auth.rs b/crates/miden-standards/src/testing/account_component/conditional_auth.rs index 64a5f4ce46..aded39dd36 100644 --- a/crates/miden-standards/src/testing/account_component/conditional_auth.rs +++ b/crates/miden-standards/src/testing/account_component/conditional_auth.rs @@ -37,7 +37,7 @@ static CONDITIONAL_AUTH_CODE: LazyLock = LazyLock::new(|| { static CONDITIONAL_AUTH_LIBRARY: LazyLock = LazyLock::new(|| { CodeBuilder::default() - .compile_component_code("mock::conditional_auth", CONDITIONAL_AUTH_CODE.as_str()) + .compile_component_code(ConditionalAuthComponent::NAME, CONDITIONAL_AUTH_CODE.as_str()) .expect("conditional auth code should be valid") }); @@ -50,10 +50,14 @@ static CONDITIONAL_AUTH_LIBRARY: LazyLock = LazyLock::new( /// In case it succeeds, it conditionally increments the nonce based on the fourth argument. pub struct ConditionalAuthComponent; +impl ConditionalAuthComponent { + pub const NAME: &str = "miden::testing::conditional_auth"; +} + impl From for AccountComponent { fn from(_: ConditionalAuthComponent) -> Self { let metadata = - AccountComponentMetadata::new("miden::testing::conditional_auth", AccountType::all()) + AccountComponentMetadata::new(ConditionalAuthComponent::NAME, AccountType::all()) .with_description("Testing auth component with conditional behavior"); AccountComponent::new(CONDITIONAL_AUTH_LIBRARY.clone(), vec![], metadata) diff --git a/crates/miden-standards/src/testing/account_component/incr_nonce.rs b/crates/miden-standards/src/testing/account_component/incr_nonce.rs index 96dc055ba2..533463cb10 100644 --- a/crates/miden-standards/src/testing/account_component/incr_nonce.rs +++ b/crates/miden-standards/src/testing/account_component/incr_nonce.rs @@ -16,7 +16,7 @@ const INCR_NONCE_AUTH_CODE: &str = " static INCR_NONCE_AUTH_LIBRARY: LazyLock = LazyLock::new(|| { CodeBuilder::default() - .compile_component_code("incr_nonce", INCR_NONCE_AUTH_CODE) + .compile_component_code(IncrNonceAuthComponent::NAME, INCR_NONCE_AUTH_CODE) .expect("incr nonce code should be valid") .into_library() }); @@ -27,10 +27,14 @@ static INCR_NONCE_AUTH_LIBRARY: LazyLock = LazyLock::new(|| { /// The component defines an `auth_incr_nonce` procedure that always increments the nonce by 1. pub struct IncrNonceAuthComponent; +impl IncrNonceAuthComponent { + pub const NAME: &str = "miden::testing::incr_nonce_auth"; +} + impl From for AccountComponent { fn from(_: IncrNonceAuthComponent) -> Self { let metadata = - AccountComponentMetadata::new("miden::testing::incr_nonce_auth", AccountType::all()) + AccountComponentMetadata::new(IncrNonceAuthComponent::NAME, AccountType::all()) .with_description("Testing auth component that always increments nonce"); AccountComponent::new(INCR_NONCE_AUTH_LIBRARY.clone(), vec![], metadata) diff --git a/crates/miden-standards/src/testing/account_component/mock_account_component.rs b/crates/miden-standards/src/testing/account_component/mock_account_component.rs index e3e089e2cb..ec2db7425e 100644 --- a/crates/miden-standards/src/testing/account_component/mock_account_component.rs +++ b/crates/miden-standards/src/testing/account_component/mock_account_component.rs @@ -29,6 +29,11 @@ pub struct MockAccountComponent { } impl MockAccountComponent { + // CONSTANTS + // -------------------------------------------------------------------------------------------- + + pub const NAME: &str = "mock::account"; + // CONSTRUCTORS // -------------------------------------------------------------------------------------------- @@ -62,7 +67,7 @@ impl MockAccountComponent { impl From for AccountComponent { fn from(mock_component: MockAccountComponent) -> Self { let metadata = - AccountComponentMetadata::new("miden::testing::mock_account", AccountType::all()) + AccountComponentMetadata::new(MockAccountComponent::NAME, AccountType::all()) .with_description("Mock account component for testing"); AccountComponent::new( diff --git a/crates/miden-standards/src/testing/account_component/mock_faucet_component.rs b/crates/miden-standards/src/testing/account_component/mock_faucet_component.rs index 23cffa2ec3..19c47a33c5 100644 --- a/crates/miden-standards/src/testing/account_component/mock_faucet_component.rs +++ b/crates/miden-standards/src/testing/account_component/mock_faucet_component.rs @@ -17,10 +17,14 @@ use crate::testing::mock_account_code::MockAccountCodeExt; /// [faucet_lib]: crate::testing::mock_account_code::MockAccountCodeExt::mock_faucet_library pub struct MockFaucetComponent; +impl MockFaucetComponent { + pub const NAME: &str = "mock::faucet"; +} + impl From for AccountComponent { fn from(_: MockFaucetComponent) -> Self { let metadata = AccountComponentMetadata::new( - "miden::testing::mock_faucet", + MockFaucetComponent::NAME, [AccountType::FungibleFaucet, AccountType::NonFungibleFaucet], ) .with_description("Mock faucet component for testing"); diff --git a/crates/miden-standards/src/testing/mock_account_code.rs b/crates/miden-standards/src/testing/mock_account_code.rs index 8146673c82..badbb39659 100644 --- a/crates/miden-standards/src/testing/mock_account_code.rs +++ b/crates/miden-standards/src/testing/mock_account_code.rs @@ -3,6 +3,7 @@ use miden_protocol::assembly::Library; use miden_protocol::utils::sync::LazyLock; use crate::code_builder::CodeBuilder; +use crate::testing::account_component::{MockAccountComponent, MockFaucetComponent}; const MOCK_FAUCET_CODE: &str = " use miden::protocol::faucet @@ -140,14 +141,14 @@ const MOCK_ACCOUNT_CODE: &str = " static MOCK_FAUCET_LIBRARY: LazyLock = LazyLock::new(|| { CodeBuilder::default() - .compile_component_code("mock::faucet", MOCK_FAUCET_CODE) + .compile_component_code(MockFaucetComponent::NAME, MOCK_FAUCET_CODE) .expect("mock faucet code should be valid") .into_library() }); static MOCK_ACCOUNT_LIBRARY: LazyLock = LazyLock::new(|| { CodeBuilder::default() - .compile_component_code("mock::account", MOCK_ACCOUNT_CODE) + .compile_component_code(MockAccountComponent::NAME, MOCK_ACCOUNT_CODE) .expect("mock account code should be valid") .into_library() }); diff --git a/crates/miden-testing/src/kernel_tests/tx/test_account.rs b/crates/miden-testing/src/kernel_tests/tx/test_account.rs index b91a873ce0..30ef8cf6cb 100644 --- a/crates/miden-testing/src/kernel_tests/tx/test_account.rs +++ b/crates/miden-testing/src/kernel_tests/tx/test_account.rs @@ -1545,8 +1545,8 @@ async fn transaction_executor_account_code_using_custom_library() -> anyhow::Res anyhow::anyhow!("failed to link static library: {}", PrintDiagnostic::new(&err)) })?; - let account_component_source = - NamedSource::new("account_component::account_module", ACCOUNT_COMPONENT_CODE); + let component_name = "account_component::account_module"; + let account_component_source = NamedSource::new(component_name, ACCOUNT_COMPONENT_CODE); let account_component_lib = assembler.clone().assemble_library([account_component_source]).unwrap(); @@ -1560,7 +1560,7 @@ async fn transaction_executor_account_code_using_custom_library() -> anyhow::Res let account_component = AccountComponent::new( account_component_lib.clone(), AccountStorage::mock_storage_slots(), - AccountComponentMetadata::mock("account_module"), + AccountComponentMetadata::mock(component_name), )?; // Build an existing account with nonce 1. diff --git a/crates/miden-testing/src/kernel_tests/tx/test_auth.rs b/crates/miden-testing/src/kernel_tests/tx/test_auth.rs index e24157d1a5..ab25e6f8f5 100644 --- a/crates/miden-testing/src/kernel_tests/tx/test_auth.rs +++ b/crates/miden-testing/src/kernel_tests/tx/test_auth.rs @@ -77,7 +77,7 @@ async fn test_auth_procedure_called_from_wrong_context() -> anyhow::Result<()> { // Create a transaction script that calls the auth procedure let tx_script_source = " begin - call.::incr_nonce::auth_incr_nonce + call.::miden::testing::incr_nonce_auth::auth_incr_nonce end "; diff --git a/crates/miden-testing/src/kernel_tests/tx/test_fpi.rs b/crates/miden-testing/src/kernel_tests/tx/test_fpi.rs index 9ae7d70fbd..30724a40c5 100644 --- a/crates/miden-testing/src/kernel_tests/tx/test_fpi.rs +++ b/crates/miden-testing/src/kernel_tests/tx/test_fpi.rs @@ -1436,16 +1436,14 @@ async fn test_nested_fpi_stack_overflow() -> anyhow::Result<()> { next_foreign_prefix = next_account.id().prefix().as_felt(), ); + let name = format!("test::foreign_account_chain_{foreign_account_index}"); let foreign_account_code = CodeBuilder::default() - .compile_component_code( - format!("test::foreign_account_chain_{foreign_account_index}"), - foreign_account_code_source, - ) + .compile_component_code(name.as_str(), foreign_account_code_source) .unwrap(); let foreign_account_component = AccountComponent::new( foreign_account_code, vec![], - AccountComponentMetadata::mock("test::foreign_account_chain"), + AccountComponentMetadata::mock(name.as_str()), ) .unwrap(); From 8132b31bc9df7324948dc277605c3e3a105bf70a Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Thu, 12 Mar 2026 10:23:29 +0100 Subject: [PATCH 2/2] chore: add changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ba3e62c93..f50d634b67 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -87,6 +87,7 @@ - Explicitly use `get_native_account_active_storage_slots_ptr` in `account::set_item` and `account::set_map_item`. - Added Ownable2Step as an Account Component ([#2572](https://github.com/0xMiden/protocol/pull/2572)) - [BREAKING] Introduced `PrivateNoteHeader` for output notes and removed `RawOutputNote::Header` variant ([#2569](https://github.com/0xMiden/protocol/pull/2569)). +- Enforce consistency between `AccountComponentMetadata` names and the account component's library path ([#2593](https://github.com/0xMiden/protocol/pull/2593)). ## 0.13.3 (2026-01-27)