diff --git a/CHANGELOG.md b/CHANGELOG.md index ff897a298..0c8fdd662 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,8 +49,9 @@ - Increased the maximum query limit for the store ([#1443](https://github.com/0xMiden/miden-node/pull/1443)). - [BREAKING] Migrated to version `v0.20` of the VM ([#1476](https://github.com/0xMiden/miden-node/pull/1476)). - [BREAKING] Change account in database representation ([#1481](https://github.com/0xMiden/miden-node/pull/1481)). -- Remove the cyclic database optimization ([#1497](https://github.com/0xMiden/miden-node/pull/1497)). +- Remove the cyclic database optimization ([#1497](https://github.com/0xMiden/miden-node/pull/1497)). - Fix race condition at DB shutdown in tests ([#1503](https://github.com/0xMiden/miden-node/pull/1503)). +- [BREAKING] Updated to new miden-base protocol: removed `aux` and `execution_hint` from `NoteMetadata`, removed `NoteExecutionMode`, and `NoteMetadata::new()` is now infallible ([#1526](https://github.com/0xMiden/miden-node/pull/1526)). ### Fixes diff --git a/Cargo.lock b/Cargo.lock index 2d9c82f3b..15ad3a6f4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -27,6 +27,17 @@ dependencies = [ "generic-array", ] +[[package]] +name = "ahash" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" +dependencies = [ + "getrandom 0.2.17", + "once_cell", + "version_check", +] + [[package]] name = "ahash" version = "0.8.12" @@ -1355,7 +1366,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -1700,6 +1711,9 @@ name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash 0.7.8", +] [[package]] name = "hashbrown" @@ -2130,7 +2144,7 @@ checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46" dependencies = [ "hermit-abi 0.5.2", "libc", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -2497,6 +2511,22 @@ dependencies = [ "autocfg", ] +[[package]] +name = "miden-agglayer" +version = "0.14.0" +source = "git+https://github.com/0xMiden/miden-base.git?branch=next#99c6b5116a88cb3efc54bd8250a06ae082e9648f" +dependencies = [ + "fs-err", + "miden-assembly", + "miden-core", + "miden-core-lib", + "miden-protocol", + "miden-standards", + "miden-utils-sync", + "regex", + "walkdir", +] + [[package]] name = "miden-air" version = "0.20.2" @@ -2551,8 +2581,8 @@ dependencies = [ [[package]] name = "miden-block-prover" -version = "0.13.0" -source = "git+https://github.com/0xMiden/miden-base.git?branch=next#20014df8b7e64648cf771a56572e47f78911b712" +version = "0.14.0" +source = "git+https://github.com/0xMiden/miden-base.git?branch=next#99c6b5116a88cb3efc54bd8250a06ae082e9648f" dependencies = [ "miden-protocol", "thiserror 2.0.17", @@ -2852,6 +2882,7 @@ dependencies = [ "miden-node-proto-build", "miden-node-utils", "miden-protocol", + "miden-standards", "miette", "proptest", "prost", @@ -3044,8 +3075,8 @@ dependencies = [ [[package]] name = "miden-protocol" -version = "0.13.0" -source = "git+https://github.com/0xMiden/miden-base.git?branch=next#20014df8b7e64648cf771a56572e47f78911b712" +version = "0.14.0" +source = "git+https://github.com/0xMiden/miden-base.git?branch=next#99c6b5116a88cb3efc54bd8250a06ae082e9648f" dependencies = [ "bech32", "fs-err", @@ -3074,8 +3105,8 @@ dependencies = [ [[package]] name = "miden-protocol-macros" -version = "0.13.0" -source = "git+https://github.com/0xMiden/miden-base.git?branch=next#20014df8b7e64648cf771a56572e47f78911b712" +version = "0.14.0" +source = "git+https://github.com/0xMiden/miden-base.git?branch=next#99c6b5116a88cb3efc54bd8250a06ae082e9648f" dependencies = [ "proc-macro2", "quote", @@ -3164,8 +3195,8 @@ dependencies = [ [[package]] name = "miden-standards" -version = "0.13.0" -source = "git+https://github.com/0xMiden/miden-base.git?branch=next#20014df8b7e64648cf771a56572e47f78911b712" +version = "0.14.0" +source = "git+https://github.com/0xMiden/miden-base.git?branch=next#99c6b5116a88cb3efc54bd8250a06ae082e9648f" dependencies = [ "fs-err", "miden-assembly", @@ -3181,12 +3212,15 @@ dependencies = [ [[package]] name = "miden-testing" -version = "0.13.0" -source = "git+https://github.com/0xMiden/miden-base.git?branch=next#20014df8b7e64648cf771a56572e47f78911b712" +version = "0.14.0" +source = "git+https://github.com/0xMiden/miden-base.git?branch=next#99c6b5116a88cb3efc54bd8250a06ae082e9648f" dependencies = [ "anyhow", "itertools 0.14.0", + "miden-agglayer", + "miden-assembly", "miden-block-prover", + "miden-core-lib", "miden-processor", "miden-protocol", "miden-standards", @@ -3194,13 +3228,14 @@ dependencies = [ "miden-tx-batch-prover", "rand 0.9.2", "rand_chacha 0.9.0", + "thiserror 2.0.17", "winterfell", ] [[package]] name = "miden-tx" -version = "0.13.0" -source = "git+https://github.com/0xMiden/miden-base.git?branch=next#20014df8b7e64648cf771a56572e47f78911b712" +version = "0.14.0" +source = "git+https://github.com/0xMiden/miden-base.git?branch=next#99c6b5116a88cb3efc54bd8250a06ae082e9648f" dependencies = [ "miden-processor", "miden-protocol", @@ -3212,8 +3247,8 @@ dependencies = [ [[package]] name = "miden-tx-batch-prover" -version = "0.13.0" -source = "git+https://github.com/0xMiden/miden-base.git?branch=next#20014df8b7e64648cf771a56572e47f78911b712" +version = "0.14.0" +source = "git+https://github.com/0xMiden/miden-base.git?branch=next#99c6b5116a88cb3efc54bd8250a06ae082e9648f" dependencies = [ "miden-protocol", "miden-tx", @@ -3466,7 +3501,7 @@ version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -3862,7 +3897,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ef622051fbb2cb98a524df3a8112f02d0919ccda600a44d705ec550f1a28fe2" dependencies = [ - "ahash", + "ahash 0.8.12", "async-trait", "blake2", "bytes", @@ -3898,7 +3933,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76f63d3f67d99c95a1f85623fc43242fd644dd12ccbaa18c38a54e1580c6846a" dependencies = [ - "ahash", + "ahash 0.8.12", "async-trait", "brotli", "bytes", @@ -3988,7 +4023,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b93c897e8cc04ff0d077ee2a655142910618222aeefc83f7f99f5b9fc59ccb13" dependencies = [ - "ahash", + "ahash 0.8.12", ] [[package]] @@ -4020,7 +4055,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba89e4400cb978f0d7be1c14bd7ab4168c8e2c00d97ff19f964fc0048780237c" dependencies = [ "arrayvec", - "hashbrown 0.16.1", + "hashbrown 0.12.3", "parking_lot", "rand 0.8.5", ] @@ -4840,7 +4875,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.11.0", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -5473,7 +5508,7 @@ dependencies = [ "getrandom 0.3.4", "once_cell", "rustix 1.1.3", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -5482,7 +5517,7 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8c27177b12a6399ffc08b98f76f7c9a1f4fe9fc967c784c5a071fa8d93cf7e1" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -6487,7 +6522,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] diff --git a/bin/network-monitor/src/counter.rs b/bin/network-monitor/src/counter.rs index b64a85f2b..86eb7a2f2 100644 --- a/bin/network-monitor/src/counter.rs +++ b/bin/network-monitor/src/counter.rs @@ -20,7 +20,6 @@ use miden_protocol::crypto::dsa::falcon512_rpo::SecretKey; use miden_protocol::note::{ Note, NoteAssets, - NoteExecutionHint, NoteInputs, NoteMetadata, NoteRecipient, @@ -30,7 +29,7 @@ use miden_protocol::note::{ }; use miden_protocol::transaction::{InputNotes, PartialBlockchain, TransactionArgs}; use miden_protocol::utils::Deserializable; -use miden_protocol::{Felt, Word, ZERO}; +use miden_protocol::{Felt, Word}; use miden_standards::account::interface::{AccountInterface, AccountInterfaceExt}; use miden_standards::code_builder::CodeBuilder; use miden_tx::auth::BasicAuthenticator; @@ -318,7 +317,7 @@ async fn setup_increment_task( .await? .unwrap_or(wallet_account_file.account.clone()); - let AuthSecretKey::RpoFalcon512(secret_key) = wallet_account_file + let AuthSecretKey::Falcon512Rpo(secret_key) = wallet_account_file .auth_secret_keys .first() .expect("wallet account file should have one auth secret key") @@ -770,7 +769,7 @@ async fn create_and_submit_network_note( rng: &mut ChaCha20Rng, ) -> Result<(String, AccountHeader, BlockNumber)> { // Create authenticator for transaction signing - let authenticator = BasicAuthenticator::new(&[AuthSecretKey::RpoFalcon512(secret_key.clone())]); + let authenticator = BasicAuthenticator::new(&[AuthSecretKey::Falcon512Rpo(secret_key.clone())]); let account_interface = AccountInterface::from_account(wallet_account); @@ -794,6 +793,8 @@ async fn create_and_submit_network_note( .await .context("Failed to execute transaction")?; + let tx_inputs = executed_tx.tx_inputs().to_bytes(); + let final_account = executed_tx.final_account().clone(); // Prove the transaction @@ -803,7 +804,7 @@ async fn create_and_submit_network_note( // Submit the proven transaction let request = ProvenTransaction { transaction: proven_tx.to_bytes(), - transaction_inputs: None, + transaction_inputs: Some(tx_inputs), }; let block_height: BlockNumber = rpc_client @@ -851,10 +852,8 @@ fn create_network_note( let metadata = NoteMetadata::new( wallet_account.id(), NoteType::Public, - NoteTag::from_account_id(counter_account.id()), - NoteExecutionHint::Always, - ZERO, - )?; + NoteTag::with_account_target(counter_account.id()), + ); let serial_num = Word::new([ Felt::new(rng.random()), diff --git a/bin/network-monitor/src/deploy/wallet.rs b/bin/network-monitor/src/deploy/wallet.rs index 89c616c17..de687ab6d 100644 --- a/bin/network-monitor/src/deploy/wallet.rs +++ b/bin/network-monitor/src/deploy/wallet.rs @@ -22,7 +22,7 @@ use crate::COMPONENT; pub fn create_wallet_account() -> Result<(Account, SecretKey)> { let mut rng = ChaCha20Rng::from_seed(rand::random()); let secret_key = SecretKey::with_rng(&mut get_rpo_random_coin(&mut rng)); - let auth = AuthScheme::RpoFalcon512 { pub_key: secret_key.public_key().into() }; + let auth = AuthScheme::Falcon512Rpo { pub_key: secret_key.public_key().into() }; let init_seed: [u8; 32] = rng.random(); let wallet_account = create_basic_wallet( @@ -41,7 +41,7 @@ pub fn save_wallet_account( secret_key: &SecretKey, file_path: &Path, ) -> Result<()> { - let auth_secret_key = AuthSecretKey::RpoFalcon512(secret_key.clone()); + let auth_secret_key = AuthSecretKey::Falcon512Rpo(secret_key.clone()); let account_file = AccountFile::new(account.clone(), vec![auth_secret_key]); account_file.write(file_path)?; Ok(()) diff --git a/bin/stress-test/src/seeding/mod.rs b/bin/stress-test/src/seeding/mod.rs index a3a258892..e0fe79338 100644 --- a/bin/stress-test/src/seeding/mod.rs +++ b/bin/stress-test/src/seeding/mod.rs @@ -34,6 +34,7 @@ use miden_protocol::block::{ use miden_protocol::crypto::dsa::ecdsa_k256_keccak::SecretKey as EcdsaSecretKey; use miden_protocol::crypto::dsa::falcon512_rpo::{PublicKey, SecretKey}; use miden_protocol::crypto::rand::RpoRandomCoin; +use miden_protocol::errors::AssetError; use miden_protocol::note::{Note, NoteHeader, NoteId, NoteInclusionProof}; use miden_protocol::transaction::{ InputNote, @@ -45,8 +46,8 @@ use miden_protocol::transaction::{ TransactionHeader, }; use miden_protocol::utils::Serializable; -use miden_protocol::{AssetError, Felt, ONE, Word}; -use miden_standards::account::auth::AuthRpoFalcon512; +use miden_protocol::{Felt, ONE, Word}; +use miden_standards::account::auth::AuthFalcon512Rpo; use miden_standards::account::faucets::BasicFungibleFaucet; use miden_standards::account::wallets::BasicWallet; use miden_standards::note::create_p2id_note; @@ -314,7 +315,7 @@ fn create_note(faucet_id: AccountId, target_id: AccountId, rng: &mut RpoRandomCo target_id, vec![asset], miden_protocol::note::NoteType::Public, - Felt::default(), + miden_protocol::note::NoteAttachment::default(), rng, ) .expect("note creation failed") @@ -327,7 +328,7 @@ fn create_account(public_key: PublicKey, index: u64, storage_mode: AccountStorag AccountBuilder::new(init_seed.try_into().unwrap()) .account_type(AccountType::RegularAccountImmutableCode) .storage_mode(storage_mode) - .with_auth_component(AuthRpoFalcon512::new(public_key.into())) + .with_auth_component(AuthFalcon512Rpo::new(public_key.into())) .with_component(BasicWallet) .build() .unwrap() @@ -345,7 +346,7 @@ fn create_faucet() -> Account { .account_type(AccountType::FungibleFaucet) .storage_mode(AccountStorageMode::Private) .with_component(BasicFungibleFaucet::new(token_symbol, 2, Felt::new(u64::MAX)).unwrap()) - .with_auth_component(AuthRpoFalcon512::new(key_pair.public_key().into())) + .with_auth_component(AuthFalcon512Rpo::new(key_pair.public_key().into())) .build() .unwrap() } diff --git a/bin/stress-test/src/store/mod.rs b/bin/stress-test/src/store/mod.rs index 59e094ba5..e4960bb7e 100644 --- a/bin/stress-test/src/store/mod.rs +++ b/bin/stress-test/src/store/mod.rs @@ -92,7 +92,7 @@ pub async fn sync_state( ) -> (Duration, proto::rpc::SyncStateResponse) { let note_tags = account_ids .iter() - .map(|id| u32::from(NoteTag::from_account_id(*id))) + .map(|id| u32::from(NoteTag::with_account_target(*id))) .collect::>(); let account_ids = account_ids @@ -158,7 +158,7 @@ pub async fn sync_notes( ) -> Duration { let note_tags = account_ids .iter() - .map(|id| u32::from(NoteTag::from_account_id(*id))) + .map(|id| u32::from(NoteTag::with_account_target(*id))) .collect::>(); let sync_request = proto::rpc::SyncNotesRequest { block_range: Some(proto::rpc::BlockRange { block_from: 0, block_to: None }), diff --git a/crates/block-producer/src/domain/transaction.rs b/crates/block-producer/src/domain/transaction.rs index 0c819d06f..5b2ab30b3 100644 --- a/crates/block-producer/src/domain/transaction.rs +++ b/crates/block-producer/src/domain/transaction.rs @@ -6,7 +6,7 @@ use std::sync::Arc; use miden_protocol::Word; use miden_protocol::account::AccountId; use miden_protocol::block::BlockNumber; -use miden_protocol::note::Nullifier; +use miden_protocol::note::{NoteHeader, Nullifier}; use miden_protocol::transaction::{OutputNote, ProvenTransaction, TransactionId, TxAccountUpdate}; use crate::errors::VerifyTxError; @@ -119,8 +119,7 @@ impl AuthenticatedTransaction { pub fn unauthenticated_note_commitments(&self) -> impl Iterator + '_ { self.inner .unauthenticated_notes() - .copied() - .map(|header| header.commitment()) + .map(NoteHeader::commitment) .filter(|commitment| !self.notes_authenticated_by_store.contains(commitment)) } diff --git a/crates/block-producer/src/errors.rs b/crates/block-producer/src/errors.rs index 38ac06716..40c74c99f 100644 --- a/crates/block-producer/src/errors.rs +++ b/crates/block-producer/src/errors.rs @@ -2,11 +2,12 @@ use core::error::Error as CoreError; use miden_block_prover::BlockProverError; use miden_node_proto::errors::{ConversionError, GrpcError}; +use miden_protocol::Word; use miden_protocol::account::AccountId; use miden_protocol::block::BlockNumber; +use miden_protocol::errors::{ProposedBatchError, ProposedBlockError, ProvenBatchError}; use miden_protocol::note::Nullifier; use miden_protocol::transaction::TransactionId; -use miden_protocol::{ProposedBatchError, ProposedBlockError, ProvenBatchError, Word}; use miden_remote_prover_client::RemoteProverClientError; use thiserror::Error; use tokio::task::JoinError; diff --git a/crates/block-producer/src/test_utils/proven_tx.rs b/crates/block-producer/src/test_utils/proven_tx.rs index aa6ec310e..b8d67e9fb 100644 --- a/crates/block-producer/src/test_utils/proven_tx.rs +++ b/crates/block-producer/src/test_utils/proven_tx.rs @@ -131,7 +131,7 @@ impl MockProvenTxBuilder { .map(|note_index| { let note = Note::mock_noop(Word::from([0, 0, 0, note_index])); - OutputNote::Header(*note.header()) + OutputNote::Header(note.header().clone()) }) .collect(); diff --git a/crates/ntx-builder/src/actor/account_state.rs b/crates/ntx-builder/src/actor/account_state.rs index bfc5a41b7..3a9015a26 100644 --- a/crates/ntx-builder/src/actor/account_state.rs +++ b/crates/ntx-builder/src/actor/account_state.rs @@ -1,7 +1,7 @@ use std::collections::{BTreeMap, BTreeSet, HashSet}; use std::num::NonZeroUsize; -use miden_node_proto::domain::account::NetworkAccountPrefix; +use miden_node_proto::domain::account::NetworkAccountId; use miden_node_proto::domain::mempool::MempoolEvent; use miden_node_proto::domain::note::{NetworkNote, SingleTargetNetworkNote}; use miden_node_utils::tracing::OpenTelemetrySpanExt; @@ -49,8 +49,8 @@ pub struct TransactionCandidate { /// The current state of a network account. #[derive(Clone)] pub struct NetworkAccountState { - /// The network account prefix corresponding to the network account this state represents. - account_prefix: NetworkAccountPrefix, + /// The network account ID corresponding to the network account this state represents. + account_id: NetworkAccountId, /// Component of this state which Contains the committed and inflight account updates as well /// as available and nullified notes. @@ -74,26 +74,23 @@ impl NetworkAccountState { #[instrument(target = COMPONENT, name = "ntx.state.load", skip_all)] pub async fn load( account: Account, - account_prefix: NetworkAccountPrefix, + account_id: NetworkAccountId, store: &StoreClient, block_num: BlockNumber, ) -> Result { - let notes = store.get_unconsumed_network_notes(account_prefix, block_num.as_u32()).await?; + let notes = store.get_unconsumed_network_notes(account_id, block_num.as_u32()).await?; let notes = notes .into_iter() - .filter_map(|note| { - if let NetworkNote::SingleTarget(note) = note { - Some(note) - } else { - None - } + .map(|note| { + let NetworkNote::SingleTarget(note) = note; + note }) .collect::>(); let account = NetworkAccountNoteState::new(account, notes); let state = Self { account, - account_prefix, + account_id, inflight_txs: BTreeMap::default(), nullifier_idx: HashSet::default(), }; @@ -166,7 +163,7 @@ impl NetworkAccountState { } => { // Filter network notes relevant to this account. let network_notes = filter_by_prefix_and_map_to_single_target( - self.account_prefix, + self.account_id, network_notes.clone(), ); self.add_transaction(*id, nullifiers, &network_notes, account_delta.as_ref()); @@ -209,12 +206,12 @@ impl NetworkAccountState { let mut tx_impact = TransactionImpact::default(); if let Some(update) = account_delta.and_then(NetworkAccountEffect::from_protocol) { - let account_prefix = update.prefix(); - if account_prefix == self.account_prefix { + let account_id = update.network_account_id(); + if account_id == self.account_id { match update { NetworkAccountEffect::Updated(account_delta) => { self.account.add_delta(&account_delta); - tx_impact.account_delta = Some(account_prefix); + tx_impact.account_delta = Some(account_id); }, NetworkAccountEffect::Created(_) => {}, } @@ -222,9 +219,9 @@ impl NetworkAccountState { } for note in network_notes { assert_eq!( - note.account_prefix(), - self.account_prefix, - "transaction note prefix does not match network account actor's prefix" + note.account_id(), + self.account_id, + "note's account ID does not match network account actor's account ID" ); tx_impact.notes.insert(note.nullifier()); self.nullifier_idx.insert(note.nullifier()); @@ -253,7 +250,7 @@ impl NetworkAccountState { }; if let Some(prefix) = impact.account_delta { - if prefix == self.account_prefix { + if prefix == self.account_id { self.account.commit_delta(); } } @@ -276,10 +273,10 @@ impl NetworkAccountState { }; // Revert account creation. - if let Some(account_prefix) = impact.account_delta { + if let Some(account_id) = impact.account_delta { // Account creation reverted, actor must stop. - if account_prefix == self.account_prefix && self.account.revert_delta() { - return Some(ActorShutdownReason::AccountReverted(account_prefix)); + if account_id == self.account_id && self.account.revert_delta() { + return Some(ActorShutdownReason::AccountReverted(account_id)); } } @@ -318,7 +315,7 @@ impl NetworkAccountState { #[derive(Clone, Default)] struct TransactionImpact { /// The network account this transaction added an account delta to. - account_delta: Option, + account_delta: Option, /// Network notes this transaction created. notes: BTreeSet, @@ -335,16 +332,14 @@ impl TransactionImpact { /// Filters network notes by prefix and maps them to single target network notes. fn filter_by_prefix_and_map_to_single_target( - account_prefix: NetworkAccountPrefix, + account_id: NetworkAccountId, notes: Vec, ) -> Vec { notes .into_iter() .filter_map(|note| match note { - NetworkNote::SingleTarget(note) if note.account_prefix() == account_prefix => { - Some(note) - }, - _ => None, + NetworkNote::SingleTarget(note) if note.account_id() == account_id => Some(note), + NetworkNote::SingleTarget(_) => None, }) .collect::>() } diff --git a/crates/ntx-builder/src/actor/execute.rs b/crates/ntx-builder/src/actor/execute.rs index cb38dc89a..66f22f8c0 100644 --- a/crates/ntx-builder/src/actor/execute.rs +++ b/crates/ntx-builder/src/actor/execute.rs @@ -4,6 +4,7 @@ use miden_node_proto::clients::ValidatorClient; use miden_node_proto::generated::{self as proto}; use miden_node_utils::lru_cache::LruCache; use miden_node_utils::tracing::OpenTelemetrySpanExt; +use miden_protocol::Word; use miden_protocol::account::{ Account, AccountId, @@ -13,6 +14,7 @@ use miden_protocol::account::{ }; use miden_protocol::asset::{AssetVaultKey, AssetWitness}; use miden_protocol::block::{BlockHeader, BlockNumber}; +use miden_protocol::errors::TransactionInputError; use miden_protocol::note::{Note, NoteScript}; use miden_protocol::transaction::{ AccountInputs, @@ -26,7 +28,6 @@ use miden_protocol::transaction::{ TransactionInputs, }; use miden_protocol::vm::FutureMaybeSend; -use miden_protocol::{TransactionInputError, Word}; use miden_remote_prover_client::remote_prover::tx_prover::RemoteTransactionProver; use miden_tx::auth::UnreachableAuth; use miden_tx::utils::Serializable; diff --git a/crates/ntx-builder/src/actor/inflight_note.rs b/crates/ntx-builder/src/actor/inflight_note.rs index 626b474ac..23c7d06d7 100644 --- a/crates/ntx-builder/src/actor/inflight_note.rs +++ b/crates/ntx-builder/src/actor/inflight_note.rs @@ -46,15 +46,10 @@ impl InflightNetworkNote { /// Checks if the network note is available for execution. /// - /// The note is available if it can be consumed and the backoff period has passed. + /// The note is available if the backoff period has passed. pub fn is_available(&self, block_num: BlockNumber) -> bool { - let can_consume = self - .to_inner() - .metadata() - .execution_hint() - .can_be_consumed(block_num) - .unwrap_or(true); - can_consume && has_backoff_passed(block_num, self.last_attempt, self.attempt_count) + self.note.can_be_consumed(block_num).unwrap_or(true) + && has_backoff_passed(block_num, self.last_attempt, self.attempt_count) } /// Registers a failed attempt to execute the network note at the specified block number. diff --git a/crates/ntx-builder/src/actor/mod.rs b/crates/ntx-builder/src/actor/mod.rs index 602dde11b..f743d7908 100644 --- a/crates/ntx-builder/src/actor/mod.rs +++ b/crates/ntx-builder/src/actor/mod.rs @@ -9,7 +9,7 @@ use std::time::Duration; use account_state::{NetworkAccountState, TransactionCandidate}; use futures::FutureExt; use miden_node_proto::clients::{Builder, ValidatorClient}; -use miden_node_proto::domain::account::NetworkAccountPrefix; +use miden_node_proto::domain::account::NetworkAccountId; use miden_node_proto::domain::mempool::MempoolEvent; use miden_node_utils::ErrorReport; use miden_node_utils::lru_cache::LruCache; @@ -33,7 +33,7 @@ use crate::store::StoreClient; /// The reason an actor has shut down. pub enum ActorShutdownReason { /// Occurs when the transaction that created the actor is reverted. - AccountReverted(NetworkAccountPrefix), + AccountReverted(NetworkAccountId), /// Occurs when an account actor detects failure in the messaging channel used by the /// coordinator. EventChannelClosed, @@ -42,7 +42,7 @@ pub enum ActorShutdownReason { /// Occurs when an account actor detects its corresponding cancellation token has been triggered /// by the coordinator. Cancellation tokens are triggered by the coordinator to initiate /// graceful shutdown of actors. - Cancelled(NetworkAccountPrefix), + Cancelled(NetworkAccountId), } // ACCOUNT ACTOR CONFIG @@ -78,7 +78,7 @@ pub enum AccountOrigin { /// store yet. Transaction(Box), /// Accounts that already exist in the store. - Store(NetworkAccountPrefix), + Store(NetworkAccountId), } impl AccountOrigin { @@ -93,16 +93,16 @@ impl AccountOrigin { } /// Returns an [`AccountOrigin::Store`]. - pub fn store(prefix: NetworkAccountPrefix) -> Self { - AccountOrigin::Store(prefix) + pub fn store(account_id: NetworkAccountId) -> Self { + AccountOrigin::Store(account_id) } - /// Returns the [`NetworkAccountPrefix`] of the account. - pub fn prefix(&self) -> NetworkAccountPrefix { + /// Returns the [`NetworkAccountId`] of the account. + pub fn id(&self) -> NetworkAccountId { match self { - AccountOrigin::Transaction(account) => NetworkAccountPrefix::try_from(account.id()) + AccountOrigin::Transaction(account) => NetworkAccountId::try_from(account.id()) .expect("actor accounts are always network accounts"), - AccountOrigin::Store(prefix) => *prefix, + AccountOrigin::Store(account_id) => *account_id, } } } @@ -213,7 +213,7 @@ impl AccountActor { }; let block_num = self.chain_state.read().await.chain_tip_header.block_num(); let mut state = - NetworkAccountState::load(account, self.origin.prefix(), &self.store, block_num) + NetworkAccountState::load(account, self.origin.id(), &self.store, block_num) .await .expect("actor should be able to load account state"); @@ -229,7 +229,7 @@ impl AccountActor { }; tokio::select! { _ = self.cancel_token.cancelled() => { - return ActorShutdownReason::Cancelled(self.origin.prefix()); + return ActorShutdownReason::Cancelled(self.origin.id()); } // Handle mempool events. event = self.event_rx.recv() => { diff --git a/crates/ntx-builder/src/actor/note_state.rs b/crates/ntx-builder/src/actor/note_state.rs index 9de85dd6a..87b91fc21 100644 --- a/crates/ntx-builder/src/actor/note_state.rs +++ b/crates/ntx-builder/src/actor/note_state.rs @@ -1,6 +1,6 @@ use std::collections::{HashMap, VecDeque}; -use miden_node_proto::domain::account::NetworkAccountPrefix; +use miden_node_proto::domain::account::NetworkAccountId; use miden_node_proto::domain::note::SingleTargetNetworkNote; use miden_protocol::account::delta::AccountUpdateDetails; use miden_protocol::account::{Account, AccountDelta, AccountId}; @@ -33,7 +33,7 @@ pub struct NetworkAccountNoteState { impl NetworkAccountNoteState { /// Creates a new account state from the supplied account and notes. pub fn new(account: Account, notes: Vec) -> Self { - let account_prefix = NetworkAccountPrefix::try_from(account.id()) + let account_id = NetworkAccountId::try_from(account.id()) .expect("only network accounts are used for account state"); let mut state = Self { @@ -46,8 +46,8 @@ impl NetworkAccountNoteState { for note in notes { // Currently only support single target network notes in NTB. assert!( - note.account_prefix() == account_prefix, - "Notes supplied into account state must match expected account prefix" + note.account_id() == account_id, + "Notes supplied into account state must match expected account ID" ); state.add_note(note); } @@ -210,15 +210,15 @@ impl NetworkAccountEffect { AccountUpdateDetails::Delta(update) => NetworkAccountEffect::Updated(update.clone()), }; - update.account_id().is_network().then_some(update) + update.protocol_account_id().is_network().then_some(update) } - pub fn prefix(&self) -> NetworkAccountPrefix { + pub fn network_account_id(&self) -> NetworkAccountId { // SAFETY: This is a network account by construction. - self.account_id().try_into().unwrap() + self.protocol_account_id().try_into().unwrap() } - fn account_id(&self) -> AccountId { + fn protocol_account_id(&self) -> AccountId { match self { NetworkAccountEffect::Created(acc) => acc.id(), NetworkAccountEffect::Updated(delta) => delta.id(), diff --git a/crates/ntx-builder/src/builder.rs b/crates/ntx-builder/src/builder.rs index 5a1b091a6..84c711385 100644 --- a/crates/ntx-builder/src/builder.rs +++ b/crates/ntx-builder/src/builder.rs @@ -4,7 +4,7 @@ use std::time::Duration; use anyhow::Context; use futures::TryStreamExt; -use miden_node_proto::domain::account::NetworkAccountPrefix; +use miden_node_proto::domain::account::NetworkAccountId; use miden_node_proto::domain::mempool::MempoolEvent; use miden_node_utils::lru_cache::LruCache; use miden_protocol::Word; @@ -155,9 +155,9 @@ impl NetworkTransactionBuilder { // Create initial set of actors based on all known network accounts. let account_ids = store.get_network_account_ids().await?; for account_id in account_ids { - if let Ok(account_prefix) = NetworkAccountPrefix::try_from(account_id) { + if let Ok(account_id) = NetworkAccountId::try_from(account_id) { self.coordinator - .spawn_actor(AccountOrigin::store(account_prefix), &actor_context) + .spawn_actor(AccountOrigin::store(account_id), &actor_context) .await?; } } diff --git a/crates/ntx-builder/src/coordinator.rs b/crates/ntx-builder/src/coordinator.rs index 7b5a588a9..f6c038911 100644 --- a/crates/ntx-builder/src/coordinator.rs +++ b/crates/ntx-builder/src/coordinator.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use anyhow::Context; use indexmap::IndexMap; -use miden_node_proto::domain::account::NetworkAccountPrefix; +use miden_node_proto::domain::account::NetworkAccountId; use miden_node_proto::domain::mempool::MempoolEvent; use miden_node_proto::domain::note::NetworkNote; use miden_protocol::account::delta::AccountUpdateDetails; @@ -69,7 +69,7 @@ pub struct Coordinator { /// When actors are spawned, they register their communication channel here. When events need /// to be broadcast, this registry is used to locate the appropriate actors. The registry is /// automatically cleaned up when actors complete their execution. - actor_registry: HashMap, + actor_registry: HashMap, /// Join set for managing actor tasks and monitoring their completion status. /// @@ -89,7 +89,7 @@ pub struct Coordinator { /// Cache of events received from the mempool that predate corresponding network accounts. /// Grouped by account prefix to allow targeted event delivery to actors upon creation. - predating_events: HashMap>>, + predating_events: HashMap>>, } impl Coordinator { @@ -118,7 +118,7 @@ impl Coordinator { origin: AccountOrigin, actor_context: &AccountActorContext, ) -> Result<(), SendError>> { - let account_prefix = origin.prefix(); + let account_prefix = origin.id(); // If an actor already exists for this account prefix, something has gone wrong. if let Some(handle) = self.actor_registry.remove(&account_prefix) { @@ -248,15 +248,14 @@ impl Coordinator { // Determine target actors for each note. for note in network_notes { - if let NetworkNote::SingleTarget(note) = note { - let prefix = note.account_prefix(); - if let Some(actor) = self.actor_registry.get(&prefix) { - // Register actor as target. - target_actors.insert(prefix, actor); - } else { - // Cache event for every note that doesn't have a corresponding actor. - self.predating_events.entry(prefix).or_default().insert(*id, event.clone()); - } + let NetworkNote::SingleTarget(note) = note; + let prefix = note.account_id(); + if let Some(actor) = self.actor_registry.get(&prefix) { + // Register actor as target. + target_actors.insert(prefix, actor); + } else { + // Cache event for every note that doesn't have a corresponding actor. + self.predating_events.entry(prefix).or_default().insert(*id, event.clone()); } } } diff --git a/crates/ntx-builder/src/store.rs b/crates/ntx-builder/src/store.rs index 447571a5a..784a27101 100644 --- a/crates/ntx-builder/src/store.rs +++ b/crates/ntx-builder/src/store.rs @@ -1,7 +1,7 @@ use std::time::Duration; use miden_node_proto::clients::{Builder, StoreNtxBuilderClient}; -use miden_node_proto::domain::account::NetworkAccountPrefix; +use miden_node_proto::domain::account::NetworkAccountId; use miden_node_proto::domain::note::NetworkNote; use miden_node_proto::errors::ConversionError; use miden_node_proto::generated::rpc::BlockRange; @@ -109,9 +109,9 @@ impl StoreClient { #[instrument(target = COMPONENT, name = "store.client.get_network_account", skip_all, err)] pub async fn get_network_account( &self, - prefix: NetworkAccountPrefix, + account_id: NetworkAccountId, ) -> Result, StoreError> { - let request = proto::store::AccountIdPrefix { account_id_prefix: prefix.inner() }; + let request = proto::store::AccountIdPrefix { account_id_prefix: account_id.prefix() }; let store_response = self .inner @@ -140,7 +140,7 @@ impl StoreClient { #[instrument(target = COMPONENT, name = "store.client.get_unconsumed_network_notes", skip_all, err)] pub async fn get_unconsumed_network_notes( &self, - network_account_prefix: NetworkAccountPrefix, + network_account_id: NetworkAccountId, block_num: u32, ) -> Result, StoreError> { // Upper bound of each note is ~10KB. Limit page size to ~10MB. @@ -154,7 +154,7 @@ impl StoreClient { let req = proto::store::UnconsumedNetworkNotesRequest { page_token, page_size: PAGE_SIZE, - network_account_id_prefix: network_account_prefix.inner(), + network_account_id_prefix: network_account_id.prefix(), block_num, }; let resp = store_client.get_unconsumed_network_notes(req).await?.into_inner(); diff --git a/crates/proto/Cargo.toml b/crates/proto/Cargo.toml index 255b27c9d..6d3589ca3 100644 --- a/crates/proto/Cargo.toml +++ b/crates/proto/Cargo.toml @@ -21,6 +21,7 @@ http = { workspace = true } miden-node-grpc-error-macro = { workspace = true } miden-node-utils = { workspace = true } miden-protocol = { workspace = true } +miden-standards = { workspace = true } prost = { workspace = true } thiserror = { workspace = true } tonic = { default-features = true, workspace = true } diff --git a/crates/proto/src/domain/account.rs b/crates/proto/src/domain/account.rs index 57e9a4de8..3bd3aa87c 100644 --- a/crates/proto/src/domain/account.rs +++ b/crates/proto/src/domain/account.rs @@ -18,8 +18,9 @@ use miden_protocol::block::BlockNumber; use miden_protocol::block::account_tree::AccountWitness; use miden_protocol::crypto::merkle::SparseMerklePath; use miden_protocol::crypto::merkle::smt::SmtProof; -use miden_protocol::note::{NoteExecutionMode, NoteTag}; +use miden_protocol::note::NoteAttachment; use miden_protocol::utils::{Deserializable, DeserializationError, Serializable}; +use miden_standards::note::NetworkAccountTarget; use thiserror::Error; use super::try_convert; @@ -1022,76 +1023,95 @@ impl From for proto::primitives::Asset { pub type AccountPrefix = u32; -/// Newtype wrapper for network account prefix. +/// Newtype wrapper for network account IDs. +/// /// Provides type safety for accounts that are meant for network execution. +/// This wraps the full `AccountId` of a network account, typically extracted +/// from a `NetworkAccountTarget` attachment. #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] -pub struct NetworkAccountPrefix(u32); +pub struct NetworkAccountId(AccountId); -impl std::fmt::Display for NetworkAccountPrefix { +impl std::fmt::Display for NetworkAccountId { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(&self.0, f) } } -impl NetworkAccountPrefix { - pub fn inner(&self) -> u32 { +impl NetworkAccountId { + /// Returns the inner `AccountId`. + pub fn inner(&self) -> AccountId { self.0 } -} -impl TryFrom for NetworkAccountPrefix { - type Error = NetworkAccountError; - - fn try_from(value: u32) -> Result { - if value >> 30 != 0 { - return Err(NetworkAccountError::InvalidPrefix(value)); - } - Ok(NetworkAccountPrefix(value)) + /// Gets the 30-bit prefix of the account ID used for tag matching. + pub fn prefix(&self) -> AccountPrefix { + get_account_id_tag_prefix(self.0) } } -impl TryFrom for NetworkAccountPrefix { +impl TryFrom for NetworkAccountId { type Error = NetworkAccountError; fn try_from(id: AccountId) -> Result { if !id.is_network() { return Err(NetworkAccountError::NotNetworkAccount(id)); } - let prefix = get_account_id_tag_prefix(id); - Ok(NetworkAccountPrefix(prefix)) + Ok(NetworkAccountId(id)) } } -impl TryFrom for NetworkAccountPrefix { +impl TryFrom<&NoteAttachment> for NetworkAccountId { type Error = NetworkAccountError; - fn try_from(tag: NoteTag) -> Result { - if tag.execution_mode() != NoteExecutionMode::Network || !tag.is_single_target() { - return Err(NetworkAccountError::InvalidExecutionMode(tag)); - } + fn try_from(attachment: &NoteAttachment) -> Result { + let target = NetworkAccountTarget::try_from(attachment) + .map_err(|e| NetworkAccountError::InvalidAttachment(e.to_string()))?; + Ok(NetworkAccountId(target.target_id())) + } +} - let tag_inner: u32 = tag.into(); - assert!(tag_inner >> 30 == 0, "first 2 bits have to be 0"); - Ok(NetworkAccountPrefix(tag_inner)) +impl TryFrom for NetworkAccountId { + type Error = NetworkAccountError; + + fn try_from(attachment: NoteAttachment) -> Result { + NetworkAccountId::try_from(&attachment) } } -impl From for u32 { - fn from(value: NetworkAccountPrefix) -> Self { +impl From for AccountId { + fn from(value: NetworkAccountId) -> Self { value.inner() } } +impl From for u32 { + /// Returns the 30-bit prefix of the network account ID. + /// This is used for note tag matching. + fn from(value: NetworkAccountId) -> Self { + value.prefix() + } +} + #[derive(Debug, Error)] pub enum NetworkAccountError { #[error("account ID {0} is not a valid network account ID")] NotNetworkAccount(AccountId), - #[error("note tag {0} is not valid for network account execution")] - InvalidExecutionMode(NoteTag), - #[error("note prefix should be 30-bit long ({0} has non-zero in the 2 most significant bits)")] + #[error("invalid network account attachment: {0}")] + InvalidAttachment(String), + #[error("invalid network account prefix: {0}")] InvalidPrefix(u32), } +/// Validates that a u32 represents a valid network account prefix. +/// +/// Network accounts have a 30-bit prefix (top 2 bits must be 0). +pub fn validate_network_account_prefix(prefix: u32) -> Result { + if prefix >> 30 != 0 { + return Err(NetworkAccountError::InvalidPrefix(prefix)); + } + Ok(prefix) +} + /// Gets the 30-bit prefix of the account ID. fn get_account_id_tag_prefix(id: AccountId) -> AccountPrefix { (id.prefix().as_u64() >> 34) as AccountPrefix diff --git a/crates/proto/src/domain/note.rs b/crates/proto/src/domain/note.rs index c4065b298..5098ef41f 100644 --- a/crates/proto/src/domain/note.rs +++ b/crates/proto/src/domain/note.rs @@ -1,8 +1,10 @@ +use miden_protocol::Word; +use miden_protocol::block::BlockNumber; use miden_protocol::crypto::merkle::SparseMerklePath; use miden_protocol::note::{ Note, + NoteAttachment, NoteDetails, - NoteExecutionHint, NoteId, NoteInclusionProof, NoteMetadata, @@ -12,10 +14,10 @@ use miden_protocol::note::{ Nullifier, }; use miden_protocol::utils::{Deserializable, Serializable}; -use miden_protocol::{Felt, Word}; +use miden_standards::note::NetworkAccountTarget; use thiserror::Error; -use super::account::NetworkAccountPrefix; +use super::account::NetworkAccountId; use crate::errors::{ConversionError, MissingFieldHelper}; use crate::generated as proto; @@ -28,20 +30,24 @@ impl TryFrom for NoteMetadata { .ok_or_else(|| proto::note::NoteMetadata::missing_field(stringify!(sender)))? .try_into()?; let note_type = NoteType::try_from(u64::from(value.note_type))?; - let tag = NoteTag::from(value.tag); + let tag = NoteTag::new(value.tag); - let execution_hint = NoteExecutionHint::try_from(value.execution_hint)?; - - let aux = Felt::try_from(value.aux).map_err(|_| ConversionError::NotAValidFelt)?; + // Deserialize attachment if present + let attachment = if value.attachment.is_empty() { + NoteAttachment::default() + } else { + NoteAttachment::read_from_bytes(&value.attachment) + .map_err(|err| ConversionError::deserialization_error("NoteAttachment", err))? + }; - Ok(NoteMetadata::new(sender, note_type, tag, execution_hint, aux)?) + Ok(NoteMetadata::new(sender, note_type, tag).with_attachment(attachment)) } } impl From for proto::note::NetworkNote { fn from(note: Note) -> Self { Self { - metadata: Some(proto::note::NoteMetadata::from(*note.metadata())), + metadata: Some(proto::note::NoteMetadata::from(note.metadata().clone())), details: NoteDetails::from(note).to_bytes(), } } @@ -50,7 +56,7 @@ impl From for proto::note::NetworkNote { impl From for proto::note::Note { fn from(note: Note) -> Self { Self { - metadata: Some(proto::note::NoteMetadata::from(*note.metadata())), + metadata: Some(proto::note::NoteMetadata::from(note.metadata().clone())), details: Some(NoteDetails::from(note).to_bytes()), } } @@ -60,7 +66,7 @@ impl From for proto::note::NetworkNote { fn from(note: NetworkNote) -> Self { let note = Note::from(note); Self { - metadata: Some(proto::note::NoteMetadata::from(*note.metadata())), + metadata: Some(proto::note::NoteMetadata::from(note.metadata().clone())), details: NoteDetails::from(note).to_bytes(), } } @@ -70,17 +76,10 @@ impl From for proto::note::NoteMetadata { fn from(val: NoteMetadata) -> Self { let sender = Some(val.sender().into()); let note_type = val.note_type() as u32; - let tag = val.tag().into(); - let execution_hint: u64 = val.execution_hint().into(); - let aux = val.aux().into(); - - proto::note::NoteMetadata { - sender, - note_type, - tag, - execution_hint, - aux, - } + let tag = val.tag().as_u32(); + let attachment = val.attachment().to_bytes(); + + proto::note::NoteMetadata { sender, note_type, tag, attachment } } } @@ -184,14 +183,12 @@ impl TryFrom for Note { #[derive(Clone, Debug, PartialEq, Eq)] pub enum NetworkNote { SingleTarget(SingleTargetNetworkNote), - MultiTarget(MultiTargetNetworkNote), } impl NetworkNote { pub fn inner(&self) -> &Note { match self { - NetworkNote::SingleTarget(note) => ¬e.0, - NetworkNote::MultiTarget(note) => ¬e.0, + NetworkNote::SingleTarget(note) => note.inner(), } } @@ -211,8 +208,7 @@ impl NetworkNote { impl From for Note { fn from(value: NetworkNote) -> Self { match value { - NetworkNote::SingleTarget(note) => note.0, - NetworkNote::MultiTarget(note) => note.0, + NetworkNote::SingleTarget(note) => note.into(), } } } @@ -221,15 +217,7 @@ impl TryFrom for NetworkNote { type Error = NetworkNoteError; fn try_from(note: Note) -> Result { - if note.is_network_note() { - if note.metadata().tag().is_single_target() { - Ok(NetworkNote::SingleTarget(SingleTargetNetworkNote(note))) - } else { - Ok(NetworkNote::MultiTarget(MultiTargetNetworkNote(note))) - } - } else { - Err(NetworkNoteError::InvalidExecutionMode(note.metadata().tag())) - } + SingleTargetNetworkNote::try_from(note).map(NetworkNote::SingleTarget) } } @@ -241,43 +229,22 @@ impl TryFrom for NetworkNote { } } -// MULTI TARGET NETWORK NOTE -// ================================================================================================ - -/// A newtype that wraps around notes having multiple targets to be used in a network mode. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct MultiTargetNetworkNote(Note); - -impl TryFrom for MultiTargetNetworkNote { - type Error = NetworkNoteError; - - fn try_from(note: Note) -> Result { - if note.is_network_note() && !note.metadata().tag().is_single_target() { - Ok(Self(note)) - } else { - Err(NetworkNoteError::InvalidExecutionMode(note.metadata().tag())) - } - } -} - -impl TryFrom for MultiTargetNetworkNote { - type Error = ConversionError; - - fn try_from(proto_note: proto::note::NetworkNote) -> Result { - from_proto(proto_note) - } -} - // SINGLE TARGET NETWORK NOTE // ================================================================================================ -/// A newtype that wraps around notes targeting a single account to be used in a network mode. +/// A newtype that wraps around notes targeting a single network account. +/// +/// A note is considered a single-target network note if its attachment +/// is a valid `NetworkAccountTarget`. #[derive(Clone, Debug, PartialEq, Eq)] -pub struct SingleTargetNetworkNote(Note); +pub struct SingleTargetNetworkNote { + note: Note, + account_target: NetworkAccountTarget, +} impl SingleTargetNetworkNote { pub fn inner(&self) -> &Note { - &self.0 + &self.note } pub fn metadata(&self) -> &NoteMetadata { @@ -292,18 +259,19 @@ impl SingleTargetNetworkNote { self.inner().id() } - /// The account prefix that this note targets. - pub fn account_prefix(&self) -> NetworkAccountPrefix { - self.metadata() - .tag() - .try_into() - .expect("Single target network note's tag should contain an account prefix") + /// The network account ID that this note targets. + pub fn account_id(&self) -> NetworkAccountId { + self.account_target.target_id().try_into().expect("always a network account ID") + } + + pub fn can_be_consumed(&self, block_num: BlockNumber) -> Option { + self.account_target.execution_hint().can_be_consumed(block_num) } } impl From for Note { fn from(value: SingleTargetNetworkNote) -> Self { - value.0 + value.note } } @@ -311,11 +279,11 @@ impl TryFrom for SingleTargetNetworkNote { type Error = NetworkNoteError; fn try_from(note: Note) -> Result { - if note.is_network_note() && note.metadata().tag().is_single_target() { - Ok(Self(note)) - } else { - Err(NetworkNoteError::InvalidExecutionMode(note.metadata().tag())) - } + // Single-target network notes are identified by having a NetworkAccountTarget attachment + let attachment = note.metadata().attachment(); + let account_target = NetworkAccountTarget::try_from(attachment) + .map_err(|e| NetworkNoteError::InvalidAttachment(e.to_string()))?; + Ok(Self { note, account_target }) } } @@ -346,8 +314,8 @@ where #[derive(Debug, Error)] pub enum NetworkNoteError { - #[error("note tag {0} is not a valid network note tag")] - InvalidExecutionMode(NoteTag), + #[error("note does not have a valid NetworkAccountTarget attachment: {0}")] + InvalidAttachment(String), } // NOTE SCRIPT diff --git a/crates/proto/src/errors/mod.rs b/crates/proto/src/errors/mod.rs index 49f0f30bd..d65414188 100644 --- a/crates/proto/src/errors/mod.rs +++ b/crates/proto/src/errors/mod.rs @@ -4,8 +4,8 @@ use std::num::TryFromIntError; // Re-export the GrpcError derive macro for convenience pub use miden_node_grpc_error_macro::GrpcError; use miden_protocol::crypto::merkle::smt::{SmtLeafError, SmtProofError}; +use miden_protocol::errors::{AccountError, AssetError, FeeError, NoteError, StorageSlotNameError}; use miden_protocol::utils::DeserializationError; -use miden_protocol::{AccountError, AssetError, FeeError, StorageSlotNameError}; use thiserror::Error; use crate::domain::note::NetworkNoteError; @@ -24,7 +24,7 @@ pub enum ConversionError { #[error("hex error")] HexError(#[from] hex::FromHexError), #[error("note error")] - NoteError(#[from] miden_protocol::NoteError), + NoteError(#[from] NoteError), #[error("network note error")] NetworkNoteError(#[from] NetworkNoteError), #[error("SMT leaf error")] diff --git a/crates/proto/src/generated/note.rs b/crates/proto/src/generated/note.rs index 239d6f6d0..83d56aeb6 100644 --- a/crates/proto/src/generated/note.rs +++ b/crates/proto/src/generated/note.rs @@ -27,14 +27,11 @@ pub struct NoteMetadata { /// See `miden_protocol::note::note_tag` for more info. #[prost(fixed32, tag = "3")] pub tag: u32, - /// Specifies when a note is ready to be consumed. + /// Serialized note attachment /// - /// See `miden_protocol::note::execution_hint` for more info. - #[prost(fixed64, tag = "4")] - pub execution_hint: u64, - /// An arbitrary user-defined value. - #[prost(fixed64, tag = "5")] - pub aux: u64, + /// See `miden_protocol::note::NoteAttachment` for more info. + #[prost(bytes = "vec", tag = "4")] + pub attachment: ::prost::alloc::vec::Vec, } /// Represents a note. /// diff --git a/crates/rpc/src/server/api.rs b/crates/rpc/src/server/api.rs index 42889ef63..fd3ee97c6 100644 --- a/crates/rpc/src/server/api.rs +++ b/crates/rpc/src/server/api.rs @@ -360,7 +360,7 @@ impl api_server::Api for RpcService { let script = NoteScript::from_parts(mast, note.script().entrypoint()); let recipient = NoteRecipient::new(note.serial_num(), script, note.inputs().clone()); - let new_note = Note::new(note.assets().clone(), *note.metadata(), recipient); + let new_note = Note::new(note.assets().clone(), note.metadata().clone(), recipient); OutputNote::Full(new_note) }, other => other.clone(), @@ -423,7 +423,8 @@ impl api_server::Api for RpcService { let script = NoteScript::from_parts(mast, note.script().entrypoint()); let recipient = NoteRecipient::new(note.serial_num(), script, note.inputs().clone()); - let new_note = Note::new(note.assets().clone(), *note.metadata(), recipient); + let new_note = + Note::new(note.assets().clone(), note.metadata().clone(), recipient); OutputNote::Full(new_note) }, other => other.clone(), diff --git a/crates/store/src/accounts/mod.rs b/crates/store/src/accounts/mod.rs index 7fa5be8e7..d015408ad 100644 --- a/crates/store/src/accounts/mod.rs +++ b/crates/store/src/accounts/mod.rs @@ -21,7 +21,8 @@ use miden_protocol::crypto::merkle::{ NodeIndex, SparseMerklePath, }; -use miden_protocol::{AccountTreeError, EMPTY_WORD, Word}; +use miden_protocol::errors::AccountTreeError; +use miden_protocol::{EMPTY_WORD, Word}; #[cfg(test)] mod tests; diff --git a/crates/store/src/db/migrations/2025062000000_setup/up.sql b/crates/store/src/db/migrations/2025062000000_setup/up.sql index adf06e2a3..32c618aab 100644 --- a/crates/store/src/db/migrations/2025062000000_setup/up.sql +++ b/crates/store/src/db/migrations/2025062000000_setup/up.sql @@ -43,28 +43,27 @@ CREATE INDEX idx_accounts_block_num ON accounts(block_num); CREATE INDEX idx_accounts_code_commitment ON accounts(code_commitment) WHERE code_commitment IS NOT NULL; CREATE TABLE notes ( - committed_at INTEGER NOT NULL, -- Block number when the note was committed - batch_index INTEGER NOT NULL, -- Index of batch in block, starting from 0 - note_index INTEGER NOT NULL, -- Index of note in batch, starting from 0 - note_id BLOB NOT NULL, - note_commitment BLOB NOT NULL, - note_type INTEGER NOT NULL, -- 1-Public (0b01), 2-Private (0b10), 3-Encrypted (0b11) - sender BLOB NOT NULL, - tag INTEGER NOT NULL, - execution_mode INTEGER NOT NULL, -- 0-Network, 1-Local - aux INTEGER NOT NULL, - execution_hint INTEGER NOT NULL, - inclusion_path BLOB NOT NULL, -- Serialized sparse Merkle path of the note in the block's note tree - consumed_at INTEGER, -- Block number when the note was consumed - nullifier BLOB, -- Only known for public notes, null for private notes - assets BLOB, - inputs BLOB, - script_root BLOB, - serial_num BLOB, + committed_at INTEGER NOT NULL, -- Block number when the note was committed + batch_index INTEGER NOT NULL, -- Index of batch in block, starting from 0 + note_index INTEGER NOT NULL, -- Index of note in batch, starting from 0 + note_id BLOB NOT NULL, + note_commitment BLOB NOT NULL, + note_type INTEGER NOT NULL, -- 1-Public (0b01), 2-Private (0b10), 3-Encrypted (0b11) + sender BLOB NOT NULL, + tag INTEGER NOT NULL, + is_single_target_network_note INTEGER NOT NULL, -- 1 if note has NetworkAccountTarget attachment, 0 otherwise + attachment BLOB NOT NULL, -- Serialized note attachment data + inclusion_path BLOB NOT NULL, -- Serialized sparse Merkle path of the note in the block's note tree + consumed_at INTEGER, -- Block number when the note was consumed + nullifier BLOB, -- Only known for public notes, null for private notes + assets BLOB, + inputs BLOB, + script_root BLOB, + serial_num BLOB, PRIMARY KEY (committed_at, batch_index, note_index), CONSTRAINT notes_type_in_enum CHECK (note_type BETWEEN 1 AND 3), - CONSTRAINT notes_execution_mode_in_enum CHECK (execution_mode BETWEEN 0 AND 1), + CONSTRAINT notes_is_single_target_network_note_is_bool CHECK (is_single_target_network_note BETWEEN 0 AND 1), CONSTRAINT notes_consumed_at_is_u32 CHECK (consumed_at BETWEEN 0 AND 0xFFFFFFFF), CONSTRAINT notes_batch_index_is_u32 CHECK (batch_index BETWEEN 0 AND 0xFFFFFFFF), CONSTRAINT notes_note_index_is_u32 CHECK (note_index BETWEEN 0 AND 0xFFFFFFFF) @@ -75,7 +74,7 @@ CREATE INDEX idx_notes_note_commitment ON notes(note_commitment); CREATE INDEX idx_notes_sender ON notes(sender, committed_at); CREATE INDEX idx_notes_tag ON notes(tag, committed_at); CREATE INDEX idx_notes_nullifier ON notes(nullifier); -CREATE INDEX idx_unconsumed_network_notes ON notes(execution_mode, consumed_at); +CREATE INDEX idx_unconsumed_network_notes ON notes(is_single_target_network_note, consumed_at); -- Index for joining with block_headers on committed_at CREATE INDEX idx_notes_committed_at ON notes(committed_at); -- Index for joining with note_scripts diff --git a/crates/store/src/db/mod.rs b/crates/store/src/db/mod.rs index fc96212b5..7fe9c7497 100644 --- a/crates/store/src/db/mod.rs +++ b/crates/store/src/db/mod.rs @@ -4,7 +4,7 @@ use std::path::PathBuf; use anyhow::Context; use diesel::{Connection, QueryableByName, RunQueryDsl, SqliteConnection}; -use miden_node_proto::domain::account::{AccountInfo, AccountSummary, NetworkAccountPrefix}; +use miden_node_proto::domain::account::{AccountInfo, AccountSummary}; use miden_node_proto::generated as proto; use miden_node_utils::tracing::OpenTelemetrySpanExt; use miden_protocol::Word; @@ -652,7 +652,7 @@ impl Db { /// Pagination is used to limit the number of notes returned. pub(crate) async fn select_unconsumed_network_notes( &self, - network_account_id_prefix: NetworkAccountPrefix, + network_account_prefix: u32, block_num: BlockNumber, page: Page, ) -> Result<(Vec, Page)> { @@ -662,7 +662,7 @@ impl Db { self.transact("unconsumed network notes for account", move |conn| { models::queries::select_unconsumed_network_notes_by_tag( conn, - network_account_id_prefix.into(), + network_account_prefix, block_num, page, ) diff --git a/crates/store/src/db/models/conv.rs b/crates/store/src/db/models/conv.rs index 37a9b019f..4dcd012ef 100644 --- a/crates/store/src/db/models/conv.rs +++ b/crates/store/src/db/models/conv.rs @@ -32,11 +32,11 @@ on relevant platforms" )] -use miden_node_proto::domain::account::NetworkAccountPrefix; +use miden_node_proto::domain::account::NetworkAccountId; use miden_protocol::Felt; use miden_protocol::account::{StorageSlotName, StorageSlotType}; use miden_protocol::block::BlockNumber; -use miden_protocol::note::{NoteExecutionMode, NoteTag}; +use miden_protocol::note::NoteTag; #[derive(Debug, thiserror::Error)] #[error("failed to convert from database type {from_type} into {into_type}")] @@ -78,42 +78,10 @@ impl SqlTypeConvert for BlockNumber { } } -impl SqlTypeConvert for NetworkAccountPrefix { - type Raw = i64; - - fn from_raw_sql(raw: Self::Raw) -> Result { - NetworkAccountPrefix::try_from(raw as u32).map_err(Self::map_err) - } - fn to_raw_sql(self) -> Self::Raw { - i64::from(self.inner()) - } -} - -impl SqlTypeConvert for NoteExecutionMode { - type Raw = i32; - - #[inline(always)] - fn from_raw_sql(raw: Self::Raw) -> Result { - #[derive(Debug, thiserror::Error)] - #[error("valid values are 0 or 1 but found {0}")] - struct ValueError(i32); - - Ok(match raw { - 0 => Self::Network, - 1 => Self::Local, - invalid => { - return Err(Self::map_err(ValueError(invalid))); - }, - }) - } - - #[inline(always)] - fn to_raw_sql(self) -> Self::Raw { - match self { - NoteExecutionMode::Network => 0, - NoteExecutionMode::Local => 1, - } - } +/// Converts a network account ID to its 30-bit prefix for database indexing. +#[inline(always)] +pub(crate) fn network_account_id_to_prefix_sql(id: NetworkAccountId) -> i64 { + i64::from(id.prefix()) } impl SqlTypeConvert for NoteTag { @@ -122,12 +90,12 @@ impl SqlTypeConvert for NoteTag { #[inline(always)] fn from_raw_sql(raw: Self::Raw) -> Result { #[allow(clippy::cast_sign_loss)] - Ok(NoteTag::from(raw as u32)) + Ok(NoteTag::new(raw as u32)) } #[inline(always)] fn to_raw_sql(self) -> Self::Raw { - u32::from(self) as i32 + self.as_u32() as i32 } } @@ -212,24 +180,6 @@ pub(crate) fn note_type_to_raw_sql(note_type: u8) -> i32 { i32::from(note_type) } -#[inline(always)] -pub(crate) fn raw_sql_to_execution_hint(raw: i64) -> u64 { - raw as u64 -} -#[inline(always)] -pub(crate) fn execution_hint_to_raw_sql(hint: u64) -> i64 { - hint as i64 -} - -#[inline(always)] -pub(crate) fn raw_sql_to_aux(raw: i64) -> Felt { - Felt::try_from(raw as u64).unwrap() -} -#[inline(always)] -pub(crate) fn aux_to_raw_sql(hint: Felt) -> i64 { - hint.inner() as i64 -} - #[inline(always)] pub(crate) fn raw_sql_to_idx(raw: i32) -> usize { raw as usize diff --git a/crates/store/src/db/models/queries/accounts.rs b/crates/store/src/db/models/queries/accounts.rs index f23ecf793..5c049916e 100644 --- a/crates/store/src/db/models/queries/accounts.rs +++ b/crates/store/src/db/models/queries/accounts.rs @@ -44,7 +44,12 @@ use miden_protocol::block::{BlockAccountUpdate, BlockNumber}; use miden_protocol::utils::{Deserializable, Serializable}; use crate::COMPONENT; -use crate::db::models::conv::{SqlTypeConvert, nonce_to_raw_sql, raw_sql_to_nonce}; +use crate::db::models::conv::{ + SqlTypeConvert, + network_account_id_to_prefix_sql, + nonce_to_raw_sql, + raw_sql_to_nonce, +}; use crate::db::models::{serialize_vec, vec_raw_try_into}; use crate::db::{AccountVaultValue, schema}; use crate::errors::DatabaseError; @@ -917,7 +922,7 @@ pub(crate) fn upsert_accounts( accounts: &[BlockAccountUpdate], block_num: BlockNumber, ) -> Result { - use proto::domain::account::NetworkAccountPrefix; + use proto::domain::account::NetworkAccountId; let mut count = 0; for update in accounts { @@ -925,8 +930,8 @@ pub(crate) fn upsert_accounts( let account_id_bytes = account_id.to_bytes(); let block_num_raw = block_num.to_raw_sql(); - let network_account_id_prefix = if account_id.is_network() { - Some(NetworkAccountPrefix::try_from(account_id)?) + let network_account_id = if account_id.is_network() { + Some(NetworkAccountId::try_from(account_id)?) } else { None }; @@ -1056,8 +1061,7 @@ pub(crate) fn upsert_accounts( let account_value = AccountRowInsert { account_id: account_id_bytes, - network_account_id_prefix: network_account_id_prefix - .map(NetworkAccountPrefix::to_raw_sql), + network_account_id_prefix: network_account_id.map(network_account_id_to_prefix_sql), account_commitment: update.final_state_commitment().to_bytes(), block_num: block_num_raw, nonce: full_account.as_ref().map(|account| nonce_to_raw_sql(account.nonce())), diff --git a/crates/store/src/db/models/queries/accounts/tests.rs b/crates/store/src/db/models/queries/accounts/tests.rs index 2df630987..9206311a1 100644 --- a/crates/store/src/db/models/queries/accounts/tests.rs +++ b/crates/store/src/db/models/queries/accounts/tests.rs @@ -35,7 +35,7 @@ use miden_protocol::block::{BlockAccountUpdate, BlockHeader, BlockNumber}; use miden_protocol::crypto::dsa::ecdsa_k256_keccak::SecretKey; use miden_protocol::utils::{Deserializable, Serializable}; use miden_protocol::{EMPTY_WORD, Felt, Word}; -use miden_standards::account::auth::AuthRpoFalcon512; +use miden_standards::account::auth::AuthFalcon512Rpo; use miden_standards::code_builder::CodeBuilder; use super::*; @@ -151,7 +151,7 @@ fn create_test_account_with_storage() -> (Account, AccountId) { .account_type(AccountType::RegularAccountImmutableCode) .storage_mode(AccountStorageMode::Public) .with_component(component) - .with_auth_component(AuthRpoFalcon512::new(PublicKeyCommitment::from(EMPTY_WORD))) + .with_auth_component(AuthFalcon512Rpo::new(PublicKeyCommitment::from(EMPTY_WORD))) .build_existing() .unwrap(); @@ -410,7 +410,7 @@ fn test_upsert_accounts_updates_is_latest_flag() { .account_type(AccountType::RegularAccountImmutableCode) .storage_mode(AccountStorageMode::Public) .with_component(component_2) - .with_auth_component(AuthRpoFalcon512::new(PublicKeyCommitment::from(EMPTY_WORD))) + .with_auth_component(AuthFalcon512Rpo::new(PublicKeyCommitment::from(EMPTY_WORD))) .build_existing() .unwrap(); @@ -503,7 +503,7 @@ fn test_upsert_accounts_with_multiple_storage_slots() { .account_type(AccountType::RegularAccountImmutableCode) .storage_mode(AccountStorageMode::Public) .with_component(component) - .with_auth_component(AuthRpoFalcon512::new(PublicKeyCommitment::from(EMPTY_WORD))) + .with_auth_component(AuthFalcon512Rpo::new(PublicKeyCommitment::from(EMPTY_WORD))) .build_existing() .unwrap(); @@ -565,7 +565,7 @@ fn test_upsert_accounts_with_empty_storage() { .account_type(AccountType::RegularAccountImmutableCode) .storage_mode(AccountStorageMode::Public) .with_component(component) - .with_auth_component(AuthRpoFalcon512::new(PublicKeyCommitment::from(EMPTY_WORD))) + .with_auth_component(AuthFalcon512Rpo::new(PublicKeyCommitment::from(EMPTY_WORD))) .build_existing() .unwrap(); diff --git a/crates/store/src/db/models/queries/notes.rs b/crates/store/src/db/models/queries/notes.rs index 9204adea7..f68d5447b 100644 --- a/crates/store/src/db/models/queries/notes.rs +++ b/crates/store/src/db/models/queries/notes.rs @@ -31,14 +31,14 @@ use miden_node_utils::limiter::{ QueryParamNoteCommitmentLimit, QueryParamNoteTagLimit, }; +use miden_protocol::Word; use miden_protocol::account::AccountId; use miden_protocol::block::{BlockNoteIndex, BlockNumber}; use miden_protocol::crypto::merkle::SparseMerklePath; use miden_protocol::note::{ NoteAssets, + NoteAttachment, NoteDetails, - NoteExecutionHint, - NoteExecutionMode, NoteId, NoteInclusionProof, NoteInputs, @@ -50,13 +50,11 @@ use miden_protocol::note::{ Nullifier, }; use miden_protocol::utils::{Deserializable, Serializable}; -use miden_protocol::{Felt, Word}; +use miden_standards::note::NetworkAccountTarget; use crate::COMPONENT; use crate::db::models::conv::{ SqlTypeConvert, - aux_to_raw_sql, - execution_hint_to_raw_sql, idx_to_raw_sql, note_type_to_raw_sql, raw_sql_to_idx, @@ -97,8 +95,7 @@ use crate::errors::NoteSyncError; /// note_type, /// sender, /// tag, -/// aux, -/// execution_hint, +/// attachment, /// inclusion_path /// FROM /// notes @@ -185,8 +182,7 @@ pub(crate) fn select_notes_since_block_by_tag_and_sender( /// notes.note_type, /// notes.sender, /// notes.tag, -/// notes.aux, -/// notes.execution_hint, +/// notes.attachment, /// notes.assets, /// notes.inputs, /// notes.serial_num, @@ -266,8 +262,7 @@ pub(crate) fn select_existing_note_commitments( /// notes.note_type, /// notes.sender, /// notes.tag, -/// notes.aux, -/// notes.execution_hint, +/// notes.attachment, /// notes.assets, /// notes.inputs, /// notes.serial_num, @@ -411,8 +406,7 @@ pub(crate) fn select_note_script_by_root( /// notes.note_type, /// notes.sender, /// notes.tag, -/// notes.aux, -/// notes.execution_hint, +/// notes.attachment, /// notes.assets, /// notes.inputs, /// notes.serial_num, @@ -422,7 +416,7 @@ pub(crate) fn select_note_script_by_root( /// FROM notes /// LEFT JOIN note_scripts ON notes.script_root = note_scripts.script_root /// WHERE -/// execution_mode = 0 AND tag = ?1 AND +/// is_single_target_network_note = TRUE AND tag = ?1 AND /// committed_at <= ?2 AND /// (consumed_at IS NULL OR consumed_at > ?2) AND notes.rowid >= ?3 /// ORDER BY notes.rowid ASC @@ -442,12 +436,6 @@ pub(crate) fn select_unconsumed_network_notes_by_tag( block_num: BlockNumber, mut page: Page, ) -> Result<(Vec, Page), DatabaseError> { - assert_eq!( - NoteExecutionMode::Network as u8, - 0, - "Hardcoded execution value must match query" - ); - let rowid_sel = diesel::dsl::sql::("notes.rowid"); let rowid_sel_ge = diesel::dsl::sql::("notes.rowid >= ") @@ -486,7 +474,7 @@ pub(crate) fn select_unconsumed_network_notes_by_tag( rowid_sel.clone(), ), ) - .filter(schema::notes::execution_mode.eq(NoteExecutionMode::Network.to_raw_sql())) + .filter(schema::notes::is_single_target_network_note.eq(true)) .filter(schema::notes::tag.eq(tag as i32)) .filter(schema::notes::committed_at.le(block_num.to_raw_sql())) .filter( @@ -590,8 +578,7 @@ pub struct NoteRecordWithScriptRawJoined { pub note_type: i32, pub sender: Vec, // AccountId pub tag: i32, - pub aux: i64, - pub execution_hint: i64, + pub attachment: Vec, // #[diesel(embed)] // pub metadata: NoteMetadataRaw, pub assets: Option>, @@ -615,8 +602,7 @@ impl From<(NoteRecordRawRow, Option>)> for NoteRecordWithScriptRawJoined note_type, sender, tag, - aux, - execution_hint, + attachment, assets, inputs, serial_num, @@ -631,8 +617,7 @@ impl From<(NoteRecordRawRow, Option>)> for NoteRecordWithScriptRawJoined note_type, sender, tag, - aux, - execution_hint, + attachment, assets, inputs, serial_num, @@ -659,8 +644,7 @@ impl TryInto for NoteRecordWithScriptRawJoined { note_type, sender, tag, - execution_hint, - aux, + attachment, // metadata ^^^, assets, inputs, @@ -671,13 +655,7 @@ impl TryInto for NoteRecordWithScriptRawJoined { .. } = raw; let index = BlockNoteIndexRawRow { batch_index, note_index }; - let metadata = NoteMetadataRawRow { - note_type, - sender, - tag, - aux, - execution_hint, - }; + let metadata = NoteMetadataRawRow { note_type, sender, tag, attachment }; let details = NoteDetailsRawRow { assets, inputs, serial_num }; let metadata = metadata.try_into()?; @@ -730,8 +708,7 @@ pub struct NoteRecordRawRow { pub note_type: i32, pub sender: Vec, // AccountId pub tag: i32, - pub aux: i64, - pub execution_hint: i64, + pub attachment: Vec, pub assets: Option>, pub inputs: Option>, @@ -747,8 +724,7 @@ pub struct NoteMetadataRawRow { note_type: i32, sender: Vec, // AccountId tag: i32, - aux: i64, - execution_hint: i64, + attachment: Vec, } #[allow(clippy::cast_sign_loss)] @@ -758,11 +734,9 @@ impl TryInto for NoteMetadataRawRow { let sender = AccountId::read_from_bytes(&self.sender[..])?; let note_type = NoteType::try_from(self.note_type as u32) .map_err(DatabaseError::conversiont_from_sql::)?; - let tag = NoteTag::from(self.tag as u32); - let execution_hint = NoteExecutionHint::try_from(self.execution_hint as u64) - .map_err(DatabaseError::conversiont_from_sql::)?; - let aux = Felt::new(self.aux as u64); - Ok(NoteMetadata::new(sender, note_type, tag, execution_hint, aux)?) + let tag = NoteTag::new(self.tag as u32); + let attachment = NoteAttachment::read_from_bytes(&self.attachment)?; + Ok(NoteMetadata::new(sender, note_type, tag).with_attachment(attachment)) } } @@ -867,21 +841,26 @@ pub struct NoteInsertRowInsert { pub note_type: i32, pub sender: Vec, // AccountId pub tag: i32, - pub aux: i64, - pub execution_hint: i64, + pub attachment: Vec, pub consumed_at: Option, pub assets: Option>, pub inputs: Option>, pub serial_num: Option>, pub nullifier: Option>, pub script_root: Option>, - pub execution_mode: i32, + pub is_single_target_network_note: bool, pub inclusion_path: Vec, } impl From<(NoteRecord, Option)> for NoteInsertRowInsert { fn from((note, nullifier): (NoteRecord, Option)) -> Self { + let attachment = note.metadata.attachment(); + + let is_single_target_network_note = NetworkAccountTarget::try_from(attachment).is_ok(); + + let attachment_bytes = attachment.to_bytes(); + Self { committed_at: note.block_num.to_raw_sql(), batch_index: idx_to_raw_sql(note.note_index.batch_idx()), @@ -891,12 +870,11 @@ impl From<(NoteRecord, Option)> for NoteInsertRowInsert { note_type: note_type_to_raw_sql(note.metadata.note_type() as u8), sender: note.metadata.sender().to_bytes(), tag: note.metadata.tag().to_raw_sql(), - execution_mode: note.metadata.tag().execution_mode().to_raw_sql(), - aux: aux_to_raw_sql(note.metadata.aux()), - execution_hint: execution_hint_to_raw_sql(note.metadata.execution_hint().into()), + is_single_target_network_note, + attachment: attachment_bytes, inclusion_path: note.inclusion_path.to_bytes(), consumed_at: None::, // New notes are always unconsumed. - nullifier: nullifier.as_ref().map(Nullifier::to_bytes), /* Beware: `Option` also implements `to_bytes`, but this is not what you want. */ + nullifier: nullifier.as_ref().map(Nullifier::to_bytes), assets: note.details.as_ref().map(|d| d.assets().to_bytes()), inputs: note.details.as_ref().map(|d| d.inputs().to_bytes()), script_root: note.details.as_ref().map(|d| d.script().root().to_bytes()), diff --git a/crates/store/src/db/schema.rs b/crates/store/src/db/schema.rs index 6bf6af3cf..e9333057c 100644 --- a/crates/store/src/db/schema.rs +++ b/crates/store/src/db/schema.rs @@ -67,9 +67,8 @@ diesel::table! { note_type -> Integer, sender -> Binary, tag -> Integer, - execution_mode -> Integer, - aux -> BigInt, - execution_hint -> BigInt, + is_single_target_network_note -> Bool, + attachment -> Binary, inclusion_path -> Binary, consumed_at -> Nullable, nullifier -> Nullable, diff --git a/crates/store/src/db/tests.rs b/crates/store/src/db/tests.rs index 3988e160d..5d3785b45 100644 --- a/crates/store/src/db/tests.rs +++ b/crates/store/src/db/tests.rs @@ -39,6 +39,7 @@ use miden_protocol::crypto::merkle::SparseMerklePath; use miden_protocol::crypto::rand::RpoRandomCoin; use miden_protocol::note::{ Note, + NoteAttachment, NoteDetails, NoteExecutionHint, NoteHeader, @@ -64,10 +65,10 @@ use miden_protocol::transaction::{ TransactionId, }; use miden_protocol::utils::{Deserializable, Serializable}; -use miden_protocol::{EMPTY_WORD, Felt, FieldElement, Word, ZERO}; -use miden_standards::account::auth::AuthRpoFalcon512; +use miden_protocol::{EMPTY_WORD, Felt, FieldElement, Word}; +use miden_standards::account::auth::AuthFalcon512Rpo; use miden_standards::code_builder::CodeBuilder; -use miden_standards::note::create_p2id_note; +use miden_standards::note::{NetworkAccountTarget, create_p2id_note}; use pretty_assertions::assert_eq; use rand::Rng; @@ -225,7 +226,7 @@ pub fn create_note(account_id: AccountId) -> Note { FungibleAsset::new(ACCOUNT_ID_PUBLIC_FUNGIBLE_FAUCET.try_into().unwrap(), 10).unwrap(), )], NoteType::Public, - Felt::default(), + NoteAttachment::default(), &mut *rng, ) .expect("Failed to create note") @@ -257,7 +258,7 @@ fn sql_select_notes() { note_index: BlockNoteIndex::new(0, i.try_into().unwrap()).unwrap(), note_id: num_to_word(u64::try_from(i).unwrap()), note_commitment: num_to_word(u64::try_from(i).unwrap()), - metadata: *new_note.metadata(), + metadata: new_note.metadata().clone(), details: Some(NoteDetails::from(&new_note)), inclusion_path: SparseMerklePath::default(), }; @@ -280,108 +281,6 @@ fn sql_select_notes() { } } -#[test] -#[miden_node_test_macro::enable_logging] -fn sql_select_notes_different_execution_hints() { - let mut conn = create_db(); - let conn = &mut conn; - - let block_num = 1.into(); - create_block(conn, block_num); - - // test querying empty table - let notes = queries::select_all_notes(conn).unwrap(); - assert!(notes.is_empty()); - - let sender = AccountId::try_from(ACCOUNT_ID_PRIVATE_SENDER).unwrap(); - - queries::upsert_accounts(conn, &[mock_block_account_update(sender, 0)], block_num).unwrap(); - - // test multiple entries - let mut state = vec![]; - - let new_note = create_note(sender); - - let note_none = NoteRecord { - block_num, - note_index: BlockNoteIndex::new(0, 0).unwrap(), - note_id: num_to_word(0), - note_commitment: num_to_word(0), - metadata: NoteMetadata::new( - sender, - NoteType::Public, - 0.into(), - NoteExecutionHint::none(), - Felt::default(), - ) - .unwrap(), - details: Some(NoteDetails::from(&new_note)), - inclusion_path: SparseMerklePath::default(), - }; - state.push(note_none.clone()); - - queries::insert_scripts(conn, [¬e_none]).unwrap(); // only necessary for the first note - let res = queries::insert_notes(conn, &[(note_none, None)]); - assert_eq!(res.unwrap(), 1, "One element must have been inserted"); - - let note_id = NoteId::from_raw(num_to_word(0)); - let note = &queries::select_notes_by_id(conn, &[note_id]).unwrap()[0]; - - assert_eq!(note.metadata.execution_hint(), NoteExecutionHint::none()); - - let note_always = NoteRecord { - block_num, - note_index: BlockNoteIndex::new(0, 1).unwrap(), - note_id: num_to_word(1), - note_commitment: num_to_word(1), - metadata: NoteMetadata::new( - sender, - NoteType::Public, - 0.into(), - NoteExecutionHint::always(), - Felt::default(), - ) - .unwrap(), - details: Some(NoteDetails::from(&new_note)), - inclusion_path: SparseMerklePath::default(), - }; - state.push(note_always.clone()); - - let res = queries::insert_notes(conn, &[(note_always, None)]); - assert_eq!(res.unwrap(), 1, "One element must have been inserted"); - - let note_id = NoteId::from_raw(num_to_word(1)); - let note = &queries::select_notes_by_id(conn, &[note_id]).unwrap()[0]; - assert_eq!(note.metadata.execution_hint(), NoteExecutionHint::always()); - - let note_after_block = NoteRecord { - block_num, - note_index: BlockNoteIndex::new(0, 2).unwrap(), - note_id: num_to_word(2), - note_commitment: num_to_word(2), - metadata: NoteMetadata::new( - sender, - NoteType::Public, - 2.into(), - NoteExecutionHint::after_block(12.into()).unwrap(), - Felt::default(), - ) - .unwrap(), - details: Some(NoteDetails::from(&new_note)), - inclusion_path: SparseMerklePath::default(), - }; - state.push(note_after_block.clone()); - - let res = queries::insert_notes(conn, &[(note_after_block, None)]); - assert_eq!(res.unwrap(), 1, "One element must have been inserted"); - let note_id = NoteId::from_raw(num_to_word(2)); - let note = &queries::select_notes_by_id(conn, &[note_id]).unwrap()[0]; - assert_eq!( - note.metadata.execution_hint(), - NoteExecutionHint::after_block(12.into()).unwrap() - ); -} - #[test] #[miden_node_test_macro::enable_logging] fn sql_select_note_script_by_root() { @@ -403,7 +302,7 @@ fn sql_select_note_script_by_root() { note_index: BlockNoteIndex::new(0, 0.try_into().unwrap()).unwrap(), note_id: num_to_word(0), note_commitment: num_to_word(0), - metadata: *new_note.metadata(), + metadata: new_note.metadata().clone(), details: Some(NoteDetails::from(&new_note)), inclusion_path: SparseMerklePath::default(), }; @@ -466,6 +365,11 @@ fn sql_unconsumed_network_notes() { create_block(&mut conn, 0.into()); create_block(&mut conn, 1.into()); + // Create a NetworkAccountTarget attachment for the network account + let target = NetworkAccountTarget::new(account_note.0, NoteExecutionHint::Always) + .expect("NetworkAccountTarget creation should succeed for network account"); + let attachment: NoteAttachment = target.into(); + // Create an unconsumed note in each block. let notes = Vec::from_iter((0..2).map(|i: u32| { let note = NoteRecord { @@ -476,11 +380,9 @@ fn sql_unconsumed_network_notes() { metadata: NoteMetadata::new( account_note.0, NoteType::Public, - NoteTag::from_account_id(account_note.0), - NoteExecutionHint::none(), - Felt::default(), + NoteTag::with_account_target(account_note.0), ) - .unwrap(), + .with_attachment(attachment.clone()), details: None, inclusion_path: SparseMerklePath::default(), }; @@ -493,7 +395,7 @@ fn sql_unconsumed_network_notes() { (0..2).for_each(|i: u32| { let (result, _) = queries::select_unconsumed_network_notes_by_tag( &mut conn, - NoteTag::from_account_id(account_note.0).into(), + NoteTag::with_account_target(account_note.0).into(), i.into(), Page { token: None, @@ -510,7 +412,7 @@ fn sql_unconsumed_network_notes() { // Query against first block should return both notes. let (result, _) = queries::select_unconsumed_network_notes_by_tag( &mut conn, - NoteTag::from_account_id(account_note.0).into(), + NoteTag::with_account_target(account_note.0).into(), 0.into(), Page { token: None, @@ -523,7 +425,7 @@ fn sql_unconsumed_network_notes() { // Query against second block should return only first note. let (result, _) = queries::select_unconsumed_network_notes_by_tag( &mut conn, - NoteTag::from_account_id(account_note.0).into(), + NoteTag::with_account_target(account_note.0).into(), 1.into(), Page { token: None, @@ -1016,12 +918,10 @@ fn notes() { let new_note = create_note(sender); let note_index = BlockNoteIndex::new(0, 2).unwrap(); let tag = 5u32; - let note_metadata = - NoteMetadata::new(sender, NoteType::Public, tag.into(), NoteExecutionHint::none(), ZERO) - .unwrap(); + let note_metadata = NoteMetadata::new(sender, NoteType::Public, tag.into()); - let values = [(note_index, new_note.id(), note_metadata)]; - let notes_db = BlockNoteTree::with_entries(values.iter().copied()).unwrap(); + let values = [(note_index, new_note.id(), ¬e_metadata)]; + let notes_db = BlockNoteTree::with_entries(values).unwrap(); let inclusion_path = notes_db.open(note_index); let note = NoteRecord { @@ -1029,14 +929,7 @@ fn notes() { note_index, note_id: new_note.id().as_word(), note_commitment: new_note.commitment(), - metadata: NoteMetadata::new( - sender, - NoteType::Public, - tag.into(), - NoteExecutionHint::none(), - Felt::default(), - ) - .unwrap(), + metadata: NoteMetadata::new(sender, NoteType::Public, tag.into()), details: Some(NoteDetails::from(&new_note)), inclusion_path: inclusion_path.clone(), }; @@ -1076,7 +969,7 @@ fn notes() { note_index: note.note_index, note_id: new_note.id().as_word(), note_commitment: new_note.commitment(), - metadata: note.metadata, + metadata: note.metadata.clone(), details: None, inclusion_path: inclusion_path.clone(), }; @@ -1345,7 +1238,7 @@ fn create_account_with_code(code_str: &str, seed: [u8; 32]) -> Account { .account_type(AccountType::RegularAccountUpdatableCode) .storage_mode(AccountStorageMode::Public) .with_component(component) - .with_auth_component(AuthRpoFalcon512::new(PublicKeyCommitment::from(EMPTY_WORD))) + .with_auth_component(AuthFalcon512Rpo::new(PublicKeyCommitment::from(EMPTY_WORD))) .build_existing() .unwrap() } @@ -1364,14 +1257,7 @@ fn mock_block_transaction(account_id: AccountId, num: u64) -> TransactionHeader Word::try_from([num, num, 0, 0]).unwrap(), Word::try_from([0, 0, num, num]).unwrap(), ), - NoteMetadata::new( - account_id, - NoteType::Public, - NoteTag::LocalAny(num as u32), - NoteExecutionHint::None, - Felt::default(), - ) - .unwrap(), + NoteMetadata::new(account_id, NoteType::Public, NoteTag::new(num as u32)), )]; TransactionHeader::new_unchecked( @@ -1447,7 +1333,7 @@ fn mock_account_code_and_storage( .storage_mode(storage_mode) .with_assets(assets) .with_component(account_component) - .with_auth_component(AuthRpoFalcon512::new(PublicKeyCommitment::from(EMPTY_WORD))) + .with_auth_component(AuthFalcon512Rpo::new(PublicKeyCommitment::from(EMPTY_WORD))) .build_existing() .unwrap() } @@ -1608,7 +1494,7 @@ fn genesis_with_account_assets() { .storage_mode(AccountStorageMode::Public) .with_component(account_component) .with_assets([fungible_asset.into()]) - .with_auth_component(AuthRpoFalcon512::new(PublicKeyCommitment::from(EMPTY_WORD))) + .with_auth_component(AuthFalcon512Rpo::new(PublicKeyCommitment::from(EMPTY_WORD))) .build_existing() .unwrap(); @@ -1657,7 +1543,7 @@ fn genesis_with_account_storage_map() { .account_type(AccountType::RegularAccountImmutableCode) .storage_mode(AccountStorageMode::Public) .with_component(account_component) - .with_auth_component(AuthRpoFalcon512::new(PublicKeyCommitment::from(EMPTY_WORD))) + .with_auth_component(AuthFalcon512Rpo::new(PublicKeyCommitment::from(EMPTY_WORD))) .build_existing() .unwrap(); @@ -1704,7 +1590,7 @@ fn genesis_with_account_assets_and_storage() { .storage_mode(AccountStorageMode::Public) .with_component(account_component) .with_assets([fungible_asset.into()]) - .with_auth_component(AuthRpoFalcon512::new(PublicKeyCommitment::from(EMPTY_WORD))) + .with_auth_component(AuthFalcon512Rpo::new(PublicKeyCommitment::from(EMPTY_WORD))) .build_existing() .unwrap(); @@ -1735,7 +1621,7 @@ fn genesis_with_multiple_accounts() { .account_type(AccountType::RegularAccountImmutableCode) .storage_mode(AccountStorageMode::Public) .with_component(account_component1) - .with_auth_component(AuthRpoFalcon512::new(PublicKeyCommitment::from(EMPTY_WORD))) + .with_auth_component(AuthFalcon512Rpo::new(PublicKeyCommitment::from(EMPTY_WORD))) .build_existing() .unwrap(); @@ -1754,7 +1640,7 @@ fn genesis_with_multiple_accounts() { .storage_mode(AccountStorageMode::Public) .with_component(account_component2) .with_assets([fungible_asset.into()]) - .with_auth_component(AuthRpoFalcon512::new(PublicKeyCommitment::from(EMPTY_WORD))) + .with_auth_component(AuthFalcon512Rpo::new(PublicKeyCommitment::from(EMPTY_WORD))) .build_existing() .unwrap(); @@ -1777,7 +1663,7 @@ fn genesis_with_multiple_accounts() { .account_type(AccountType::RegularAccountUpdatableCode) .storage_mode(AccountStorageMode::Public) .with_component(account_component3) - .with_auth_component(AuthRpoFalcon512::new(PublicKeyCommitment::from(EMPTY_WORD))) + .with_auth_component(AuthFalcon512Rpo::new(PublicKeyCommitment::from(EMPTY_WORD))) .build_existing() .unwrap(); @@ -1940,15 +1826,8 @@ fn serialization_symmetry_note_metadata() { let sender = AccountId::try_from(ACCOUNT_ID_PRIVATE_SENDER).unwrap(); // Use a tag that roundtrips properly - NoteTag::LocalAny stores the full u32 including type // bits - let tag = NoteTag::from_account_id(sender); - let metadata = NoteMetadata::new( - sender, - NoteType::Public, - tag, - NoteExecutionHint::always(), - Felt::new(42), - ) - .unwrap(); + let tag = NoteTag::with_account_target(sender); + let metadata = NoteMetadata::new(sender, NoteType::Public, tag); let bytes = metadata.to_bytes(); let restored = NoteMetadata::read_from_bytes(&bytes).unwrap(); @@ -2086,7 +1965,7 @@ fn db_roundtrip_notes() { note_index, note_id: new_note.id().as_word(), note_commitment: new_note.commitment(), - metadata: *new_note.metadata(), + metadata: new_note.metadata().clone(), details: Some(NoteDetails::from(&new_note)), inclusion_path: SparseMerklePath::default(), }; @@ -2280,7 +2159,7 @@ fn db_roundtrip_account_storage_with_maps() { .account_type(AccountType::RegularAccountUpdatableCode) .storage_mode(AccountStorageMode::Public) .with_component(account_component) - .with_auth_component(AuthRpoFalcon512::new(PublicKeyCommitment::from(EMPTY_WORD))) + .with_auth_component(AuthFalcon512Rpo::new(PublicKeyCommitment::from(EMPTY_WORD))) .build_existing() .unwrap(); @@ -2348,3 +2227,57 @@ fn db_roundtrip_account_storage_with_maps() { "Full account commitment must match after DB roundtrip" ); } + +#[test] +#[miden_node_test_macro::enable_logging] +fn test_note_metadata_with_attachment_roundtrip() { + let mut conn = create_db(); + let block_num = BlockNumber::from(1); + create_block(&mut conn, block_num); + + let (account_id, _) = + make_account_and_note(&mut conn, block_num, [1u8; 32], AccountStorageMode::Network); + + let target = NetworkAccountTarget::new(account_id, NoteExecutionHint::Always) + .expect("NetworkAccountTarget creation should succeed for network account"); + let attachment: NoteAttachment = target.into(); + + // Create NoteMetadata with the attachment + let metadata = + NoteMetadata::new(account_id, NoteType::Public, NoteTag::with_account_target(account_id)) + .with_attachment(attachment.clone()); + + let note = NoteRecord { + block_num, + note_index: BlockNoteIndex::new(0, 0).unwrap(), + note_id: num_to_word(1), + note_commitment: num_to_word(1), + metadata: metadata.clone(), + details: None, + inclusion_path: SparseMerklePath::default(), + }; + + queries::insert_scripts(&mut conn, [¬e]).unwrap(); + queries::insert_notes(&mut conn, &[(note.clone(), None)]).unwrap(); + + // Fetch the note back and verify the attachment is preserved + let retrieved = queries::select_notes_by_id(&mut conn, &[NoteId::from_raw(note.note_id)]) + .expect("select_notes_by_id should succeed"); + + assert_eq!(retrieved.len(), 1, "Should retrieve exactly one note"); + + let retrieved_metadata = &retrieved[0].metadata; + assert_eq!( + retrieved_metadata.attachment(), + metadata.attachment(), + "Attachment should be preserved after DB roundtrip" + ); + + let retrieved_target = NetworkAccountTarget::try_from(retrieved_metadata.attachment()) + .expect("Should be able to parse NetworkAccountTarget from retrieved attachment"); + assert_eq!( + retrieved_target.target_id(), + account_id, + "NetworkAccountTarget should have the correct target account ID" + ); +} diff --git a/crates/store/src/errors.rs b/crates/store/src/errors.rs index 32c345a98..a842c449d 100644 --- a/crates/store/src/errors.rs +++ b/crates/store/src/errors.rs @@ -6,14 +6,13 @@ use miden_node_proto::domain::account::NetworkAccountError; use miden_node_proto::domain::block::InvalidBlockRange; use miden_node_proto::errors::{ConversionError, GrpcError}; use miden_node_utils::limiter::QueryLimitError; +use miden_protocol::Word; use miden_protocol::account::AccountId; use miden_protocol::block::BlockNumber; use miden_protocol::crypto::merkle::MerkleError; use miden_protocol::crypto::merkle::mmr::MmrError; use miden_protocol::crypto::utils::DeserializationError; -use miden_protocol::note::{NoteId, Nullifier}; -use miden_protocol::transaction::OutputNote; -use miden_protocol::{ +use miden_protocol::errors::{ AccountDeltaError, AccountError, AccountTreeError, @@ -23,8 +22,9 @@ use miden_protocol::{ NoteError, NullifierTreeError, StorageMapError, - Word, }; +use miden_protocol::note::{NoteId, Nullifier}; +use miden_protocol::transaction::OutputNote; use thiserror::Error; use tokio::sync::oneshot::error::RecvError; use tonic::Status; diff --git a/crates/store/src/genesis/config/errors.rs b/crates/store/src/genesis/config/errors.rs index e4eb4810e..b39495c87 100644 --- a/crates/store/src/genesis/config/errors.rs +++ b/crates/store/src/genesis/config/errors.rs @@ -1,6 +1,12 @@ use miden_protocol::account::AccountId; +use miden_protocol::errors::{ + AccountDeltaError, + AccountError, + AssetError, + FeeError, + TokenSymbolError, +}; use miden_protocol::utils::DeserializationError; -use miden_protocol::{AccountError, AssetError, FeeError, TokenSymbolError}; use miden_standards::account::faucets::FungibleFaucetError; use miden_standards::account::wallets::BasicWalletError; @@ -16,7 +22,7 @@ pub enum GenesisConfigError { #[error("asset translation from config to state failed")] Asset(#[from] AssetError), #[error("adding assets to account failed")] - AccountDelta(#[from] miden_protocol::AccountDeltaError), + AccountDelta(#[from] AccountDeltaError), #[error("the defined asset {symbol:?} has no corresponding faucet")] MissingFaucetDefinition { symbol: TokenSymbolStr }, #[error("account with id {account_id} was referenced but is not part of given genesis state")] diff --git a/crates/store/src/genesis/config/mod.rs b/crates/store/src/genesis/config/mod.rs index ed0c0077c..8d1a83437 100644 --- a/crates/store/src/genesis/config/mod.rs +++ b/crates/store/src/genesis/config/mod.rs @@ -23,9 +23,10 @@ use miden_protocol::account::{ use miden_protocol::asset::{FungibleAsset, TokenSymbol}; use miden_protocol::block::FeeParameters; use miden_protocol::crypto::dsa::falcon512_rpo::SecretKey as RpoSecretKey; -use miden_protocol::{Felt, FieldElement, ONE, TokenSymbolError, ZERO}; +use miden_protocol::errors::TokenSymbolError; +use miden_protocol::{Felt, FieldElement, ONE, ZERO}; use miden_standards::AuthScheme; -use miden_standards::account::auth::AuthRpoFalcon512; +use miden_standards::account::auth::AuthFalcon512Rpo; use miden_standards::account::faucets::BasicFungibleFaucet; use miden_standards::account::wallets::create_basic_wallet; use rand::distr::weighted::Weight; @@ -159,7 +160,7 @@ impl GenesisConfig { let mut rng = ChaCha20Rng::from_seed(rand::random()); let secret_key = RpoSecretKey::with_rng(&mut get_rpo_random_coin(&mut rng)); - let auth = AuthScheme::RpoFalcon512 { pub_key: secret_key.public_key().into() }; + let auth = AuthScheme::Falcon512Rpo { pub_key: secret_key.public_key().into() }; let init_seed: [u8; 32] = rng.random(); let account_type = if has_updatable_code { @@ -346,7 +347,7 @@ impl FungibleFaucetConfig { } = self; let mut rng = ChaCha20Rng::from_seed(rand::random()); let secret_key = RpoSecretKey::with_rng(&mut get_rpo_random_coin(&mut rng)); - let auth = AuthRpoFalcon512::new(secret_key.public_key().into()); + let auth = AuthFalcon512Rpo::new(secret_key.public_key().into()); let init_seed: [u8; 32] = rng.random(); let max_supply = Felt::try_from(max_supply) @@ -451,7 +452,7 @@ impl AccountSecrets { .get(&account_id) .ok_or(GenesisConfigError::MissingGenesisAccount { account_id })?; let account_file = - AccountFile::new(account.clone(), vec![AuthSecretKey::RpoFalcon512(secret_key)]); + AccountFile::new(account.clone(), vec![AuthSecretKey::Falcon512Rpo(secret_key)]); Ok(AccountFileWithName { name, account_file }) }) } diff --git a/crates/store/src/server/ntx_builder.rs b/crates/store/src/server/ntx_builder.rs index 40f1ae5b3..f08e32728 100644 --- a/crates/store/src/server/ntx_builder.rs +++ b/crates/store/src/server/ntx_builder.rs @@ -1,6 +1,6 @@ use std::num::{NonZero, TryFromIntError}; -use miden_node_proto::domain::account::{AccountInfo, NetworkAccountPrefix}; +use miden_node_proto::domain::account::{AccountInfo, validate_network_account_prefix}; use miden_node_proto::generated::rpc::BlockRange; use miden_node_proto::generated::store::ntx_builder_server; use miden_node_proto::generated::{self as proto}; @@ -91,13 +91,13 @@ impl ntx_builder_server::NtxBuilder for StoreApi { let request = request.into_inner(); // Validate that the call is for a valid network account prefix - let prefix = NetworkAccountPrefix::try_from(request.account_id_prefix).map_err(|err| { + let prefix = validate_network_account_prefix(request.account_id_prefix).map_err(|err| { Status::invalid_argument( err.as_report_context("request does not contain a valid network account prefix"), ) })?; let account_info: Option = - self.state.get_network_account_details_by_prefix(prefix.inner()).await?; + self.state.get_network_account_details_by_prefix(prefix).await?; Ok(Response::new(proto::store::MaybeAccountDetails { details: account_info.map(|acc| (&acc).into()), @@ -117,8 +117,8 @@ impl ntx_builder_server::NtxBuilder for StoreApi { ) -> Result, Status> { let request = request.into_inner(); let block_num = BlockNumber::from(request.block_num); - let network_account_id_prefix = - NetworkAccountPrefix::try_from(request.network_account_id_prefix).map_err(|err| { + let network_account_prefix = + validate_network_account_prefix(request.network_account_id_prefix).map_err(|err| { invalid_argument(err.as_report_context("invalid network_account_id_prefix")) })?; @@ -132,7 +132,7 @@ impl ntx_builder_server::NtxBuilder for StoreApi { // TODO: no need to get the whole NoteRecord here, a NetworkNote wrapper should be created // instead let (notes, next_page) = state - .get_unconsumed_network_notes_for_account(network_account_id_prefix, block_num, page) + .get_unconsumed_network_notes_for_account(network_account_prefix, block_num, page) .await .map_err(internal_error)?; diff --git a/crates/store/src/state/mod.rs b/crates/store/src/state/mod.rs index a798defcd..d33a9aaf4 100644 --- a/crates/store/src/state/mod.rs +++ b/crates/store/src/state/mod.rs @@ -17,7 +17,6 @@ use miden_node_proto::domain::account::{ AccountStorageDetails, AccountStorageMapDetails, AccountVaultDetails, - NetworkAccountPrefix, SlotData, StorageMapRequest, }; @@ -367,7 +366,7 @@ impl State { note_index, note_id: note.id().as_word(), note_commitment: note.commitment(), - metadata: *note.metadata(), + metadata: note.metadata().clone(), details, inclusion_path, }; @@ -1207,12 +1206,12 @@ impl State { /// along with the next pagination token. pub async fn get_unconsumed_network_notes_for_account( &self, - network_account_id_prefix: NetworkAccountPrefix, + network_account_prefix: u32, block_num: BlockNumber, page: Page, ) -> Result<(Vec, Page), DatabaseError> { self.db - .select_unconsumed_network_notes(network_account_id_prefix, block_num, page) + .select_unconsumed_network_notes(network_account_prefix, block_num, page) .await } diff --git a/crates/validator/src/block_validation/mod.rs b/crates/validator/src/block_validation/mod.rs index 68744010f..416b2beb9 100644 --- a/crates/validator/src/block_validation/mod.rs +++ b/crates/validator/src/block_validation/mod.rs @@ -1,8 +1,8 @@ use std::sync::Arc; -use miden_protocol::ProposedBlockError; use miden_protocol::block::{BlockNumber, BlockSigner, ProposedBlock}; use miden_protocol::crypto::dsa::ecdsa_k256_keccak::Signature; +use miden_protocol::errors::ProposedBlockError; use miden_protocol::transaction::TransactionId; use crate::server::ValidatedTransactions; diff --git a/crates/validator/src/tx_validation/data_store.rs b/crates/validator/src/tx_validation/data_store.rs index a48c2e8e6..749ddaac1 100644 --- a/crates/validator/src/tx_validation/data_store.rs +++ b/crates/validator/src/tx_validation/data_store.rs @@ -58,37 +58,11 @@ impl DataStore for TransactionInputsDataStore { fn get_vault_asset_witnesses( &self, - account_id: AccountId, - vault_root: Word, - vault_keys: BTreeSet, + _account_id: AccountId, + _vault_root: Word, + _vault_keys: BTreeSet, ) -> impl FutureMaybeSend, DataStoreError>> { - async move { - if self.tx_inputs.account().id() != account_id { - return Err(DataStoreError::AccountNotFound(account_id)); - } - - if self.tx_inputs.account().vault().root() != vault_root { - return Err(DataStoreError::Other { - error_msg: "vault root mismatch".into(), - source: None, - }); - } - - Result::, _>::from_iter(vault_keys.into_iter().map(|vault_key| { - match self.tx_inputs.account().vault().open(vault_key) { - Ok(vault_proof) => { - AssetWitness::new(vault_proof.into()).map_err(|err| DataStoreError::Other { - error_msg: "failed to open vault asset tree".into(), - source: Some(err.into()), - }) - }, - Err(err) => Err(DataStoreError::Other { - error_msg: "failed to open vault".into(), - source: Some(err.into()), - }), - } - })) - } + std::future::ready(Ok(vec![])) } fn get_storage_map_witness( diff --git a/proto/proto/types/note.proto b/proto/proto/types/note.proto index 1177f350c..ac125daa0 100644 --- a/proto/proto/types/note.proto +++ b/proto/proto/types/note.proto @@ -32,13 +32,10 @@ message NoteMetadata { // See `miden_protocol::note::note_tag` for more info. fixed32 tag = 3; - // Specifies when a note is ready to be consumed. + // Serialized note attachment // - // See `miden_protocol::note::execution_hint` for more info. - fixed64 execution_hint = 4; - - // An arbitrary user-defined value. - fixed64 aux = 5; + // See `miden_protocol::note::NoteAttachment` for more info. + bytes attachment = 4; } // Represents a note.