feat(debug): add initial support for debugging inline calls - #1295
Draft
djolertrk wants to merge 23 commits into
Draft
feat(debug): add initial support for debugging inline calls#1295djolertrk wants to merge 23 commits into
djolertrk wants to merge 23 commits into
Conversation
* feat(sdk): migrate SDK bindings and scripts to protocol 0.16 Protocol 0.16 reshaped the transaction-kernel API surface the SDK binds: the note asset readers moved to creation-time semantics (get_assets -> get_initial_assets, get_assets_info -> get_initial_assets_info), account membership generalized to has_asset by asset id, the initial-state readers moved from active_account to native_account, and fungible balance reads plus in-kernel asset construction (asset/faucet create_*, has_callbacks) were removed entirely. Sync all five binding layers (externs, stubs, frontend signatures, transform strategies, compile tests) to the new kernel, delete the emptied asset module, and document the breaking surface in the SDK changelog and migration guide. Protocol 0.16 also recognizes account-interface procedures only via export attributes, and restricts output_note::create to account-component context. Tag lifted component exports so account-code construction and FPI can see them, emit the @transaction_script attribute for #[tx_script] entrypoints so TransactionScript::from_library can locate them, and route note creation in the basic-wallet example through a new create_note component method that tx scripts call instead of output_note::create. Pin miden-protocol and miden-standards to =0.16.0-alpha.4: the kernel API is identical through 0.16.0-beta.1, but miden-client 0.16.0-alpha.1 (required by the network tests) is not source-compatible with the beta protocol crates yet. Adapt the test harnesses accordingly and refresh the cycle and package-size expectations that legitimately moved with the new kernel. * feat(sdk): require explicit #[account_procedure] marking on component methods The interim frontend behavior tagged every lifted component export as an account procedure, which made the entire component surface (including internals like init) part of the account interface and left users no way to keep a method out of it. Replace the blanket tagging with a user-facing #[account_procedure] attribute that mirrors #[auth_script]: it must be applied to methods of a #[component] trait, any number of methods may be marked, and the two attributes are mutually exclusive per component since auth components carry only their authentication entrypoint. The component macro emits one frontend metadata section per crate whose payload is now a list of entries, the frontend stamps the account_procedure attribute only on metadata-selected exports, and unmarked methods remain ordinary exports invisible to account-code construction and FPI. Mark the deployed examples and test fixtures accordingly, leave compile-only guests unmarked to keep that path covered, and record the breaking change with a before/after example in the SDK changelog and migration guide. * test(integration): fix executor host handlers and synthetic project namespace VM v0.25 reports division and debug-helper errors through events, but the shared test host loaded the core library through its package form, and that conversion drops the library's event-handler registry — executions surfaced UnhandledEvent instead of the expected traps. Load the CoreLibrary directly so its handlers reach the host; the trap expectations are unchanged. The project assembler now requires a library target's namespace to match its root module. The synthetic manifests generated for inline-source tests omitted [lib].namespace, defaulting to the package name, while core Wasm translation produces the root_ns:root@1.0.0 wrapper component identity. Declare that identity in the generated manifest so the two agree.
Plain dependency imports and #[account] bindings could describe the same canonical WIT interface differently because FPI generation added fpi-* functions in place. Component linking then depended on section ordering and could fail with an incompatible interface definition. Keep canonical dependency interfaces unchanged and place generated FPI adapters in deterministic private interfaces, using local aliases to preserve dependency-owned type identity. Native calls retain the canonical module path, foreign calls use the synthetic path, and repeated account expansions receive distinct component-type sections without changing public binding paths.
FPI binding interfaces and component metadata need distinct identities when the same dependency is imported through multiple account wrappers. Encoding source text and positions made otherwise identical builds sensitive to harmless code movement, while opaque hexadecimal names obscured generated imports. Create readable canonical synthetic package identities and scope component metadata sections with the generated Rust module path. This preserves the original dependency interface and keeps repeated bindings distinct without coupling package output to source locations.
FPI prefix structure and source-function selection were duplicated across generation and validation, which made the two paths easy to drift apart. Generated Rust signatures were also validated twice. Share the ABI parameter definition and source-function predicate, give the generated-function filter an explicit name, and retain one Rust-signature validation point.
Synthetic FPI interfaces treated every resolved type ID as a named interface type and compared generated aliases by Rust token spelling. Anonymous compounds could produce invalid resolves, while sibling-interface use aliases were rejected despite naming the same semantic type. Rebuild anonymous constructors recursively and validate resolved WIT identity before relying on Rust type checking for transparent alias compatibility.
Every account wrapper previously emitted the same package and world identity even when its selected dependency set differed. Merging separately encoded component metadata then treated incompatible worlds as duplicate definitions. Derive the binding identity from the sorted canonical import set and FPI ABI version. Equal views remain merge-compatible, while different views receive distinct stable identities.
Generated FPI interfaces use deterministic package identities derived from source packages. A real WIT package could already occupy one of those legal identities and be silently reused or mutated, producing an opaque compatibility failure. Track packages created during one injection and reject any pre-existing ambient package with a precise collision diagnostic, while still reusing a generated package for multiple interfaces in the same injection.
Module paths alone do not distinguish generated metadata emitted by different package versions, so equal section names can still be concatenated during linking. Prefix the stable module discriminator with the Cargo package name and version. Document the module-scope requirement because function-local scopes are intentionally excluded to keep identities independent of source positions.
Synthetic FPI interfaces are assembled inside the SDK proc macros, which makes their resolved shape difficult to inspect when component metadata fails later in compilation. Add an internal MIDENC_EMIT_WIT renderer that writes inline worlds after FPI injection, including their nested synthetic packages. Keep the printer dependency behind an SDK-forwarded feature so normal builds do not gain a direct dependency on it.
Compiler integration failures can involve both the public generated interface and private inline worlds, but the harness previously exposed only macro-expanded Rust. Teach MIDENC_EMIT_WIT to copy each fixture's public WIT alongside the proc-macro artifacts, sharing output-directory handling with macro expansion. Generated SDK fixtures explicitly enable the internal renderer so feature selection remains in test configuration rather than compiler manifest inspection.
The workspace inheritance gate rejects dependencies repeated across normal and development scopes unless their version is centralized. The optional WIT printer declared wit-component in both scopes of base-macros, leaving CI unable to validate the manifests. Promote the version to the workspace dependency table and inherit it for both declarations. This preserves internal-wit-emit feature gating while satisfying the workspace ownership rule.
Naturally aligned Wasm scalar accesses were asserted in byte space, normalized again during MASM lowering, and then routed through dynamic-offset memory helpers. Normalize proven four-byte-aligned scalar addresses once and carry the quotient as an element-space pointer. This lets later lowering select element-space memory operations while potentially unaligned accesses remain on the byte-pointer path.
…re_addr The element fast path made the alignment assertion load-bearing: the divmod quotient becomes the address, so disabling the assertion (as the pre-existing TODO above the shared alignment block suggested) would make a misaligned access silently target the containing element instead of trapping. Extract the alignment handling into enforce_alignment, scope the TODO to the byte-space branch where it still applies, and spell out the constraint on the element branch. Document the changed contract of prepare_addr: the returned pointer is an element-space pointer holding an element address for naturally aligned element-sized accesses, and a byte-space pointer holding the byte address otherwise, with alignment promises enforced at runtime as a deliberate deviation from Wasm's hint-only semantics. Derive the element size from ELEMENT_ALIGNMENT_LOG2 and compare the promised alignment with `>=` to state the "at least element-aligned" requirement directly. The emitted IR is unchanged.
compile_test_module_with_masm duplicated the context/signature/component/ entrypoint ceremony of compile_test_module verbatim, leaving two copies of the test-harness setup that could silently drift apart. Extract the shared setup into a private build_test_component helper so the two compile paths differ only in how the codegen output is consumed.
The aligned-access round-trip could pass with a symmetric addressing bug: an element-space pointer still carrying the byte address would store to and load from the same wrong element. Verify the store through an independent read of the targeted cell, and add a load-only case that seeds the expected element next to a decoy, so ignoring the static offset or mis-scaling the address can no longer round-trip. Also cover the remaining prepare_addr paths: a felt round-trip proving whole field elements move through element pointers without the felt byte-space intrinsics, and an align=1 access that keeps the byte-space intrinsics while still trapping when the smaller promise is violated. The exact u32divmod count is relaxed to presence, since a CSE pass may legally merge the two address conversions.
Size-optimized LLVM output leaves execution improvements on the table for release guest builds, while the resulting package-size tradeoff depends on the guest. Select optimization level two while preserving the existing release LTO, codegen-unit, and panic settings. Update the recorded execution-cycle and stripped MAST size measurements to reflect the new release output.
Release Cargo guest builds hard-coded LLVM level two, so explicit compiler optimization choices could not tune the Rust guest compilation profile. Map compiler optimization levels to Cargo profile values and build guests with the selected value. Preserve level two for the existing default and balanced modes while allowing basic, maximum, and size-focused modes to drive Cargo.
Collaborator
Author
|
This relies on the #1293 |
Collaborator
Author
|
Note added to #1293 (comment), that one piece of this will be needed on the main migration PR. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.