Skip to content

Commit b2b8c20

Browse files
feat: introduce standard NetworkAccountTarget attachment (#2257)
* feat: Implement `NetworkAccountTarget` * chore: Let SPAWN note create output notes with attachment * chore: test creating note with NetworkAccountTarget attachment * chore: add changelog * fix: don't use super::* import * feat: Add `WellKnownNoteAttachment` * chore: Use 8-bit tag for exec hint; remove `AfterBlockNumber` * chore: improve network account target error
1 parent de42e84 commit b2b8c20

10 files changed

Lines changed: 286 additions & 89 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
- Add `read_foreign_account_inputs()`, `read_vault_asset_witnesses()`, and `read_storage_map_witness()` for `TransactionInputs` ([#2246](https://github.com/0xMiden/miden-base/pull/2246)).
1212
- [BREAKING] Introduce `NoteAttachment` as part of `NoteMetadata` and remove `aux` and `execution_hint` ([#2249](https://github.com/0xMiden/miden-base/pull/2249)).
1313
- [BREAKING] Introduce `NoteAttachment` as part of `NoteMetadata` and remove `aux` and `execution_hint` ([#2249](https://github.com/0xMiden/miden-base/pull/2249), [#2252](https://github.com/0xMiden/miden-base/pull/2252)).
14+
- Introduce standard `NetworkAccountTarget` attachment for use in network transactions which replaces `NoteTag::NetworkAccount` ([#2257](https://github.com/0xMiden/miden-base/pull/2257)).
1415

1516
### Changes
1617

crates/miden-protocol/src/note/attachment.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,18 @@ impl TryFrom<u8> for NoteAttachmentContentType {
443443
}
444444
}
445445

446+
impl core::fmt::Display for NoteAttachmentContentType {
447+
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
448+
let output = match self {
449+
NoteAttachmentContentType::None => "None",
450+
NoteAttachmentContentType::Word => "Word",
451+
NoteAttachmentContentType::Array => "Array",
452+
};
453+
454+
f.write_str(output)
455+
}
456+
}
457+
446458
impl Serializable for NoteAttachmentContentType {
447459
fn write_into<W: ByteWriter>(&self, target: &mut W) {
448460
self.as_u8().write_into(target);

crates/miden-protocol/src/note/execution_hint.rs

Lines changed: 14 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use crate::{Felt, NoteError};
1515
/// [`NoteExecutionHint`] can be encoded into a [`Felt`] with the following layout:
1616
///
1717
/// ```text
18-
/// [26 zero bits | payload (32 bits) | tag (6 bits)]
18+
/// [24 zero bits | payload (32 bits) | tag (8 bits)]
1919
/// ```
2020
///
2121
/// This way, hints such as [NoteExecutionHint::Always], are represented by `Felt::new(1)`.
@@ -27,10 +27,7 @@ pub enum NoteExecutionHint {
2727
/// The note's script can be executed at any time.
2828
Always,
2929
/// The note's script can be executed after the specified block number.
30-
///
31-
/// The block number cannot be [`u32::MAX`] which is enforced through the [`AfterBlockNumber`]
32-
/// type.
33-
AfterBlock { block_num: AfterBlockNumber },
30+
AfterBlock { block_num: BlockNumber },
3431
/// The note's script can be executed in the specified slot within the specified round.
3532
///
3633
/// The slot is defined as follows:
@@ -74,13 +71,8 @@ impl NoteExecutionHint {
7471
}
7572

7673
/// Creates a [NoteExecutionHint::AfterBlock] variant based on the given `block_num`
77-
///
78-
/// # Errors
79-
///
80-
/// Returns an error if `block_num` is equal to [`u32::MAX`].
81-
pub fn after_block(block_num: BlockNumber) -> Result<Self, NoteError> {
82-
AfterBlockNumber::new(block_num)
83-
.map(|block_number| NoteExecutionHint::AfterBlock { block_num: block_number })
74+
pub fn after_block(block_num: BlockNumber) -> Self {
75+
NoteExecutionHint::AfterBlock { block_num }
8476
}
8577

8678
/// Creates a [NoteExecutionHint::OnBlockSlot] for the given parameters. See the variants
@@ -103,7 +95,7 @@ impl NoteExecutionHint {
10395
}
10496
Ok(NoteExecutionHint::Always)
10597
},
106-
Self::AFTER_BLOCK_TAG => NoteExecutionHint::after_block(payload.into()),
98+
Self::AFTER_BLOCK_TAG => Ok(NoteExecutionHint::after_block(BlockNumber::from(payload))),
10799
Self::ON_BLOCK_SLOT_TAG => {
108100
let remainder = ((payload >> 24) & 0xff) as u8;
109101
if remainder != 0 {
@@ -151,15 +143,7 @@ impl NoteExecutionHint {
151143
}
152144
}
153145

154-
/// Encodes the [`NoteExecutionHint`] into a 6-bit tag and a 32-bit payload.
155-
///
156-
/// # Guarantees
157-
///
158-
/// Since the tag has at most 6 bits, the returned byte is guaranteed to have its two most
159-
/// significant bits set to `0`.
160-
///
161-
/// The payload is guaranteed to contain at least one `0` bit to make encoding it into
162-
/// [`NoteMetadata`](crate::note::NoteMetadata) safely possible.
146+
/// Encodes the [`NoteExecutionHint`] into an 8-bit tag and a 32-bit payload.
163147
pub fn into_parts(&self) -> (u8, u32) {
164148
match self {
165149
NoteExecutionHint::None => (Self::NONE_TAG, 0),
@@ -187,12 +171,13 @@ impl From<NoteExecutionHint> for Felt {
187171
/// Tries to convert a `u64` into a [`NoteExecutionHint`] with the expected layout documented on the
188172
/// type.
189173
///
190-
/// Note: The upper 26 bits are not enforced to be zero.
174+
/// Note: The upper 24 bits are not enforced to be zero.
191175
impl TryFrom<u64> for NoteExecutionHint {
192176
type Error = NoteError;
193177
fn try_from(value: u64) -> Result<Self, Self::Error> {
194-
let tag = (value & 0b111111) as u8;
195-
let payload = ((value >> 6) & 0xffffffff) as u32;
178+
let tag = (value & 0b1111_1111) as u8;
179+
// Shift the payload and cut off / ignore the upper 32 bits.
180+
let payload = (value >> 8) as u32;
196181

197182
Self::from_parts(tag, payload)
198183
}
@@ -202,51 +187,7 @@ impl TryFrom<u64> for NoteExecutionHint {
202187
impl From<NoteExecutionHint> for u64 {
203188
fn from(value: NoteExecutionHint) -> Self {
204189
let (tag, payload) = value.into_parts();
205-
((payload as u64) << 6) | (tag as u64)
206-
}
207-
}
208-
209-
// AFTER BLOCK NUMBER
210-
// ================================================================================================
211-
212-
/// A wrapper around a block number which enforces that it is not `u32::MAX`.
213-
///
214-
/// Used for the [`NoteExecutionHint::AfterBlock`] variant where this constraint is needed.
215-
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
216-
pub struct AfterBlockNumber(BlockNumber);
217-
218-
impl AfterBlockNumber {
219-
/// Creates a new [`AfterBlockNumber`] from the given `block_number`.
220-
///
221-
/// # Errors
222-
///
223-
/// Returns an error if:
224-
/// - `block_number` is equal to `u32::MAX`.
225-
pub fn new(block_number: BlockNumber) -> Result<Self, NoteError> {
226-
if block_number.as_u32() == u32::MAX {
227-
Err(NoteError::NoteExecutionHintAfterBlockCannotBeU32Max)
228-
} else {
229-
Ok(Self(block_number))
230-
}
231-
}
232-
233-
/// Returns the block number as a `u32`.
234-
pub fn as_u32(&self) -> u32 {
235-
self.0.as_u32()
236-
}
237-
}
238-
239-
impl From<AfterBlockNumber> for u32 {
240-
fn from(block_number: AfterBlockNumber) -> Self {
241-
block_number.0.as_u32()
242-
}
243-
}
244-
245-
impl TryFrom<u32> for AfterBlockNumber {
246-
type Error = NoteError;
247-
248-
fn try_from(block_number: u32) -> Result<Self, Self::Error> {
249-
Self::new(block_number.into())
190+
((payload as u64) << 8) | (tag as u64)
250191
}
251192
}
252193

@@ -255,7 +196,6 @@ impl TryFrom<u32> for AfterBlockNumber {
255196

256197
#[cfg(test)]
257198
mod tests {
258-
use assert_matches::assert_matches;
259199

260200
use super::*;
261201

@@ -269,7 +209,7 @@ mod tests {
269209
fn test_serialization_round_trip() {
270210
assert_hint_serde(NoteExecutionHint::None);
271211
assert_hint_serde(NoteExecutionHint::Always);
272-
assert_hint_serde(NoteExecutionHint::after_block(15.into()).unwrap());
212+
assert_hint_serde(NoteExecutionHint::after_block(15.into()));
273213
assert_hint_serde(NoteExecutionHint::OnBlockSlot {
274214
round_len: 9,
275215
slot_len: 12,
@@ -279,7 +219,7 @@ mod tests {
279219

280220
#[test]
281221
fn test_encode_round_trip() {
282-
let hint = NoteExecutionHint::after_block(15.into()).unwrap();
222+
let hint = NoteExecutionHint::after_block(15.into());
283223
let hint_int: u64 = hint.into();
284224
let decoded_hint: NoteExecutionHint = hint_int.try_into().unwrap();
285225
assert_eq!(hint, decoded_hint);
@@ -305,7 +245,7 @@ mod tests {
305245
let always = NoteExecutionHint::always();
306246
assert!(always.can_be_consumed(100.into()).unwrap());
307247

308-
let after_block = NoteExecutionHint::after_block(12345.into()).unwrap();
248+
let after_block = NoteExecutionHint::after_block(12345.into());
309249
assert!(!after_block.can_be_consumed(12344.into()).unwrap());
310250
assert!(after_block.can_be_consumed(12345.into()).unwrap());
311251

@@ -331,12 +271,4 @@ mod tests {
331271

332272
NoteExecutionHint::from_parts(10, 1).unwrap_err();
333273
}
334-
335-
#[test]
336-
fn test_after_block_fails_on_u32_max() {
337-
assert_matches!(
338-
NoteExecutionHint::after_block(u32::MAX.into()).unwrap_err(),
339-
NoteError::NoteExecutionHintAfterBlockCannotBeU32Max
340-
);
341-
}
342274
}

crates/miden-protocol/src/note/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ pub use attachment::{
3030
};
3131

3232
mod execution_hint;
33-
pub use execution_hint::{AfterBlockNumber, NoteExecutionHint};
33+
pub use execution_hint::NoteExecutionHint;
3434

3535
mod note_id;
3636
pub use note_id::NoteId;

crates/miden-standards/src/note/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@ use utils::build_swap_tag;
2121
pub mod mint_inputs;
2222
pub mod utils;
2323

24+
mod network_account_target;
25+
pub use network_account_target::NetworkAccountTarget;
26+
27+
mod well_known_note_attachment;
28+
pub use well_known_note_attachment::WellKnownNoteAttachment;
29+
2430
mod well_known_note;
2531
pub use mint_inputs::MintNoteInputs;
2632
pub use well_known_note::{NoteConsumptionStatus, WellKnownNote};

0 commit comments

Comments
 (0)