Skip to content

Commit

Permalink
note: implement note storage modes
Browse files Browse the repository at this point in the history
Notes can be stored offchain, on-chain, or encrypted. This is an
orthogonal concept to how the notes are executed. This commit adds a new
metadata field to encode the storage type.
  • Loading branch information
hackaugusto committed Mar 26, 2024
1 parent 2922568 commit 3756f4a
Show file tree
Hide file tree
Showing 25 changed files with 412 additions and 143 deletions.
10 changes: 5 additions & 5 deletions miden-lib/asm/kernels/transaction/api.masm
Original file line number Diff line number Diff line change
Expand Up @@ -421,21 +421,21 @@ end

#! Creates a new note and returns a pointer to the memory address at which the note is stored.
#!
#! Inputs: [ASSET, tag, RECIPIENT]
#! Outputs: [ptr, 0, 0, 0, 0, 0, 0, 0, 0]
#! Inputs: [ASSET, tag, note_type, RECIPIENT]
#! Outputs: [ptr, 0, 0, 0, 0, 0, 0, 0, 0, 0]
#!
#! ASSET is the asset to be included in the note.
#! tag is the tag to be included in the note.
#! note_type is the note storage type
#! RECIPIENT is the recipient of the note.
#! ptr is the pointer to the memory address at which the note is stored.
export.create_note
# authenticate that the procedure invocation originates from the account context
exec.authenticate_account_origin
# => [ASSET, tag, RECIPIENT]
# => [ASSET, tag, note_type, RECIPIENT]

# create the note
exec.tx::create_note
# => [ptr, 0, 0, 0, 0, 0, 0, 0, 0]
# => [ptr, 0, 0, 0, 0, 0, 0, 0, 0, 0]
end

#! Returns a commitment to the account vault the transaction is being executed against.
Expand Down
7 changes: 7 additions & 0 deletions miden-lib/asm/miden/contracts/faucets/basic_fungible.masm
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ use.miden::faucet
use.miden::tx
use.miden::contracts::auth::basic

# CONSTANTS
# =================================================================================================
const.OFFCHAIN_NOTE=0

# ERRORS
# =================================================================================================

Expand Down Expand Up @@ -68,6 +72,9 @@ export.distribute
exec.faucet::mint
# => [ASSET, tag, RECIPIENT, ...]

push.OFFCHAIN_NOTE movdn.5
# => [ASSET, tag, note_type, RECIPIENT, ...]

# create a note containing the asset
exec.tx::create_note
# => [note_ptr, ZERO, ZERO, ...]
Expand Down
32 changes: 22 additions & 10 deletions miden-lib/asm/miden/contracts/wallets/basic.masm
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
use.miden::account
use.miden::tx

# CONSTANTS
# =================================================================================================
const.PUBLIC_NOTE=2

#! Adds the provided asset to the current account.
#!
#! Inputs: [ASSET]
Expand All @@ -20,11 +24,12 @@ end
#! Creates a note which sends the specified asset out of the current account
#! to the specified recipient.
#!
#! Inputs: [ASSET, tag, RECIPIENT, ...]
#! Outputs: [note_ptr, 0, 0, 0, 0, 0, 0, 0, 0, ...]
#! Inputs: [ASSET, tag, note_type, RECIPIENT, ...]
#! Outputs: [note_ptr, ZERO, ZERO, 0, ...]
#!
#! - ASSET is the non-fungible asset of interest.
#! - tag is the tag to be included in the note.
#! - note_type is the note's storage type
#! - RECIPIENT is the recipient of the note, i.e.,
#! hash(hash(hash(serial_num, [0; 4]), script_hash), input_hash)
#! - note_ptr is the pointer to the memory address in the kernel.
Expand All @@ -34,16 +39,23 @@ end
#! - The fungible asset is not found in the vault.
#! - The amount of the fungible asset in the vault is less than the amount to be removed.
#! - The non-fungible asset is not found in the vault.
export.send_asset.1
export.send_asset
exec.account::remove_asset
# => [ASSET, tag, RECIPIENT, ...]

# insert 8 ZEROs into the stack right after recipient; we temporarily store one of the
# elements of ASSET in memory to make stack manipulation easier
push.0 swap loc_store.0 padw push.0.0.0 swapdw loc_load.0
# => [ASSET, tag, RECIPIENT, ZERO, ZERO, ...]
# => [ASSET, tag, note_type, RECIPIENT, ...]

# This procedure is written to be executed with `exec` or `call`. When this
# procedure is `call`ed the stack has to be carefully manipulated to avoid
# inserting unwanted elements between the user data. The convention is to
# ensure the input&output data have the same length. This code pads the
# stack so the output stack will be the same length as the the input.
#
# The padding must be added before calling `create_note`, not after. This
# is because the VM stack has a minimum size of 16 elements, trying to push
# elements after the call to `create_note` would increase the stack in
# addition to the minimum 16 elements.
push.0.0 padw movdnw.3 padw movdnw.3 movdn.11 drop
# => [ASSET, tag, note_type, RECIPIENT, ZERO, ZERO, 0, ...]

exec.tx::create_note
# => [note_ptr, ZERO, ZERO, ...]
# => [note_ptr, ZERO, ZERO, 0, ...]
end
28 changes: 22 additions & 6 deletions miden-lib/asm/miden/kernels/tx/tx.masm
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,23 @@ use.miden::kernels::tx::constants
use.miden::kernels::tx::memory
use.miden::kernels::tx::note

# CONSTANTS
# =================================================================================================

# Constants for different note types
const.OFFCHAIN_NOTE=0
const.ENCRYPTED_NOTE=1
const.PUBLIC_NOTE=2

# ERRORS
# =================================================================================================

# Output notes exceeded the maximum limit
const.ERR_TX_OUTPUT_NOTES_OVERFLOW=0x00020020

# Invalid note type
const.ERR_INVALID_NOTE_TYPE=0x00020044

#! Returns the block hash of the last known block at the time of transaction execution.
#!
#! Inputs: []
Expand Down Expand Up @@ -64,7 +75,7 @@ end

#! Creates a new note and returns a pointer to the memory address at which the note is stored.
#!
#! Inputs: [ASSET, tag, RECIPIENT]
#! Inputs: [ASSET, tag, note_type, RECIPIENT]
#! Outputs: [ptr, 0, 0, 0, 0, 0, 0, 0, 0]
#!
#! ASSET is the asset to be included in the note.
Expand All @@ -74,19 +85,24 @@ end
export.create_note
# validate the asset
exec.asset::validate_asset
# => [ASSET, tag, RECIPIENT]
# => [ASSET, tag, note_type, RECIPIENT]

# validate the note type
# NOTE: encrypted notes are currently unsupported `dup.6 push.ENCRYPTED_NOTE eq or`
dup.5 push.OFFCHAIN_NOTE eq dup.6 push.PUBLIC_NOTE eq or assert.err=ERR_INVALID_NOTE_TYPE
# => [ASSET, tag, note_type, RECIPIENT]

# get the index for the next note to be created and increment counter
exec.increment_num_created_notes
# => [note_idx, ASSET, tag, RECIPIENT]
# => [note_idx, ASSET, tag, note_type, RECIPIENT]

# get a pointer to the memory address at which the note will be stored
exec.memory::get_created_note_ptr
# => [note_ptr, ASSET, tag, RECIPIENT]
# => [note_ptr, ASSET, tag, note_type, RECIPIENT]

# populate the metadata
movup.5 exec.account::get_id push.0.0
# => [0, 0, acct_id, tag, note_ptr, ASSET, RECIPIENT]
movup.5 exec.account::get_id movup.7 push.0
# => [0, note_type, acct_id, tag, note_ptr, ASSET, RECIPIENT]

# set the metadata for the new created note
dup.4 exec.memory::set_created_note_metadata
Expand Down
8 changes: 5 additions & 3 deletions miden-lib/asm/miden/tx.masm
Original file line number Diff line number Diff line change
Expand Up @@ -58,17 +58,19 @@ end

#! Creates a new note and returns a pointer to the memory address at which the note is stored.
#!
#! Inputs: [ASSET, tag, RECIPIENT]
#! Inputs: [ASSET, tag, note_type, RECIPIENT]
#! Outputs: [ptr]
#!
#! ASSET is the asset to be included in the note.
#! tag is the tag to be included in the note.
#! note_type is the storage type of the note
#! RECIPIENT is the recipient of the note.
#! ptr is the pointer to the memory address at which the note is stored.
export.create_note
syscall.create_note
# => [ptr, 0, 0, 0, 0, 0, 0, 0, 0]
# => [ptr, ZERO, ZERO, 0]

movdn.8 dropw dropw
# clear the padding from the kernel response
movdn.8 dropw dropw swap drop
# => [ptr]
end
14 changes: 13 additions & 1 deletion miden-lib/asm/note_scripts/SWAP.masm
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
use.miden::note
use.miden::contracts::wallets::basic->wallet

# CONSTANTS
# =================================================================================================

const.OFFCHAIN_NOTE=0

# ERRORS
# =================================================================================================

Expand Down Expand Up @@ -63,7 +68,14 @@ begin
drop drop drop movdn.4
# => [ASSET, tag, RECIPIENT]

push.OFFCHAIN_NOTE movdn.5
# => [ASSET, tag, note_type, RECIPIENT]

# create a note using inputs
call.wallet::send_asset dropw dropw
call.wallet::send_asset
# => [ptr, ZERO, ZERO, 0]

# clean stack
dropw dropw drop drop
# => []
end
23 changes: 19 additions & 4 deletions miden-lib/src/notes/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
use alloc::vec::Vec;

use miden_objects::{
accounts::AccountId, assets::Asset, crypto::rand::FeltRng, notes::Note, Felt, NoteError, Word,
accounts::AccountId,
assets::Asset,
crypto::rand::FeltRng,
notes::{Note, NoteType},
Felt, NoteError, Word,
};

use self::utils::build_note_script;
Expand All @@ -25,6 +29,7 @@ pub fn create_p2id_note<R: FeltRng>(
sender: AccountId,
target: AccountId,
assets: Vec<Asset>,
note_type: NoteType,
mut rng: R,
) -> Result<Note, NoteError> {
let bytes = include_bytes!(concat!(env!("OUT_DIR"), "/assets/note_scripts/P2ID.masb"));
Expand All @@ -34,7 +39,7 @@ pub fn create_p2id_note<R: FeltRng>(
let tag: Felt = target.into();
let serial_num = rng.draw_word();

Note::new(note_script, &inputs, &assets, serial_num, sender, tag)
Note::new(note_script, &inputs, &assets, serial_num, sender, note_type, tag)
}

/// Generates a P2IDR note - pay to id with recall after a certain block height.
Expand All @@ -53,6 +58,7 @@ pub fn create_p2idr_note<R: FeltRng>(
sender: AccountId,
target: AccountId,
assets: Vec<Asset>,
note_type: NoteType,
recall_height: u32,
mut rng: R,
) -> Result<Note, NoteError> {
Expand All @@ -63,7 +69,7 @@ pub fn create_p2idr_note<R: FeltRng>(
let tag: Felt = target.into();
let serial_num = rng.draw_word();

Note::new(note_script.clone(), &inputs, &assets, serial_num, sender, tag)
Note::new(note_script.clone(), &inputs, &assets, serial_num, sender, note_type, tag)
}

/// Generates a SWAP note - swap of assets between two accounts.
Expand All @@ -78,6 +84,7 @@ pub fn create_swap_note<R: FeltRng>(
sender: AccountId,
offered_asset: Asset,
requested_asset: Asset,
note_type: NoteType,
mut rng: R,
) -> Result<(Note, Word), NoteError> {
let bytes = include_bytes!(concat!(env!("OUT_DIR"), "/assets/note_scripts/SWAP.masb"));
Expand All @@ -102,7 +109,15 @@ pub fn create_swap_note<R: FeltRng>(
let tag: Felt = Felt::new(0);
let serial_num = rng.draw_word();

let note = Note::new(note_script.clone(), &inputs, &[offered_asset], serial_num, sender, tag)?;
let note = Note::new(
note_script.clone(),
&inputs,
&[offered_asset],
serial_num,
sender,
note_type,
tag,
)?;

Ok((note, payback_serial_num))
}
Loading

0 comments on commit 3756f4a

Please sign in to comment.