Skip to content

Comments

feat: add .is_network_note() helper method for Note#2365

Open
partylikeits1983 wants to merge 8 commits intonextfrom
ajl-network-note-newtype
Open

feat: add .is_network_note() helper method for Note#2365
partylikeits1983 wants to merge 8 commits intonextfrom
ajl-network-note-newtype

Conversation

@partylikeits1983
Copy link
Contributor

This PR adds a new NetworkNote type which makes it easy to determine if a Note is a network note or not.

Resolves: #2362

@partylikeits1983 partylikeits1983 force-pushed the ajl-network-note-newtype branch from 3b1b042 to c1aea73 Compare January 29, 2026 01:03
@partylikeits1983 partylikeits1983 marked this pull request as ready for review January 29, 2026 01:05
Comment on lines 6 to 12
/// A view over a [`Note`] that is guaranteed to target a network account via a
/// [`NetworkAccountTarget`] attachment.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct NetworkNote<'a> {
note: &'a Note,
target: NetworkAccountTarget,
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This basically defines "network note = note targeted at a network account". This is fine, but the definition may also be too narrow. E.g. in the future network notes could also include SWAP notes that are not targeted but can still be consumed by network accounts. So, I think it would be good to reflect this in the name, e.g. NetworkAccountTargetNote or AccountTargetNetworkNote. The node terms this SingleTargetNetworkNote which may also be fine.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a good idea, however for now, I kept NetworkNote for API simplicity since we don't have these multi-targeted network notes just yet. I added docs clarifying it's specifically for account-targeted notes. We can introduce more specific types later if needed for SWAP notes or other network note variants. What do you think, can we keep NetworkNote as is, or should we add the AccountTargetNetworkNote as you suggested now, or leave this for a later PR?

My goal with this PR is just to have a super simple method for seeing if a given Note is a network note or not.

Like this:

let is_network_note: bool = note.is_network_note();

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My goal with this PR is just to have a super simple method for seeing if a given Note is a network note or not.

Yes, that's completely fair, and I don't want to make it more complicated than it needs to be. As we're nearing a 1.0 release, in my mind, and I could be misguided, it's worth thinking about whether this structure will still be accurate in 6-12 months when we can't do a refactor of this type anymore and when we may have introduced the concept of a "multi-target network note". Then, having NetworkNote (representing singel target notes) and MultiTargetNetworkNote will be an inconsistent API. Because of that, I still think the NetworkNote type is named too generically, since it does not and cannot represent any network note, just "single target" ones.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense! I updated the naming to AccountTargetNetworkNote

@partylikeits1983 partylikeits1983 marked this pull request as draft January 29, 2026 15:07
@mmagician mmagician added the pr-from-maintainers PRs that come from internal contributors or integration partners. They should be given priority label Feb 9, 2026
@partylikeits1983 partylikeits1983 marked this pull request as ready for review February 18, 2026 21:46
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a new AccountTargetNetworkNote type and NetworkNoteExt trait to make it easier to determine if a Note is a network note and to access network-specific properties. This addresses issue #2362 by providing a cleaner, more discoverable API compared to the previous approach of using NetworkAccountTarget::try_from(note.metadata().attachment()).

Changes:

  • Added AccountTargetNetworkNote<'a> struct providing a view over notes with NetworkAccountTarget attachments
  • Added NetworkNoteExt trait with is_network_note() and as_account_target_network_note() convenience methods
  • Added integration test test_network_note_unwrap() verifying the new API works correctly

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.

File Description
crates/miden-standards/src/note/network_note.rs New module defining AccountTargetNetworkNote struct and NetworkNoteExt trait for working with network notes
crates/miden-standards/src/note/mod.rs Exports the new AccountTargetNetworkNote and NetworkNoteExt types
crates/miden-testing/src/kernel_tests/tx/test_output_note.rs Adds integration test verifying the new network note API
CHANGELOG.md Documents the addition of the NetworkNote type in release 0.14.0

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +37 to +56
/// Returns the target network [`AccountId`].
pub fn target_account_id(&self) -> AccountId {
self.target().target_id()
}

/// Returns the decoded [`NetworkAccountTarget`] attachment.
pub fn target(&self) -> NetworkAccountTarget {
NetworkAccountTarget::try_from(self.note.metadata().attachment())
.expect("AccountTargetNetworkNote guarantees valid NetworkAccountTarget attachment")
}

/// Returns the raw [`NoteAttachment`] from the note metadata.
pub fn attachment(&self) -> &NoteAttachment {
self.metadata().attachment()
}

/// Returns the [`NoteType`] of the underlying note.
pub fn note_type(&self) -> NoteType {
self.metadata().note_type()
}
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding an execution_hint() accessor method to AccountTargetNetworkNote for consistency and convenience. While users can access it via network_note.target().execution_hint(), having a direct accessor like network_note.execution_hint() would match the pattern established with target_account_id() and provide a more convenient API. The NetworkAccountTarget already has an execution_hint() method that could be exposed here.

Copilot uses AI. Check for mistakes.

Ok(())
}

Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test test_network_note_unwrap only verifies the positive case where a note has a valid NetworkAccountTarget attachment. Consider also testing the negative cases where:

  1. A note without a NetworkAccountTarget attachment (e.g., a regular P2ID note) returns false for is_network_note()
  2. as_account_target_network_note() returns an appropriate error for non-network notes

This would provide more comprehensive coverage of the new API and ensure it correctly distinguishes between network and non-network notes.

Suggested change
#[tokio::test]
async fn test_non_network_note_is_not_marked_as_network() -> anyhow::Result<()> {
let sender = Account::mock(ACCOUNT_ID_PRIVATE_FUNGIBLE_FAUCET, Auth::IncrNonce);
let mut rng = RpoRandomCoin::new(Word::from([4, 3, 2, 1u32]));
// Build a regular note without a NetworkAccountTarget attachment.
let note = NoteBuilder::new(sender.id(), &mut rng)
.note_type(NoteType::Public)
.build()?;
assert!(!note.is_network_note());
Ok(())
}
#[tokio::test]
async fn test_non_network_note_unwrap_returns_error() -> anyhow::Result<()> {
let sender = Account::mock(ACCOUNT_ID_PRIVATE_FUNGIBLE_FAUCET, Auth::IncrNonce);
let mut rng = RpoRandomCoin::new(Word::from([5, 6, 7, 8u32]));
// Build a regular note without a NetworkAccountTarget attachment.
let note = NoteBuilder::new(sender.id(), &mut rng)
.note_type(NoteType::Public)
.build()?;
let result = note.as_account_target_network_note();
assert!(result.is_err());
Ok(())
}

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +89
use miden_protocol::account::AccountId;
use miden_protocol::note::{Note, NoteAttachment, NoteMetadata, NoteType};

use crate::note::{NetworkAccountTarget, NetworkAccountTargetError};

/// A view over a [`Note`] that is guaranteed to target a network account via a
/// [`NetworkAccountTarget`] attachment.
///
/// This represents a note that is specifically targeted at a single network account. In the future,
/// other types of network notes may exist (e.g., SWAP notes that can be consumed by network
/// accounts but are not targeted at a specific one).
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct AccountTargetNetworkNote<'a> {
note: &'a Note,
}

impl<'a> AccountTargetNetworkNote<'a> {
/// Attempts to construct an [`AccountTargetNetworkNote`] view over `note`.
///
/// Returns an error if the note's attachment cannot be decoded as a [`NetworkAccountTarget`].
pub fn new(note: &'a Note) -> Result<Self, NetworkAccountTargetError> {
// Validate that the attachment is a valid NetworkAccountTarget
NetworkAccountTarget::try_from(note.metadata().attachment())?;
Ok(Self { note })
}

/// Returns the underlying [`Note`].
pub fn as_note(&self) -> &'a Note {
self.note
}

/// Returns the [`NoteMetadata`] of the underlying note.
pub fn metadata(&self) -> &NoteMetadata {
self.note.metadata()
}

/// Returns the target network [`AccountId`].
pub fn target_account_id(&self) -> AccountId {
self.target().target_id()
}

/// Returns the decoded [`NetworkAccountTarget`] attachment.
pub fn target(&self) -> NetworkAccountTarget {
NetworkAccountTarget::try_from(self.note.metadata().attachment())
.expect("AccountTargetNetworkNote guarantees valid NetworkAccountTarget attachment")
}

/// Returns the raw [`NoteAttachment`] from the note metadata.
pub fn attachment(&self) -> &NoteAttachment {
self.metadata().attachment()
}

/// Returns the [`NoteType`] of the underlying note.
pub fn note_type(&self) -> NoteType {
self.metadata().note_type()
}
}

/// Convenience helpers for [`Note`]s that may target a network account.
pub trait NetworkNoteExt {
/// Returns `true` if this note's attachment decodes as a [`NetworkAccountTarget`].
fn is_network_note(&self) -> bool;

/// Returns an [`AccountTargetNetworkNote`] view, or an error if the attachment is not a valid
/// target.
fn as_account_target_network_note(
&self,
) -> Result<AccountTargetNetworkNote<'_>, NetworkAccountTargetError>;
}

impl NetworkNoteExt for Note {
fn is_network_note(&self) -> bool {
NetworkAccountTarget::try_from(self.metadata().attachment()).is_ok()
}

fn as_account_target_network_note(
&self,
) -> Result<AccountTargetNetworkNote<'_>, NetworkAccountTargetError> {
AccountTargetNetworkNote::new(self)
}
}

impl<'a> TryFrom<&'a Note> for AccountTargetNetworkNote<'a> {
type Error = NetworkAccountTargetError;

fn try_from(note: &'a Note) -> Result<Self, Self::Error> {
Self::new(note)
}
}
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The network_note.rs module lacks unit tests. Similar modules in this crate (such as network_account_target.rs, p2id.rs, p2ide.rs, and swap.rs) all include unit tests under a #[cfg(test)] section to validate their functionality. Consider adding unit tests that verify:

  1. AccountTargetNetworkNote::new() succeeds when given a note with a valid NetworkAccountTarget attachment
  2. AccountTargetNetworkNote::new() fails when given a note with an invalid attachment
  3. is_network_note() returns true for notes with valid NetworkAccountTarget attachments and false otherwise
  4. as_account_target_network_note() returns the correct result for both valid and invalid notes
  5. The TryFrom implementation works correctly

These tests would complement the integration test in test_output_note.rs and ensure the module behaves correctly in isolation.

Copilot uses AI. Check for mistakes.
@partylikeits1983 partylikeits1983 changed the title feat: implement NetworkNote newtype feat: add .is_network_note() helper method for Note Feb 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr-from-maintainers PRs that come from internal contributors or integration partners. They should be given priority

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add method for determining if Note is a network note

5 participants