diff --git a/miden-lib/asm/miden/kernels/tx/tx.masm b/miden-lib/asm/miden/kernels/tx/tx.masm index 83c46960c..6a8892e36 100644 --- a/miden-lib/asm/miden/kernels/tx/tx.masm +++ b/miden-lib/asm/miden/kernels/tx/tx.masm @@ -111,7 +111,7 @@ export.create_note assertz.err=ERR_NOTE_INVALID_TAG_HIGH_BIT_SET # => [tag_low, note_type, ASSET, tag, note_type, RECIPIENT] - u32shr.30 assert_eq.err=ERR_NOTE_INVALID_TAG_PREFIX_FOR_TYPE + u32shr.30 u32and assertz.err=ERR_NOTE_INVALID_TAG_PREFIX_FOR_TYPE # => [ASSET, tag, note_type, RECIPIENT] # get the index for the next note to be created and increment counter diff --git a/miden-lib/src/notes/mod.rs b/miden-lib/src/notes/mod.rs index 044e5e166..47f1838cb 100644 --- a/miden-lib/src/notes/mod.rs +++ b/miden-lib/src/notes/mod.rs @@ -4,7 +4,10 @@ use miden_objects::{ accounts::AccountId, assets::Asset, crypto::rand::FeltRng, - notes::{Note, NoteAssets, NoteInputs, NoteMetadata, NoteRecipient, NoteTag, NoteType}, + notes::{ + Note, NoteAssets, NoteExecutionMode, NoteInputs, NoteMetadata, NoteRecipient, NoteTag, + NoteType, + }, NoteError, Word, ZERO, }; @@ -36,7 +39,7 @@ pub fn create_p2id_note( let note_script = build_note_script(bytes)?; let inputs = NoteInputs::new(vec![target.into()])?; - let tag = NoteTag::from_account_id(target, NoteType::Public)?; + let tag = NoteTag::from_account_id(target, NoteExecutionMode::Local)?; let serial_num = rng.draw_word(); let aux = ZERO; @@ -70,7 +73,7 @@ pub fn create_p2idr_note( let note_script = build_note_script(bytes)?; let inputs = NoteInputs::new(vec![target.into(), recall_height.into()])?; - let tag = NoteTag::from_account_id(target, NoteType::Public)?; + let tag = NoteTag::from_account_id(target, NoteExecutionMode::Local)?; let serial_num = rng.draw_word(); let aux = ZERO; @@ -95,19 +98,13 @@ pub fn create_swap_note( note_type: NoteType, mut rng: R, ) -> Result<(Note, Word), NoteError> { - assert_eq!( - note_type, - NoteType::OffChain, - "OffChain note type is currently hardcoded in the SWAP script" - ); - let bytes = include_bytes!(concat!(env!("OUT_DIR"), "/assets/note_scripts/SWAP.masb")); let note_script = build_note_script(bytes)?; let payback_serial_num = rng.draw_word(); let payback_recipient = utils::build_p2id_recipient(sender, payback_serial_num)?; let asset_word: Word = requested_asset.into(); - let payback_tag = NoteTag::from_account_id(sender, note_type)?; + let payback_tag = NoteTag::from_account_id(sender, NoteExecutionMode::Local)?; let inputs = NoteInputs::new(vec![ payback_recipient[0], @@ -121,8 +118,8 @@ pub fn create_swap_note( payback_tag.inner().into(), ])?; - // TODO: build a tag for the SWAP use case (#640) - let tag = NoteTag::from(note_type); + // TODO: build the tag for the SWAP use case + let tag = 0.into(); let serial_num = rng.draw_word(); let aux = ZERO; diff --git a/miden-lib/src/tests/test_tx.rs b/miden-lib/src/tests/test_tx.rs index defa74d96..31a21129a 100644 --- a/miden-lib/src/tests/test_tx.rs +++ b/miden-lib/src/tests/test_tx.rs @@ -2,7 +2,7 @@ use alloc::vec::Vec; use miden_objects::{ accounts::account_id::testing::ACCOUNT_ID_FUNGIBLE_FAUCET_ON_CHAIN, - notes::{Note, NoteAssets, NoteInputs, NoteMetadata, NoteRecipient, NoteTag, NoteType}, + notes::{Note, NoteAssets, NoteInputs, NoteMetadata, NoteRecipient, NoteType}, transaction::{OutputNote, OutputNotes}, Word, ONE, ZERO, }; @@ -30,7 +30,7 @@ fn test_create_note() { let account_id = tx_inputs.account().id(); let recipient = [ZERO, ONE, Felt::new(2), Felt::new(3)]; - let tag: NoteTag = NoteType::Public.into(); + let tag = Felt::new(4); let asset = [Felt::new(10), ZERO, ZERO, Felt::new(ACCOUNT_ID_FUNGIBLE_FAUCET_ON_CHAIN)]; let code = format!( @@ -72,7 +72,7 @@ fn test_create_note() { assert_eq!( read_root_mem_value(&process, CREATED_NOTE_SECTION_OFFSET + CREATED_NOTE_METADATA_OFFSET), - [tag.into(), Felt::from(account_id), NoteType::Public.into(), ZERO], + [tag, Felt::from(account_id), NoteType::Public.into(), ZERO], "metadata must be stored at the correct memory location", ); @@ -102,7 +102,7 @@ fn test_create_note_with_invalid_tag() { mock_inputs(MockAccountType::StandardExisting, AssetPreservationStatus::Preserved); let recipient = [ZERO, ONE, Felt::new(2), Felt::new(3)]; - let tag = 0; + let tag = Felt::new((NoteType::Public as u64) << 62); let asset = [Felt::new(10), ZERO, ZERO, Felt::new(ACCOUNT_ID_FUNGIBLE_FAUCET_ON_CHAIN)]; let code = format!( @@ -136,7 +136,7 @@ fn test_create_note_with_invalid_tag() { #[test] fn test_create_note_too_many_notes() { let recipient = [ZERO, ONE, Felt::new(2), Felt::new(3)]; - let tag: NoteTag = NoteType::Public.into(); + let tag = Felt::new(4); let asset = [Felt::new(10), ZERO, ZERO, Felt::new(ACCOUNT_ID_FUNGIBLE_FAUCET_ON_CHAIN)]; let code = format!( @@ -183,28 +183,20 @@ fn test_get_output_notes_hash() { // create output note 1 let output_serial_no_1 = [Felt::new(8); 4]; + let output_tag_1 = 8888.into(); let assets = NoteAssets::new(vec![input_asset_1]).unwrap(); - let metadata = NoteMetadata::new( - tx_inputs.account().id(), - NoteType::Public, - NoteType::Public.into(), - ZERO, - ) - .unwrap(); + let metadata = + NoteMetadata::new(tx_inputs.account().id(), NoteType::Public, output_tag_1, ZERO).unwrap(); let inputs = NoteInputs::new(vec![]).unwrap(); let recipient = NoteRecipient::new(output_serial_no_1, input_note_1.script().clone(), inputs); let output_note_1 = Note::new(assets, metadata, recipient); // create output note 2 let output_serial_no_2 = [Felt::new(11); 4]; + let output_tag_2 = 1111.into(); let assets = NoteAssets::new(vec![input_asset_2]).unwrap(); - let metadata = NoteMetadata::new( - tx_inputs.account().id(), - NoteType::Public, - NoteType::Public.into(), - ZERO, - ) - .unwrap(); + let metadata = + NoteMetadata::new(tx_inputs.account().id(), NoteType::Public, output_tag_2, ZERO).unwrap(); let inputs = NoteInputs::new(vec![]).unwrap(); let recipient = NoteRecipient::new(output_serial_no_2, input_note_2.script().clone(), inputs); let output_note_2 = Note::new(assets, metadata, recipient); diff --git a/miden-tx/src/compiler/tests.rs b/miden-tx/src/compiler/tests.rs index 9bd299bab..1801ed1de 100644 --- a/miden-tx/src/compiler/tests.rs +++ b/miden-tx/src/compiler/tests.rs @@ -160,8 +160,7 @@ fn mock_consumed_notes( const SERIAL_NUM_1: Word = [Felt::new(1), Felt::new(2), Felt::new(3), Felt::new(4)]; let vault = NoteAssets::new(vec![fungible_asset_1, fungible_asset_2, fungible_asset_3]).unwrap(); - let metadata = - NoteMetadata::new(sender, NoteType::Public, NoteType::Public.into(), ZERO).unwrap(); + let metadata = NoteMetadata::new(sender, NoteType::Public, 0.into(), ZERO).unwrap(); let inputs = NoteInputs::new(vec![Felt::new(1)]).unwrap(); let recipient = NoteRecipient::new(SERIAL_NUM_1, note_script.clone(), inputs); let note_1 = Note::new(vault, metadata, recipient); @@ -169,8 +168,7 @@ fn mock_consumed_notes( const SERIAL_NUM_2: Word = [Felt::new(5), Felt::new(6), Felt::new(7), Felt::new(8)]; let vault = NoteAssets::new(vec![fungible_asset_1, fungible_asset_2, fungible_asset_3]).unwrap(); - let metadata = - NoteMetadata::new(sender, NoteType::Public, NoteType::Public.into(), ZERO).unwrap(); + let metadata = NoteMetadata::new(sender, NoteType::Public, 0.into(), ZERO).unwrap(); let inputs = NoteInputs::new(vec![Felt::new(2)]).unwrap(); let recipient = NoteRecipient::new(SERIAL_NUM_2, note_script, inputs); let note_2 = Note::new(vault, metadata, recipient); diff --git a/miden-tx/src/tests.rs b/miden-tx/src/tests.rs index 759fb30b3..5e426d224 100644 --- a/miden-tx/src/tests.rs +++ b/miden-tx/src/tests.rs @@ -12,7 +12,7 @@ use miden_objects::{ assembly::{Assembler, ModuleAst, ProgramAst}, assets::{Asset, FungibleAsset}, block::BlockHeader, - notes::{NoteId, NoteTag, NoteType}, + notes::{NoteId, NoteType}, transaction::{ ChainMmr, InputNote, InputNotes, ProvenTransaction, TransactionArgs, TransactionWitness, }, @@ -203,7 +203,7 @@ fn executed_transaction_account_delta() { # partially deplete fungible asset balance push.0.1.2.3 # recipient push.{OFFCHAIN} # note_type - push.{tag_1} # tag + push.999 # tag push.{REMOVED_ASSET_1} # asset call.wallet::send_asset dropw dropw drop drop # => [] @@ -211,7 +211,7 @@ fn executed_transaction_account_delta() { # totally deplete fungible asset balance push.0.1.2.3 # recipient push.{OFFCHAIN} # note_type - push.{tag_2} # tag + push.998 # tag push.{REMOVED_ASSET_2} # asset call.wallet::send_asset dropw dropw drop drop # => [] @@ -219,7 +219,7 @@ fn executed_transaction_account_delta() { # send non-fungible asset push.0.1.2.3 # recipient push.{OFFCHAIN} # note_type - push.{tag_3} # tag + push.997 # tag push.{REMOVED_ASSET_3} # asset call.wallet::send_asset dropw dropw drop drop # => [] @@ -242,9 +242,6 @@ fn executed_transaction_account_delta() { REMOVED_ASSET_1 = prepare_word(&Word::from(removed_asset_1)), REMOVED_ASSET_2 = prepare_word(&Word::from(removed_asset_2)), REMOVED_ASSET_3 = prepare_word(&Word::from(removed_asset_3)), - tag_1 = NoteTag::from(NoteType::OffChain), - tag_2 = NoteTag::from(NoteType::OffChain), - tag_3 = NoteTag::from(NoteType::OffChain), OFFCHAIN = NoteType::OffChain as u8, ); let tx_script_code = ProgramAst::parse(&tx_script).unwrap(); diff --git a/miden-tx/tests/integration/main.rs b/miden-tx/tests/integration/main.rs index 2f713d378..d8b343c73 100644 --- a/miden-tx/tests/integration/main.rs +++ b/miden-tx/tests/integration/main.rs @@ -207,8 +207,7 @@ pub fn get_note_with_fungible_asset_and_script( let sender_id = AccountId::try_from(ACCOUNT_ID_SENDER).unwrap(); let vault = NoteAssets::new(vec![fungible_asset.into()]).unwrap(); - let metadata = - NoteMetadata::new(sender_id, NoteType::Public, NoteType::Public.into(), ZERO).unwrap(); + let metadata = NoteMetadata::new(sender_id, NoteType::Public, 1.into(), ZERO).unwrap(); let inputs = NoteInputs::new(vec![]).unwrap(); let recipient = NoteRecipient::new(SERIAL_NUM, note_script, inputs); diff --git a/miden-tx/tests/integration/scripts/faucet.rs b/miden-tx/tests/integration/scripts/faucet.rs index fc567c869..0959c5c4d 100644 --- a/miden-tx/tests/integration/scripts/faucet.rs +++ b/miden-tx/tests/integration/scripts/faucet.rs @@ -44,7 +44,7 @@ fn prove_faucet_contract_mint_fungible_asset_succeeds() { let note_ids = data_store.notes.iter().map(|note| note.id()).collect::>(); let recipient = [Felt::new(0), Felt::new(1), Felt::new(2), Felt::new(3)]; - let tag = NoteType::OffChain.into(); + let tag = 4.into(); let amount = Felt::new(100); let tx_script_code = ProgramAst::parse( diff --git a/miden-tx/tests/integration/scripts/swap.rs b/miden-tx/tests/integration/scripts/swap.rs index 02bcdc37a..e482e69a0 100644 --- a/miden-tx/tests/integration/scripts/swap.rs +++ b/miden-tx/tests/integration/scripts/swap.rs @@ -10,7 +10,7 @@ use miden_objects::{ assembly::ProgramAst, assets::{Asset, AssetVault, FungibleAsset, NonFungibleAsset, NonFungibleAssetDetails}, crypto::rand::RpoRandomCoin, - notes::{NoteAssets, NoteEnvelope, NoteId, NoteMetadata, NoteTag, NoteType}, + notes::{NoteAssets, NoteEnvelope, NoteExecutionMode, NoteId, NoteMetadata, NoteTag, NoteType}, transaction::TransactionArgs, Felt, ZERO, }; @@ -52,7 +52,7 @@ fn prove_swap_script() { sender_account_id, fungible_asset, non_fungible_asset, - NoteType::OffChain, + NoteType::Public, RpoRandomCoin::new([Felt::new(1), Felt::new(2), Felt::new(3), Felt::new(4)]), ) .unwrap(); @@ -98,7 +98,7 @@ fn prove_swap_script() { // Check if the created `Note` is what we expect let recipient = build_p2id_recipient(sender_account_id, repay_serial_num).unwrap(); - let tag = NoteTag::from_account_id(sender_account_id, NoteType::OffChain).unwrap(); + let tag = NoteTag::from_account_id(sender_account_id, NoteExecutionMode::Local).unwrap(); let note_metadata = NoteMetadata::new(target_account_id, NoteType::OffChain, tag, ZERO).unwrap(); let assets = NoteAssets::new(vec![non_fungible_asset]).unwrap(); diff --git a/miden-tx/tests/integration/wallet/mod.rs b/miden-tx/tests/integration/wallet/mod.rs index 7a41b543f..96086cb14 100644 --- a/miden-tx/tests/integration/wallet/mod.rs +++ b/miden-tx/tests/integration/wallet/mod.rs @@ -10,7 +10,7 @@ use miden_objects::{ assembly::ProgramAst, assets::{Asset, AssetVault, FungibleAsset}, crypto::dsa::rpo_falcon512::SecretKey, - notes::{NoteTag, NoteType}, + notes::NoteType, transaction::TransactionArgs, Felt, Word, ONE, ZERO, }; @@ -124,12 +124,14 @@ fn prove_send_asset_via_wallet() { // -------------------------------------------------------------------------------------------- let data_store = MockDataStore::with_existing(Some(sender_account.clone()), Some(vec![])); - let mut executor = TransactionExecutor::new(data_store.clone()).with_debug_mode(true); + let mut executor = TransactionExecutor::new(data_store.clone()); executor.load_account(sender_account.id()).unwrap(); let block_ref = data_store.block_header.block_num(); let note_ids = data_store.notes.iter().map(|note| note.id()).collect::>(); + let recipient = [ZERO, ONE, Felt::new(2), Felt::new(3)]; + let tag = Felt::new(4); let tx_script_code = ProgramAst::parse( format!( @@ -149,7 +151,7 @@ fn prove_send_asset_via_wallet() { ", recipient = prepare_word(&recipient), note_type = NoteType::OffChain as u8, - tag = NoteTag::from(NoteType::OffChain), + tag = tag, asset = prepare_word(&fungible_asset_1.into()) ) .as_str(), diff --git a/mock/src/builders/note.rs b/mock/src/builders/note.rs index 90fe6aa8a..bf8899364 100644 --- a/mock/src/builders/note.rs +++ b/mock/src/builders/note.rs @@ -51,7 +51,7 @@ impl NoteBuilder { assets: vec![], note_type: NoteType::Public, serial_num, - tag: NoteType::Public.into(), + tag: 0.into(), code: DEFAULT_NOTE_CODE.to_string(), proof: None, aux: ZERO, @@ -69,8 +69,8 @@ impl NoteBuilder { self } - pub fn tag(mut self, tag: NoteTag) -> Self { - self.tag = tag; + pub fn tag(mut self, tag: u32) -> Self { + self.tag = tag.into(); self } diff --git a/mock/src/mock/account.rs b/mock/src/mock/account.rs index e2496f7f2..4618d233a 100644 --- a/mock/src/mock/account.rs +++ b/mock/src/mock/account.rs @@ -109,12 +109,12 @@ pub fn mock_account_storage() -> AccountStorage { // account's procedures. const MASTS: [&str; 9] = [ "0xe06a83054c72efc7e32698c4fc6037620cde834c9841afb038a5d39889e502b6", - "0xb39350cf554e78d4819764a1755f219abf4a6ab8dae5aa3be809c9d65f03c955", + "0xd0260c15a64e796833eb2987d4072ac2ea824b3ce4a54a1e693bada6e82f71dd", "0xd765111e22479256e87a57eaf3a27479d19cc876c9a715ee6c262e0a0d47a2ac", "0x17b326d5403115afccc0727efa72bd929bfdc7bbf284c7c28a7aadade5d4cc9d", "0x6682a0e0f4e49820e5c547f1b60a82cb326a56c972999e36bf6d45459393ac87", "0x73c14f65d2bab6f52eafc4397e104b3ab22a470f6b5cbc86d4aa4d3978c8b7d4", - "0x5bdf8858cc463910f9cfc9864f0ef42501baf8bd38d9e8848d3decde2e440bed", + "0xef07641ea1aa8fe85d8f854d29bf729b92251e1433244892138fd9ca898a5a22", "0xff06b90f849c4b262cbfbea67042c4ea017ea0e9c558848a951d44b23370bec5", "0x8ef0092134469a1330e3c468f57c7f085ce611645d09cc7516c786fefc71d794", ]; diff --git a/mock/src/mock/notes.rs b/mock/src/mock/notes.rs index f2c2f7e02..92a7067eb 100644 --- a/mock/src/mock/notes.rs +++ b/mock/src/mock/notes.rs @@ -62,22 +62,19 @@ pub fn mock_notes( let inputs = NoteInputs::new(vec![Felt::new(1)]).unwrap(); let vault = NoteAssets::new(vec![fungible_asset_1]).unwrap(); - let metadata = - NoteMetadata::new(sender, NoteType::Public, NoteType::Public.into(), ZERO).unwrap(); + let metadata = NoteMetadata::new(sender, NoteType::Public, 0.into(), ZERO).unwrap(); let recipient = NoteRecipient::new(serial_num_gen.next(), note_script.clone(), inputs); let created_note_1 = Note::new(vault, metadata, recipient); let inputs = NoteInputs::new(vec![Felt::new(2)]).unwrap(); let vault = NoteAssets::new(vec![fungible_asset_2]).unwrap(); - let metadata = - NoteMetadata::new(sender, NoteType::Public, NoteType::Public.into(), ZERO).unwrap(); + let metadata = NoteMetadata::new(sender, NoteType::Public, 0.into(), ZERO).unwrap(); let recipient = NoteRecipient::new(serial_num_gen.next(), note_script.clone(), inputs); let created_note_2 = Note::new(vault, metadata, recipient); let inputs = NoteInputs::new(vec![Felt::new(3)]).unwrap(); let vault = NoteAssets::new(vec![fungible_asset_3]).unwrap(); - let metadata = - NoteMetadata::new(sender, NoteType::Public, NoteType::Public.into(), ZERO).unwrap(); + let metadata = NoteMetadata::new(sender, NoteType::Public, 0.into(), ZERO).unwrap(); let recipient = NoteRecipient::new(serial_num_gen.next(), note_script.clone(), inputs); let created_note_3 = Note::new(vault, metadata, recipient); @@ -88,7 +85,7 @@ pub fn mock_notes( begin # create note 0 push.{recipient0} - push.{type0} + push.{PUBLIC_NOTE} push.{tag0} push.{asset0} # MAST root of the `create_note` mock account procedure @@ -97,7 +94,7 @@ pub fn mock_notes( # create note 1 push.{recipient1} - push.{type1} + push.{PUBLIC_NOTE} push.{tag1} push.{asset1} # MAST root of the `create_note` mock account procedure @@ -105,19 +102,17 @@ pub fn mock_notes( drop drop dropw dropw end ", + PUBLIC_NOTE = NoteType::Public as u8, recipient0 = prepare_word(&created_note_1.recipient_digest()), - type0 = created_note_1.metadata().note_type() as u8, tag0 = created_note_1.metadata().tag(), asset0 = prepare_assets(created_note_1.assets())[0], recipient1 = prepare_word(&created_note_2.recipient_digest()), - type1 = created_note_1.metadata().note_type() as u8, tag1 = created_note_2.metadata().tag(), asset1 = prepare_assets(created_note_2.assets())[0], ); let note_1_script_ast = ProgramAst::parse(¬e_1_script_src).unwrap(); let (note_1_script, _) = NoteScript::new(note_1_script_ast, assembler).unwrap(); - let metadata = - NoteMetadata::new(sender, NoteType::Public, NoteType::Public.into(), ZERO).unwrap(); + let metadata = NoteMetadata::new(sender, NoteType::Public, 0.into(), ZERO).unwrap(); let vault = NoteAssets::new(vec![fungible_asset_1]).unwrap(); let inputs = NoteInputs::new(vec![Felt::new(1)]).unwrap(); let recipient = NoteRecipient::new(serial_num_gen.next(), note_1_script, inputs); @@ -128,7 +123,7 @@ pub fn mock_notes( begin # create note 2 push.{recipient} - push.{note_type} + push.{PUBLIC_NOTE} push.{tag} push.{asset} # MAST root of the `create_note` mock account procedure @@ -136,15 +131,14 @@ pub fn mock_notes( drop drop dropw dropw end ", + PUBLIC_NOTE = NoteType::Public as u8, recipient = prepare_word(&created_note_3.recipient_digest()), - note_type = created_note_3.metadata().note_type() as u8, tag = created_note_3.metadata().tag(), asset = prepare_assets(created_note_3.assets())[0], ); let note_2_script_ast = ProgramAst::parse(¬e_2_script_src).unwrap(); let (note_2_script, _) = NoteScript::new(note_2_script_ast, assembler).unwrap(); - let metadata = - NoteMetadata::new(sender, NoteType::Public, NoteType::Public.into(), ZERO).unwrap(); + let metadata = NoteMetadata::new(sender, NoteType::Public, 0.into(), ZERO).unwrap(); let vault = NoteAssets::new(vec![fungible_asset_2, fungible_asset_3]).unwrap(); let inputs = NoteInputs::new(vec![Felt::new(2)]).unwrap(); let recipient = NoteRecipient::new(serial_num_gen.next(), note_2_script, inputs); @@ -152,8 +146,7 @@ pub fn mock_notes( let note_3_script_ast = ProgramAst::parse("begin push.1 drop end").unwrap(); let (note_3_script, _) = NoteScript::new(note_3_script_ast, assembler).unwrap(); - let metadata = - NoteMetadata::new(sender, NoteType::Public, NoteType::Public.into(), ZERO).unwrap(); + let metadata = NoteMetadata::new(sender, NoteType::Public, 0.into(), ZERO).unwrap(); let vault = NoteAssets::new(vec![fungible_asset_2, fungible_asset_3]).unwrap(); let inputs = NoteInputs::new(vec![Felt::new(2)]).unwrap(); let recipient = NoteRecipient::new(serial_num_gen.next(), note_3_script, inputs); @@ -161,8 +154,7 @@ pub fn mock_notes( let note_4_script_ast = ProgramAst::parse("begin push.1 drop end").unwrap(); let (note_4_script, _) = NoteScript::new(note_4_script_ast, assembler).unwrap(); - let metadata = - NoteMetadata::new(sender, NoteType::Public, NoteType::Public.into(), ZERO).unwrap(); + let metadata = NoteMetadata::new(sender, NoteType::Public, 0.into(), ZERO).unwrap(); let vault = NoteAssets::new(vec![non_fungible_asset_2(ACCOUNT_ID_NON_FUNGIBLE_FAUCET_ON_CHAIN)]) .unwrap(); @@ -202,8 +194,7 @@ pub fn mock_notes( .unwrap(); let (note_5_script, _) = NoteScript::new(note_5_script_ast, assembler).unwrap(); - let metadata = - NoteMetadata::new(sender, NoteType::Public, NoteType::Public.into(), ZERO).unwrap(); + let metadata = NoteMetadata::new(sender, NoteType::Public, 0.into(), ZERO).unwrap(); let vault = NoteAssets::new(vec![ fungible_asset_1, fungible_asset_3, diff --git a/objects/src/notes/metadata.rs b/objects/src/notes/metadata.rs index 879d28a08..47b7aa027 100644 --- a/objects/src/notes/metadata.rs +++ b/objects/src/notes/metadata.rs @@ -5,10 +5,31 @@ use super::{ NoteTag, NoteType, Serializable, Word, }; +// CONSTANTS +// ================================================================================================ +const NETWORK_EXECUTION: u8 = 0; +const LOCAL_EXECUTION: u8 = 1; + +/// Determines if a note is intended to be consumed by the network or not. +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u8)] +pub enum NoteExecutionMode { + Network = NETWORK_EXECUTION, + Local = LOCAL_EXECUTION, +} + // NOTE METADATA // ================================================================================================ /// Metadata associated with a note. +/// +/// Note type and tag must be internally consistent according to the following rules: +/// +/// - For off-chain notes, the most significant bit of the tag must be 0. +/// - For public notes, the second most significant bit of the tag must be 0. +/// - For encrypted notes, two most significant bits of the tag must be 00. +/// #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct NoteMetadata { @@ -85,8 +106,9 @@ impl TryFrom for NoteMetadata { let sender = elements[1].try_into().map_err(NoteError::InvalidNoteSender)?; let note_type = elements[2].try_into()?; let tag: u64 = elements[0].into(); - let tag: NoteTag = tag.try_into()?; - Self::new(sender, note_type, tag, elements[3]) + let tag: u32 = + tag.try_into().map_err(|_| NoteError::InconsistentNoteTag(note_type, tag))?; + Self::new(sender, note_type, tag.into(), elements[3]) } } diff --git a/objects/src/notes/mod.rs b/objects/src/notes/mod.rs index 2b22fc033..40ab650be 100644 --- a/objects/src/notes/mod.rs +++ b/objects/src/notes/mod.rs @@ -22,16 +22,16 @@ mod inputs; pub use inputs::NoteInputs; mod metadata; -pub use metadata::NoteMetadata; +pub use metadata::{NoteExecutionMode, NoteMetadata}; mod note_id; pub use note_id::NoteId; mod note_tag; -pub use note_tag::{NoteTag, NOTE_TYPE_MASK, NOTE_TYPE_MASK_SHIFT}; +pub use note_tag::NoteTag; mod note_type; -pub use note_type::{NoteType, ENCRYPTED, OFF_CHAIN, PUBLIC}; +pub use note_type::NoteType; mod nullifier; pub use nullifier::Nullifier; diff --git a/objects/src/notes/note_tag.rs b/objects/src/notes/note_tag.rs index bffc3a912..949258630 100644 --- a/objects/src/notes/note_tag.rs +++ b/objects/src/notes/note_tag.rs @@ -1,21 +1,16 @@ -use core::fmt; +use core::{fmt, num::TryFromIntError}; use miden_crypto::Felt; use super::{ - note_type::{ENCRYPTED, OFF_CHAIN, PUBLIC}, - AccountId, ByteReader, ByteWriter, Deserializable, DeserializationError, NoteError, NoteType, - Serializable, + AccountId, ByteReader, ByteWriter, Deserializable, DeserializationError, NoteError, + NoteExecutionMode, NoteType, Serializable, }; // NOTE TAG // ================================================================================================ -// The higher two bits of the tag encode the note's type. -pub const NOTE_TYPE_MASK_SHIFT: u32 = 30; -pub const NOTE_TYPE_MASK: u32 = 0b11 << NOTE_TYPE_MASK_SHIFT; - -#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct NoteTag(u32); @@ -24,17 +19,72 @@ impl NoteTag { // -------------------------------------------------------------------------------------------- /// Returns a new [NoteTag] instantiated from the specified account ID. - pub fn from_account_id(account_id: AccountId, note_type: NoteType) -> Result { - let note_type_bits = (note_type as u32) << 30; - let account_id_highbits = (u64::from(account_id) & 0xffff000000000000) >> 34; - let tag = note_type_bits | (account_id_highbits as u32); - - Ok(NoteTag(tag)) + /// + /// The tag is constructed as follows: + /// - For local execution, the two most significant bits are set to 0b00, the following 16 bits + /// are set to the 16 most significant bits of the account ID, and the remaining 14 bits are + /// set to 0. + /// - For network execution, the two most significant bits are set to 0b10 and the remaining + /// bits are set to the 30 most significant bits of the account ID. + pub fn from_account_id( + account_id: AccountId, + execution: NoteExecutionMode, + ) -> Result { + match execution { + NoteExecutionMode::Local => { + let id: u64 = account_id.into(); + // select the 16 high bits of the account id + let high_bits = id & 0xffff000000000000; + // set bits (30,14] with the account id data + // set bits (32,30] as `0b00` identifying the note as intended for local execution + Ok(Self((high_bits >> 34) as u32)) + }, + NoteExecutionMode::Network => { + if !account_id.is_on_chain() { + Err(NoteError::NetworkExecutionRequiresOnChainAccount) + } else { + let id: u64 = account_id.into(); + // select the 30 high bits of the account id + let high_bits = id & 0xfffffffc00000000; + // set bits (30,0] with the account id data + let tag = (high_bits >> 34) as u32; + // set bits (32,30] as `0b10` identifying the note as intended for network + // execution + Ok(Self(tag | 0x80000000)) + } + }, + } } // PUBLIC ACCESSORS // -------------------------------------------------------------------------------------------- + /// Returns true if the note is intended for execution by a specific account. + /// + /// A note is intended for execution by a single account if either the first two bits are zeros + /// or the first 3 bits are 0b100. + pub fn is_single_target(&self) -> bool { + let first_2_bit = self.0 >> 30; + let first_3_bits = self.0 >> 29; + first_2_bit == 0b00 || first_3_bits == 0b100 + } + + /// Returns note execution mode defined by this tag. + /// + /// If the most significant bit of the tag is 0 or the 3 most significant bits are equal to + /// 0b101, the note is intended for local execution; otherwise, the note is intended for + /// network execution. + pub fn execution_mode(&self) -> NoteExecutionMode { + let first_bit = self.0 >> 31; + let first_3_bits = self.0 >> 29; + + if first_bit == 0 || first_3_bits == 0b101 { + NoteExecutionMode::Local + } else { + NoteExecutionMode::Network + } + } + /// Returns the inner u32 value of this tag. pub fn inner(&self) -> u32 { self.0 @@ -45,9 +95,14 @@ impl NoteTag { /// Returns an error if this tag is not consistent with the specified note type, and self /// otherwise. + /// + /// The tag and the note type are consistent if they satisfy the following rules: + /// - For off-chain notes, the most significant bit of the tag is 0. + /// - For public notes, the second most significant bit of the tag is 0. + /// - For encrypted notes, two most significant bits of the tag is 00. pub fn validate(&self, note_type: NoteType) -> Result { - let encoded_type = (self.0 & NOTE_TYPE_MASK) >> NOTE_TYPE_MASK_SHIFT; - if encoded_type != (note_type as u32) { + let tag_mask = note_type as u32; + if (self.0 >> 30) & tag_mask != 0 { Err(NoteError::InconsistentNoteTag(note_type, self.0 as u64)) } else { Ok(*self) @@ -64,40 +119,25 @@ impl fmt::Display for NoteTag { // CONVERSIONS INTO NOTE TAG // ================================================================================================ -impl TryFrom for NoteTag { - type Error = NoteError; - - fn try_from(tag: u32) -> Result { - let note_type = (tag >> NOTE_TYPE_MASK_SHIFT) as u8; - - if note_type != PUBLIC && note_type != OFF_CHAIN && note_type != ENCRYPTED { - return Err(NoteError::InvalidNoteTypeValue(tag.into())); - } - - Ok(NoteTag(tag)) +impl From for NoteTag { + fn from(value: u32) -> Self { + Self(value) } } impl TryFrom for NoteTag { - type Error = NoteError; + type Error = TryFromIntError; fn try_from(value: u64) -> Result { - let tag: u32 = value.try_into().map_err(|_| NoteError::InvalidNoteTypeValue(value))?; - tag.try_into() + Ok(Self(value.try_into()?)) } } impl TryFrom for NoteTag { - type Error = NoteError; + type Error = TryFromIntError; fn try_from(value: Felt) -> Result { - value.as_int().try_into() - } -} - -impl From for NoteTag { - fn from(value: NoteType) -> Self { - NoteTag((value as u32) << NOTE_TYPE_MASK_SHIFT) + Ok(Self(value.as_int().try_into()?)) } } @@ -137,52 +177,3 @@ impl Deserializable for NoteTag { Ok(Self(tag)) } } - -#[cfg(test)] -mod test { - use miden_crypto::Felt; - - use super::NoteTag; - use crate::notes::{NoteType, ENCRYPTED, NOTE_TYPE_MASK_SHIFT, OFF_CHAIN, PUBLIC}; - - #[test] - fn test_conversion() { - let public = (PUBLIC as u32) << NOTE_TYPE_MASK_SHIFT; - let off_chain = (OFF_CHAIN as u32) << NOTE_TYPE_MASK_SHIFT; - let encrypted = (ENCRYPTED as u32) << NOTE_TYPE_MASK_SHIFT; - - assert_eq!(NoteTag::from(NoteType::Public), NoteTag(public)); - assert_eq!(NoteTag::from(NoteType::OffChain), NoteTag(off_chain)); - assert_eq!(NoteTag::from(NoteType::Encrypted), NoteTag(encrypted)); - - assert_eq!(NoteTag::from(NoteType::Public), public.try_into().unwrap()); - assert_eq!(NoteTag::from(NoteType::OffChain), off_chain.try_into().unwrap()); - assert_eq!(NoteTag::from(NoteType::Encrypted), encrypted.try_into().unwrap()); - - let public = u64::from(public); - let off_chain = u64::from(off_chain); - let encrypted = u64::from(encrypted); - - assert_eq!(NoteTag::from(NoteType::Public), public.try_into().unwrap()); - assert_eq!(NoteTag::from(NoteType::OffChain), off_chain.try_into().unwrap()); - assert_eq!(NoteTag::from(NoteType::Encrypted), encrypted.try_into().unwrap()); - - assert_eq!(NoteTag::from(NoteType::Public), Felt::new(public).try_into().unwrap()); - assert_eq!(NoteTag::from(NoteType::OffChain), Felt::new(off_chain).try_into().unwrap()); - assert_eq!(NoteTag::from(NoteType::Encrypted), Felt::new(encrypted).try_into().unwrap()); - } - - #[test] - fn test_validation() { - assert!(NoteTag::from(NoteType::Public).validate(NoteType::Public).is_ok()); - assert!(NoteTag::from(NoteType::OffChain).validate(NoteType::OffChain).is_ok()); - assert!(NoteTag::from(NoteType::Encrypted).validate(NoteType::Encrypted).is_ok()); - - assert!(NoteTag::from(NoteType::Public).validate(NoteType::OffChain).is_err()); - assert!(NoteTag::from(NoteType::Public).validate(NoteType::Encrypted).is_err()); - assert!(NoteTag::from(NoteType::OffChain).validate(NoteType::Public).is_err()); - assert!(NoteTag::from(NoteType::OffChain).validate(NoteType::Encrypted).is_err()); - assert!(NoteTag::from(NoteType::Encrypted).validate(NoteType::OffChain).is_err()); - assert!(NoteTag::from(NoteType::Encrypted).validate(NoteType::Public).is_err()); - } -} diff --git a/objects/src/notes/note_type.rs b/objects/src/notes/note_type.rs index cd7c89789..18eb48040 100644 --- a/objects/src/notes/note_type.rs +++ b/objects/src/notes/note_type.rs @@ -1,5 +1,3 @@ -use core::fmt::Display; - use crate::{ utils::serde::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable}, Felt, NoteError, @@ -9,9 +7,9 @@ use crate::{ // ================================================================================================ // Keep these masks in sync with `miden-lib/asm/miden/kernels/tx/tx.masm` -pub const PUBLIC: u8 = 0b01; -pub const OFF_CHAIN: u8 = 0b10; -pub const ENCRYPTED: u8 = 0b11; +const PUBLIC: u8 = 0b01; +const OFF_CHAIN: u8 = 0b10; +const ENCRYPTED: u8 = 0b11; // NOTE TYPE // ================================================================================================ @@ -30,43 +28,9 @@ pub enum NoteType { Public = PUBLIC, } -impl Display for NoteType { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - match self { - NoteType::OffChain => write!(f, "offchain"), - NoteType::Encrypted => write!(f, "encrypted"), - NoteType::Public => write!(f, "public"), - } - } -} - // CONVERSIONS FROM NOTE TYPE // ================================================================================================ -impl From for u8 { - fn from(id: NoteType) -> Self { - id as u8 - } -} - -impl From for u16 { - fn from(id: NoteType) -> Self { - id as u16 - } -} - -impl From for u32 { - fn from(id: NoteType) -> Self { - id as u32 - } -} - -impl From for u64 { - fn from(id: NoteType) -> Self { - id as u64 - } -} - impl From for Felt { fn from(id: NoteType) -> Self { Felt::new(id as u64)