From c3928620d18352955fac16e1bbed92455f585cbb Mon Sep 17 00:00:00 2001 From: Vaibhav Jindal Date: Tue, 23 Jun 2026 03:31:00 +0530 Subject: [PATCH 1/5] feat(standards): add P2idNote bon builder, require at least one asset Replace the `P2idNote` marker type and its `P2idNote::create` factory with a `P2idNote` struct built via a `bon` typestate builder (`P2idNote::builder()`): - `.sender()`, `.target()`, and a serial number (`.serial_number()` or `.generate_serial_number(rng)`) are required; `.note_type()` defaults to private and attachments are optional. - `.asset()`/`.assets()` and `.attachment()`/`.attachments()` append items. - P2ID notes must now carry at least one asset, enforced in `new()` via the new `NoteError::MissingAsset`. - `From for Note` converts infallibly. Migrate all `P2idNote::create` call sites to the builder. Incidental 0-asset P2ID notes in kernel tests move to P2ANY (which legitimately carries no assets), preserving the 0-asset coverage. Part of #2283 --- CHANGELOG.md | 6 + crates/miden-protocol/src/errors/mod.rs | 2 + crates/miden-standards/src/note/p2id.rs | 285 ++++++++++++++++-- .../src/kernel_tests/batch/proposed_batch.rs | 5 +- .../block/proposed_block_errors.rs | 15 +- .../block/proposed_block_success.rs | 5 +- .../block/proven_block_success.rs | 62 ++-- .../miden-testing/src/kernel_tests/tx/mod.rs | 16 +- .../kernel_tests/tx/test_account_interface.rs | 16 +- .../src/kernel_tests/tx/test_input_note.rs | 24 +- .../src/kernel_tests/tx/test_output_note.rs | 57 ++-- .../src/kernel_tests/tx/test_tx.rs | 23 +- .../src/mock_chain/chain_builder.rs | 16 +- .../tests/auth/hybrid_multisig.rs | 18 +- crates/miden-testing/tests/auth/multisig.rs | 34 +-- .../tests/auth/multisig_smart.rs | 18 +- crates/miden-testing/tests/scripts/p2id.rs | 52 ++-- .../miden-testing/tests/scripts/send_note.rs | 18 +- 18 files changed, 442 insertions(+), 230 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b979014a98..fd3a8a0709 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,12 @@ ## v0.16.0 (TBD) ### Changes +- [BREAKING] Replaced the `P2idNote` marker type and its `P2idNote::create` factory with a `P2idNote` struct built via a `bon` typestate builder (`P2idNote::builder()`). P2ID notes must now carry at least one asset (new `NoteError::MissingAsset`); a `P2idNote` converts into a `Note` via `Note::from`, and the builder offers `.asset()`/`.assets()`, `.attachment()`/`.attachments()`, and `.generate_serial_number()` ([#2283](https://github.com/0xMiden/protocol/issues/2283)). +- Fixed misleading documentation in the faucet and transfer policy procedures ([#3119](https://github.com/0xMiden/protocol/pull/3119)). +- [BREAKING] Removed the automatic fee computation and removal from the transaction kernel ([#3108](https://github.com/0xMiden/protocol/issues/3108)). +- Simplified the Ownable2Step owner-check API: merged the owner assertion into a single `exec` `assert_sender_is_owner` and renamed `is_sender_owner_internal` to `is_sender_owner` ([#3088](https://github.com/0xMiden/protocol/pull/3088)). +- [BREAKING] Renamed the `miden-tx-batch-prover` crate to `miden-tx-batch` ([#3035](https://github.com/0xMiden/protocol/pull/3035)). +- Added a skeleton batch kernel ([#1122](https://github.com/0xMiden/protocol/issues/1122)) wired through `LocalBatchProver::prove` and attached to `ProvenBatch` as an `ExecutionProof`. It does not yet perform any verification. - Added a skeleton batch kernel ([#1122](https://github.com/0xMiden/protocol/issues/1122)) wired through `LocalBatchProver::prove` and attached to `ProvenBatch` as an `ExecutionProof`. It does not yet perform any verification. - [BREAKING] Renamed `AccountStorageDelta` to `AccountStoragePatch` ([#3002](https://github.com/0xMiden/protocol/pull/3002)). diff --git a/crates/miden-protocol/src/errors/mod.rs b/crates/miden-protocol/src/errors/mod.rs index da63392796..49d8d809e4 100644 --- a/crates/miden-protocol/src/errors/mod.rs +++ b/crates/miden-protocol/src/errors/mod.rs @@ -736,6 +736,8 @@ pub enum NoteError { NoteScriptAssemblyError(Report), #[error("failed to deserialize note script")] NoteScriptDeserializationError(#[source] DeserializationError), + #[error("note must contain at least one asset")] + MissingAsset, #[error("note contains {0} assets which exceeds the maximum of {max}", max = NoteAssets::MAX_NUM_ASSETS)] TooManyAssets(usize), #[error("note contains {0} storage items which exceeds the maximum of {max}", max = MAX_NOTE_STORAGE_ITEMS)] diff --git a/crates/miden-standards/src/note/p2id.rs b/crates/miden-standards/src/note/p2id.rs index 41f06c3e33..fd78650432 100644 --- a/crates/miden-standards/src/note/p2id.rs +++ b/crates/miden-standards/src/note/p2id.rs @@ -8,6 +8,7 @@ use miden_protocol::errors::NoteError; use miden_protocol::note::{ Note, NoteAssets, + NoteAttachment, NoteAttachments, NoteRecipient, NoteScript, @@ -38,8 +39,65 @@ static P2ID_SCRIPT: LazyLock = LazyLock::new(|| { // P2ID NOTE // ================================================================================================ -/// TODO: add docs -pub struct P2idNote; +/// A Pay-to-ID (P2ID) note: transfers `assets` from `sender` to the `target` account. +/// +/// Only the `target` account can consume the note and claim its assets. +/// +/// Construct one with the [builder](P2idNote::builder), which sets sensible defaults for the +/// optional parameters (private note type, no attachments) and requires at least one asset. +/// Convert a `P2idNote` into a protocol [`Note`] infallibly via `Note::from`. +#[derive(Debug, Clone)] +pub struct P2idNote { + sender: AccountId, + storage: P2idNoteStorage, + serial_number: Word, + note_type: NoteType, + assets: NoteAssets, + attachments: NoteAttachments, +} + +#[bon::bon] +impl P2idNote { + /// Builds a new [`P2idNote`]. + /// + /// Set the recipient with `.target(account_id)`, add assets with `.asset()` / `.assets()` + /// (at least one is required), and optionally add attachments with `.attachment()`. The note + /// type defaults to [`NoteType::Private`]. The serial number can be set explicitly with + /// `.serial_number(word)` or drawn from an RNG with `.generate_serial_number(rng)`. + /// + /// # Errors + /// + /// Returns an error if: + /// - No assets were provided ([`NoteError::MissingAsset`]). + /// - The assets or attachments exceed their protocol limits (see [`NoteAssets::new`] and + /// [`NoteAttachments::new`]). + #[builder] + pub fn new( + #[builder(field)] assets: Vec, + #[builder(field)] attachments: Vec, + sender: AccountId, + #[builder(name = target, with = |target: AccountId| P2idNoteStorage::new(target))] + storage: P2idNoteStorage, + serial_number: Word, + #[builder(default)] note_type: NoteType, + ) -> Result { + if assets.is_empty() { + return Err(NoteError::MissingAsset); + } + + let assets = NoteAssets::new(assets)?; + let attachments = NoteAttachments::new(attachments)?; + + Ok(Self { + sender, + storage, + serial_number, + note_type, + assets, + attachments, + }) + } +} impl P2idNote { // CONSTANTS @@ -61,39 +119,105 @@ impl P2idNote { P2ID_SCRIPT.root() } - // BUILDERS - // -------------------------------------------------------------------------------------------- + /// Returns the account ID of the note's sender. + pub fn sender(&self) -> AccountId { + self.sender + } - /// Generates a P2ID note - Pay-to-ID note. - /// - /// This script enables the transfer of assets from the `sender` account to the `target` account - /// by specifying the target's account ID. - /// - /// The passed-in `rng` is used to generate a serial number for the note. The returned note's - /// tag is set to the target's account ID. - /// - /// # Errors - /// Returns an error if deserialization or compilation of the `P2ID` script fails. - pub fn create( - sender: AccountId, - target: AccountId, - assets: Vec, - note_type: NoteType, - attachments: NoteAttachments, - rng: &mut R, - ) -> Result { - let serial_num = rng.draw_word(); - let recipient = P2idNoteStorage::new(target).into_recipient(serial_num); + /// Returns the note's storage. + pub fn storage(&self) -> P2idNoteStorage { + self.storage + } + + /// Returns the account ID of the note's target (the only account that can consume it). + pub fn target(&self) -> AccountId { + self.storage.target() + } + + /// Returns the note's serial number. + pub fn serial_number(&self) -> Word { + self.serial_number + } + + /// Returns the note's type. + pub fn note_type(&self) -> NoteType { + self.note_type + } + + /// Returns the assets carried by the note. + pub fn assets(&self) -> &NoteAssets { + &self.assets + } + + /// Returns the attachments carried by the note. + pub fn attachments(&self) -> &NoteAttachments { + &self.attachments + } +} + +// BUILDER EXTENSIONS +// ================================================================================================ + +impl P2idNoteBuilder { + /// Adds a single asset to the note. At least one asset is required for `.build()` to succeed; + /// this can be called multiple times to add several assets. + pub fn asset(mut self, asset: impl Into) -> Self { + self.assets.push(asset.into()); + self + } + + /// Adds multiple assets to the note. Can be combined freely with [`Self::asset`]. + pub fn assets(mut self, assets: impl IntoIterator>) -> Self { + self.assets.extend(assets.into_iter().map(Into::into)); + self + } + + /// Adds a single attachment to the note. Can be called multiple times to add several + /// attachments. + pub fn attachment(mut self, attachment: impl Into) -> Self { + self.attachments.push(attachment.into()); + self + } + + /// Adds multiple attachments to the note. Can be combined freely with [`Self::attachment`]. + pub fn attachments( + mut self, + attachments: impl IntoIterator>, + ) -> Self { + self.attachments.extend(attachments.into_iter().map(Into::into)); + self + } +} - let tag = NoteTag::with_account_target(target); +impl P2idNoteBuilder +where + S::SerialNumber: p2id_note_builder::IsUnset, +{ + /// Draws a serial number from `rng` and sets it on the builder. + pub fn generate_serial_number( + self, + rng: &mut impl FeltRng, + ) -> P2idNoteBuilder> { + self.serial_number(rng.draw_word()) + } +} + +// CONVERSIONS +// ================================================================================================ - let metadata = PartialNoteMetadata::new(sender, note_type).with_tag(tag); - let vault = NoteAssets::new(assets)?; +impl From for Note { + fn from(note: P2idNote) -> Self { + let recipient = note.storage.into_recipient(note.serial_number); + let tag = NoteTag::with_account_target(note.storage.target()); + let metadata = PartialNoteMetadata::new(note.sender, note.note_type).with_tag(tag); - Ok(Note::with_attachments(vault, metadata, recipient, attachments)) + Note::with_attachments(note.assets, metadata, recipient, note.attachments) } } +// P2ID NOTE STORAGE +// ================================================================================================ + /// Canonical storage representation for a P2ID note. /// /// Contains the identifier of the target account that is authorized @@ -162,12 +286,17 @@ impl TryFrom<&[Felt]> for P2idNoteStorage { #[cfg(test)] mod tests { - use miden_protocol::Felt; use miden_protocol::account::{AccountId, AccountIdVersion, AccountType}; + use miden_protocol::asset::FungibleAsset; + use miden_protocol::crypto::rand::RandomCoin; use miden_protocol::errors::NoteError; + use miden_protocol::{Felt, Word}; use super::*; + // STORAGE TESTS + // -------------------------------------------------------------------------------------------- + #[test] fn try_from_valid_storage_succeeds() { let target = AccountId::dummy([1u8; 15], AccountIdVersion::Version1, AccountType::Private); @@ -205,4 +334,102 @@ mod tests { assert!(matches!(err, NoteError::Other { source: Some(_), .. })); } + + // BUILDER TESTS + // -------------------------------------------------------------------------------------------- + + fn sender() -> AccountId { + AccountId::dummy([1u8; 15], AccountIdVersion::Version1, AccountType::Private) + } + + fn target() -> AccountId { + AccountId::dummy([2u8; 15], AccountIdVersion::Version1, AccountType::Private) + } + + fn faucet_a() -> AccountId { + AccountId::dummy([3u8; 15], AccountIdVersion::Version1, AccountType::Public) + } + + fn faucet_b() -> AccountId { + AccountId::dummy([4u8; 15], AccountIdVersion::Version1, AccountType::Public) + } + + /// The minimal builder uses defaults for everything but the required fields. + #[test] + fn builder_minimal_uses_defaults() { + let note = P2idNote::builder() + .sender(sender()) + .target(target()) + .serial_number(Word::empty()) + .asset(FungibleAsset::new(faucet_a(), 1).unwrap()) + .build() + .unwrap(); + + assert_eq!(note.sender(), sender()); + assert_eq!(note.target(), target()); + assert_eq!(note.note_type(), NoteType::Private); + assert_eq!(note.assets().num_assets(), 1); + assert_eq!(note.attachments().num_attachments(), 0); + } + + /// `.asset()` and `.assets()` both append, so they can be combined and called repeatedly. + #[test] + fn builder_accumulates_assets() { + let note = P2idNote::builder() + .sender(sender()) + .target(target()) + .serial_number(Word::empty()) + .asset(FungibleAsset::new(faucet_a(), 100).unwrap()) + .assets([Asset::from(FungibleAsset::new(faucet_b(), 200).unwrap())]) + .build() + .unwrap(); + + assert_eq!(note.assets().num_assets(), 2); + } + + /// A P2ID note must carry at least one asset. + #[test] + fn builder_rejects_empty_assets() { + let err = P2idNote::builder() + .sender(sender()) + .target(target()) + .serial_number(Word::empty()) + .build() + .expect_err("a note without assets must be rejected"); + + assert!(matches!(err, NoteError::MissingAsset)); + } + + /// `.generate_serial_number()` draws the serial from the RNG. + #[test] + fn builder_generates_serial_number() { + let mut rng = RandomCoin::new(Word::empty()); + let note = P2idNote::builder() + .sender(sender()) + .target(target()) + .asset(FungibleAsset::new(faucet_a(), 1).unwrap()) + .generate_serial_number(&mut rng) + .build() + .unwrap(); + + assert_ne!(note.serial_number(), Word::empty()); + } + + /// `Note::from(p2id_note)` is infallible and preserves the assets. + #[test] + fn into_note_preserves_assets() { + let p2id_note = P2idNote::builder() + .sender(sender()) + .target(target()) + .serial_number(Word::empty()) + .asset(FungibleAsset::new(faucet_a(), 42).unwrap()) + .note_type(NoteType::Public) + .build() + .unwrap(); + + let assets = p2id_note.assets().clone(); + let note = Note::from(p2id_note); + + assert_eq!(note.assets(), &assets); + } } diff --git a/crates/miden-testing/src/kernel_tests/batch/proposed_batch.rs b/crates/miden-testing/src/kernel_tests/batch/proposed_batch.rs index c9b0c57905..c55ec44424 100644 --- a/crates/miden-testing/src/kernel_tests/batch/proposed_batch.rs +++ b/crates/miden-testing/src/kernel_tests/batch/proposed_batch.rs @@ -67,9 +67,10 @@ pub fn setup_chain() -> TestSetup { let mut builder = MockChain::builder(); let account1 = generate_account(&mut builder); let account2 = generate_account(&mut builder); + // Use P2ANY: a P2ID note must carry at least one asset. let note1 = builder - .add_p2id_note(account1.id(), account2.id(), &[], NoteType::Public) - .expect("adding p2id note1 should work"); + .add_p2any_note(account1.id(), NoteType::Public, []) + .expect("adding p2any note1 should work"); let mut chain = builder.build().expect("genesis should be valid"); chain.prove_next_block().expect("valid setup"); diff --git a/crates/miden-testing/src/kernel_tests/block/proposed_block_errors.rs b/crates/miden-testing/src/kernel_tests/block/proposed_block_errors.rs index 7998f7d3ff..f7513690a2 100644 --- a/crates/miden-testing/src/kernel_tests/block/proposed_block_errors.rs +++ b/crates/miden-testing/src/kernel_tests/block/proposed_block_errors.rs @@ -9,8 +9,7 @@ use miden_protocol::asset::FungibleAsset; use miden_protocol::block::{BlockInputs, BlockNumber, ProposedBlock}; use miden_protocol::crypto::merkle::SparseMerklePath; use miden_protocol::errors::ProposedBlockError; -use miden_protocol::note::{NoteAttachments, NoteInclusionProof, NoteType}; -use miden_standards::note::P2idNote; +use miden_protocol::note::{NoteInclusionProof, NoteType}; use miden_tx::LocalTransactionProver; use crate::kernel_tests::batch::proposed_batch::setup_circular_note_dependency_test; @@ -352,14 +351,8 @@ async fn proposed_block_fails_on_invalid_proof_or_missing_note_inclusion_referen let mut builder = MockChain::builder(); let account0 = builder.add_existing_mock_account(Auth::IncrNonce)?; let account1 = builder.add_existing_mock_account(Auth::IncrNonce)?; - let p2id_note = P2idNote::create( - account0.id(), - account1.id(), - vec![], - NoteType::Private, - NoteAttachments::default(), - builder.rng_mut(), - )?; + // Use P2ANY: a P2ID note must carry at least one asset. + let p2id_note = create_p2any_note(account0.id(), NoteType::Private, [], builder.rng_mut()); let spawn_note = builder.add_spawn_note([&p2id_note])?; let mut chain = builder.build()?; @@ -373,7 +366,7 @@ async fn proposed_block_fails_on_invalid_proof_or_missing_note_inclusion_referen // inclusion of the unauthenticated note. let batch0 = chain.create_batch(vec![tx0])?; - // Add the P2ID note to the chain by consuming the SPAWN note. The note will hence be created as + // Add the note to the chain by consuming the SPAWN note. The note will hence be created as // part of block 2 and the note inclusion proof references that block. let tx = chain .build_tx_context(account0.id(), &[spawn_note.id()], &[])? diff --git a/crates/miden-testing/src/kernel_tests/block/proposed_block_success.rs b/crates/miden-testing/src/kernel_tests/block/proposed_block_success.rs index 9bc4fee198..0959df3f03 100644 --- a/crates/miden-testing/src/kernel_tests/block/proposed_block_success.rs +++ b/crates/miden-testing/src/kernel_tests/block/proposed_block_success.rs @@ -189,8 +189,9 @@ async fn proposed_block_authenticating_unauthenticated_notes() -> anyhow::Result let mut builder = MockChain::builder(); let account0 = builder.add_existing_mock_account(Auth::IncrNonce)?; let account1 = builder.add_existing_mock_account(Auth::IncrNonce)?; - let note0 = builder.add_p2id_note(sender_id, account0.id(), &[], NoteType::Private)?; - let note1 = builder.add_p2id_note(sender_id, account1.id(), &[], NoteType::Public)?; + // Use P2ANY: a P2ID note must carry at least one asset. + let note0 = builder.add_p2any_note(sender_id, NoteType::Private, [])?; + let note1 = builder.add_p2any_note(sender_id, NoteType::Public, [])?; let chain = builder.build()?; // These txs will use block1 as the reference block. diff --git a/crates/miden-testing/src/kernel_tests/block/proven_block_success.rs b/crates/miden-testing/src/kernel_tests/block/proven_block_success.rs index 865d0a244c..3bebcfc077 100644 --- a/crates/miden-testing/src/kernel_tests/block/proven_block_success.rs +++ b/crates/miden-testing/src/kernel_tests/block/proven_block_success.rs @@ -8,7 +8,7 @@ use miden_protocol::batch::BatchNoteTree; use miden_protocol::block::account_tree::AccountTree; use miden_protocol::block::{BlockInputs, BlockNoteIndex, BlockNoteTree, ProposedBlock}; use miden_protocol::crypto::merkle::smt::Smt; -use miden_protocol::note::{NoteAttachments, NoteType}; +use miden_protocol::note::{Note, NoteType}; use miden_protocol::transaction::InputNoteCommitment; use miden_standards::note::P2idNote; @@ -32,38 +32,34 @@ async fn proven_block_success() -> anyhow::Result<()> { let account2 = builder.add_existing_mock_account_with_assets(Auth::IncrNonce, [asset])?; let account3 = builder.add_existing_mock_account_with_assets(Auth::IncrNonce, [asset])?; - let output_note0 = P2idNote::create( - account0.id(), - account0.id(), - vec![asset], - NoteType::Private, - NoteAttachments::default(), - builder.rng_mut(), - )?; - let output_note1 = P2idNote::create( - account1.id(), - account1.id(), - vec![asset], - NoteType::Private, - NoteAttachments::default(), - builder.rng_mut(), - )?; - let output_note2 = P2idNote::create( - account2.id(), - account2.id(), - vec![asset], - NoteType::Private, - NoteAttachments::default(), - builder.rng_mut(), - )?; - let output_note3 = P2idNote::create( - account3.id(), - account3.id(), - vec![asset], - NoteType::Private, - NoteAttachments::default(), - builder.rng_mut(), - )?; + let output_note0: Note = P2idNote::builder() + .sender(account0.id()) + .target(account0.id()) + .asset(asset) + .generate_serial_number(builder.rng_mut()) + .build()? + .into(); + let output_note1: Note = P2idNote::builder() + .sender(account1.id()) + .target(account1.id()) + .asset(asset) + .generate_serial_number(builder.rng_mut()) + .build()? + .into(); + let output_note2: Note = P2idNote::builder() + .sender(account2.id()) + .target(account2.id()) + .asset(asset) + .generate_serial_number(builder.rng_mut()) + .build()? + .into(); + let output_note3: Note = P2idNote::builder() + .sender(account3.id()) + .target(account3.id()) + .asset(asset) + .generate_serial_number(builder.rng_mut()) + .build()? + .into(); let input_note0 = builder.add_spawn_note([&output_note0])?; let input_note1 = builder.add_spawn_note([&output_note1])?; diff --git a/crates/miden-testing/src/kernel_tests/tx/mod.rs b/crates/miden-testing/src/kernel_tests/tx/mod.rs index 7345c084eb..cd0e4bb967 100644 --- a/crates/miden-testing/src/kernel_tests/tx/mod.rs +++ b/crates/miden-testing/src/kernel_tests/tx/mod.rs @@ -101,12 +101,13 @@ pub fn input_note_data_ptr(note_idx: u32) -> memory::MemoryAddress { struct TestSetup { mock_chain: MockChain, account: Account, - p2id_note_0_assets: Note, + p2any_note_0_assets: Note, p2id_note_1_asset: Note, p2id_note_2_assets: Note, } -/// Return a [`TestSetup`], whose notes contain 0, 1 and 2 assets respectively. +/// Return a [`TestSetup`] whose notes contain 0, 1 and 2 assets respectively. The 0-asset note is +/// a P2ANY note, since P2ID notes must carry at least one asset. fn setup_test() -> anyhow::Result { let mut builder = MockChain::builder(); @@ -144,12 +145,9 @@ fn setup_test() -> anyhow::Result { )?; // Notes - let p2id_note_0_assets = builder.add_p2id_note( - ACCOUNT_ID_SENDER.try_into().unwrap(), - account.id(), - &[], - NoteType::Public, - )?; + // Use P2ANY: a P2ID note must carry at least one asset. + let p2any_note_0_assets = + builder.add_p2any_note(ACCOUNT_ID_SENDER.try_into().unwrap(), NoteType::Public, [])?; let p2id_note_1_asset = builder.add_p2id_note( ACCOUNT_ID_SENDER.try_into().unwrap(), account.id(), @@ -168,7 +166,7 @@ fn setup_test() -> anyhow::Result { anyhow::Ok(TestSetup { mock_chain, account, - p2id_note_0_assets, + p2any_note_0_assets, p2id_note_1_asset, p2id_note_2_assets, }) diff --git a/crates/miden-testing/src/kernel_tests/tx/test_account_interface.rs b/crates/miden-testing/src/kernel_tests/tx/test_account_interface.rs index ba09751323..41fc138ee8 100644 --- a/crates/miden-testing/src/kernel_tests/tx/test_account_interface.rs +++ b/crates/miden-testing/src/kernel_tests/tx/test_account_interface.rs @@ -45,14 +45,14 @@ use crate::{Auth, MockChain, TransactionContextBuilder, TxContextInput}; #[tokio::test] async fn check_note_consumability_standard_notes_success() -> anyhow::Result<()> { - let p2id_note = P2idNote::create( - ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_IMMUTABLE_CODE.try_into().unwrap(), - ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_UPDATABLE_CODE.try_into().unwrap(), - vec![FungibleAsset::mock(10)], - NoteType::Public, - Default::default(), - &mut RandomCoin::new(Word::from([2u32; 4])), - )?; + let p2id_note: Note = P2idNote::builder() + .sender(ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_IMMUTABLE_CODE.try_into().unwrap()) + .target(ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_UPDATABLE_CODE.try_into().unwrap()) + .asset(FungibleAsset::mock(10)) + .note_type(NoteType::Public) + .generate_serial_number(&mut RandomCoin::new(Word::from([2u32; 4]))) + .build()? + .into(); let p2ide_note = P2ideNote::create( ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_IMMUTABLE_CODE.try_into().unwrap(), diff --git a/crates/miden-testing/src/kernel_tests/tx/test_input_note.rs b/crates/miden-testing/src/kernel_tests/tx/test_input_note.rs index 63507ede66..3bb63a4840 100644 --- a/crates/miden-testing/src/kernel_tests/tx/test_input_note.rs +++ b/crates/miden-testing/src/kernel_tests/tx/test_input_note.rs @@ -16,7 +16,7 @@ async fn test_get_asset_info() -> anyhow::Result<()> { let TestSetup { mock_chain, account, - p2id_note_0_assets, + p2any_note_0_assets, p2id_note_1_asset, p2id_note_2_assets, } = setup_test()?; @@ -60,8 +60,8 @@ async fn test_get_asset_info() -> anyhow::Result<()> { ", check_note_0 = check_asset_info_code( 0, - p2id_note_0_assets.assets().commitment(), - p2id_note_0_assets.assets().num_assets() + p2any_note_0_assets.assets().commitment(), + p2any_note_0_assets.assets().num_assets() ), check_note_1 = check_asset_info_code( 1, @@ -81,7 +81,7 @@ async fn test_get_asset_info() -> anyhow::Result<()> { .build_tx_context( TxContextInput::AccountId(account.id()), &[], - &[p2id_note_0_assets, p2id_note_1_asset, p2id_note_2_assets], + &[p2any_note_0_assets, p2id_note_1_asset, p2id_note_2_assets], )? .tx_script(tx_script) .build()?; @@ -98,7 +98,7 @@ async fn test_get_recipient_and_metadata() -> anyhow::Result<()> { let TestSetup { mock_chain, account, - p2id_note_0_assets: _, + p2any_note_0_assets: _, p2id_note_1_asset, p2id_note_2_assets: _, } = setup_test()?; @@ -151,7 +151,7 @@ async fn test_get_sender() -> anyhow::Result<()> { let TestSetup { mock_chain, account, - p2id_note_0_assets: _, + p2any_note_0_assets: _, p2id_note_1_asset, p2id_note_2_assets: _, } = setup_test()?; @@ -200,7 +200,7 @@ async fn test_get_assets() -> anyhow::Result<()> { let TestSetup { mock_chain, account, - p2id_note_0_assets, + p2any_note_0_assets, p2id_note_1_asset, p2id_note_2_assets, } = setup_test()?; @@ -283,7 +283,7 @@ async fn test_get_assets() -> anyhow::Result<()> { {check_note_2} end ", - check_note_0 = check_assets_code(0, 0, &p2id_note_0_assets), + check_note_0 = check_assets_code(0, 0, &p2any_note_0_assets), check_note_1 = check_assets_code(1, 8, &p2id_note_1_asset), check_note_2 = check_assets_code(2, 16, &p2id_note_2_assets), ); @@ -294,7 +294,7 @@ async fn test_get_assets() -> anyhow::Result<()> { .build_tx_context( TxContextInput::AccountId(account.id()), &[], - &[p2id_note_0_assets, p2id_note_1_asset, p2id_note_2_assets], + &[p2any_note_0_assets, p2id_note_1_asset, p2id_note_2_assets], )? .tx_script(tx_script) .build()?; @@ -311,7 +311,7 @@ async fn test_get_storage_info() -> anyhow::Result<()> { let TestSetup { mock_chain, account, - p2id_note_0_assets: _, + p2any_note_0_assets: _, p2id_note_1_asset, p2id_note_2_assets: _, } = setup_test()?; @@ -361,7 +361,7 @@ async fn test_get_script_root() -> anyhow::Result<()> { let TestSetup { mock_chain, account, - p2id_note_0_assets: _, + p2any_note_0_assets: _, p2id_note_1_asset, p2id_note_2_assets: _, } = setup_test()?; @@ -404,7 +404,7 @@ async fn test_get_serial_number() -> anyhow::Result<()> { let TestSetup { mock_chain, account, - p2id_note_0_assets: _, + p2any_note_0_assets: _, p2id_note_1_asset, p2id_note_2_assets: _, } = setup_test()?; diff --git a/crates/miden-testing/src/kernel_tests/tx/test_output_note.rs b/crates/miden-testing/src/kernel_tests/tx/test_output_note.rs index d2997342aa..38688981d4 100644 --- a/crates/miden-testing/src/kernel_tests/tx/test_output_note.rs +++ b/crates/miden-testing/src/kernel_tests/tx/test_output_note.rs @@ -886,23 +886,24 @@ async fn test_get_asset_info() -> anyhow::Result<()> { let mock_chain = builder.build()?; - let output_note_0 = P2idNote::create( - account.id(), - ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_IMMUTABLE_CODE.try_into()?, - vec![fungible_asset_0], - NoteType::Public, - NoteAttachments::default(), - &mut RandomCoin::new(Word::from([1, 2, 3, 4u32])), - )?; + let output_note_0: Note = P2idNote::builder() + .sender(account.id()) + .target(ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_IMMUTABLE_CODE.try_into()?) + .asset(fungible_asset_0) + .note_type(NoteType::Public) + .generate_serial_number(&mut RandomCoin::new(Word::from([1, 2, 3, 4u32]))) + .build()? + .into(); - let output_note_1 = P2idNote::create( - account.id(), - ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_IMMUTABLE_CODE.try_into()?, - vec![fungible_asset_0, fungible_asset_1], - NoteType::Public, - NoteAttachments::default(), - &mut RandomCoin::new(Word::from([4, 3, 2, 1u32])), - )?; + let output_note_1: Note = P2idNote::builder() + .sender(account.id()) + .target(ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_IMMUTABLE_CODE.try_into()?) + .asset(fungible_asset_0) + .asset(fungible_asset_1) + .note_type(NoteType::Public) + .generate_serial_number(&mut RandomCoin::new(Word::from([4, 3, 2, 1u32]))) + .build()? + .into(); let tx_script_src = &format!( r#" @@ -1016,14 +1017,14 @@ async fn test_get_recipient_and_metadata() -> anyhow::Result<()> { let mock_chain = builder.build()?; - let output_note = P2idNote::create( - account.id(), - ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_IMMUTABLE_CODE.try_into()?, - vec![FungibleAsset::mock(5)], - NoteType::Public, - NoteAttachments::default(), - &mut RandomCoin::new(Word::from([1, 2, 3, 4u32])), - )?; + let output_note: Note = P2idNote::builder() + .sender(account.id()) + .target(ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_IMMUTABLE_CODE.try_into()?) + .asset(FungibleAsset::mock(5)) + .note_type(NoteType::Public) + .generate_serial_number(&mut RandomCoin::new(Word::from([1, 2, 3, 4u32]))) + .build()? + .into(); let tx_script_src = &format!( r#" @@ -1083,7 +1084,7 @@ async fn test_get_assets() -> anyhow::Result<()> { let TestSetup { mock_chain, account, - p2id_note_0_assets, + p2any_note_0_assets, p2id_note_1_asset, p2id_note_2_assets, } = setup_test()?; @@ -1173,8 +1174,8 @@ async fn test_get_assets() -> anyhow::Result<()> { exec.sys::truncate_stack end ", - create_note_0 = create_output_note(&p2id_note_0_assets), - check_note_0 = check_assets_code(0, 0, &p2id_note_0_assets), + create_note_0 = create_output_note(&p2any_note_0_assets), + check_note_0 = check_assets_code(0, 0, &p2any_note_0_assets), create_note_1 = create_output_note(&p2id_note_1_asset), check_note_1 = check_assets_code(1, 8, &p2id_note_1_asset), create_note_2 = create_output_note(&p2id_note_2_assets), @@ -1186,7 +1187,7 @@ async fn test_get_assets() -> anyhow::Result<()> { let tx_context = mock_chain .build_tx_context(account.id(), &[], &[])? .extend_expected_output_notes(vec![ - RawOutputNote::Full(p2id_note_0_assets), + RawOutputNote::Full(p2any_note_0_assets), RawOutputNote::Full(p2id_note_1_asset), RawOutputNote::Full(p2id_note_2_assets), ]) diff --git a/crates/miden-testing/src/kernel_tests/tx/test_tx.rs b/crates/miden-testing/src/kernel_tests/tx/test_tx.rs index bfe77467a8..1562dde2c0 100644 --- a/crates/miden-testing/src/kernel_tests/tx/test_tx.rs +++ b/crates/miden-testing/src/kernel_tests/tx/test_tx.rs @@ -67,7 +67,6 @@ use miden_standards::account::interface::{ }; use miden_standards::account::wallets::BasicWallet; use miden_standards::code_builder::CodeBuilder; -use miden_standards::note::P2idNote; use miden_standards::testing::account_component::IncrNonceAuthComponent; use miden_standards::testing::account_interface::get_public_keys_from_account; use miden_standards::testing::mock_account::MockAccountExt; @@ -489,14 +488,7 @@ async fn user_code_can_abort_transaction_with_summary() -> anyhow::Result<()> { // Consume and create a note so the input and outputs notes commitment is not the empty word. let mut rng = RandomCoin::new(Word::empty()); - let output_note = P2idNote::create( - account.id(), - account.id(), - vec![], - NoteType::Private, - NoteAttachments::default(), - &mut rng, - )?; + let output_note = create_p2any_note(account.id(), NoteType::Private, [], &mut rng); let input_note = create_spawn_note(vec![&output_note])?; let mut builder = MockChain::builder(); @@ -537,15 +529,8 @@ async fn tx_summary_commitment_is_signed_by_auth_singlesig( let mut builder = MockChain::builder(); let account = builder.add_existing_mock_account(Auth::BasicAuth { auth_scheme })?; let mut rng = RandomCoin::new(Word::empty()); - let p2id_note = P2idNote::create( - account.id(), - account.id(), - vec![], - NoteType::Private, - NoteAttachments::default(), - &mut rng, - )?; - let spawn_note = builder.add_spawn_note([&p2id_note])?; + let p2any_note = create_p2any_note(account.id(), NoteType::Private, [], &mut rng); + let spawn_note = builder.add_spawn_note([&p2any_note])?; let chain = builder.build()?; let tx_builder = @@ -566,7 +551,7 @@ async fn tx_summary_commitment_is_signed_by_auth_singlesig( let expected_summary = TransactionSummary::new( account_delta, InputNotes::new(vec![InputNote::unauthenticated(spawn_note)])?, - RawOutputNotes::new(vec![RawOutputNote::Partial(PartialNote::from(p2id_note))])?, + RawOutputNotes::new(vec![RawOutputNote::Partial(PartialNote::from(p2any_note))])?, Word::from([0, 0, ref_block_num.as_u32(), final_nonce.as_canonical_u64() as u32]), ); diff --git a/crates/miden-testing/src/mock_chain/chain_builder.rs b/crates/miden-testing/src/mock_chain/chain_builder.rs index b379ae645f..3736f9a8ab 100644 --- a/crates/miden-testing/src/mock_chain/chain_builder.rs +++ b/crates/miden-testing/src/mock_chain/chain_builder.rs @@ -669,14 +669,14 @@ impl MockChainBuilder { asset: &[Asset], note_type: NoteType, ) -> Result { - let note = P2idNote::create( - sender_account_id, - target_account_id, - asset.to_vec(), - note_type, - NoteAttachments::default(), - &mut self.rng, - )?; + let note: Note = P2idNote::builder() + .sender(sender_account_id) + .target(target_account_id) + .assets(asset.iter().copied()) + .note_type(note_type) + .generate_serial_number(&mut self.rng) + .build()? + .into(); self.add_output_note(RawOutputNote::Full(note.clone())); Ok(note) diff --git a/crates/miden-testing/tests/auth/hybrid_multisig.rs b/crates/miden-testing/tests/auth/hybrid_multisig.rs index 995f2ae1f4..a8f9dac449 100644 --- a/crates/miden-testing/tests/auth/hybrid_multisig.rs +++ b/crates/miden-testing/tests/auth/hybrid_multisig.rs @@ -9,7 +9,7 @@ use miden_protocol::account::{ StorageMapKey, }; use miden_protocol::asset::FungibleAsset; -use miden_protocol::note::NoteType; +use miden_protocol::note::{Note, NoteType}; use miden_protocol::testing::account_id::ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_UPDATABLE_CODE; use miden_protocol::transaction::RawOutputNote; use miden_protocol::vm::AdviceMap; @@ -489,14 +489,14 @@ async fn test_multisig_update_signers() -> anyhow::Result<()> { } // Create a new output note for the second transaction with new signers - let output_note_new = P2idNote::create( - updated_multisig_account.id(), - ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_UPDATABLE_CODE.try_into().unwrap(), - vec![output_note_asset], - NoteType::Public, - Default::default(), - &mut RandomCoin::new(Word::empty()), - )?; + let output_note_new: Note = P2idNote::builder() + .sender(updated_multisig_account.id()) + .target(ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_UPDATABLE_CODE.try_into().unwrap()) + .asset(output_note_asset) + .note_type(NoteType::Public) + .generate_serial_number(&mut RandomCoin::new(Word::empty())) + .build()? + .into(); // Create a new spawn note for the second transaction let input_note_new = create_spawn_note([&output_note_new])?; diff --git a/crates/miden-testing/tests/auth/multisig.rs b/crates/miden-testing/tests/auth/multisig.rs index 1ba4998bda..a5712549d5 100644 --- a/crates/miden-testing/tests/auth/multisig.rs +++ b/crates/miden-testing/tests/auth/multisig.rs @@ -10,7 +10,7 @@ use miden_protocol::account::{ StorageMapKey, }; use miden_protocol::asset::{AssetCallbackFlag, AssetVaultKey, FungibleAsset}; -use miden_protocol::note::NoteType; +use miden_protocol::note::{Note, NoteType}; use miden_protocol::testing::account_id::{ ACCOUNT_ID_PUBLIC_FUNGIBLE_FAUCET, ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_UPDATABLE_CODE, @@ -612,14 +612,14 @@ async fn test_multisig_update_signers(#[case] auth_scheme: AuthScheme) -> anyhow } // Create a new output note for the second transaction with new signers - let output_note_new = P2idNote::create( - updated_multisig_account.id(), - ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_UPDATABLE_CODE.try_into().unwrap(), - vec![output_note_asset], - NoteType::Public, - Default::default(), - &mut RandomCoin::new(Word::empty()), - )?; + let output_note_new: Note = P2idNote::builder() + .sender(updated_multisig_account.id()) + .target(ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_UPDATABLE_CODE.try_into().unwrap()) + .asset(output_note_asset) + .note_type(NoteType::Public) + .generate_serial_number(&mut RandomCoin::new(Word::empty())) + .build()? + .into(); // Create a new spawn note for the second transaction let input_note_new = create_spawn_note([&output_note_new])?; @@ -1156,14 +1156,14 @@ async fn test_multisig_proc_threshold_overrides( // Create output note to send 5 units from the account let asset = FungibleAsset::mock(5); - let output_note = P2idNote::create( - multisig_account.id(), - ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_UPDATABLE_CODE.try_into().unwrap(), - vec![asset], - NoteType::Public, - Default::default(), - &mut RandomCoin::new(Word::from([Felt::new_unchecked(42); 4])), - )?; + let output_note: Note = P2idNote::builder() + .sender(multisig_account.id()) + .target(ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_UPDATABLE_CODE.try_into().unwrap()) + .asset(asset) + .note_type(NoteType::Public) + .generate_serial_number(&mut RandomCoin::new(Word::from([Felt::new_unchecked(42); 4]))) + .build()? + .into(); let send_note_transaction_script = TransactionScript::from(SendNotesTransactionScript::new( &multisig_account.code_interface(), &[output_note.clone().into()], diff --git a/crates/miden-testing/tests/auth/multisig_smart.rs b/crates/miden-testing/tests/auth/multisig_smart.rs index 775d453865..965dace99a 100644 --- a/crates/miden-testing/tests/auth/multisig_smart.rs +++ b/crates/miden-testing/tests/auth/multisig_smart.rs @@ -2,7 +2,7 @@ use miden_processor::advice::AdviceInputs; use miden_protocol::account::auth::{AuthScheme, PublicKey}; use miden_protocol::account::{Account, AccountBuilder, AccountId, AccountType, StorageMapKey}; use miden_protocol::asset::FungibleAsset; -use miden_protocol::note::NoteType; +use miden_protocol::note::{Note, NoteType}; use miden_protocol::testing::account_id::ACCOUNT_ID_PUBLIC_FUNGIBLE_FAUCET; use miden_protocol::transaction::TransactionScript; use miden_protocol::vm::AdviceMap; @@ -235,14 +235,14 @@ async fn test_multisig_smart_enforces_note_restrictions_on_tx_with_output_notes( )], )?; - let output_note = P2idNote::create( - multisig_account.id(), - ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_UPDATABLE_CODE.try_into().unwrap(), - vec![FungibleAsset::mock(5)], - NoteType::Public, - Default::default(), - &mut RandomCoin::new(Word::from([Felt::new_unchecked(7); 4])), - )?; + let output_note: Note = P2idNote::builder() + .sender(multisig_account.id()) + .target(ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_UPDATABLE_CODE.try_into().unwrap()) + .asset(FungibleAsset::mock(5)) + .note_type(NoteType::Public) + .generate_serial_number(&mut RandomCoin::new(Word::from([Felt::new_unchecked(7); 4]))) + .build()? + .into(); let send_note_script = TransactionScript::from(SendNotesTransactionScript::new( &multisig_account.code_interface(), diff --git a/crates/miden-testing/tests/scripts/p2id.rs b/crates/miden-testing/tests/scripts/p2id.rs index 0bbda5c114..acba3c05cc 100644 --- a/crates/miden-testing/tests/scripts/p2id.rs +++ b/crates/miden-testing/tests/scripts/p2id.rs @@ -2,7 +2,7 @@ use miden_protocol::account::Account; use miden_protocol::account::auth::AuthScheme; use miden_protocol::asset::{Asset, AssetVault, FungibleAsset}; use miden_protocol::crypto::rand::RandomCoin; -use miden_protocol::note::{NoteAttachments, NoteTag, NoteType}; +use miden_protocol::note::{Note, NoteTag, NoteType}; use miden_protocol::testing::account_id::{ ACCOUNT_ID_PRIVATE_FUNGIBLE_FAUCET, ACCOUNT_ID_PUBLIC_FUNGIBLE_FAUCET_2, @@ -222,23 +222,23 @@ async fn test_create_consume_multiple_notes() -> anyhow::Result<()> { let asset_1 = FungibleAsset::mock(10); let asset_2 = FungibleAsset::mock(5); - let output_note_1 = P2idNote::create( - account.id(), - ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_IMMUTABLE_CODE_2.try_into()?, - vec![asset_1], - NoteType::Public, - NoteAttachments::default(), - &mut RandomCoin::new(Word::from([1, 2, 3, 4u32])), - )?; - - let output_note_2 = P2idNote::create( - account.id(), - ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_IMMUTABLE_CODE.try_into()?, - vec![asset_2], - NoteType::Public, - NoteAttachments::default(), - &mut RandomCoin::new(Word::from([4, 3, 2, 1u32])), - )?; + let output_note_1: Note = P2idNote::builder() + .sender(account.id()) + .target(ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_IMMUTABLE_CODE_2.try_into()?) + .asset(asset_1) + .note_type(NoteType::Public) + .generate_serial_number(&mut RandomCoin::new(Word::from([1, 2, 3, 4u32]))) + .build()? + .into(); + + let output_note_2: Note = P2idNote::builder() + .sender(account.id()) + .target(ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_IMMUTABLE_CODE.try_into()?) + .asset(asset_2) + .note_type(NoteType::Public) + .generate_serial_number(&mut RandomCoin::new(Word::from([4, 3, 2, 1u32]))) + .build()? + .into(); let tx_script_src = &format!( " @@ -366,14 +366,14 @@ async fn test_p2id_new_constructor() -> anyhow::Result<()> { let tx_script = CodeBuilder::default().compile_tx_script(&tx_script_src)?; // Build expected output note - let expected_output_note = P2idNote::create( - sender_account.id(), - target_account.id(), - vec![FungibleAsset::mock(50)], - NoteType::Public, - NoteAttachments::default(), - &mut RandomCoin::new(serial_num), - )?; + let expected_output_note: Note = P2idNote::builder() + .sender(sender_account.id()) + .target(target_account.id()) + .asset(FungibleAsset::mock(50)) + .note_type(NoteType::Public) + .generate_serial_number(&mut RandomCoin::new(serial_num)) + .build()? + .into(); let tx_context = mock_chain .build_tx_context(sender_account.id(), &[], &[])? diff --git a/crates/miden-testing/tests/scripts/send_note.rs b/crates/miden-testing/tests/scripts/send_note.rs index 5b1ed6596c..33486b5169 100644 --- a/crates/miden-testing/tests/scripts/send_note.rs +++ b/crates/miden-testing/tests/scripts/send_note.rs @@ -82,14 +82,16 @@ async fn test_send_note_script_basic_wallet() -> anyhow::Result<()> { "test should use max num of attachments" ); - let p2id_note = P2idNote::create( - sender_basic_wallet_account.id(), - sender_basic_wallet_account.id(), - vec![sent_asset0, sent_asset2], - NoteType::Public, - attachments, - &mut rng, - )?; + let p2id_note: Note = P2idNote::builder() + .sender(sender_basic_wallet_account.id()) + .target(sender_basic_wallet_account.id()) + .asset(sent_asset0) + .asset(sent_asset2) + .attachments(attachments.iter().cloned()) + .note_type(NoteType::Public) + .generate_serial_number(&mut rng) + .build()? + .into(); let partial_note = PartialNote::from(p2id_note.clone()); let expiration_delta = NonZeroU16::new(10).expect("10 is non-zero"); From 22af944f1cb3fa4f4dc8c7a7d3b448ecb0fbebc7 Mon Sep 17 00:00:00 2001 From: Vaibhav Jindal Date: Tue, 23 Jun 2026 09:45:13 +0530 Subject: [PATCH 2/5] docs(standards): address P2ID builder review comments - Drop the builder usage description from `P2idNote::new` docs; the typestate builder is self-documenting. - Trim redundant tails from the builder extension method docs. - Remove the "Use P2ANY ..." rationalization comments across the kernel tests and the P2ANY reference in the `setup_test` doc comment. - Assert the note type against `NoteType::default()` instead of a hardcoded `NoteType::Private` in the minimal-builder test. - Add a `compile_fail` doctest showing `.serial_number()` and `.generate_serial_number()` are mutually exclusive at compile time. --- crates/miden-standards/src/note/p2id.rs | 38 +++++++++++++------ .../src/kernel_tests/batch/proposed_batch.rs | 1 - .../block/proposed_block_errors.rs | 1 - .../block/proposed_block_success.rs | 1 - .../miden-testing/src/kernel_tests/tx/mod.rs | 4 +- 5 files changed, 27 insertions(+), 18 deletions(-) diff --git a/crates/miden-standards/src/note/p2id.rs b/crates/miden-standards/src/note/p2id.rs index fd78650432..f510cd9177 100644 --- a/crates/miden-standards/src/note/p2id.rs +++ b/crates/miden-standards/src/note/p2id.rs @@ -60,11 +60,6 @@ pub struct P2idNote { impl P2idNote { /// Builds a new [`P2idNote`]. /// - /// Set the recipient with `.target(account_id)`, add assets with `.asset()` / `.assets()` - /// (at least one is required), and optionally add attachments with `.attachment()`. The note - /// type defaults to [`NoteType::Private`]. The serial number can be set explicitly with - /// `.serial_number(word)` or drawn from an RNG with `.generate_serial_number(rng)`. - /// /// # Errors /// /// Returns an error if: @@ -159,27 +154,25 @@ impl P2idNote { // ================================================================================================ impl P2idNoteBuilder { - /// Adds a single asset to the note. At least one asset is required for `.build()` to succeed; - /// this can be called multiple times to add several assets. + /// Adds a single asset to the note. At least one asset is required for `.build()` to succeed. pub fn asset(mut self, asset: impl Into) -> Self { self.assets.push(asset.into()); self } - /// Adds multiple assets to the note. Can be combined freely with [`Self::asset`]. + /// Adds multiple assets to the note. pub fn assets(mut self, assets: impl IntoIterator>) -> Self { self.assets.extend(assets.into_iter().map(Into::into)); self } - /// Adds a single attachment to the note. Can be called multiple times to add several - /// attachments. + /// Adds a single attachment to the note. pub fn attachment(mut self, attachment: impl Into) -> Self { self.attachments.push(attachment.into()); self } - /// Adds multiple attachments to the note. Can be combined freely with [`Self::attachment`]. + /// Adds multiple attachments to the note. pub fn attachments( mut self, attachments: impl IntoIterator>, @@ -194,6 +187,27 @@ where S::SerialNumber: p2id_note_builder::IsUnset, { /// Draws a serial number from `rng` and sets it on the builder. + /// + /// This and `serial_number` are mutually exclusive: the builder's typestate rejects setting + /// the serial number twice at compile time. + /// + /// ```compile_fail + /// # #[allow(dead_code)] + /// # fn demo( + /// # sender: miden_protocol::account::AccountId, + /// # target: miden_protocol::account::AccountId, + /// # rng: &mut impl miden_protocol::crypto::rand::FeltRng, + /// # ) { + /// use miden_protocol::Word; + /// use miden_standards::note::P2idNote; + /// + /// let _ = P2idNote::builder() + /// .sender(sender) + /// .target(target) + /// .serial_number(Word::empty()) + /// .generate_serial_number(rng); // serial number already set: compile error + /// # } + /// ``` pub fn generate_serial_number( self, rng: &mut impl FeltRng, @@ -367,7 +381,7 @@ mod tests { assert_eq!(note.sender(), sender()); assert_eq!(note.target(), target()); - assert_eq!(note.note_type(), NoteType::Private); + assert_eq!(note.note_type(), NoteType::default()); assert_eq!(note.assets().num_assets(), 1); assert_eq!(note.attachments().num_attachments(), 0); } diff --git a/crates/miden-testing/src/kernel_tests/batch/proposed_batch.rs b/crates/miden-testing/src/kernel_tests/batch/proposed_batch.rs index c55ec44424..62a3fc4dac 100644 --- a/crates/miden-testing/src/kernel_tests/batch/proposed_batch.rs +++ b/crates/miden-testing/src/kernel_tests/batch/proposed_batch.rs @@ -67,7 +67,6 @@ pub fn setup_chain() -> TestSetup { let mut builder = MockChain::builder(); let account1 = generate_account(&mut builder); let account2 = generate_account(&mut builder); - // Use P2ANY: a P2ID note must carry at least one asset. let note1 = builder .add_p2any_note(account1.id(), NoteType::Public, []) .expect("adding p2any note1 should work"); diff --git a/crates/miden-testing/src/kernel_tests/block/proposed_block_errors.rs b/crates/miden-testing/src/kernel_tests/block/proposed_block_errors.rs index f7513690a2..0976475b56 100644 --- a/crates/miden-testing/src/kernel_tests/block/proposed_block_errors.rs +++ b/crates/miden-testing/src/kernel_tests/block/proposed_block_errors.rs @@ -351,7 +351,6 @@ async fn proposed_block_fails_on_invalid_proof_or_missing_note_inclusion_referen let mut builder = MockChain::builder(); let account0 = builder.add_existing_mock_account(Auth::IncrNonce)?; let account1 = builder.add_existing_mock_account(Auth::IncrNonce)?; - // Use P2ANY: a P2ID note must carry at least one asset. let p2id_note = create_p2any_note(account0.id(), NoteType::Private, [], builder.rng_mut()); let spawn_note = builder.add_spawn_note([&p2id_note])?; let mut chain = builder.build()?; diff --git a/crates/miden-testing/src/kernel_tests/block/proposed_block_success.rs b/crates/miden-testing/src/kernel_tests/block/proposed_block_success.rs index 0959df3f03..03a8ed3b23 100644 --- a/crates/miden-testing/src/kernel_tests/block/proposed_block_success.rs +++ b/crates/miden-testing/src/kernel_tests/block/proposed_block_success.rs @@ -189,7 +189,6 @@ async fn proposed_block_authenticating_unauthenticated_notes() -> anyhow::Result let mut builder = MockChain::builder(); let account0 = builder.add_existing_mock_account(Auth::IncrNonce)?; let account1 = builder.add_existing_mock_account(Auth::IncrNonce)?; - // Use P2ANY: a P2ID note must carry at least one asset. let note0 = builder.add_p2any_note(sender_id, NoteType::Private, [])?; let note1 = builder.add_p2any_note(sender_id, NoteType::Public, [])?; let chain = builder.build()?; diff --git a/crates/miden-testing/src/kernel_tests/tx/mod.rs b/crates/miden-testing/src/kernel_tests/tx/mod.rs index cd0e4bb967..cf8f843c3e 100644 --- a/crates/miden-testing/src/kernel_tests/tx/mod.rs +++ b/crates/miden-testing/src/kernel_tests/tx/mod.rs @@ -106,8 +106,7 @@ struct TestSetup { p2id_note_2_assets: Note, } -/// Return a [`TestSetup`] whose notes contain 0, 1 and 2 assets respectively. The 0-asset note is -/// a P2ANY note, since P2ID notes must carry at least one asset. +/// Return a [`TestSetup`] whose notes contain 0, 1 and 2 assets respectively. fn setup_test() -> anyhow::Result { let mut builder = MockChain::builder(); @@ -145,7 +144,6 @@ fn setup_test() -> anyhow::Result { )?; // Notes - // Use P2ANY: a P2ID note must carry at least one asset. let p2any_note_0_assets = builder.add_p2any_note(ACCOUNT_ID_SENDER.try_into().unwrap(), NoteType::Public, [])?; let p2id_note_1_asset = builder.add_p2id_note( From b622351222def998e82530309874b843c192051d Mon Sep 17 00:00:00 2001 From: Vaibhav Jindal Date: Tue, 23 Jun 2026 10:11:31 +0530 Subject: [PATCH 3/5] docs(standards): drop the dual-serial compile_fail doctest Per review feedback, remove the `compile_fail` doctest (and its explanation) on `generate_serial_number`; the typestate already enforces that the serial number cannot be set twice. --- crates/miden-standards/src/note/p2id.rs | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/crates/miden-standards/src/note/p2id.rs b/crates/miden-standards/src/note/p2id.rs index f510cd9177..c171e53fcf 100644 --- a/crates/miden-standards/src/note/p2id.rs +++ b/crates/miden-standards/src/note/p2id.rs @@ -187,27 +187,6 @@ where S::SerialNumber: p2id_note_builder::IsUnset, { /// Draws a serial number from `rng` and sets it on the builder. - /// - /// This and `serial_number` are mutually exclusive: the builder's typestate rejects setting - /// the serial number twice at compile time. - /// - /// ```compile_fail - /// # #[allow(dead_code)] - /// # fn demo( - /// # sender: miden_protocol::account::AccountId, - /// # target: miden_protocol::account::AccountId, - /// # rng: &mut impl miden_protocol::crypto::rand::FeltRng, - /// # ) { - /// use miden_protocol::Word; - /// use miden_standards::note::P2idNote; - /// - /// let _ = P2idNote::builder() - /// .sender(sender) - /// .target(target) - /// .serial_number(Word::empty()) - /// .generate_serial_number(rng); // serial number already set: compile error - /// # } - /// ``` pub fn generate_serial_number( self, rng: &mut impl FeltRng, From 104ac301698460f52bdb098799e5b2d4e1e21928 Mon Sep 17 00:00:00 2001 From: Vaibhav Jindal Date: Thu, 25 Jun 2026 01:00:09 +0530 Subject: [PATCH 4/5] fix(standards): address #3126 review feedback - Use `NoteError::other` instead of adding a dedicated `MissingAsset` variant to the protocol crate; the "at least one asset" rule is a standards concern. - Remove the hand-rolled `create_p2id_note_exact` helper and inline the builder (with `.serial_number()`) at all 9 call sites. - Drop the low-value `builder_generates_serial_number` and `into_note_preserves_assets` tests; exercise `generate_serial_number` inside `builder_accumulates_assets` instead. - Remove the 5 duplicate CHANGELOG entries the rebase re-inserted. --- CHANGELOG.md | 8 +- crates/miden-protocol/src/errors/mod.rs | 2 - crates/miden-standards/src/note/p2id.rs | 43 +------ crates/miden-testing/src/utils.rs | 22 +--- .../miden-testing/tests/agglayer/bridge_in.rs | 39 ++++--- crates/miden-testing/tests/scripts/faucet.rs | 105 ++++++++++-------- crates/miden-testing/tests/scripts/swap.rs | 20 ++-- 7 files changed, 98 insertions(+), 141 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fd3a8a0709..eac8622c1b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,13 +3,7 @@ ## v0.16.0 (TBD) ### Changes -- [BREAKING] Replaced the `P2idNote` marker type and its `P2idNote::create` factory with a `P2idNote` struct built via a `bon` typestate builder (`P2idNote::builder()`). P2ID notes must now carry at least one asset (new `NoteError::MissingAsset`); a `P2idNote` converts into a `Note` via `Note::from`, and the builder offers `.asset()`/`.assets()`, `.attachment()`/`.attachments()`, and `.generate_serial_number()` ([#2283](https://github.com/0xMiden/protocol/issues/2283)). -- Fixed misleading documentation in the faucet and transfer policy procedures ([#3119](https://github.com/0xMiden/protocol/pull/3119)). -- [BREAKING] Removed the automatic fee computation and removal from the transaction kernel ([#3108](https://github.com/0xMiden/protocol/issues/3108)). -- Simplified the Ownable2Step owner-check API: merged the owner assertion into a single `exec` `assert_sender_is_owner` and renamed `is_sender_owner_internal` to `is_sender_owner` ([#3088](https://github.com/0xMiden/protocol/pull/3088)). -- [BREAKING] Renamed the `miden-tx-batch-prover` crate to `miden-tx-batch` ([#3035](https://github.com/0xMiden/protocol/pull/3035)). -- Added a skeleton batch kernel ([#1122](https://github.com/0xMiden/protocol/issues/1122)) wired through `LocalBatchProver::prove` and attached to `ProvenBatch` as an `ExecutionProof`. It does not yet perform any verification. - +- [BREAKING] Replaced the `P2idNote` marker type and its `P2idNote::create` factory with a `P2idNote` struct built via a `bon` typestate builder (`P2idNote::builder()`). P2ID notes must now carry at least one asset; a `P2idNote` converts into a `Note` via `Note::from`, and the builder offers `.asset()`/`.assets()`, `.attachment()`/`.attachments()`, and `.generate_serial_number()` ([#2283](https://github.com/0xMiden/protocol/issues/2283)). - Added a skeleton batch kernel ([#1122](https://github.com/0xMiden/protocol/issues/1122)) wired through `LocalBatchProver::prove` and attached to `ProvenBatch` as an `ExecutionProof`. It does not yet perform any verification. - [BREAKING] Renamed `AccountStorageDelta` to `AccountStoragePatch` ([#3002](https://github.com/0xMiden/protocol/pull/3002)). - [BREAKING] Replaced the per-tree account and nullifier backend traits with shared `SmtBackend` and `SmtBackendReader` traits, split into read-only and read-write capabilities, enabling read-only `LargeSmt`-backed tree views via `reader()` ([#2755](https://github.com/0xMiden/protocol/pull/2755), [#3009](https://github.com/0xMiden/protocol/pull/3009)). diff --git a/crates/miden-protocol/src/errors/mod.rs b/crates/miden-protocol/src/errors/mod.rs index 49d8d809e4..da63392796 100644 --- a/crates/miden-protocol/src/errors/mod.rs +++ b/crates/miden-protocol/src/errors/mod.rs @@ -736,8 +736,6 @@ pub enum NoteError { NoteScriptAssemblyError(Report), #[error("failed to deserialize note script")] NoteScriptDeserializationError(#[source] DeserializationError), - #[error("note must contain at least one asset")] - MissingAsset, #[error("note contains {0} assets which exceeds the maximum of {max}", max = NoteAssets::MAX_NUM_ASSETS)] TooManyAssets(usize), #[error("note contains {0} storage items which exceeds the maximum of {max}", max = MAX_NOTE_STORAGE_ITEMS)] diff --git a/crates/miden-standards/src/note/p2id.rs b/crates/miden-standards/src/note/p2id.rs index c171e53fcf..060c582f7a 100644 --- a/crates/miden-standards/src/note/p2id.rs +++ b/crates/miden-standards/src/note/p2id.rs @@ -63,7 +63,7 @@ impl P2idNote { /// # Errors /// /// Returns an error if: - /// - No assets were provided ([`NoteError::MissingAsset`]). + /// - No assets were provided. /// - The assets or attachments exceed their protocol limits (see [`NoteAssets::new`] and /// [`NoteAttachments::new`]). #[builder] @@ -77,7 +77,7 @@ impl P2idNote { #[builder(default)] note_type: NoteType, ) -> Result { if assets.is_empty() { - return Err(NoteError::MissingAsset); + return Err(NoteError::other("a P2ID note must contain at least one asset")); } let assets = NoteAssets::new(assets)?; @@ -368,16 +368,18 @@ mod tests { /// `.asset()` and `.assets()` both append, so they can be combined and called repeatedly. #[test] fn builder_accumulates_assets() { + let mut rng = RandomCoin::new(Word::empty()); let note = P2idNote::builder() .sender(sender()) .target(target()) - .serial_number(Word::empty()) .asset(FungibleAsset::new(faucet_a(), 100).unwrap()) .assets([Asset::from(FungibleAsset::new(faucet_b(), 200).unwrap())]) + .generate_serial_number(&mut rng) .build() .unwrap(); assert_eq!(note.assets().num_assets(), 2); + assert_ne!(note.serial_number(), Word::empty()); } /// A P2ID note must carry at least one asset. @@ -390,39 +392,6 @@ mod tests { .build() .expect_err("a note without assets must be rejected"); - assert!(matches!(err, NoteError::MissingAsset)); - } - - /// `.generate_serial_number()` draws the serial from the RNG. - #[test] - fn builder_generates_serial_number() { - let mut rng = RandomCoin::new(Word::empty()); - let note = P2idNote::builder() - .sender(sender()) - .target(target()) - .asset(FungibleAsset::new(faucet_a(), 1).unwrap()) - .generate_serial_number(&mut rng) - .build() - .unwrap(); - - assert_ne!(note.serial_number(), Word::empty()); - } - - /// `Note::from(p2id_note)` is infallible and preserves the assets. - #[test] - fn into_note_preserves_assets() { - let p2id_note = P2idNote::builder() - .sender(sender()) - .target(target()) - .serial_number(Word::empty()) - .asset(FungibleAsset::new(faucet_a(), 42).unwrap()) - .note_type(NoteType::Public) - .build() - .unwrap(); - - let assets = p2id_note.assets().clone(); - let note = Note::from(p2id_note); - - assert_eq!(note.assets(), &assets); + assert!(matches!(err, NoteError::Other { .. })); } } diff --git a/crates/miden-testing/src/utils.rs b/crates/miden-testing/src/utils.rs index 7fb9126976..91d6859ded 100644 --- a/crates/miden-testing/src/utils.rs +++ b/crates/miden-testing/src/utils.rs @@ -6,11 +6,9 @@ use miden_protocol::Word; use miden_protocol::account::AccountId; use miden_protocol::asset::Asset; use miden_protocol::crypto::rand::FeltRng; -use miden_protocol::errors::NoteError; -use miden_protocol::note::{Note, NoteAssets, NoteTag, NoteType, PartialNoteMetadata}; +use miden_protocol::note::{Note, NoteType}; use miden_protocol::vm::AdviceMap; use miden_standards::code_builder::CodeBuilder; -use miden_standards::note::P2idNoteStorage; use miden_standards::testing::note::NoteBuilder; use rand::SeedableRng; use rand::rngs::SmallRng; @@ -322,21 +320,3 @@ fn note_script_that_creates_notes<'note>( Ok((out, advice_map)) } - -/// Generates a P2ID note - Pay-to-ID note with an exact serial number -pub fn create_p2id_note_exact( - sender: AccountId, - target: AccountId, - assets: Vec, - note_type: NoteType, - serial_num: Word, -) -> Result { - let recipient = P2idNoteStorage::new(target).into_recipient(serial_num); - - let tag = NoteTag::with_account_target(target); - - let metadata = PartialNoteMetadata::new(sender, note_type).with_tag(tag); - let vault = NoteAssets::new(assets)?; - - Ok(Note::new(vault, metadata, recipient)) -} diff --git a/crates/miden-testing/tests/agglayer/bridge_in.rs b/crates/miden-testing/tests/agglayer/bridge_in.rs index 90d8a9e8c0..1882475f62 100644 --- a/crates/miden-testing/tests/agglayer/bridge_in.rs +++ b/crates/miden-testing/tests/agglayer/bridge_in.rs @@ -34,7 +34,7 @@ use miden_protocol::account::{Account, AccountId, AccountIdVersion, AccountType} use miden_protocol::asset::{Asset, AssetAmount, AssetCallbackFlag, FungibleAsset}; use miden_protocol::crypto::SequentialCommit; use miden_protocol::crypto::rand::FeltRng; -use miden_protocol::note::{NoteAssets, NoteType}; +use miden_protocol::note::{Note, NoteAssets, NoteType}; use miden_protocol::transaction::RawOutputNote; use miden_standards::account::policies::MintPolicy; use miden_standards::account::wallets::BasicWallet; @@ -43,7 +43,6 @@ use miden_standards::errors::standards::ERR_FUNGIBLE_MINT_NOTE_ASSET_NOT_FROM_TH use miden_standards::note::P2idNote; use miden_standards::testing::account_component::IncrNonceAuthComponent; use miden_standards::testing::mock_account::MockAccountExt; -use miden_testing::utils::create_p2id_note_exact; use miden_testing::{ AccountState, Auth, @@ -383,14 +382,16 @@ async fn test_bridge_in_claim_to_p2id(#[case] data_source: ClaimDataSource) -> a .unwrap() .with_callbacks(AssetCallbackFlag::Enabled) .into(); - let expected_output_p2id_note = create_p2id_note_exact( - agglayer_faucet.id(), - destination_account_id, - vec![expected_asset], - NoteType::Public, - serial_num, - ) - .unwrap(); + let expected_output_p2id_note = Note::from( + P2idNote::builder() + .sender(agglayer_faucet.id()) + .target(destination_account_id) + .assets(vec![expected_asset]) + .note_type(NoteType::Public) + .serial_number(serial_num) + .build() + .unwrap(), + ); assert_eq!(RawOutputNote::Full(expected_output_p2id_note.clone()), *output_note); @@ -1307,14 +1308,16 @@ async fn bridge_in_unlock_native_token() -> anyhow::Result<()> { // Cross-check storage directly: it should encode the destination account ID the same way // `P2idNoteStorage::from` does ([suffix, prefix]). - let expected_p2id_note = create_p2id_note_exact( - bridge_account.id(), - destination_account_id, - vec![expected_asset], - NoteType::Public, - serial_num, - ) - .unwrap(); + let expected_p2id_note = Note::from( + P2idNote::builder() + .sender(bridge_account.id()) + .target(destination_account_id) + .assets(vec![expected_asset]) + .note_type(NoteType::Public) + .serial_number(serial_num) + .build() + .unwrap(), + ); let actual_storage = output_note.recipient().storage(); let expected_storage = expected_p2id_note.recipient().storage(); assert_eq!( diff --git a/crates/miden-testing/tests/scripts/faucet.rs b/crates/miden-testing/tests/scripts/faucet.rs index 8a11e69f99..17106b49d8 100644 --- a/crates/miden-testing/tests/scripts/faucet.rs +++ b/crates/miden-testing/tests/scripts/faucet.rs @@ -54,9 +54,8 @@ use miden_standards::errors::standards::{ ERR_MINT_POLICY_ROOT_NOT_ALLOWED, ERR_SENDER_NOT_OWNER, }; -use miden_standards::note::{BurnNote, MintNote, MintNoteStorage, StandardNote}; +use miden_standards::note::{BurnNote, MintNote, MintNoteStorage, P2idNote, StandardNote}; use miden_standards::testing::note::NoteBuilder; -use miden_testing::utils::create_p2id_note_exact; use miden_testing::{ AccountState, Auth, @@ -914,14 +913,16 @@ async fn network_faucet_mint() -> anyhow::Result<()> { let serial_num = Word::default(); let output_note_tag = NoteTag::with_account_target(target_account.id()); - let p2id_mint_output_note = create_p2id_note_exact( - faucet.id(), - target_account.id(), - vec![mint_asset.into()], - NoteType::Private, - serial_num, - ) - .unwrap(); + let p2id_mint_output_note = Note::from( + P2idNote::builder() + .sender(faucet.id()) + .target(target_account.id()) + .assets(vec![mint_asset]) + .note_type(NoteType::Private) + .serial_number(serial_num) + .build() + .unwrap(), + ); let recipient = p2id_mint_output_note.recipient().digest(); // Create the MINT note using the helper function @@ -1011,13 +1012,15 @@ async fn test_network_faucet_owner_can_mint() -> anyhow::Result<()> { .with_callbacks(AssetCallbackFlag::Enabled); let output_note_tag = NoteTag::with_account_target(target_account.id()); - let p2id_note = create_p2id_note_exact( - faucet.id(), - target_account.id(), - vec![mint_asset.into()], - NoteType::Private, - Word::default(), - )?; + let p2id_note = Note::from( + P2idNote::builder() + .sender(faucet.id()) + .target(target_account.id()) + .assets(vec![mint_asset]) + .note_type(NoteType::Private) + .serial_number(Word::default()) + .build()?, + ); let recipient = p2id_note.recipient().digest(); let mint_inputs = MintNoteStorage::new_private(recipient, mint_asset, output_note_tag.into()); @@ -1193,13 +1196,15 @@ async fn test_network_faucet_non_owner_cannot_mint() -> anyhow::Result<()> { .with_callbacks(AssetCallbackFlag::Enabled); let output_note_tag = NoteTag::with_account_target(target_account.id()); - let p2id_note = create_p2id_note_exact( - faucet.id(), - target_account.id(), - vec![mint_asset.into()], - NoteType::Private, - Word::default(), - )?; + let p2id_note = Note::from( + P2idNote::builder() + .sender(faucet.id()) + .target(target_account.id()) + .assets(vec![mint_asset]) + .note_type(NoteType::Private) + .serial_number(Word::default()) + .build()?, + ); let recipient = p2id_note.recipient().digest(); let mint_inputs = MintNoteStorage::new_private(recipient, mint_asset, output_note_tag.into()); @@ -1319,13 +1324,15 @@ async fn test_network_faucet_transfer_ownership() -> anyhow::Result<()> { .with_callbacks(AssetCallbackFlag::Enabled); let output_note_tag = NoteTag::with_account_target(target_account.id()); - let p2id_note = create_p2id_note_exact( - faucet.id(), - target_account.id(), - vec![mint_asset.into()], - NoteType::Private, - Word::default(), - )?; + let p2id_note = Note::from( + P2idNote::builder() + .sender(faucet.id()) + .target(target_account.id()) + .assets(vec![mint_asset]) + .note_type(NoteType::Private) + .serial_number(Word::default()) + .build()?, + ); let recipient = p2id_note.recipient().digest(); // Sanity Check: Prove that the initial owner can mint assets @@ -2147,14 +2154,16 @@ async fn test_mint_note_output_note_types(#[case] note_type: NoteType) -> anyhow let serial_num = Word::from([1, 2, 3, 4u32]); // Create the expected P2ID output note - let p2id_mint_output_note = create_p2id_note_exact( - faucet.id(), - target_account.id(), - vec![mint_asset.into()], - note_type, - serial_num, - ) - .unwrap(); + let p2id_mint_output_note = Note::from( + P2idNote::builder() + .sender(faucet.id()) + .target(target_account.id()) + .assets(vec![mint_asset]) + .note_type(note_type) + .serial_number(serial_num) + .build() + .unwrap(), + ); // Create MINT note based on note type let mint_storage = match note_type { @@ -2428,14 +2437,16 @@ async fn network_faucet_mint_with_blocklist() -> anyhow::Result<()> { let serial_num = Word::default(); let output_note_tag = NoteTag::with_account_target(target_account.id()); - let p2id_mint_output_note = create_p2id_note_exact( - faucet.id(), - target_account.id(), - vec![mint_asset.into()], - NoteType::Private, - serial_num, - ) - .unwrap(); + let p2id_mint_output_note = Note::from( + P2idNote::builder() + .sender(faucet.id()) + .target(target_account.id()) + .assets(vec![mint_asset]) + .note_type(NoteType::Private) + .serial_number(serial_num) + .build() + .unwrap(), + ); let recipient = p2id_mint_output_note.recipient().digest(); let mint_storage = MintNoteStorage::new_private(recipient, mint_asset, output_note_tag.into()); diff --git a/crates/miden-testing/tests/scripts/swap.rs b/crates/miden-testing/tests/scripts/swap.rs index 72a980ac50..3cfd1ff288 100644 --- a/crates/miden-testing/tests/scripts/swap.rs +++ b/crates/miden-testing/tests/scripts/swap.rs @@ -11,7 +11,7 @@ use miden_protocol::testing::account_id::{ }; use miden_protocol::transaction::RawOutputNote; use miden_standards::code_builder::CodeBuilder; -use miden_testing::utils::create_p2id_note_exact; +use miden_standards::note::P2idNote; use miden_testing::{Auth, MockChain}; use crate::prove_and_verify_transaction; @@ -182,14 +182,16 @@ async fn consume_swap_note_public_payback_note() -> anyhow::Result<()> { // When consuming a SWAP note with a public payback note output // it is necessary to add the details of the public note to the advice provider // via `.extend_expected_output_notes()` - let payback_p2id_note = create_p2id_note_exact( - target_account.id(), - sender_account.id(), - vec![requested_asset], - payback_note_type, - payback_note.serial_num(), - ) - .unwrap(); + let payback_p2id_note = Note::from( + P2idNote::builder() + .sender(target_account.id()) + .target(sender_account.id()) + .assets(vec![requested_asset]) + .note_type(payback_note_type) + .serial_number(payback_note.serial_num()) + .build() + .unwrap(), + ); let consume_swap_note_tx = mock_chain .build_tx_context(target_account.id(), &[swap_note.id()], &[]) From 7dd36d7ffc6df4ebdbf29a8b675858a0bf389b0f Mon Sep 17 00:00:00 2001 From: Vaibhav Jindal Date: Thu, 25 Jun 2026 09:36:37 +0530 Subject: [PATCH 5/5] fix(testing): remove unused `Word` import Left over from removing `create_p2id_note_exact`; clippy (-D warnings) flagged it. --- crates/miden-testing/src/utils.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/miden-testing/src/utils.rs b/crates/miden-testing/src/utils.rs index 91d6859ded..405011ee1e 100644 --- a/crates/miden-testing/src/utils.rs +++ b/crates/miden-testing/src/utils.rs @@ -2,7 +2,6 @@ use alloc::string::String; use alloc::vec::Vec; use miden_processor::crypto::random::RandomCoin; -use miden_protocol::Word; use miden_protocol::account::AccountId; use miden_protocol::asset::Asset; use miden_protocol::crypto::rand::FeltRng;