Skip to content

Commit 8d8beb2

Browse files
authored
feat: handle standards scripts directly in TransactionExecutorHost w/o DataStore query (0xMiden#2417)
* feat: handle standards scripts directly w/o DataStore query * chore: no need to explicitly add standard scripts to tx context in tests * changelog * chore: add note to DataStore::get_note_script * chore: clarify docs and add panics
1 parent b9fbf9b commit 8d8beb2

File tree

6 files changed

+40
-30
lines changed

6 files changed

+40
-30
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
- [BREAKING] Added `get_asset` and `get_initial_asset` kernel procedures and removed `get_balance`, `get_initial_balance` and `has_non_fungible_asset` kernel procedures ([#2369](https://github.com/0xMiden/miden-base/pull/2369)).
1616
- Introduced `TokenMetadata` type to encapsulate fungible faucet metadata ([#2344](https://github.com/0xMiden/miden-base/issues/2344)).
1717
- Added `StandardNote::from_script_root()` and `StandardNote::name()` methods, and exposed `NoteType` `PUBLIC`/`PRIVATE` masks as public constants ([#2411](https://github.com/0xMiden/miden-base/pull/2411)).
18+
- Resolve standard note scripts directly in `TransactionExecutorHost` instead of querying the data store ([#2417](https://github.com/0xMiden/miden-base/pull/2417)).
1819

1920
### Changes
2021

crates/miden-testing/tests/agglayer/bridge_in.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,6 @@ async fn test_bridge_in_claim_to_p2id() -> anyhow::Result<()> {
173173

174174
let tx_context = mock_chain
175175
.build_tx_context(agglayer_faucet.id(), &[], &[claim_note])?
176-
.add_note_script(p2id_script.clone())
177176
.foreign_accounts(vec![foreign_account_inputs])
178177
.build()?;
179178

crates/miden-testing/tests/agglayer/bridge_out.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use miden_crypto::rand::FeltRng;
66
use miden_protocol::Felt;
77
use miden_protocol::account::{AccountId, AccountIdVersion, AccountStorageMode, AccountType};
88
use miden_protocol::asset::{Asset, FungibleAsset};
9-
use miden_protocol::note::{NoteAssets, NoteScript, NoteTag, NoteType};
9+
use miden_protocol::note::{NoteAssets, NoteTag, NoteType};
1010
use miden_protocol::transaction::OutputNote;
1111
use miden_standards::account::faucets::TokenMetadata;
1212
use miden_standards::note::StandardNote;
@@ -68,14 +68,10 @@ async fn test_bridge_out_consumes_b2agg_note() -> anyhow::Result<()> {
6868
builder.add_output_note(OutputNote::Full(b2agg_note.clone()));
6969
let mut mock_chain = builder.build()?;
7070

71-
// Get BURN note script to add to the transaction context
72-
let burn_note_script: NoteScript = StandardNote::BURN.script();
73-
7471
// EXECUTE B2AGG NOTE AGAINST BRIDGE ACCOUNT (NETWORK TRANSACTION)
7572
// --------------------------------------------------------------------------------------------
7673
let tx_context = mock_chain
7774
.build_tx_context(bridge_account.id(), &[b2agg_note.id()], &[])?
78-
.add_note_script(burn_note_script.clone())
7975
.build()?;
8076
let executed_transaction = tx_context.execute().await?;
8177

@@ -116,7 +112,7 @@ async fn test_bridge_out_consumes_b2agg_note() -> anyhow::Result<()> {
116112
// Verify the BURN note uses the correct script
117113
assert_eq!(
118114
burn_note.recipient().script().root(),
119-
burn_note_script.root(),
115+
StandardNote::BURN.script_root(),
120116
"BURN note should use the BURN script"
121117
);
122118

crates/miden-testing/tests/scripts/faucet.rs

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1241,15 +1241,7 @@ async fn test_mint_note_output_note_types(#[case] note_type: NoteType) -> anyhow
12411241
builder.add_output_note(OutputNote::Full(mint_note.clone()));
12421242
let mut mock_chain = builder.build()?;
12431243

1244-
let mut tx_context_builder =
1245-
mock_chain.build_tx_context(faucet.id(), &[mint_note.id()], &[])?;
1246-
1247-
if note_type == NoteType::Public {
1248-
let p2id_script = StandardNote::P2ID.script();
1249-
tx_context_builder = tx_context_builder.add_note_script(p2id_script);
1250-
}
1251-
1252-
let tx_context = tx_context_builder.build()?;
1244+
let tx_context = mock_chain.build_tx_context(faucet.id(), &[mint_note.id()], &[])?.build()?;
12531245
let executed_transaction = tx_context.execute().await?;
12541246

12551247
assert_eq!(executed_transaction.output_notes().num_notes(), 1);

crates/miden-tx/src/executor/data_store.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ pub trait DataStore: MastForestStore {
7676
/// If the script is not found, it returns `Ok(None)` rather than an error, as "not found"
7777
/// is a valid, expected outcome.
7878
///
79+
/// **Note:** Data store implementers do not need to handle standard note scripts (e.g. P2ID).
80+
/// These are resolved directly by the transaction executor and will not trigger this method.
81+
///
7982
/// # Errors
8083
/// Returns an error if the data store encountered an internal error while attempting to
8184
/// retrieve the script.

crates/miden-tx/src/executor/exec_host.rs

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use miden_protocol::assembly::{SourceFile, SourceManagerSync, SourceSpan};
2626
use miden_protocol::asset::{AssetVaultKey, AssetWitness, FungibleAsset};
2727
use miden_protocol::block::BlockNumber;
2828
use miden_protocol::crypto::merkle::smt::SmtProof;
29-
use miden_protocol::note::{NoteMetadata, NoteRecipient, NoteStorage};
29+
use miden_protocol::note::{NoteMetadata, NoteRecipient, NoteScript, NoteStorage};
3030
use miden_protocol::transaction::{
3131
InputNote,
3232
InputNotes,
@@ -36,6 +36,7 @@ use miden_protocol::transaction::{
3636
};
3737
use miden_protocol::vm::AdviceMap;
3838
use miden_protocol::{Felt, Hasher, Word};
39+
use miden_standards::note::StandardNote;
3940

4041
use crate::auth::{SigningInputs, TransactionAuthenticator};
4142
use crate::errors::TransactionKernelError;
@@ -364,11 +365,22 @@ where
364365
Ok(asset_witnesses.into_iter().flat_map(asset_witness_to_advice_mutation).collect())
365366
}
366367

367-
/// Handles a request for a [`NoteScript`] by querying the [`DataStore`].
368+
/// Handles a request for a [`NoteScript`] during transaction execution when the script is not
369+
/// already in the advice provider.
368370
///
369-
/// The script is fetched from the data store and used to build a [`NoteRecipient`], which is
370-
/// then used to create an [`OutputNoteBuilder`]. This function is only called for public notes
371-
/// where the script is not already available in the advice provider.
371+
/// Standard note scripts (P2ID, etc.) are resolved directly from [`StandardNote`], avoiding a
372+
/// data store round-trip. Non-standard scripts are fetched from the [`DataStore`].
373+
///
374+
/// The resolved script is used to build a [`NoteRecipient`], which is then used to create
375+
/// an [`OutputNoteBuilder`]. This function is only called for notes where the script is not
376+
/// already in the advice provider.
377+
///
378+
/// # Errors
379+
/// Returns an error if:
380+
/// - The note is public and the script is not found in the data store.
381+
/// - Constructing the recipient with the fetched script does not match the expected recipient
382+
/// digest.
383+
/// - The data store returns an error when fetching the script.
372384
async fn on_note_script_requested(
373385
&mut self,
374386
note_idx: usize,
@@ -378,10 +390,21 @@ where
378390
note_storage: NoteStorage,
379391
serial_num: Word,
380392
) -> Result<Vec<AdviceMutation>, TransactionKernelError> {
381-
let note_script_result = self.base_host.store().get_note_script(script_root).await;
393+
// Resolve standard note scripts directly, avoiding a data store round-trip.
394+
let note_script: Option<NoteScript> =
395+
if let Some(standard_note) = StandardNote::from_script_root(script_root) {
396+
Some(standard_note.script())
397+
} else {
398+
self.base_host.store().get_note_script(script_root).await.map_err(|err| {
399+
TransactionKernelError::other_with_source(
400+
"failed to retrieve note script from data store",
401+
err,
402+
)
403+
})?
404+
};
382405

383-
match note_script_result {
384-
Ok(Some(note_script)) => {
406+
match note_script {
407+
Some(note_script) => {
385408
let script_felts: Vec<Felt> = (&note_script).into();
386409
let recipient = NoteRecipient::new(serial_num, note_script, note_storage);
387410

@@ -399,7 +422,7 @@ where
399422
script_felts,
400423
)]))])
401424
},
402-
Ok(None) if metadata.is_private() => {
425+
None if metadata.is_private() => {
403426
self.base_host.output_note_from_recipient_digest(
404427
note_idx,
405428
metadata,
@@ -408,13 +431,9 @@ where
408431

409432
Ok(Vec::new())
410433
},
411-
Ok(None) => Err(TransactionKernelError::other(format!(
434+
None => Err(TransactionKernelError::other(format!(
412435
"note script with root {script_root} not found in data store for public note"
413436
))),
414-
Err(err) => Err(TransactionKernelError::other_with_source(
415-
"failed to retrieve note script from data store",
416-
err,
417-
)),
418437
}
419438
}
420439

0 commit comments

Comments
 (0)