-
Notifications
You must be signed in to change notification settings - Fork 24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
PoC of the Miden SDK and rollup account implementation #75
Closed
Closed
Changes from 1 commit
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
b27a75e
feature: draft Miden SDK and add rollup account example compilation test
greenhat 703f0f9
test: draft send and recv notes code as bin targets and filled missin…
greenhat 57cb255
test: draft stack/advice provider callconv and compiled basic-wallet …
greenhat 6b938a0
test: introduce `build_notes` feature for note's code conditional
greenhat 871cbfb
test: switch to the macros generated wrappers of the user's code when…
greenhat 9a5bd87
test: use serde and postcard for function arguments marshalling
greenhat 07364a8
test: implement func args marshalling for `MyWallet::send_note`;
greenhat a0e1583
test: move calls to `account::*` behind `MyWallet` methods
greenhat f446cc5
test: introduce FuncArgPassingConv to encode stack vs. advice provide…
greenhat 27486c2
test: add `wasm32-wasi` target installation for tests on CI
greenhat 04032f7
test: rename `note_*` to `tx_script_*`
greenhat f8a983c
test: add note_p2id with p2id note skeleton
greenhat File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains 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
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
[package] | ||
name = "miden" | ||
description = "Miden SDK" | ||
version.workspace = true | ||
rust-version.workspace = true | ||
authors.workspace = true | ||
repository.workspace = true | ||
categories.workspace = true | ||
keywords.workspace = true | ||
license.workspace = true | ||
readme.workspace = true | ||
edition.workspace = true | ||
|
||
[dependencies] |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
use crate::asset::Asset; | ||
|
||
extern "C" { | ||
#[link_name = "miden::sat::account::add_asset"] | ||
pub fn add_asset_inner(asset: Asset) -> Asset; | ||
#[link_name = "miden::sat::account::remove_asset"] | ||
pub fn remove_asset_inner(asset: Asset) -> Asset; | ||
} | ||
|
||
pub fn add_asset(asset: Asset) -> Asset { | ||
unsafe { add_asset_inner(asset) } | ||
} | ||
|
||
pub fn remove_asset(asset: Asset) -> Asset { | ||
unsafe { remove_asset_inner(asset) } | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
use crate::felt::Word; | ||
|
||
#[repr(transparent)] | ||
pub struct Asset(Word); | ||
|
||
impl From<Word> for Asset { | ||
fn from(value: Word) -> Self { | ||
Self(value) | ||
} | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
/// Number of field elements in a word. | ||
pub const WORD_SIZE: usize = 4; | ||
|
||
/// A group of four field elements in the Miden base field. | ||
pub type Word = [Felt; WORD_SIZE]; | ||
|
||
#[repr(transparent)] | ||
pub struct Felt(u64); | ||
|
||
impl From<u64> for Felt { | ||
fn from(value: u64) -> Self { | ||
Self(value) | ||
} | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
#![no_std] | ||
#![deny(warnings)] | ||
|
||
pub mod account; | ||
pub mod asset; | ||
pub mod felt; | ||
pub mod note; | ||
pub mod tx; |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
use crate::felt::Felt; | ||
use crate::felt::Word; | ||
|
||
#[repr(transparent)] | ||
pub struct Recipient(Word); | ||
|
||
impl From<Word> for Recipient { | ||
fn from(value: Word) -> Self { | ||
Self(value) | ||
} | ||
} | ||
|
||
#[repr(transparent)] | ||
pub struct Tag(Felt); | ||
|
||
impl Tag { | ||
pub fn new(value: u64) -> Self { | ||
Self(Felt::from(value)) | ||
} | ||
} | ||
|
||
impl From<Felt> for Tag { | ||
fn from(value: Felt) -> Self { | ||
Self(value) | ||
} | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
use crate::asset::Asset; | ||
use crate::note::Recipient; | ||
use crate::note::Tag; | ||
|
||
extern "C" { | ||
#[link_name = "miden::sat::tx::create_note"] | ||
pub fn create_note_inner(asset: Asset, tag: Tag, recipient: Recipient); | ||
} | ||
|
||
pub fn create_note(asset: Asset, tag: Tag, recipient: Recipient) { | ||
unsafe { create_note_inner(asset, tag, recipient) } | ||
} |
This file contains 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
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,219 @@ | ||
(module | ||
(type (;0;) (func (param i32 i32))) | ||
(type (;1;) (func (param i32 i64 i32))) | ||
(type (;2;) (func (param i32 i32 i32))) | ||
(type (;3;) (func (param i64) (result i64))) | ||
(import "env" "miden::sat::account::add_asset" (func $miden::sat::account::add_asset (;0;) (type 0))) | ||
(import "env" "miden::sat::account::remove_asset" (func $miden::sat::account::remove_asset (;1;) (type 0))) | ||
(import "env" "miden::sat::tx::create_note" (func $miden::sat::tx::create_note (;2;) (type 1))) | ||
(func $receive_asset (;3;) (type 0) (param i32 i32) | ||
(local i32) | ||
global.get $__stack_pointer | ||
i32.const 32 | ||
i32.sub | ||
local.tee 2 | ||
global.set $__stack_pointer | ||
local.get 2 | ||
local.get 1 | ||
call $miden::account::add_asset | ||
local.get 2 | ||
i32.const 32 | ||
i32.add | ||
global.set $__stack_pointer | ||
) | ||
(func $send_asset (;4;) (type 2) (param i32 i32 i32) | ||
(local i32) | ||
global.get $__stack_pointer | ||
i32.const 32 | ||
i32.sub | ||
local.tee 3 | ||
global.set $__stack_pointer | ||
local.get 3 | ||
local.get 1 | ||
call $miden::account::remove_asset | ||
local.get 3 | ||
i64.const 4 | ||
call $miden::note::Tag::new | ||
local.get 2 | ||
call $miden::tx::create_note | ||
local.get 3 | ||
i32.const 32 | ||
i32.add | ||
global.set $__stack_pointer | ||
) | ||
(func $miden::account::add_asset (;5;) (type 0) (param i32 i32) | ||
(local i32) | ||
global.get $__stack_pointer | ||
i32.const 32 | ||
i32.sub | ||
local.tee 2 | ||
global.set $__stack_pointer | ||
local.get 2 | ||
i32.const 24 | ||
i32.add | ||
local.get 1 | ||
i32.const 24 | ||
i32.add | ||
i64.load | ||
i64.store | ||
local.get 2 | ||
i32.const 16 | ||
i32.add | ||
local.get 1 | ||
i32.const 16 | ||
i32.add | ||
i64.load | ||
i64.store | ||
local.get 2 | ||
i32.const 8 | ||
i32.add | ||
local.get 1 | ||
i32.const 8 | ||
i32.add | ||
i64.load | ||
i64.store | ||
local.get 2 | ||
local.get 1 | ||
i64.load | ||
i64.store | ||
local.get 0 | ||
local.get 2 | ||
call $miden::sat::account::add_asset | ||
local.get 2 | ||
i32.const 32 | ||
i32.add | ||
global.set $__stack_pointer | ||
) | ||
(func $miden::account::remove_asset (;6;) (type 0) (param i32 i32) | ||
(local i32) | ||
global.get $__stack_pointer | ||
i32.const 32 | ||
i32.sub | ||
local.tee 2 | ||
global.set $__stack_pointer | ||
local.get 2 | ||
i32.const 24 | ||
i32.add | ||
local.get 1 | ||
i32.const 24 | ||
i32.add | ||
i64.load | ||
i64.store | ||
local.get 2 | ||
i32.const 16 | ||
i32.add | ||
local.get 1 | ||
i32.const 16 | ||
i32.add | ||
i64.load | ||
i64.store | ||
local.get 2 | ||
i32.const 8 | ||
i32.add | ||
local.get 1 | ||
i32.const 8 | ||
i32.add | ||
i64.load | ||
i64.store | ||
local.get 2 | ||
local.get 1 | ||
i64.load | ||
i64.store | ||
local.get 0 | ||
local.get 2 | ||
call $miden::sat::account::remove_asset | ||
local.get 2 | ||
i32.const 32 | ||
i32.add | ||
global.set $__stack_pointer | ||
) | ||
(func $miden::note::Tag::new (;7;) (type 3) (param i64) (result i64) | ||
local.get 0 | ||
) | ||
(func $miden::tx::create_note (;8;) (type 1) (param i32 i64 i32) | ||
(local i32) | ||
global.get $__stack_pointer | ||
i32.const 64 | ||
i32.sub | ||
local.tee 3 | ||
global.set $__stack_pointer | ||
local.get 3 | ||
i32.const 32 | ||
i32.add | ||
i32.const 24 | ||
i32.add | ||
local.get 0 | ||
i32.const 24 | ||
i32.add | ||
i64.load | ||
i64.store | ||
local.get 3 | ||
i32.const 32 | ||
i32.add | ||
i32.const 16 | ||
i32.add | ||
local.get 0 | ||
i32.const 16 | ||
i32.add | ||
i64.load | ||
i64.store | ||
local.get 3 | ||
i32.const 32 | ||
i32.add | ||
i32.const 8 | ||
i32.add | ||
local.get 0 | ||
i32.const 8 | ||
i32.add | ||
i64.load | ||
i64.store | ||
local.get 3 | ||
local.get 0 | ||
i64.load | ||
i64.store offset=32 | ||
local.get 3 | ||
i32.const 8 | ||
i32.add | ||
local.get 2 | ||
i32.const 8 | ||
i32.add | ||
i64.load | ||
i64.store | ||
local.get 3 | ||
i32.const 16 | ||
i32.add | ||
local.get 2 | ||
i32.const 16 | ||
i32.add | ||
i64.load | ||
i64.store | ||
local.get 3 | ||
i32.const 24 | ||
i32.add | ||
local.get 2 | ||
i32.const 24 | ||
i32.add | ||
i64.load | ||
i64.store | ||
local.get 3 | ||
local.get 2 | ||
i64.load | ||
i64.store | ||
local.get 3 | ||
i32.const 32 | ||
i32.add | ||
local.get 1 | ||
local.get 3 | ||
call $miden::sat::tx::create_note | ||
local.get 3 | ||
i32.const 64 | ||
i32.add | ||
global.set $__stack_pointer | ||
) | ||
(table (;0;) 1 1 funcref) | ||
(memory (;0;) 16) | ||
(global $__stack_pointer (;0;) (mut i32) i32.const 1048576) | ||
(export "memory" (memory 0)) | ||
(export "receive_asset" (func $receive_asset)) | ||
(export "send_asset" (func $send_asset)) | ||
) |
Oops, something went wrong.
Oops, something went wrong.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bobbinth @bitwalker This Wasm is compiled from https://github.com/0xPolygonMiden/miden-ir/blob/b27a75e13810fc55a115d9cdee9f0cab7e6f16e5/tests/rust-apps-wasm/sdk-account/src/lib.rs#L1-L29 which uses the SDK skeleton I drafted (see https://github.com/0xPolygonMiden/compiler/tree/b27a75e13810fc55a115d9cdee9f0cab7e6f16e5/sdk/src )
The calling convention is defined at https://github.com/WebAssembly/tool-conventions/blob/main/BasicCABI.md
Side note: To get the above calling convention, I switched to
wasm32-wasi
target becausewasm32-unknown-unknown
actually produces a different calling convention - the one inspired bywasm-bindgen
. See https://users.rust-lang.org/t/how-are-structs-represented-in-web-assembly/57317/6 for more details.The main challenge I see and focus on is that structs are passed by reference (address on the linear stack) while callers and callees are always expecting function parameters on the stack.
In the case of imported
miden::sat::account::add_asset
and others, I can naively imagine we could rewrite them inmiden-base
to expect a pointer to the struct instead of the struct itself and then load it on the stack. But in case of exported functions likereceive_asset
andsend_asset
it's not even possible since they are supposed to be called viacall
(see miden-base) meaning we can only pass values on stack and/or via advice provider.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since the account methods can be externally called only from notes, I'm also bringing the note code into this PoC.
I plan to use macros to "wrap" note to account calls in serialization/deserialization code to pass arguments and return values via stack and advice provider. Initially, though I'll write this glue code manually and implement its generation via macros.
Let's see what it might look like for the
MyWallet::receive_asset
method:The original user's
MyWallet::receive_asset
was renamed toreceive_asset_original
. The note code calls viacall
the createdMyWallet::receive_asset
which serializes the arguments and callsMyWallet::receive_asset_extern
which is anextern "C"
to the account's Miden code. The corresponding Miden code forMyWallet::receive_asset_extern
is provided by the account'sMyWallet::receive_asset_impl
which deserializes the arguments and callsMyWallet::receive_asset_original
which is the user-written original method. The return value is serialized byMyWallet::receive_asset_impl
and returned to the note code deserialized inMyWallet::receive_asset
.Or in a diagram:
Note
->
call
->
MyWallet::recieve_asset
do args serialization->
extern "C" MyWallet::receive_asset_extern
->
exec MyWallet::receive_asset_impl
exported from the account's code does args deserialization.->
exec MyWallet::receive_asset_original
->
MyWallet::receive_asset_impl
does return value serialization.->
MyWallet::receive_asset
does return value deserialization.->
Note
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I took a stab at
MyWallet::receive_assets
at the scheme above and got quite far - https://github.com/0xPolygonMiden/miden-ir/blob/57cb25537964986a50e115291658b6c4a20a961b/tests/rust-apps-wasm/sdk-basic-wallet/src/lib.rs#L24-L82There are a lot of todos in the code that macros will generate, but the idea seems to be viable.
Note that
receive_assets_arg_ser
andreceive_assets_arg_deser
should have the same name since it's imported func and its implementation, I just have not figured out how to do it yet.MyWallet::receive_asset
is called from the note's code. It packs the arguments and passes it either via stack or advice provider and callsreceive_assets_arg_ser
, which should end up ascall.my_wallet::receive_assets_arg_deser
in the note's MASM code. Which in turn deserializes args (stack/advice) and calls the user'sMyWallet::receive_assets
.