diff --git a/sdk/base-macros/src/component_macro/mod.rs b/sdk/base-macros/src/component_macro/mod.rs index eb2f41fbe..29604667d 100644 --- a/sdk/base-macros/src/component_macro/mod.rs +++ b/sdk/base-macros/src/component_macro/mod.rs @@ -144,7 +144,13 @@ fn expand_component_struct( let default_impl = match &mut input_struct.fields { syn::Fields::Named(fields) => { let storage_namespace = metadata.component_package.as_deref().unwrap_or(&metadata.name); - let field_inits = process_storage_fields(fields, &mut acc_builder, storage_namespace)?; + let component_struct_name = struct_name.to_string(); + let field_inits = process_storage_fields( + fields, + &mut acc_builder, + storage_namespace, + &component_struct_name, + )?; generate_default_impl(struct_name, &field_inits) } syn::Fields::Unit => quote! { diff --git a/sdk/base-macros/src/component_macro/storage.rs b/sdk/base-macros/src/component_macro/storage.rs index a909e93e8..4f3cd8c59 100644 --- a/sdk/base-macros/src/component_macro/storage.rs +++ b/sdk/base-macros/src/component_macro/storage.rs @@ -1,5 +1,6 @@ use std::collections::HashMap; +use heck::ToSnakeCase; use quote::quote; use syn::{Field, Type, spanned::Spanned}; @@ -32,6 +33,24 @@ fn sanitize_slot_name_component(component: &str) -> String { out } +/// Derives the full storage slot name for a component field. +/// +/// Slot names are part of the on-chain storage ABI, so this intentionally ignores any optional +/// version suffix in `storage_namespace` and keeps the format stable as +/// `component_package_or_name::component_struct::field_name`. +fn derive_storage_slot_name( + storage_namespace: &str, + component_struct_name: &str, + field_name: &str, +) -> String { + let storage_namespace = storage_namespace.split('@').next().unwrap_or(storage_namespace); + let namespace = sanitize_slot_name_component(storage_namespace); + let struct_component = sanitize_slot_name_component(&component_struct_name.to_snake_case()); + let field_component = sanitize_slot_name_component(field_name); + + format!("{namespace}::{struct_component}::{field_component}") +} + /// Parsed arguments collected from a `#[storage(...)]` attribute. struct StorageAttributeArgs { description: Option, @@ -99,6 +118,7 @@ pub fn process_storage_fields( fields: &mut syn::FieldsNamed, builder: &mut AccountComponentMetadataBuilder, storage_namespace: &str, + component_struct_name: &str, ) -> Result, syn::Error> { let mut field_infos = Vec::new(); let mut errors = Vec::new(); @@ -134,11 +154,9 @@ pub fn process_storage_fields( } if let Some(args) = storage_args { - // Slot names are part of the on-chain storage ABI: `StorageSlotId` values are derived - // from the slot name. Keep this format stable. - let namespace = sanitize_slot_name_component(storage_namespace); - let field_component = sanitize_slot_name_component(&field_name_str); - let slot_name_str = format!("miden::component::{namespace}::{field_component}"); + // `StorageSlotId` values are derived from slot names, so keep this format stable. + let slot_name_str = + derive_storage_slot_name(storage_namespace, component_struct_name, &field_name_str); if let Some(existing_field) = slot_names.get(&slot_name_str) { errors.push(syn::Error::new( field.span(), @@ -247,3 +265,28 @@ pub(crate) fn typecheck_storage_field(field: &Field) -> Result StorageSlotName { - StorageSlotName::new("miden::component::miden_counter_contract::count_map") +/// Returns the storage slot name used by the counter contract's storage map. +pub(super) fn counter_storage_slot_name() -> StorageSlotName { + StorageSlotName::new("miden_counter_contract::counter_contract::count_map") .expect("counter storage slot name should be valid") } fn auth_public_key_slot_name() -> StorageSlotName { - StorageSlotName::new("miden::component::miden_auth_component_rpo_falcon512::owner_public_key") + StorageSlotName::new("miden_auth_component_rpo_falcon512::auth_component::owner_public_key") .expect("auth component storage slot name should be valid") } diff --git a/tests/integration/src/rust_masm_tests/examples.rs b/tests/integration/src/rust_masm_tests/examples.rs index da4d48327..cc8359925 100644 --- a/tests/integration/src/rust_masm_tests/examples.rs +++ b/tests/integration/src/rust_masm_tests/examples.rs @@ -44,17 +44,17 @@ fn storage_example() { supported-types = ["RegularAccountUpdatableCode"] [[storage.slots]] - name = "miden::component::miden_storage_example::asset_qty_map" + name = "miden_storage_example::my_account::owner_public_key" + description = "owner public key" + type = "word" + + [[storage.slots]] + name = "miden_storage_example::my_account::asset_qty_map" description = "asset quantity map" [storage.slots.type] key = "word" value = "felt" - - [[storage.slots]] - name = "miden::component::miden_storage_example::owner_public_key" - description = "owner public key" - type = "word" "#]] .assert_eq(&toml); } @@ -237,7 +237,7 @@ fn counter_contract() { supported-types = ["RegularAccountUpdatableCode"] [[storage.slots]] - name = "miden::component::miden_counter_contract::count_map" + name = "miden_counter_contract::counter_contract::count_map" description = "counter contract storage map" [storage.slots.type]