From 9a5d19acbd73d46ed52b312334f1a0869d022ad6 Mon Sep 17 00:00:00 2001 From: Juan Munoz Date: Wed, 13 May 2026 15:38:57 -0300 Subject: [PATCH 1/4] chore: bump miden-protocol version --- Cargo.lock | 40 ++-- bin/network-monitor/src/counter.rs | 14 +- bin/stress-test/src/seeding/mod.rs | 31 ++- .../block-producer/src/test_utils/account.rs | 4 +- .../src/test_utils/proven_tx.rs | 8 +- crates/proto/src/domain/note.rs | 204 ++++++++++-------- crates/proto/src/domain/transaction.rs | 2 +- crates/rpc/src/tests.rs | 2 +- crates/store/src/db/mod.rs | 9 +- .../db/models/queries/accounts/delta/tests.rs | 2 +- .../src/db/models/queries/accounts/tests.rs | 8 +- crates/store/src/db/models/queries/notes.rs | 28 ++- crates/store/src/db/tests.rs | 100 ++++++--- crates/store/src/genesis/config/mod.rs | 56 +++-- .../agglayer_faucet_eth.mac | Bin 13601 -> 14803 bytes .../agglayer_faucet_usdc.mac | Bin 13601 -> 14803 bytes .../samples/02-with-account-files/bridge.mac | Bin 31454 -> 31421 bytes crates/store/src/genesis/config/tests.rs | 34 ++- crates/store/src/server/ntx_builder.rs | 4 +- crates/store/src/state/apply_block.rs | 17 +- proto/proto/types/note.proto | 71 +++--- 21 files changed, 353 insertions(+), 281 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e410be4c19..64c6977a46 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -177,7 +177,7 @@ version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -188,7 +188,7 @@ checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -1678,7 +1678,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -2895,7 +2895,7 @@ checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "miden-agglayer" version = "0.15.0" -source = "git+https://github.com/0xMiden/protocol?branch=next#ad7420e778af4a4b7be4f4bb24d0e7155b487e22" +source = "git+https://github.com/0xMiden/protocol?branch=next#9160eee3eea8b79bbff9ff1113c535743d6c693c" dependencies = [ "alloy-sol-types", "fs-err", @@ -2971,7 +2971,7 @@ dependencies = [ [[package]] name = "miden-block-prover" version = "0.15.0" -source = "git+https://github.com/0xMiden/protocol?branch=next#ad7420e778af4a4b7be4f4bb24d0e7155b487e22" +source = "git+https://github.com/0xMiden/protocol?branch=next#9160eee3eea8b79bbff9ff1113c535743d6c693c" dependencies = [ "miden-protocol", "thiserror 2.0.18", @@ -3561,7 +3561,7 @@ dependencies = [ [[package]] name = "miden-protocol" version = "0.15.0" -source = "git+https://github.com/0xMiden/protocol?branch=next#ad7420e778af4a4b7be4f4bb24d0e7155b487e22" +source = "git+https://github.com/0xMiden/protocol?branch=next#9160eee3eea8b79bbff9ff1113c535743d6c693c" dependencies = [ "bech32", "fs-err", @@ -3673,7 +3673,7 @@ dependencies = [ [[package]] name = "miden-standards" version = "0.15.0" -source = "git+https://github.com/0xMiden/protocol?branch=next#ad7420e778af4a4b7be4f4bb24d0e7155b487e22" +source = "git+https://github.com/0xMiden/protocol?branch=next#9160eee3eea8b79bbff9ff1113c535743d6c693c" dependencies = [ "bon", "fs-err", @@ -3690,7 +3690,7 @@ dependencies = [ [[package]] name = "miden-testing" version = "0.15.0" -source = "git+https://github.com/0xMiden/protocol?branch=next#ad7420e778af4a4b7be4f4bb24d0e7155b487e22" +source = "git+https://github.com/0xMiden/protocol?branch=next#9160eee3eea8b79bbff9ff1113c535743d6c693c" dependencies = [ "anyhow", "itertools 0.14.0", @@ -3710,7 +3710,7 @@ dependencies = [ [[package]] name = "miden-tx" version = "0.15.0" -source = "git+https://github.com/0xMiden/protocol?branch=next#ad7420e778af4a4b7be4f4bb24d0e7155b487e22" +source = "git+https://github.com/0xMiden/protocol?branch=next#9160eee3eea8b79bbff9ff1113c535743d6c693c" dependencies = [ "miden-processor", "miden-protocol", @@ -3723,7 +3723,7 @@ dependencies = [ [[package]] name = "miden-tx-batch-prover" version = "0.15.0" -source = "git+https://github.com/0xMiden/protocol?branch=next#ad7420e778af4a4b7be4f4bb24d0e7155b487e22" +source = "git+https://github.com/0xMiden/protocol?branch=next#9160eee3eea8b79bbff9ff1113c535743d6c693c" dependencies = [ "miden-protocol", "miden-tx", @@ -3967,7 +3967,7 @@ version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -4844,7 +4844,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "343d3bd7056eda839b03204e68deff7d1b13aba7af2b2fd16890697274262ee7" dependencies = [ "heck", - "itertools 0.13.0", + "itertools 0.14.0", "log", "multimap", "petgraph 0.8.3", @@ -4865,7 +4865,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "27c6023962132f4b30eb4c172c91ce92d933da334c59c23cddee82358ddafb0b" dependencies = [ "anyhow", - "itertools 0.13.0", + "itertools 0.14.0", "proc-macro2", "quote", "syn 2.0.117", @@ -5394,7 +5394,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -5465,7 +5465,7 @@ dependencies = [ "security-framework", "security-framework-sys", "webpki-root-certs", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -5872,7 +5872,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -6087,7 +6087,7 @@ dependencies = [ "getrandom 0.4.2", "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -6096,7 +6096,7 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8c27177b12a6399ffc08b98f76f7c9a1f4fe9fc967c784c5a071fa8d93cf7e1" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -6115,7 +6115,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "230a1b821ccbd75b185820a1f1ff7b14d21da1e442e22c0863ea5f08771a8874" dependencies = [ "rustix", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -7119,7 +7119,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] diff --git a/bin/network-monitor/src/counter.rs b/bin/network-monitor/src/counter.rs index 3d8c56b0f1..327d2193d2 100644 --- a/bin/network-monitor/src/counter.rs +++ b/bin/network-monitor/src/counter.rs @@ -21,11 +21,12 @@ use miden_protocol::note::{ Note, NoteAssets, NoteAttachment, - NoteMetadata, + NoteAttachments, NoteRecipient, NoteScript, NoteStorage, NoteType, + PartialNoteMetadata, }; use miden_protocol::transaction::{InputNotes, PartialBlockchain, TransactionArgs}; use miden_protocol::utils::serde::{Deserializable, Serializable}; @@ -946,9 +947,9 @@ fn create_network_note( let target = NetworkAccountTarget::new(counter_account.id(), NoteExecutionHint::Always) .context("Failed to create NetworkAccountTarget for counter account")?; let attachment: NoteAttachment = target.into(); + let attachments = NoteAttachments::from(attachment); - let metadata = - NoteMetadata::new(wallet_account.id(), NoteType::Public).with_attachment(attachment); + let partial_metadata = PartialNoteMetadata::new(wallet_account.id(), NoteType::Public); let serial_num = Word::new([ Felt::new(rng.random()), @@ -959,7 +960,12 @@ fn create_network_note( let recipient = NoteRecipient::new(serial_num, script, NoteStorage::new(vec![])?); - let network_note = Note::new(NoteAssets::new(vec![])?, metadata, recipient.clone()); + let network_note = Note::with_attachments( + NoteAssets::new(vec![])?, + partial_metadata, + recipient.clone(), + attachments, + ); Ok((network_note, recipient)) } diff --git a/bin/stress-test/src/seeding/mod.rs b/bin/stress-test/src/seeding/mod.rs index 76015acf38..a79ecc57dc 100644 --- a/bin/stress-test/src/seeding/mod.rs +++ b/bin/stress-test/src/seeding/mod.rs @@ -28,7 +28,7 @@ use miden_protocol::account::{ StorageSlot, StorageSlotName, }; -use miden_protocol::asset::{Asset, FungibleAsset, TokenSymbol}; +use miden_protocol::asset::{Asset, AssetAmount, FungibleAsset, TokenSymbol}; use miden_protocol::batch::{BatchAccountUpdate, BatchId, ProvenBatch}; use miden_protocol::block::{ BlockHeader, @@ -58,8 +58,7 @@ use miden_protocol::utils::serde::Serializable; use miden_protocol::vm::ExecutionProof; use miden_protocol::{Felt, ONE, Word}; use miden_standards::account::auth::AuthSingleSig; -use miden_standards::account::faucets::{BasicFungibleFaucet, TokenMetadata}; -use miden_standards::account::metadata::{FungibleTokenMetadata, TokenName}; +use miden_standards::account::faucets::{FungibleFaucet, TokenName}; use miden_standards::account::policies::{ BurnPolicyConfig, MintPolicyConfig, @@ -455,7 +454,7 @@ fn create_note(faucet_ids: &[AccountId], target_id: AccountId, rng: &mut RandomC target_id, assets, miden_protocol::note::NoteType::Public, - miden_protocol::note::NoteAttachment::default(), + miden_protocol::note::NoteAttachments::empty(), rng, ) .expect("note creation failed") @@ -579,20 +578,18 @@ fn create_faucet_with_seed(index: u64) -> Account { let init_seed: Vec<_> = index.to_be_bytes().into_iter().chain([0u8; 24]).collect(); let token_symbol = TokenSymbol::new("TEST").unwrap(); - let token_metadata = FungibleTokenMetadata::builder( - TokenName::new("TEST").unwrap(), - token_symbol, - 2, - FungibleAsset::MAX_AMOUNT, - ) - .build() - .unwrap(); + let faucet = FungibleFaucet::builder() + .name(TokenName::new("TEST").unwrap()) + .symbol(token_symbol) + .decimals(2) + .max_supply(AssetAmount::new(FungibleAsset::MAX_AMOUNT).unwrap()) + .build() + .unwrap(); AccountBuilder::new(init_seed.try_into().unwrap()) .account_type(AccountType::FungibleFaucet) .storage_mode(AccountStorageMode::Private) - .with_component(token_metadata) - .with_component(BasicFungibleFaucet) + .with_component(faucet) .with_components(TokenPolicyManager::new( PolicyAuthority::AuthControlled, MintPolicyConfig::AllowAll, @@ -756,11 +753,11 @@ fn create_emit_note_tx( ) -> ProvenTransaction { let initial_account_hash = faucet.to_commitment(); - let metadata_slot_name = TokenMetadata::metadata_slot(); - let slot = faucet.storage().get_item(metadata_slot_name).unwrap(); + let token_config_slot = FungibleFaucet::token_config_slot(); + let slot = faucet.storage().get_item(token_config_slot).unwrap(); faucet .storage_mut() - .set_item(metadata_slot_name, [slot[0] + Felt::new(10), slot[1], slot[2], slot[3]].into()) + .set_item(token_config_slot, [slot[0] + Felt::new(10), slot[1], slot[2], slot[3]].into()) .unwrap(); faucet.increment_nonce(ONE).unwrap(); diff --git a/crates/block-producer/src/test_utils/account.rs b/crates/block-producer/src/test_utils/account.rs index 0d1e9100bf..09b2d5f675 100644 --- a/crates/block-producer/src/test_utils/account.rs +++ b/crates/block-producer/src/test_utils/account.rs @@ -35,14 +35,14 @@ impl MockPrivateAccount { init_seed, AccountType::RegularAccountUpdatableCode, AccountStorageMode::Private, - AccountIdVersion::Version0, + AccountIdVersion::Version1, Word::empty(), Word::empty(), ) .unwrap(); Self::new( - AccountId::new(account_seed, AccountIdVersion::Version0, Word::empty(), Word::empty()) + AccountId::new(account_seed, AccountIdVersion::Version1, Word::empty(), Word::empty()) .unwrap(), if new_account { Word::empty() diff --git a/crates/block-producer/src/test_utils/proven_tx.rs b/crates/block-producer/src/test_utils/proven_tx.rs index 6af29a0ac4..e434dd52c9 100644 --- a/crates/block-producer/src/test_utils/proven_tx.rs +++ b/crates/block-producer/src/test_utils/proven_tx.rs @@ -7,12 +7,12 @@ use miden_protocol::account::AccountId; use miden_protocol::account::delta::AccountUpdateDetails; use miden_protocol::asset::FungibleAsset; use miden_protocol::block::BlockNumber; -use miden_protocol::note::{Note, Nullifier}; +use miden_protocol::note::{Note, NoteAttachments, Nullifier}; use miden_protocol::transaction::{ InputNote, InputNoteCommitment, OutputNote, - PrivateNoteHeader, + PrivateOutputNote, ProvenTransaction, TxAccountUpdate, }; @@ -134,7 +134,9 @@ impl MockProvenTxBuilder { .map(|note_index| { let note = Note::mock_noop(Word::from([0, 0, 0, note_index])); - OutputNote::Private(PrivateNoteHeader::new(note.header().clone()).unwrap()) + OutputNote::Private( + PrivateOutputNote::new(*note.header(), NoteAttachments::empty()).unwrap(), + ) }) .collect(); diff --git a/crates/proto/src/domain/note.rs b/crates/proto/src/domain/note.rs index 3ec63c2add..5184bc1b0d 100644 --- a/crates/proto/src/domain/note.rs +++ b/crates/proto/src/domain/note.rs @@ -3,17 +3,18 @@ use std::sync::Arc; use miden_protocol::crypto::merkle::SparseMerklePath; use miden_protocol::note::{ Note, - NoteAttachment, - NoteAttachmentKind, + NoteAttachmentHeader, + NoteAttachmentScheme, + NoteAttachments, NoteDetails, NoteHeader, NoteId, NoteInclusionProof, NoteMetadata, - NoteMetadataHeader, NoteScript, NoteTag, NoteType, + PartialNoteMetadata, }; use miden_protocol::utils::serde::Serializable; use miden_protocol::{MastForest, MastNodeId, Word}; @@ -49,52 +50,31 @@ impl TryFrom for NoteType { } } -// NOTE ATTACHMENT KIND -// ================================================================================================ - -impl From for proto::note::NoteAttachmentKind { - fn from(kind: NoteAttachmentKind) -> Self { - match kind { - NoteAttachmentKind::None => proto::note::NoteAttachmentKind::None, - NoteAttachmentKind::Word => proto::note::NoteAttachmentKind::Word, - NoteAttachmentKind::Array => proto::note::NoteAttachmentKind::Array, - } - } -} - -impl TryFrom for NoteAttachmentKind { - type Error = ConversionError; - - fn try_from(kind: proto::note::NoteAttachmentKind) -> Result { - match kind { - proto::note::NoteAttachmentKind::None => Ok(NoteAttachmentKind::None), - proto::note::NoteAttachmentKind::Word => Ok(NoteAttachmentKind::Word), - proto::note::NoteAttachmentKind::Array => Ok(NoteAttachmentKind::Array), - proto::note::NoteAttachmentKind::Unspecified => { - Err(ConversionError::message("enum variant discriminant out of range")) - }, - } - } -} - -// NOTE METADATA HEADER +// NOTE METADATA // ================================================================================================ -impl From for proto::note::NoteMetadataHeader { - fn from(header: NoteMetadataHeader) -> Self { - Self { - sender: Some(header.sender().into()), - note_type: proto::note::NoteType::from(header.note_type()) as i32, - tag: header.tag().as_u32(), - attachment_kind: proto::note::NoteAttachmentKind::from(header.attachment_kind()) as i32, - attachment_scheme: header.attachment_scheme().as_u32(), +impl From for proto::note::NoteMetadata { + fn from(val: NoteMetadata) -> Self { + let sender = Some(val.sender().into()); + let note_type = proto::note::NoteType::from(val.note_type()) as i32; + let tag = val.tag().as_u32(); + let attachment_schemes = val + .attachment_headers() + .iter() + .map(|header| u32::from(header.scheme().map_or(0, |s| s.as_u16()))) + .collect(); + let attachments_commitment = Some(val.attachments_commitment().into()); + + proto::note::NoteMetadata { + sender, + note_type, + tag, + attachment_schemes, + attachments_commitment, } } } -// NOTE METADATA -// ================================================================================================ - impl TryFrom for NoteMetadata { type Error = ConversionError; @@ -106,43 +86,51 @@ impl TryFrom for NoteMetadata { .try_into() .context("note_type")?; let tag = NoteTag::new(value.tag); + let attachments_commitment: Word = decode!(decoder, value.attachments_commitment)?; - // Deserialize attachment if present - let attachment = if value.attachment.is_empty() { - NoteAttachment::default() - } else { - NoteAttachment::decode_bytes(&value.attachment, "NoteAttachment")? - }; + if value.attachment_schemes.len() > NoteAttachments::MAX_COUNT { + return Err(ConversionError::message("too many attachment schemes")); + } + let mut attachment_headers = [NoteAttachmentHeader::absent(); NoteAttachments::MAX_COUNT]; + for (slot, raw) in attachment_headers.iter_mut().zip(value.attachment_schemes) { + let raw = u16::try_from(raw) + .map_err(|_| ConversionError::message("attachment scheme out of u16 range"))?; + *slot = if raw == 0 { + NoteAttachmentHeader::absent() + } else { + NoteAttachmentHeader::new(NoteAttachmentScheme::new(raw)?) + }; + } - Ok(NoteMetadata::new(sender, note_type).with_tag(tag).with_attachment(attachment)) + let partial = PartialNoteMetadata::new(sender, note_type).with_tag(tag); + Ok(NoteMetadata::from_parts(partial, attachment_headers, attachments_commitment)) } } +// NOTE +// ================================================================================================ + impl From for proto::note::NetworkNote { fn from(note: Note) -> Self { - Self { - metadata: Some(proto::note::NoteMetadata::from(note.metadata().clone())), - details: NoteDetails::from(note).to_bytes(), - } + let metadata = Some(proto::note::NoteMetadata::from(*note.metadata())); + let attachments = note.attachments().to_bytes(); + let details = NoteDetails::from(note).to_bytes(); + Self { metadata, details, attachments } } } impl From for proto::note::Note { fn from(note: Note) -> Self { - Self { - metadata: Some(proto::note::NoteMetadata::from(note.metadata().clone())), - details: Some(NoteDetails::from(note).to_bytes()), - } + let metadata = Some(proto::note::NoteMetadata::from(*note.metadata())); + let attachments = note.attachments().to_bytes(); + let details = Some(NoteDetails::from(note).to_bytes()); + Self { metadata, details, attachments } } } impl From for proto::note::NetworkNote { fn from(note: AccountTargetNetworkNote) -> Self { - let note = note.into_note(); - Self { - metadata: Some(proto::note::NoteMetadata::from(note.metadata().clone())), - details: NoteDetails::from(note).to_bytes(), - } + note.into_note().into() } } @@ -150,26 +138,44 @@ impl TryFrom for AccountTargetNetworkNote { type Error = ConversionError; fn try_from(value: proto::note::NetworkNote) -> Result { - let decoder = value.decoder(); - let details = NoteDetails::decode_bytes(&value.details, "NoteDetails")?; - let (assets, recipient) = details.into_parts(); - let metadata: NoteMetadata = decode!(decoder, value.metadata)?; - let note = Note::new(assets, metadata, recipient); + let proto::note::NetworkNote { metadata, details, attachments } = value; + + let metadata = metadata + .ok_or(ConversionError::missing_field::("metadata"))?; + let partial_metadata = partial_note_metadata_from_proto(metadata)?; + + let note_details = NoteDetails::decode_bytes(&details, "NoteDetails")?; + let (assets, recipient) = note_details.into_parts(); + let attachments = decode_attachments(&attachments)?; + + let note = Note::with_attachments(assets, partial_metadata, recipient, attachments); AccountTargetNetworkNote::new(note).map_err(ConversionError::from) } } -impl From for proto::note::NoteMetadata { - fn from(val: NoteMetadata) -> Self { - let sender = Some(val.sender().into()); - let note_type = proto::note::NoteType::from(val.note_type()) as i32; - let tag = val.tag().as_u32(); - let attachment = val.attachment().to_bytes(); +impl TryFrom for Note { + type Error = ConversionError; - proto::note::NoteMetadata { sender, note_type, tag, attachment } + fn try_from(proto_note: proto::note::Note) -> Result { + let proto::note::Note { metadata, details, attachments } = proto_note; + + let metadata = + metadata.ok_or(ConversionError::missing_field::("metadata"))?; + let partial_metadata = partial_note_metadata_from_proto(metadata)?; + + let details = + details.ok_or(ConversionError::missing_field::("details"))?; + let note_details = NoteDetails::decode_bytes(&details, "NoteDetails")?; + let (assets, recipient) = note_details.into_parts(); + let attachments = decode_attachments(&attachments)?; + + Ok(Note::with_attachments(assets, partial_metadata, recipient, attachments)) } } +// NOTE ID +// ================================================================================================ + impl From for proto::note::NoteId { fn from(digest: Word) -> Self { Self { id: Some(digest.into()) } @@ -246,24 +252,6 @@ impl TryFrom<&proto::note::NoteInclusionInBlockProof> for (NoteId, NoteInclusion } } -impl TryFrom for Note { - type Error = ConversionError; - - fn try_from(proto_note: proto::note::Note) -> Result { - let decoder = proto_note.decoder(); - let metadata: NoteMetadata = decode!(decoder, proto_note.metadata)?; - - let details = proto_note - .details - .ok_or(ConversionError::missing_field::("details"))?; - - let note_details = NoteDetails::decode_bytes(&details, "NoteDetails")?; - - let (assets, recipient) = note_details.into_parts(); - Ok(Note::new(assets, metadata, recipient)) - } -} - // NOTE HEADER // ================================================================================================ @@ -313,3 +301,33 @@ impl TryFrom for NoteScript { Ok(Self::from_parts(Arc::new(mast), entrypoint)) } } + +// HELPERS +// ================================================================================================ + +/// Decodes the `(sender, note_type, tag)` triple from a proto `NoteMetadata` into a +/// [`PartialNoteMetadata`]. The attachment-related fields on the proto are ignored — when full +/// attachments are also transmitted, the receiver derives the canonical headers and commitment +/// from those instead. +fn partial_note_metadata_from_proto( + value: proto::note::NoteMetadata, +) -> Result { + let decoder = value.decoder(); + let sender = decode!(decoder, value.sender)?; + let note_type = proto::note::NoteType::try_from(value.note_type) + .map_err(|_| ConversionError::message("enum variant discriminant out of range"))? + .try_into() + .context("note_type")?; + let tag = NoteTag::new(value.tag); + Ok(PartialNoteMetadata::new(sender, note_type).with_tag(tag)) +} + +/// Decodes a serialized [`NoteAttachments`] payload. Empty bytes are treated as an empty +/// collection so that proto3's default value round-trips cleanly. +fn decode_attachments(bytes: &[u8]) -> Result { + if bytes.is_empty() { + Ok(NoteAttachments::empty()) + } else { + NoteAttachments::decode_bytes(bytes, "NoteAttachments") + } +} diff --git a/crates/proto/src/domain/transaction.rs b/crates/proto/src/domain/transaction.rs index bc388c7b73..13fcb98a9c 100644 --- a/crates/proto/src/domain/transaction.rs +++ b/crates/proto/src/domain/transaction.rs @@ -61,7 +61,7 @@ impl From for proto::transaction::InputNoteCommitment { fn from(value: InputNoteCommitment) -> Self { Self { nullifier: Some(value.nullifier().into()), - header: value.header().cloned().map(Into::into), + header: value.header().copied().map(Into::into), } } } diff --git a/crates/rpc/src/tests.rs b/crates/rpc/src/tests.rs index ba7e40814e..f46f9c2579 100644 --- a/crates/rpc/src/tests.rs +++ b/crates/rpc/src/tests.rs @@ -76,7 +76,7 @@ fn build_test_proven_tx( ) -> ProvenTransaction { let account_id = AccountId::dummy( [0; 15], - AccountIdVersion::Version0, + AccountIdVersion::Version1, AccountType::RegularAccountImmutableCode, AccountStorageMode::Public, ); diff --git a/crates/store/src/db/mod.rs b/crates/store/src/db/mod.rs index 7653e2537c..ef18b6cbb5 100644 --- a/crates/store/src/db/mod.rs +++ b/crates/store/src/db/mod.rs @@ -15,6 +15,7 @@ use miden_protocol::asset::{Asset, AssetVaultKey}; use miden_protocol::block::{BlockHeader, BlockNoteIndex, BlockNumber, SignedBlock}; use miden_protocol::crypto::merkle::SparseMerklePath; use miden_protocol::note::{ + NoteAttachments, NoteDetails, NoteId, NoteInclusionProof, @@ -170,7 +171,7 @@ impl TransactionRecord { initial_state_commitment: Some(self.header.initial_state_commitment().into()), final_state_commitment: Some(self.header.final_state_commitment().into()), input_notes: self.header.input_notes().iter().cloned().map(Into::into).collect(), - output_notes: self.header.output_notes().iter().cloned().map(Into::into).collect(), + output_notes: self.header.output_notes().iter().copied().map(Into::into).collect(), fee: Some(Asset::from(self.header.fee()).into()), }), block_num: self.block_num.as_u32(), @@ -187,6 +188,7 @@ pub struct NoteRecord { pub note_commitment: Word, pub metadata: NoteMetadata, pub details: Option, + pub attachments: NoteAttachments, pub inclusion_path: SparseMerklePath, } @@ -201,6 +203,7 @@ impl From for proto::note::CommittedNote { let note = Some(proto::note::Note { metadata: Some(note.metadata.into()), details: note.details.map(|details| details.to_bytes()), + attachments: note.attachments.to_bytes(), }); Self { inclusion_proof, note } } @@ -223,14 +226,14 @@ pub struct NoteSyncRecord { impl From for proto::note::NoteSyncRecord { fn from(note: NoteSyncRecord) -> Self { - let metadata_header = Some(note.metadata.to_header().into()); + let metadata = Some(note.metadata.into()); let inclusion_proof = Some(proto::note::NoteInclusionInBlockProof { note_id: Some(note.note_id.into()), block_num: note.block_num.as_u32(), note_index_in_block: note.note_index.leaf_index_value().into(), inclusion_path: Some(note.inclusion_path.into()), }); - Self { metadata_header, inclusion_proof } + Self { metadata, inclusion_proof } } } diff --git a/crates/store/src/db/models/queries/accounts/delta/tests.rs b/crates/store/src/db/models/queries/accounts/delta/tests.rs index 3e82a5d9a7..3cacb46b0d 100644 --- a/crates/store/src/db/models/queries/accounts/delta/tests.rs +++ b/crates/store/src/db/models/queries/accounts/delta/tests.rs @@ -606,7 +606,7 @@ fn upsert_private_account() { // Create a private account ID let account_id = AccountId::dummy( ACCOUNT_ID_SEED, - AccountIdVersion::Version0, + AccountIdVersion::Version1, AccountType::RegularAccountImmutableCode, AccountStorageMode::Private, ); diff --git a/crates/store/src/db/models/queries/accounts/tests.rs b/crates/store/src/db/models/queries/accounts/tests.rs index 87a1fc5deb..e5c8d4dbb7 100644 --- a/crates/store/src/db/models/queries/accounts/tests.rs +++ b/crates/store/src/db/models/queries/accounts/tests.rs @@ -139,7 +139,7 @@ fn create_test_account_with_storage() -> (Account, AccountId) { // Create a simple public account with one value storage slot let account_id = AccountId::dummy( [1u8; 15], - AccountIdVersion::Version0, + AccountIdVersion::Version1, AccountType::RegularAccountImmutableCode, AccountStorageMode::Public, ); @@ -323,7 +323,7 @@ fn test_select_account_header_at_block_returns_none_for_nonexistent() { let account_id = AccountId::dummy( [99u8; 15], - AccountIdVersion::Version0, + AccountIdVersion::Version1, AccountType::RegularAccountImmutableCode, AccountStorageMode::Public, ); @@ -609,7 +609,7 @@ fn test_upsert_accounts_with_multiple_storage_slots() { // Create account with 3 storage slots let account_id = AccountId::dummy( [2u8; 15], - AccountIdVersion::Version0, + AccountIdVersion::Version1, AccountType::RegularAccountImmutableCode, AccountStorageMode::Public, ); @@ -688,7 +688,7 @@ fn test_upsert_accounts_with_empty_storage() { // Create account with no component storage slots (only auth slot) let account_id = AccountId::dummy( [3u8; 15], - AccountIdVersion::Version0, + AccountIdVersion::Version1, AccountType::RegularAccountImmutableCode, AccountStorageMode::Public, ); diff --git a/crates/store/src/db/models/queries/notes.rs b/crates/store/src/db/models/queries/notes.rs index 5b1eba78a5..4fccfdd463 100644 --- a/crates/store/src/db/models/queries/notes.rs +++ b/crates/store/src/db/models/queries/notes.rs @@ -36,7 +36,7 @@ use miden_protocol::block::{BlockNoteIndex, BlockNumber}; use miden_protocol::crypto::merkle::SparseMerklePath; use miden_protocol::note::{ NoteAssets, - NoteAttachment, + NoteAttachments, NoteDetails, NoteId, NoteInclusionProof, @@ -47,6 +47,7 @@ use miden_protocol::note::{ NoteTag, NoteType, Nullifier, + PartialNoteMetadata, }; use miden_protocol::utils::serde::{Deserializable, Serializable}; use miden_standards::note::NetworkAccountTarget; @@ -611,7 +612,7 @@ impl TryInto for NoteSyncRecordRawRow { let note_id = Word::read_from_bytes(&self.note_id[..])?; let inclusion_path = SparseMerklePath::read_from_bytes(&self.inclusion_path[..])?; - let metadata = self.metadata.try_into()?; + let (metadata, _attachments) = self.metadata.try_into()?; Ok(NoteSyncRecord { block_num, note_index, @@ -729,7 +730,7 @@ impl TryInto for NoteRecordWithScriptRawJoined { let metadata = NoteMetadataRawRow { note_type, sender, tag, attachment }; let details = NoteDetailsRawRow { assets, storage, serial_num }; - let metadata = metadata.try_into()?; + let (metadata, attachments) = metadata.try_into()?; let committed_at = BlockNumber::from_raw_sql(committed_at)?; let note_id = Word::read_from_bytes(¬e_id[..])?; let note_commitment = Word::read_from_bytes(¬e_commitment[..])?; @@ -765,6 +766,7 @@ impl TryInto for NoteRecordWithScriptRawJoined { note_commitment, metadata, details, + attachments, inclusion_path, }) } @@ -804,15 +806,21 @@ pub struct NoteMetadataRawRow { } #[expect(clippy::cast_sign_loss, clippy::cast_possible_truncation)] -impl TryInto for NoteMetadataRawRow { +impl TryInto<(NoteMetadata, NoteAttachments)> for NoteMetadataRawRow { type Error = DatabaseError; - fn try_into(self) -> Result { + fn try_into(self) -> Result<(NoteMetadata, NoteAttachments), Self::Error> { let sender = AccountId::read_from_bytes(&self.sender[..])?; let note_type = NoteType::try_from(self.note_type as u8) .map_err(miden_node_db::DatabaseError::conversiont_from_sql::)?; let tag = NoteTag::new(self.tag as u32); - let attachment = NoteAttachment::read_from_bytes(&self.attachment)?; - Ok(NoteMetadata::new(sender, note_type).with_tag(tag).with_attachment(attachment)) + let attachments = if self.attachment.is_empty() { + NoteAttachments::empty() + } else { + NoteAttachments::read_from_bytes(&self.attachment)? + }; + let partial = PartialNoteMetadata::new(sender, note_type).with_tag(tag); + let metadata = NoteMetadata::new(partial, &attachments); + Ok((metadata, attachments)) } } @@ -932,16 +940,14 @@ pub struct NoteInsertRow { impl From<(NoteRecord, Option)> for NoteInsertRow { fn from((note, nullifier): (NoteRecord, Option)) -> Self { - let attachment = note.metadata.attachment(); - - let target_account_id = NetworkAccountTarget::try_from(attachment).ok(); + let target_account_id = NetworkAccountTarget::try_from(¬e.attachments).ok(); let network_note_type = if target_account_id.is_some() && !note.metadata.is_private() { NetworkNoteType::SingleTarget } else { NetworkNoteType::None }; - let attachment_bytes = attachment.to_bytes(); + let attachment_bytes = note.attachments.to_bytes(); Self { committed_at: note.block_num.to_raw_sql(), diff --git a/crates/store/src/db/tests.rs b/crates/store/src/db/tests.rs index 7cf6720182..5142068556 100644 --- a/crates/store/src/db/tests.rs +++ b/crates/store/src/db/tests.rs @@ -45,6 +45,7 @@ use miden_protocol::crypto::rand::RandomCoin; use miden_protocol::note::{ Note, NoteAttachment, + NoteAttachments, NoteDetails, NoteHeader, NoteId, @@ -52,6 +53,7 @@ use miden_protocol::note::{ NoteTag, NoteType, Nullifier, + PartialNoteMetadata, }; use miden_protocol::testing::account_id::{ ACCOUNT_ID_PRIVATE_SENDER, @@ -233,7 +235,7 @@ pub fn create_note(account_id: AccountId) -> Note { FungibleAsset::new(ACCOUNT_ID_PUBLIC_FUNGIBLE_FAUCET.try_into().unwrap(), 10).unwrap(), )], NoteType::Public, - NoteAttachment::default(), + NoteAttachments::empty(), &mut *rng, ) .expect("Failed to create note") @@ -265,8 +267,9 @@ fn sql_select_notes() { note_index: BlockNoteIndex::new(0, i.try_into().unwrap()).unwrap(), note_id: num_to_word(u64::try_from(i).unwrap()), note_commitment: num_to_word(u64::try_from(i).unwrap()), - metadata: new_note.metadata().clone(), + metadata: *new_note.metadata(), details: Some(NoteDetails::from(&new_note)), + attachments: new_note.attachments().clone(), inclusion_path: SparseMerklePath::default(), }; state.push(note.clone()); @@ -309,8 +312,9 @@ fn sql_select_note_script_by_root() { note_index: BlockNoteIndex::new(0, 0.try_into().unwrap()).unwrap(), note_id: num_to_word(0), note_commitment: num_to_word(0), - metadata: new_note.metadata().clone(), + metadata: *new_note.metadata(), details: Some(NoteDetails::from(&new_note)), + attachments: new_note.attachments().clone(), inclusion_path: SparseMerklePath::default(), }; state.push(note.clone()); @@ -380,14 +384,19 @@ fn sql_unconsumed_network_notes() { // Create an unconsumed note in each block. let notes = Vec::from_iter((0..2).map(|i: u32| { + let attachments = NoteAttachments::from(attachment.clone()); + let metadata = NoteMetadata::new( + PartialNoteMetadata::new(account_note.0, NoteType::Public), + &attachments, + ); let note = NoteRecord { block_num: 0.into(), // Created on same block. note_index: BlockNoteIndex::new(0, i as usize).unwrap(), note_id: num_to_word(i.into()), note_commitment: num_to_word(i.into()), - metadata: NoteMetadata::new(account_note.0, NoteType::Public) - .with_attachment(attachment.clone()), + metadata, details: None, + attachments, inclusion_path: SparseMerklePath::default(), }; (note, Some(num_to_nullifier(i.into()))) @@ -457,7 +466,7 @@ fn sql_select_accounts() { for i in 0..10u8 { let account_id = AccountId::dummy( [i; 15], - AccountIdVersion::Version0, + AccountIdVersion::Version1, AccountType::RegularAccountImmutableCode, AccountStorageMode::Private, ); @@ -854,9 +863,13 @@ fn notes() { let new_note = create_note(sender); let note_index = BlockNoteIndex::new(0, 2).unwrap(); let tag = 5u32; - let note_metadata = NoteMetadata::new(sender, NoteType::Public).with_tag(tag.into()); + let note_metadata = NoteMetadata::new( + PartialNoteMetadata::new(sender, NoteType::Public).with_tag(tag.into()), + &NoteAttachments::default(), + ); - let values = [(note_index, new_note.id(), ¬e_metadata)]; + let note_header = NoteHeader::new(new_note.id(), note_metadata); + let values = [(note_index, ¬e_header)]; let notes_db = BlockNoteTree::with_entries(values).unwrap(); let inclusion_path = notes_db.open(note_index); @@ -865,8 +878,9 @@ fn notes() { note_index, note_id: new_note.id().as_word(), note_commitment: new_note.commitment(), - metadata: NoteMetadata::new(sender, NoteType::Public).with_tag(tag.into()), + metadata: note_metadata, details: Some(NoteDetails::from(&new_note)), + attachments: NoteAttachments::default(), inclusion_path: inclusion_path.clone(), }; @@ -895,8 +909,9 @@ fn notes() { note_index: note.note_index, note_id: new_note.id().as_word(), note_commitment: new_note.commitment(), - metadata: note.metadata.clone(), + metadata: note.metadata, details: None, + attachments: NoteAttachments::default(), inclusion_path: inclusion_path.clone(), }; @@ -955,8 +970,12 @@ fn note_sync_across_multiple_blocks() { .unwrap(); let new_note = create_note(sender); - let note_metadata = NoteMetadata::new(sender, NoteType::Public).with_tag(tag.into()); - let values = [(note_index, new_note.id(), ¬e_metadata)]; + let note_metadata = NoteMetadata::new( + PartialNoteMetadata::new(sender, NoteType::Public).with_tag(tag.into()), + &NoteAttachments::default(), + ); + let note_header = NoteHeader::new(new_note.id(), note_metadata); + let values = [(note_index, ¬e_header)]; let notes_db = BlockNoteTree::with_entries(values).unwrap(); let inclusion_path = notes_db.open(note_index); @@ -967,6 +986,7 @@ fn note_sync_across_multiple_blocks() { note_commitment: new_note.commitment(), metadata: note_metadata, details: Some(NoteDetails::from(&new_note)), + attachments: NoteAttachments::default(), inclusion_path, }; queries::insert_scripts(conn, [¬e]).unwrap(); @@ -1032,8 +1052,12 @@ fn note_sync_multi_respects_payload_limit() { .unwrap(); let new_note = create_note(sender); - let note_metadata = NoteMetadata::new(sender, NoteType::Public).with_tag(tag.into()); - let values = [(note_index, new_note.id(), ¬e_metadata)]; + let note_metadata = NoteMetadata::new( + PartialNoteMetadata::new(sender, NoteType::Public).with_tag(tag.into()), + &NoteAttachments::default(), + ); + let note_header = NoteHeader::new(new_note.id(), note_metadata); + let values = [(note_index, ¬e_header)]; let notes_db = BlockNoteTree::with_entries(values).unwrap(); let inclusion_path = notes_db.open(note_index); @@ -1044,6 +1068,7 @@ fn note_sync_multi_respects_payload_limit() { note_commitment: new_note.commitment(), metadata: note_metadata, details: Some(NoteDetails::from(&new_note)), + attachments: NoteAttachments::default(), inclusion_path, }; queries::insert_scripts(conn, [¬e]).unwrap(); @@ -1085,8 +1110,12 @@ fn note_sync_no_matching_tags() { // Insert a note with tag 10. let new_note = create_note(sender); let note_index = BlockNoteIndex::new(0, 0).unwrap(); - let note_metadata = NoteMetadata::new(sender, NoteType::Public).with_tag(10u32.into()); - let values = [(note_index, new_note.id(), ¬e_metadata)]; + let note_metadata = NoteMetadata::new( + PartialNoteMetadata::new(sender, NoteType::Public).with_tag(10u32.into()), + &NoteAttachments::default(), + ); + let note_header = NoteHeader::new(new_note.id(), note_metadata); + let values = [(note_index, ¬e_header)]; let notes_db = BlockNoteTree::with_entries(values).unwrap(); let inclusion_path = notes_db.open(note_index); @@ -1097,6 +1126,7 @@ fn note_sync_no_matching_tags() { note_commitment: new_note.commitment(), metadata: note_metadata, details: Some(NoteDetails::from(&new_note)), + attachments: NoteAttachments::default(), inclusion_path, }; queries::insert_scripts(conn, [¬e]).unwrap(); @@ -1753,7 +1783,11 @@ fn mock_block_transaction(account_id: AccountId, num: u64) -> TransactionHeader Word::try_from([num, num, 0, 0]).unwrap(), Word::try_from([0, 0, num, num]).unwrap(), ), - NoteMetadata::new(account_id, NoteType::Public).with_tag(NoteTag::new(num as u32)), + NoteMetadata::new( + PartialNoteMetadata::new(account_id, NoteType::Public) + .with_tag(NoteTag::new(num as u32)), + &NoteAttachments::default(), + ), )]; let fee = test_fee(); @@ -2377,7 +2411,10 @@ fn serialization_symmetry_note_metadata() { // Use a tag that roundtrips properly - NoteTag::LocalAny stores the full u32 including type // bits let tag = NoteTag::with_account_target(sender); - let metadata = NoteMetadata::new(sender, NoteType::Public).with_tag(tag); + let metadata = NoteMetadata::new( + PartialNoteMetadata::new(sender, NoteType::Public).with_tag(tag), + &NoteAttachments::default(), + ); let bytes = metadata.to_bytes(); let restored = NoteMetadata::read_from_bytes(&bytes).unwrap(); @@ -2522,8 +2559,9 @@ fn db_roundtrip_notes() { note_index, note_id: new_note.id().as_word(), note_commitment: new_note.commitment(), - metadata: new_note.metadata().clone(), + metadata: *new_note.metadata(), details: Some(NoteDetails::from(&new_note)), + attachments: new_note.attachments().clone(), inclusion_path: SparseMerklePath::default(), }; @@ -2771,16 +2809,18 @@ fn db_roundtrip_note_metadata_attachment() { let attachment: NoteAttachment = target.into(); // Create NoteMetadata with the attachment + let attachments = NoteAttachments::from(attachment.clone()); let metadata = - NoteMetadata::new(account_id, NoteType::Public).with_attachment(attachment.clone()); + NoteMetadata::new(PartialNoteMetadata::new(account_id, NoteType::Public), &attachments); let note = NoteRecord { block_num, note_index: BlockNoteIndex::new(0, 0).unwrap(), note_id: num_to_word(1), note_commitment: num_to_word(1), - metadata: metadata.clone(), + metadata, details: None, + attachments: attachments.clone(), inclusion_path: SparseMerklePath::default(), }; @@ -2793,15 +2833,14 @@ fn db_roundtrip_note_metadata_attachment() { assert_eq!(retrieved.len(), 1, "Should retrieve exactly one note"); - let retrieved_metadata = &retrieved[0].metadata; + let retrieved_attachments = &retrieved[0].attachments; assert_eq!( - retrieved_metadata.attachment(), - metadata.attachment(), - "Attachment should be preserved after DB roundtrip" + retrieved_attachments, &attachments, + "Attachments should be preserved after DB roundtrip" ); - let retrieved_target = NetworkAccountTarget::try_from(retrieved_metadata.attachment()) - .expect("Should be able to parse NetworkAccountTarget from retrieved attachment"); + let retrieved_target = NetworkAccountTarget::try_from(retrieved_attachments) + .expect("Should be able to parse NetworkAccountTarget from retrieved attachments"); assert_eq!( retrieved_target.target_id(), account_id, @@ -3616,8 +3655,9 @@ fn db_roundtrip_transactions() { note_index: BlockNoteIndex::new(0, idx).unwrap(), note_id: note.id().as_word(), note_commitment: note.to_commitment(), - metadata: note.metadata().clone(), + metadata: *note.metadata(), details: None, + attachments: NoteAttachments::default(), inclusion_path: SparseMerklePath::default(), }, None, @@ -3640,7 +3680,7 @@ fn db_roundtrip_transactions() { block_num, note_index: BlockNoteIndex::new(0, idx).unwrap(), note_id: note.id().as_word(), - metadata: note.metadata().clone(), + metadata: *note.metadata(), inclusion_path: SparseMerklePath::default(), }) .collect(); @@ -3665,7 +3705,7 @@ fn db_roundtrip_transactions() { initial_state_commitment: Some(tx.initial_state_commitment().into()), final_state_commitment: Some(tx.final_state_commitment().into()), input_notes: tx.input_notes().iter().cloned().map(Into::into).collect(), - output_notes: tx.output_notes().iter().cloned().map(Into::into).collect(), + output_notes: tx.output_notes().iter().copied().map(Into::into).collect(), fee: Some(Asset::from(tx.fee()).into()), }), output_note_proofs: expected_sync_records diff --git a/crates/store/src/genesis/config/mod.rs b/crates/store/src/genesis/config/mod.rs index 5b14c651d5..391c059e24 100644 --- a/crates/store/src/genesis/config/mod.rs +++ b/crates/store/src/genesis/config/mod.rs @@ -20,16 +20,15 @@ use miden_protocol::account::{ FungibleAssetDelta, NonFungibleAssetDelta, }; -use miden_protocol::asset::{FungibleAsset, TokenSymbol}; +use miden_protocol::asset::{AssetAmount, FungibleAsset, TokenSymbol}; use miden_protocol::block::FeeParameters; use miden_protocol::crypto::dsa::ecdsa_k256_keccak::PublicKey; use miden_protocol::crypto::dsa::falcon512_poseidon2::SecretKey as RpoSecretKey; use miden_protocol::errors::TokenSymbolError; -use miden_protocol::{Felt, ONE}; +use miden_protocol::{Felt, ONE, Word}; use miden_standards::AuthMethod; use miden_standards::account::auth::AuthSingleSig; -use miden_standards::account::faucets::{BasicFungibleFaucet, TokenMetadata}; -use miden_standards::account::metadata::{FungibleTokenMetadata, TokenName}; +use miden_standards::account::faucets::{FungibleFaucet, TokenName}; use miden_standards::account::policies::{ BurnPolicyConfig, MintPolicyConfig, @@ -288,11 +287,24 @@ impl GenesisConfig { let mut storage_delta = AccountStorageDelta::default(); if total_issuance != 0 { - let current_metadata = TokenMetadata::try_from(faucet_account.storage())?; - let updated_metadata = - current_metadata.with_token_supply(Felt::new(total_issuance))?; + let current_faucet = FungibleFaucet::try_from(faucet_account.storage())?; + let new_token_supply = AssetAmount::new(total_issuance)?; + let max_supply = current_faucet.max_supply().as_canonical_u64(); + if max_supply < total_issuance { + return Err(GenesisConfigError::MaxIssuanceExceeded { + max_supply, + symbol: symbol.clone(), + total_issuance, + }); + } + let new_token_config = Word::new([ + Felt::from(new_token_supply), + current_faucet.max_supply(), + Felt::from(current_faucet.decimals()), + Felt::from(current_faucet.symbol()), + ]); storage_delta - .set_item(TokenMetadata::metadata_slot().clone(), updated_metadata.into())?; + .set_item(FungibleFaucet::token_config_slot().clone(), new_token_config)?; tracing::debug!( "Reducing faucet account {faucet} for {symbol} by {amount}", faucet = faucet_id.to_hex(), @@ -317,8 +329,8 @@ impl GenesisConfig { debug_assert_eq!(faucet_account.nonce(), ONE); // sanity check the total issuance against - let metadata = TokenMetadata::try_from(faucet_account.storage())?; - let max_supply = metadata.max_supply().as_canonical_u64(); + let faucet = FungibleFaucet::try_from(faucet_account.storage())?; + let max_supply = faucet.max_supply().as_canonical_u64(); if max_supply < total_issuance { return Err(GenesisConfigError::MaxIssuanceExceeded { max_supply, @@ -400,9 +412,9 @@ impl NativeFaucetConfig { return Err(GenesisConfigError::NativeFaucetNotFungible { path: full_path }); } - let metadata = TokenMetadata::try_from(account.storage()) + let faucet = FungibleFaucet::try_from(account.storage()) .expect("validated as fungible faucet above"); - let symbol = TokenSymbolStr::from(metadata.symbol().clone()); + let symbol = TokenSymbolStr::from(faucet.symbol().clone()); Ok((account, symbol, None)) }, } @@ -442,22 +454,22 @@ impl FungibleFaucetConfig { AuthSingleSig::new(secret_key.public_key().into(), AuthScheme::Falcon512Poseidon2); let init_seed: [u8; 32] = rng.random(); - let token_metadata = FungibleTokenMetadata::builder( - TokenName::new(&symbol.to_string()) - .expect("token symbol fits within token name byte limit"), - symbol.as_ref().clone(), - decimals, - max_supply, - ) - .build()?; + let faucet = FungibleFaucet::builder() + .name( + TokenName::new(&symbol.to_string()) + .expect("token symbol fits within token name byte limit"), + ) + .symbol(symbol.as_ref().clone()) + .decimals(decimals) + .max_supply(AssetAmount::new(max_supply)?) + .build()?; // It's similar to `fn create_basic_fungible_faucet`, but we need to cover more cases. let faucet_account = AccountBuilder::new(init_seed) .account_type(AccountType::FungibleFaucet) .storage_mode(storage_mode.into()) .with_auth_component(auth) - .with_component(token_metadata) - .with_component(BasicFungibleFaucet) + .with_component(faucet) .with_components(TokenPolicyManager::new( PolicyAuthority::AuthControlled, MintPolicyConfig::AllowAll, 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 2753dd76d6d9d4f37277727d355bf68f9880fb0a..6ee9d158a342091e27aa0d4b4f6c92bd69080e7e 100644 GIT binary patch delta 4542 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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 607ba4c8cf1fe40ceb32b95b7a8b7685289f61b9..bb22ae3745580b000a0613dabe6f575007222c58 100644 GIT binary patch delta 3239 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 delta 3247 zcmai$c|26zAIIko3S-TZt*nnFd-m+~j3N74#?ly5LUu+fW5^mw*P58LP-JUV#+FBx z5GiYxg!qZzV5xR_xYU9_j}Gga~e0H_nQzK4v!Cm5Wkvj1{;O* zD3|YAfFm9uY~{(CzrI{uXA5!OxYjyHSvrfDCP zeX6UUSpvKGhW2I^+NB_{^BS|uS7@*dmh?E5XJY^|g2#l=lBBl+U*9bT=41OtV^)gR zdcINxr!8FlWI1t`IPF%;p4(a{0C7gj3^a$6-E_CUb;6qx;;*qn}ZkLW8kHB z2vdYu4gZhO-y;>};A#n8xKacKr!sJ>Awh>c1cHf~-V-5?mA#dkUvMOs4;zFMIo7b! zzJXnw$@N*;?<|BRBuOpzH7QlX1DeVVGO7Y_wFobR0(KWx<>Z0()5W>>^V0QL!0+Em zX~AY%swl*-r#wUucQci&b%B92(l&@<>S1X4q1Yly%KRMAfxX)~Y&vr^dtt7*0{_a5 z4~Q^ttQRcIJFh2s(%m_F#%-yuyl+JVC zZyobIMD6b6F0{iUV5D)iDM@?qDaOH}68i<++FWHnes*ZN9lwT5LYHxt;4OPSr zTFyVi@0q%UC>ZS>j^%T?rxKE&&Ux@6dsc|NuD#w0e8=!4rjd7VC*w9Q4OM!|E`OGD z=)_=CodJ)k$LEmP^9)HWCZY(05j!ZHfVKzuwwBD=X@v*LB^yS&{t=}ekwTVhtfHY> zPn?MER1>2ZUd-0M=0z4B<{v_JQ4hZ3OHKs_v~FM>RJ#X4jlBz^8wcuuni5c>?aRpD zHk-9~Ue;*Otg2QpGt$h_?7>Tx+m(+^o*_w7S)F8=Nqg!^H3mG#%(V)<^lF*A2XAn% zdYBFjE$`!Jb&(v3f4>Tp=xW+gO`0NlyGN!h=QF-8SiLj}ZNLW!$>aLX<*tiWi*v1k zHKGVOp(iG}6%8dO`l%g5n;C!y+xu|<23H~P& zQQt(&We%GrF!*z28N9G-=`7u4(bl4Nx#vP8slG#=D>1q0+j9G6^(-(@yzy&8Kc?e$ zGTr+-BKQibc7dEBkW;@iSB|mI*M203eZVw6opx|D(a}vRjF{Ae_ab9PQal9!gg~fp zx!G_8_-5mO?2z;gk%zS@;<2Aus8~F z#KcQ`=A6_aqWYNR-X%-4C8Epl1ZQ&Lwl}17#A`xVK5CKBnouw~BI? zNQl;`oW7_xnv>~DBcVXX`T#6dkECU_-C!}lMW!7^@!)uV%B0C_3*QqnPmxcadshDr zrs9;%`-BBXMsC0H4sI=F4?nhg13ljO)P=p`QhM^lyEgxYKn^gh9#ES|4l#^F5A7$8 zUNtJheYUTTEB&-SDEKL{H(x383APRi%X<-_EKn-FX~w)4n{NsBXW%L%iKPq zY|Q6zX>#&G9)xo=8>^a<1|H~K z9R>Sb@ytS1!l}IuLD7wB#nQr6+o6oQnkRyT>CMg8+fuKQ|A5Cy0xaY<$ai zCsI70aOJXiWwC^4jmPtyBHPWdCWw;urrFBh!n$Ww8P3iJua2G~HXa9IEmQi3G|DUbvFB2WhMfENR8AR4S2)B&+k8G;j$ z=9dB=%r489zhG$gb=)YEx;4M3lJpqDgonHu_EjWU*^)r*%t1|d>rZ{ z>&{z#(apLnRnxmVw5ryzr}i8p3ipS~024n#iKHSm&;iU*-1Tsgl4(qU0OsxY;p9-4 zBBhtF4o6ZdJoMXg>XYS3@nCJ^09YK!XYX_}<(M7!^F!>3%1vB8=Vp5kJ)Cr0`+Q#F zv?WUd@NgP%Sw5n)o2{{BPmgQD$CX;8w#Ue?l6}KJ;4=U6^I2Ul1PHy6VsO}vA7~4Y zbsh8r4~nEid(ffB4E=@ttp!)ltt>^BDyjm?3tSul)-Cy6oATchT^%KA?@(JbGq*_$ zL5pcQU&6TD`;YDYP9$J3=n>0VieCY>RzvG%_haV3+hMr4xh`|c#L}~JoM#GzFrw>4 zcwdodq6p&%Vy_eRB4U-AJ3BAZa(367gGz5|8S&d!>cCgST}bks>k8@DR8v2{^wjXA z$8uf$dogk1Ph{8Pl!bR%1E1Y}uO~bwnAV@!_+>E<_<#Gs$Dw=k3sZWv|Dx5Mt zJ%1r3m2gj?@Vj-%T{7TI09T7mY_(Z0b~WsNfG@D;M(xzZhX(g|_JF|$ zMb{Jk7|#6`A**w=JYb|Jo}_q>CZWHL7jk>aR1(|9-gMpnmp|~wLQU>ubKXj}G;k${ z*gst>#EyLL?fa*)7`B`~$)ppJegAhR|M0ZO4x96)x%h5oN7rc_`H-rXa_VE4ZtRe$ z-;J)irED-E1R#pGts|f0t%ayR8@;E87mA7wQPNUKJ2br0qA17m41tgXGNFSN6Xb$H z3p)j7i96!odPC{nn1A*f&ElRJ4{@`i(dD)}O1FZE^IM~e z!AeWy_G(#^FCRZeA)Gf|s;b*_LL;cIk?$bVpQu0W`hPkd{^10MatChzZP0%KZ$M{o diff --git a/crates/store/src/genesis/config/tests.rs b/crates/store/src/genesis/config/tests.rs index 3ad58f0032..743523186e 100644 --- a/crates/store/src/genesis/config/tests.rs +++ b/crates/store/src/genesis/config/tests.rs @@ -45,11 +45,11 @@ fn parsing_yields_expected_default_values() -> TestResult { assert_eq!(wallet2.nonce(), ONE); { - let metadata = TokenMetadata::try_from(native_faucet.storage()).unwrap(); + let faucet = FungibleFaucet::try_from(native_faucet.storage()).unwrap(); - assert_eq!(metadata.max_supply(), Felt::new(100_000_000_000_000_000)); - assert_eq!(metadata.decimals(), 6); - assert_eq!(*metadata.symbol(), TokenSymbol::new("MIDEN").unwrap()); + assert_eq!(faucet.max_supply(), Felt::new(100_000_000_000_000_000)); + assert_eq!(faucet.decimals(), 6); + assert_eq!(*faucet.symbol(), TokenSymbol::new("MIDEN").unwrap()); } // check account balance, and ensure ordering is retained @@ -61,8 +61,8 @@ fn parsing_yields_expected_default_values() -> TestResult { }); // check total issuance of the faucet - let metadata = TokenMetadata::try_from(native_faucet.storage()).unwrap(); - assert_eq!(metadata.token_supply(), Felt::new(999_777), "Issuance mismatch"); + let faucet = FungibleFaucet::try_from(native_faucet.storage()).unwrap(); + assert_eq!(faucet.token_supply(), Felt::new(999_777), "Issuance mismatch"); Ok(()) } @@ -147,8 +147,8 @@ path = "test_account.mac" fn parsing_native_faucet_from_file() -> TestResult { use miden_protocol::account::auth::AuthScheme; use miden_protocol::account::{AccountBuilder, AccountFile, AccountStorageMode, AccountType}; + use miden_protocol::asset::AssetAmount; use miden_standards::account::auth::AuthSingleSig; - use miden_standards::account::metadata::{FungibleTokenMetadata, TokenName}; use miden_standards::account::policies::{ BurnPolicyConfig, MintPolicyConfig, @@ -169,20 +169,18 @@ fn parsing_native_faucet_from_file() -> TestResult { ); let auth = AuthSingleSig::new(secret_key.public_key().into(), AuthScheme::Falcon512Poseidon2); - let token_metadata = FungibleTokenMetadata::builder( - TokenName::new("MIDEN").unwrap(), - TokenSymbol::new("MIDEN").unwrap(), - 6, - 1_000_000_000, - ) - .build()?; + let faucet = FungibleFaucet::builder() + .name(TokenName::new("MIDEN").unwrap()) + .symbol(TokenSymbol::new("MIDEN").unwrap()) + .decimals(6) + .max_supply(AssetAmount::new(1_000_000_000)?) + .build()?; let faucet_account = AccountBuilder::new(init_seed) .account_type(AccountType::FungibleFaucet) .storage_mode(AccountStorageMode::Public) .with_auth_component(auth) - .with_component(token_metadata) - .with_component(BasicFungibleFaucet) + .with_component(faucet) .with_components(TokenPolicyManager::new( PolicyAuthority::AuthControlled, MintPolicyConfig::AllowAll, @@ -350,8 +348,8 @@ async fn parsing_agglayer_sample_with_account_files() -> TestResult { // Verify native faucet symbol { - let metadata = TokenMetadata::try_from(native_faucet.storage()).unwrap(); - assert_eq!(*metadata.symbol(), TokenSymbol::new("MIDEN").unwrap()); + let faucet = FungibleFaucet::try_from(native_faucet.storage()).unwrap(); + assert_eq!(*faucet.symbol(), TokenSymbol::new("MIDEN").unwrap()); } // Bridge account is a regular account (not a faucet) diff --git a/crates/store/src/server/ntx_builder.rs b/crates/store/src/server/ntx_builder.rs index e0cc425c92..e947eae71b 100644 --- a/crates/store/src/server/ntx_builder.rs +++ b/crates/store/src/server/ntx_builder.rs @@ -116,7 +116,9 @@ impl ntx_builder_server::NtxBuilder for StoreApi { // SAFETY: Network notes are filtered in the database, so they should have details; // otherwise the state would be corrupted let (assets, recipient) = note.details.unwrap().into_parts(); - let note = Note::new(assets, note.metadata, recipient); + let partial_metadata = *note.metadata.partial_metadata(); + let note = + Note::with_attachments(assets, partial_metadata, recipient, note.attachments); network_notes.push(note.into()); } diff --git a/crates/store/src/state/apply_block.rs b/crates/store/src/state/apply_block.rs index c3cc48826a..8cfb396f7e 100644 --- a/crates/store/src/state/apply_block.rs +++ b/crates/store/src/state/apply_block.rs @@ -7,7 +7,7 @@ use miden_protocol::account::delta::AccountUpdateDetails; use miden_protocol::block::account_tree::AccountMutationSet; use miden_protocol::block::nullifier_tree::NullifierMutationSet; use miden_protocol::block::{BlockBody, BlockHeader, SignedBlock}; -use miden_protocol::note::{NoteDetails, Nullifier}; +use miden_protocol::note::{NoteAttachments, NoteDetails, Nullifier}; use miden_protocol::transaction::OutputNote; use miden_protocol::utils::serde::Serializable; use tokio::sync::oneshot; @@ -327,11 +327,13 @@ impl State { let notes = body .output_notes() .map(|(note_index, note)| { - let (details, nullifier) = match note { - OutputNote::Public(note) => { - (Some(NoteDetails::from(note.as_note())), Some(note.as_note().nullifier())) - }, - OutputNote::Private(_) => (None, None), + let (details, attachments, nullifier) = match note { + OutputNote::Public(public) => ( + Some(NoteDetails::from(public.as_note())), + public.as_note().attachments().clone(), + Some(public.as_note().nullifier()), + ), + OutputNote::Private(_) => (None, NoteAttachments::empty(), None), }; let inclusion_path = note_tree.open(note_index); @@ -341,8 +343,9 @@ impl State { note_index, note_id: note.id().as_word(), note_commitment: note.to_commitment(), - metadata: note.metadata().clone(), + metadata: *note.metadata(), details, + attachments, inclusion_path, }; diff --git a/proto/proto/types/note.proto b/proto/proto/types/note.proto index 8b365b1522..78c890ceaa 100644 --- a/proto/proto/types/note.proto +++ b/proto/proto/types/note.proto @@ -17,18 +17,6 @@ enum NoteType { NOTE_TYPE_PRIVATE = 2; } -// The kind of a note attachment. -enum NoteAttachmentKind { - // Unspecified attachment kind (default value, should not be used). - NOTE_ATTACHMENT_KIND_UNSPECIFIED = 0; - // No attachment. - NOTE_ATTACHMENT_KIND_NONE = 1; - // A single word attachment. - NOTE_ATTACHMENT_KIND_WORD = 2; - // An array attachment. - NOTE_ATTACHMENT_KIND_ARRAY = 3; -} - // Represents a note's ID. message NoteId { // A unique identifier of the note which is a 32-byte commitment to the underlying note data. @@ -41,30 +29,12 @@ message NoteIdList { repeated NoteId ids = 1; } -// Represents the header of a note's metadata. -// -// Contains the sender, note type, tag and attachment type information, but not the full -// attachment data. See `miden_protocol::note::NoteMetadataHeader` for more info. -message NoteMetadataHeader { - // The account which sent the note. - account.AccountId sender = 1; - - // The type of the note. - NoteType note_type = 2; - - // A value which can be used by the recipient to identify notes intended for them. - // - // See `miden_protocol::note::note_tag` for more info. - fixed32 tag = 3; - - // The kind of the note attachment. - NoteAttachmentKind attachment_kind = 4; - - // The scheme identifier of the note attachment. - fixed32 attachment_scheme = 5; -} - // Represents a note's metadata. +// +// Mirrors the protocol-level `miden_protocol::note::NoteMetadata`: it carries the partial metadata +// (sender, note type, tag), the per-slot attachment schemes, and the commitment over the note's +// attachments. The full attachment contents (when present) are carried separately on `Note` / +// `NetworkNote`. message NoteMetadata { // The account which sent the note. account.AccountId sender = 1; @@ -77,21 +47,33 @@ message NoteMetadata { // See `miden_protocol::note::note_tag` for more info. fixed32 tag = 3; - // Serialized note attachment + // The attachment scheme of each attachment slot. + // + // The protocol allows up to `NoteAttachments::MAX_COUNT` attachments per note. Each slot carries + // either a scheme value in `1..=65534` or `0` to indicate that the slot is absent. Trailing + // absent slots may be omitted, so a note with no attachments has an empty list. // - // See `miden_protocol::note::NoteAttachment` for more info. - bytes attachment = 4; + // See `miden_protocol::note::NoteAttachmentHeader` for more info. + repeated fixed32 attachment_schemes = 4; + + // Commitment over the note's attachments. + // + // See `miden_protocol::note::NoteAttachments::to_commitment` for more info. + primitives.Digest attachments_commitment = 5; } // Represents a note. // -// The note is composed of the note metadata and its serialized details. +// The note is composed of the note metadata, its serialized details, and serialized attachments. message Note { // The note's metadata. NoteMetadata metadata = 1; // Serialized note details (empty for private notes). optional bytes details = 2; + + // Serialized `miden_protocol::note::NoteAttachments`. Empty bytes encode an empty collection. + bytes attachments = 3; } // Represents a network note. @@ -104,6 +86,9 @@ message NetworkNote { // Serialized note details (i.e., assets and recipient). bytes details = 2; + + // Serialized `miden_protocol::note::NoteAttachments`. Empty bytes encode an empty collection. + bytes attachments = 3; } // Represents a committed note. @@ -140,12 +125,12 @@ message NoteInclusionInBlockProof { primitives.SparseMerklePath inclusion_path = 4; } -// Represents a note's metadata header together with proof of inclusion in a block. +// Represents a note's metadata together with proof of inclusion in a block. // -// To get the full `NoteMetadata` (including attachment), use `GetNotesById`. +// To get the full note (including attachment contents), use `GetNotesById`. message NoteSyncRecord { - // The fixed-size metadata header of the note. - NoteMetadataHeader metadata_header = 1; + // The metadata of the note. + NoteMetadata metadata = 1; // Proof of the note's inclusion in a block. NoteInclusionInBlockProof inclusion_proof = 2; From e844a0cca31f9d941aca3720b110dccc9fe9b7f4 Mon Sep 17 00:00:00 2001 From: Juan Munoz Date: Thu, 14 May 2026 14:41:18 -0300 Subject: [PATCH 2/4] chore: expose needed variable --- crates/store/src/account_state_forest/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/store/src/account_state_forest/mod.rs b/crates/store/src/account_state_forest/mod.rs index 26513dc9cd..fdf386d97e 100644 --- a/crates/store/src/account_state_forest/mod.rs +++ b/crates/store/src/account_state_forest/mod.rs @@ -87,7 +87,7 @@ pub enum AccountStorageMapResult { } /// Container for forest-related state that needs to be updated atomically. -pub(crate) struct AccountStateForest { +pub struct AccountStateForest { /// `LargeSmtForest` for efficient account storage reconstruction. /// Populated during block import with storage and vault SMTs. forest: LargeSmtForest, From 336dffff83730ddd0c89d5e8558f64a123f11daf Mon Sep 17 00:00:00 2001 From: Juan Munoz Date: Thu, 14 May 2026 15:53:06 -0300 Subject: [PATCH 3/4] docs: add changelog entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d577f88fd2..511a04e200 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ - [BREAKING] Renamed `--url` CLI flags and `*_URL` env vars to `--listen` / `*_LISTEN` across all components. - [BREAKING] Removed `miden-node validator` subcommand and created a separate `miden-validator` binary ([#2053](https://github.com/0xMiden/node/pull/2053)). - [BREAKING] Removed `miden-node ntx-builder` subcommand and created a separate `miden-ntx-builder` binary ([#2067](https://github.com/0xMiden/node/pull/2067)). +- [BREAKING] Reworked note proto types for multi-attachment support: `NoteMetadata` now carries `attachment_schemes` (repeated) and `attachments_commitment` instead of a single `attachment`. `Note` and `NetworkNote` gained an `attachments` field. `NoteSyncRecord` now embeds full `NoteMetadata` instead of `NoteMetadataHeader`. Removed `NoteAttachmentKind` enum and `NoteMetadataHeader` message ([#2078](https://github.com/0xMiden/node/pull/2078)). ## v0.14.10 (2026-05-29) From 0d7425d444d2a948f8c52b6341daee3127f9b63a Mon Sep 17 00:00:00 2001 From: Mirko von Leipzig <48352201+Mirko-von-Leipzig@users.noreply.github.com> Date: Fri, 15 May 2026 11:21:11 +0200 Subject: [PATCH 4/4] Revert pub --- crates/store/src/account_state_forest/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/store/src/account_state_forest/mod.rs b/crates/store/src/account_state_forest/mod.rs index fdf386d97e..26513dc9cd 100644 --- a/crates/store/src/account_state_forest/mod.rs +++ b/crates/store/src/account_state_forest/mod.rs @@ -87,7 +87,7 @@ pub enum AccountStorageMapResult { } /// Container for forest-related state that needs to be updated atomically. -pub struct AccountStateForest { +pub(crate) struct AccountStateForest { /// `LargeSmtForest` for efficient account storage reconstruction. /// Populated during block import with storage and vault SMTs. forest: LargeSmtForest,