feat(agglayer): add outbound message bridging (leafType=1)#3012
Draft
Dominik1999 wants to merge 17 commits into
Draft
feat(agglayer): add outbound message bridging (leafType=1)#3012Dominik1999 wants to merge 17 commits into
Dominik1999 wants to merge 17 commits into
Conversation
Add the inverse of to_account_id for converting AccountId [suffix, prefix] into Ethereum address format [limb0, limb1, limb2, limb3, limb4]. This is needed by the bridge_message procedure to derive the origin Ethereum address from the note sender's AccountId.
Adds a new public procedure that creates a leafType=1 leaf in the Local Exit Tree for outbound message bridging. Unlike bridge_out (asset transfers), this procedure does not involve faucet lookup, burn, or lock operations. The origin address is derived from the note sender via eth_address::from_account_id and the amount is always zero.
Create message_note.rs following the B2AggNote pattern but for asset-less message bridging. The note carries destination_network, destination_address, and metadata_hash in its storage (14 felts total) with no assets attached.
Fix stack depth bug in bridge_message procedure: within a `call` frame, the stack floor is 16 elements, so direct consumption of input values via mem_store cannot reduce depth below 16. Restructured to save inputs to locals first, then reload above the floor for memory operations. The test verifies: - LET num_leaves increments by 1 after consuming a MessageNote - Local exit root becomes non-zero - No output notes are produced (messages don't create BURN notes) - Bridge vault remains empty (no assets involved)
…twork The origin_network field must be stored in LE byte order in the leaf data memory layout (matching how bridge_out stores it via convert_asset). Without the swap, the Keccak leaf hash would not match Solidity's computation.
…aim + leaf hash tests - get_sender already returns [suffix, prefix], matching from_account_id's expected input - Add bridge_message_reclaim_is_noop test (passing) - Add bridge_message_leaf_hash_matches_independent_computation test (ignored pending MASM instrumentation to diagnose keccak input byte mismatch)
… leaf hash test u32split returns [lo, hi] (lo on top), not [hi, lo]. Added swap after each u32split to get hi on top before byte-swapping. This caused the origin address limbs to be swapped within each 8-byte word, producing incorrect leaf hashes. Also adds: - test_from_account_id_matches_rust: verifies MASM matches Rust conversion - bridge_message_leaf_hash_masm_unit_test: verifies hash pipeline in isolation - Un-ignores leaf hash comparison test (now passes)
…ry offsets Replace raw numeric indices (loc_store.0, loc_load.13, etc.) with named BRIDGE_MSG_*_LOC constants, matching the established convention used by bridge_out, create_burn_note, and unlock_and_send procedures.
…ature Add input (suffix: felt, prefix: felt) and return type (EthereumAddressFormat) to match the convention used by compute_leaf_value, verify_merkle_proof, and other typed public procedures in the codebase.
… validate no assets - Replace reused ERR_B2AGG_* errors with ERR_BRIDGE_MSG_NOTE_MUST_BE_PUBLIC and ERR_BRIDGE_MSG_DESTINATION_NETWORK_IS_MIDEN so error messages correctly identify the BRIDGE_MESSAGE note, not B2AGG - Fix get_sender stack comment in note script: returns [suffix, prefix] not [prefix, suffix] - Add assertz on asset count to prevent silent asset loss if a BRIDGE_MESSAGE note is manually constructed with assets
…MASM unit tests - Note script: replace 14 individual mem_load instructions with 4 idiomatic padw + mem_loadw_le word loads (matching b2agg.masm pattern) - message_note.rs: document LE byte-swap convention in build_note_storage - Move test_from_account_id_matches_rust to solidity_miden_address_conversion.rs - Move compute_leaf_value message-type test to leaf_utils.rs
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.
Summary
bridge_messageprocedure to the AggLayer bridge for sending arbitrary cross-chain messages from Miden to Ethereum/other chainsbridgeMessage())Closes #2697
Changes
eth_address.masm: Addfrom_account_id(inverse ofto_account_id) for deriving origin address from note senderbridge_out.masm: Addbridge_messagepublic procedure — populates leaf data with leafType=1, derives origin from sender, appends to LETbridge.masmcomponent: Re-exportbridge_messagebridge_message.masmnote script: Entry point for message bridging (reclaim + bridge paths)message_note.rs:MessageNoteRust type withcreate()builderbridge.rs: Register BRIDGE_MESSAGE inallowed_notes()Scope
Outbound only (Miden → other chains). Inbound message processing (
claimMessageon Miden side) is deferred.Follow-up: message + value transfer (
bridge_message_with_value)This PR enables pure messages (amount=0). The next step is combining assets and messages in a single leaf, which would enable use cases like:
deposit()calldata in one atomic operationThis mirrors Solidity's
bridgeMessageWETH(). The leaf format already has theamountfield (hardcoded to 0 in this PR), so the extension is additive: accept an asset + metadata_hash, do the faucet lookup + burn/lock (reuse frombridge_out), set the scaled amount in the leaf, and append as leafType=1.Inbound message processing (receiving messages from Ethereum on Miden) is a separate follow-up.
Test plan
9 integration tests covering:
from_account_idMASM↔Rust conversion verification