Skip to content

Commit e389b8d

Browse files
committed
feat: assemble ExpirationTransactionScript on build-time
1 parent 0ee269f commit e389b8d

6 files changed

Lines changed: 99 additions & 24 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
- Added the canonical `ExpirationTransactionScript` to `miden-standards`, with a delta-independent script root that network accounts can allowlist ([#3051](https://github.com/0xMiden/protocol/pull/3051)).
5757
- [BREAKING] Migrated the `miden-standards` library to a `miden-project.toml` project ([#3107](https://github.com/0xMiden/protocol/pull/3107)).
5858
- [BREAKING] Migrated `miden-protocol` MASM assembly to a `miden-project.toml` project ([#3094](https://github.com/0xMiden/protocol/pull/3094)).
59+
- Added `ExpirationTransactionScript` assembly in build-time into a package ([#3111](https://github.com/0xMiden/protocol/pull/3111)).
5960
- [BREAKING] Replaced `AccountInterface::build_send_notes_script` with a standalone `SendNotesTransactionScript` built against `AccountCodeInterface` ([#3055](https://github.com/0xMiden/protocol/pull/3055)).
6061
- Added an `AccountCode::interface` helper that returns the public `AccountCodeInterface` ([#3080](https://github.com/0xMiden/protocol/pull/3080)).
6162
- [BREAKING] Tightened `AccountStorage::get_map_item` to take a `StorageMapKey` instead of a raw `Word` ([#3080](https://github.com/0xMiden/protocol/pull/3080)).
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
use miden::protocol::tx
2+
3+
#! Set the transaction's expiration delta.
4+
#!
5+
#! Inputs: [[delta, 0, 0, 0], pad(12)]
6+
#! Outputs: [pad(16)]
7+
#!
8+
#! Panics if:
9+
#! - delta is 0 or not a u32 in the range 1..=0xFFFF (ERR_TX_INVALID_EXPIRATION_DELTA).
10+
#!
11+
#! Invocation: call
12+
begin
13+
exec.tx::update_expiration_block_delta
14+
# => [pad(16)]
15+
end
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[package]
2+
name = "expiration-tx-script"
3+
version.workspace = true
4+
5+
[[bin]]
6+
name = "expiration"
7+
path = "expiration.masm"
8+
9+
[dependencies]
10+
miden-core.workspace = true
11+
miden-protocol.workspace = true
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[workspace]
2+
members = ["expiration"]
3+
4+
[workspace.package]
5+
version = "0.16.0"
6+
7+
[workspace.dependencies]
8+
miden-core = { linkage = "dynamic", version = "0.24" }
9+
miden-protocol = { linkage = "dynamic", version = "0.16.0" }

crates/miden-standards/build.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ const ASSETS_DIR: &str = "assets";
1919
const ASM_DIR: &str = "asm";
2020
const ASM_STANDARDS_DIR: &str = "standards";
2121
const ASM_COMPONENTS_DIR: &str = "components";
22+
const ASM_TX_SCRIPTS_DIR: &str = "tx_scripts";
2223

2324
/// Name of the manifest file defining a Miden project.
2425
const PROJECT_MANIFEST: &str = "miden-project.toml";
@@ -35,6 +36,7 @@ const STANDARDS_ERRORS_ARRAY_NAME: &str = "STANDARDS_ERRORS";
3536
/// Read and parse the contents from `./asm`.
3637
/// - Compiles the contents of asm/standards directory into a package. Note scripts are included in
3738
/// this library.
39+
/// - Compiles the contents of asm/tx_scripts directory into individual executable packages.
3840
/// - Compiles the contents of asm/components directory into individual packages.
3941
fn main() -> Result<()> {
4042
// re-build when the MASM code changes
@@ -59,6 +61,15 @@ fn main() -> Result<()> {
5961
// compile standards library (includes note scripts) and seed it into the registry
6062
compile_standards_lib(&source_dir, &target_dir, assembler.clone(), &mut registry)?;
6163

64+
// compile transaction scripts
65+
compile_tx_scripts(
66+
&source_dir.join(ASM_TX_SCRIPTS_DIR),
67+
&target_dir.join(ASM_TX_SCRIPTS_DIR),
68+
&assembler,
69+
&mut registry,
70+
source_manager.clone(),
71+
)?;
72+
6273
// compile account components
6374
compile_account_components(
6475
&source_dir.join(ASM_COMPONENTS_DIR),
@@ -148,6 +159,45 @@ fn compile_account_components(
148159
Ok(())
149160
}
150161

162+
// COMPILE TRANSACTION SCRIPTS
163+
// ================================================================================================
164+
165+
/// Assembles each member of the tx-scripts workspace in `source_dir` into an executable MAST
166+
/// package and saves it to `target_dir`. Each file is named after its `[[bin]]` target (e.g.
167+
/// `expiration.masp`), so the include path used by the Rust side is the script name.
168+
///
169+
/// Each script's dependencies are declared in its `miden-project.toml` and resolved against the
170+
/// `registry`, which is seeded with the core, kernel, protocol, and standards packages.
171+
fn compile_tx_scripts(
172+
source_dir: &Path,
173+
target_dir: &Path,
174+
assembler: &Assembler,
175+
registry: &mut InMemoryPackageRegistry,
176+
source_manager: Arc<dyn SourceManager>,
177+
) -> Result<()> {
178+
let manifest =
179+
source_manager.load_file(&source_dir.join(PROJECT_MANIFEST)).into_diagnostic()?;
180+
let workspace = Workspace::load(manifest, source_manager.as_ref())?;
181+
182+
std::fs::create_dir_all(target_dir).into_diagnostic()?;
183+
184+
for script in workspace.members() {
185+
for target in script.executable_targets() {
186+
let target_name = target.name.inner().as_ref();
187+
188+
let package = assembler
189+
.clone()
190+
.for_project(script.clone(), registry)?
191+
.assemble(ProjectTargetSelector::Executable(target_name), BUILD_PROFILE)?;
192+
193+
let output_file = target_dir.join(target_name).with_extension(Package::EXTENSION);
194+
package.write_to_file(output_file).into_diagnostic()?;
195+
}
196+
}
197+
198+
Ok(())
199+
}
200+
151201
// ERROR CONSTANTS FILE GENERATION
152202
// ================================================================================================
153203

crates/miden-standards/src/tx_script/expiration_script.rs

Lines changed: 13 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,27 @@
11
use core::num::NonZeroU16;
22

33
use miden_protocol::transaction::{TransactionScript, TransactionScriptRoot};
4+
use miden_protocol::utils::serde::Deserializable;
45
use miden_protocol::utils::sync::LazyLock;
6+
use miden_protocol::vm::Package;
57
use miden_protocol::{Felt, Word};
68

7-
use crate::code_builder::CodeBuilder;
8-
9-
// EXPIRATION TRANSACTION SCRIPT
9+
// CONSTANTS
1010
// ================================================================================================
1111

12-
/// Transaction script that sets the expiration delta.
13-
const EXPIRATION_TX_SCRIPT_SOURCE: &str = "\
14-
use miden::protocol::tx
12+
/// The canonical expiration transaction script, assembled at build time from
13+
/// `asm/tx_scripts/expiration/expiration.masm` into an executable package.
14+
const EXPIRATION_TX_SCRIPT_BYTES: &[u8] =
15+
include_bytes!(concat!(env!("OUT_DIR"), "/assets/tx_scripts/expiration.masp"));
1516

16-
#! Set the transaction's expiration delta.
17-
#!
18-
#! Inputs: [[delta, 0, 0, 0], pad(12)]
19-
#! Outputs: [pad(16)]
20-
#!
21-
#! Panics if:
22-
#! - delta is 0 or not a u32 in the range 1..=0xFFFF (ERR_TX_INVALID_EXPIRATION_DELTA).
23-
#!
24-
#! Invocation: call
25-
@transaction_script
26-
pub proc main
27-
exec.tx::update_expiration_block_delta
28-
# => [pad(16)]
29-
end
30-
";
17+
// EXPIRATION TRANSACTION SCRIPT
18+
// ================================================================================================
3119

3220
static EXPIRATION_TX_SCRIPT: LazyLock<TransactionScript> = LazyLock::new(|| {
33-
CodeBuilder::default()
34-
.compile_tx_script(EXPIRATION_TX_SCRIPT_SOURCE)
35-
.expect("canonical expiration tx script should compile")
21+
let package = Package::read_from_bytes(EXPIRATION_TX_SCRIPT_BYTES)
22+
.expect("expiration tx script masp should be well-formed");
23+
TransactionScript::from_package(&package)
24+
.expect("expiration tx script package should contain an executable program")
3625
});
3726

3827
/// The canonical transaction script that sets the transaction's expiration delta to the value

0 commit comments

Comments
 (0)