Skip to content
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

Fix issue 600 #707

Merged
merged 2 commits into from
May 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
* Replaced `cargo-make` with just `make` for running tasks (#696).
* [BREAKING] Introduce `OutputNote::Partial` variant (#698).
* [BREAKING] Split `Account` struct constructor into `new()` and `from_parts()` (#699).
* [BREAKING] Changed the encoding of inputs notes in the advice map for consumed notes. Now the data
is prefixed by its length, and the input and output notes encoding match (#707).

## 0.3.0 (2024-05-14)

Expand Down
32 changes: 12 additions & 20 deletions miden-lib/asm/kernels/transaction/api.masm
Original file line number Diff line number Diff line change
Expand Up @@ -410,22 +410,19 @@ export.get_note_vault_info
# => [VAULT_HASH, num_assets]
end

#! Returns the number of inputs and inputs hash for the note currently being processed. Panics if
#! a note is not being processed.
#! Returns the current note's inputs hash.
#!
#! Inputs: [0, 0, 0, 0, 0]
#! Outputs: [NOTE_INPUTS_HASH, num_inputs]
#! Inputs: [ZERO]
#! Outputs: [NOTE_INPUTS_HASH]
#!
#! - num_inputs is the number of inputs associated with the note.
#! - NOTE_INPUTS_HASH is the note inputs hash of the note currently being processed.
export.get_note_inputs_info
# get the number of inputs and the inputs hash
exec.note::get_inputs_info
# => [NOTE_INPUTS_HASH, num_inputs, 0, 0, 0, 0, 0]
#! Where:
#! - NOTE_INPUTS_HASH, is the current note's inputs hash.
export.get_note_inputs_hash
exec.note::get_note_inputs_hash
# => [NOTE_INPUTS_HASH, ZERO]

# organize the stack for return
movup.5 drop movup.5 drop movup.5 drop movup.5 drop movup.5 drop
# => [NOTE_INPUTS_HASH, num_inputs]
swapw dropw
# => [NOTE_INPUTS_HASH]
end

#! Returns the sender of the note currently being processed. Panics if a note is not being
Expand All @@ -434,16 +431,11 @@ end
#! Inputs: [0]
#! Outputs: [sender]
#!
#! Where:
#! - sender is the sender of the note currently being processed.
export.get_note_sender
# get the note sender
exec.note::get_sender
# => [sender, 0]

# organize the stack for return
swap drop
exec.note::get_sender swap drop
# => [sender]

end

#! Returns the block number of the last known block at the time of transaction execution.
Expand Down
144 changes: 39 additions & 105 deletions miden-lib/asm/kernels/transaction/main.masm
Original file line number Diff line number Diff line change
Expand Up @@ -36,152 +36,94 @@ const.EPILOGUE_END=131081
# MAIN
# =================================================================================================

#! This is the entrypoint for the transaction kernel program. It is composed of the following
#! program sections:
#! Transaction kernel program.
#!
#! 1. Prologue: execute the transaction prologue which prepares the transaction for processing
#! by parsing the transaction data and setting up the root context.
#! 2. Note Processing: execute the note processing loop which consumes each input note and
#! invokes the note script of each note via a `dyncall` instruction invocation.
#! 3. Transaction Script Processing: execute the transaction script if it exists via the invocation
#! of a `dyncall` instruction.
#! 4. Epilogue: execute the transaction epilogue which finalizes the transaction by computing the
#! created notes commitment, the final account hash, asserting asset invariant conditions and
#! asserting the nonce rules are upheld.
#! This is the entry point of the transaction kernel, the program will perform the following
#! operations:
#!
#! Stack: [BH, acct_id, IAH, NC]
#! Advice stack: [NR, PH, CR, SR, BR, PH, BN,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was out-of-date, the NOTE_ROOT is much deeper in the advice stack:

#! Advice stack: [
#! PREVIOUS_BLOCK_HASH,
#! CHAIN_MMR_HASH,
#! ACCOUNT_ROOT,
#! NULLIFIER_ROOT,
#! BATCH_ROOT,
#! PROOF_HASH,
#! [block_num, version, timestamp, 0],
#! ZERO,
#! NOTE_ROOT,
#! [account_id, 0, 0, account_nonce],
#! ACCOUNT_VAULT_ROOT,
#! ACCOUNT_STORAGE_ROOT,
#! ACCOUNT_CODE_ROOT,
#! number_of_input_notes,
#! TX_SCRIPT_ROOT,

Instead of copying and pasting the docs, I added a reference to prepare_transaction

#! acct_id, ZERO, ZERO, nonce, AVR, ASR, ACR,
#! num_cn,
#! CN1_SN, CN1_SR, CN1_IR, CN1_VR, CN1_M, CN1_NA
#! CN1_A1, CN1_A2, ...
#! CN2_SN,CN2_SR, CN2_IR, CN2_VR, CN2_M, CN2_NA
#! CN2_A1, CN2_A2, ...,
#! ...,
#! TXSR]
#! Output: [CNC, FAH]
#! 1. Run the prologue to prepare the transaction's root context.
#! 2. Run all the notes' scripts.
#! 3. Run the transaction script.
#! 4. Run the epilogue to compute and validate the final state.
#!
#! See `prologue::prepare_transaction` for additional details on the VM's initial state, including the
#! advice provider.
#!
#! - BH is the latest known block hash at the time of transaction execution.
#! - acct_id is the account id of the account that the transaction is being executed against.
#! - NR is the note root of the last known block.
#! - PH is the previous hash of the last known block.
#! - CR is the chain root of the last known block.
#! - SR is the state root of the last known block.
#! - BR is the batch root of the last known block.
#! - PH is the proof hash of the last known block.
#! - BN is the block number of the last known block ([block_number, 0, 0, 0]).
#! - IAH is the initial account hash of the account that the transaction is being executed against.
#! - NC is the nullifier commitment of the transaction. This is a sequential hash of all
#! (nullifier, script_root) pairs for the notes consumed in the transaction.
#! - nonce is the account nonce.
#! - AVR is the account vault root.
#! - ASR is the account storage root.
#! - ACR is the account code root.
#! - num_cn is the number of consumed notes.
#! - CN1_SN is the serial number of consumed note 1.
#! - CN1_SR is the script root of consumed note 1.
#! - CN1_IR is the inputs root of consumed note 1.
#! - CN1_VR is the vault root of consumed note 1.
#! - CN1_M is the metadata of consumed note 1.
#! - CN1_NA are optional note args of consumed note 1.
#! - CN1_A1 is the first asset of consumed note 1.
#! - CN1_A2 is the second asset of consumed note 1.
#! - CNC is the commitment to the notes created by the transaction.
#! - FAH is the final account hash of the account that the transaction is being
#! executed against.
#! Stack: [BLOCK_HASH, account_id, INITIAL_ACCOUNT_HASH, NULLIFIER_COMMITMENT]
#! Output: [CREATED_NOTES_COMMITMENT, FINAL_ACCOUNT_HASH]
#!
#! Where:
#! - BLOCK_HASH, reference block for the transaction execution.
#! - account_id, the account that the transaction is being executed against.
#! - INITIAL_ACCOUNT_HASH, account state prior to the transaction, ZERO for new accounts.
#! - NULLIFIER_COMMITMENT, sequential hash of all input notes' nullifiers.
#! - CREATED_NOTES_COMMITMENT, commitment to the notes created by the transaction.
#! - FINAL_ACCOUNT_HASH, account's hash after execution the transaction.
proc.main.1
# Prologue
# ---------------------------------------------------------------------------------------------

# TODO: we execute `push.0 drop` before `trace` as decorators are not supported without other
# instructions - see: https://github.com/0xPolygonMiden/miden-vm/issues/1122
# emit trace to signal that the execution of the prologue has started
push.0 drop
push.0 drop # TODO: remove line, see miden-vm/#1122
trace.PROLOGUE_START

# execute the transaction prologue
exec.prologue::prepare_transaction
# => []

# TODO: we execute `push.0 drop` before `trace` as decorators are not supported without other
# instructions - see: https://github.com/0xPolygonMiden/miden-vm/issues/1122
# emit trace to signal that the execution of the prologue has ended
push.0 drop
push.0 drop # TODO: remove line, see miden-vm/#1122
trace.PROLOGUE_END

# Note Processing
# ---------------------------------------------------------------------------------------------

# TODO: we execute `push.0 drop` before `trace` as decorators are not supported without other
# instructions - see: https://github.com/0xPolygonMiden/miden-vm/issues/1122
# emit trace to signal that the notes processing has started
push.0 drop
push.0 drop # TODO: remove line, see miden-vm/#1122
trace.NOTES_PROCESSING_START

# get the total number of consumed notes
exec.memory::get_total_num_consumed_notes
# => [num_consumed_notes]

# compute the pointer to the consumed note after the last consumed note (i.e. the pointer at
# which the looping should terminate)
# compute the memory location after all input notes, i.e. the exit condition
dup exec.memory::get_consumed_note_ptr loc_store.0
# => [num_consumed_notes]

# check if we have any notes to consume
eq.0 not
# => [should_loop]

# loop while we have notes to consume
while.true
# TODO: we execute `push.0 drop` before `trace` as decorators are not supported without other
# instructions - see: https://github.com/0xPolygonMiden/miden-vm/issues/1122
# emit trace to signal that the note execution has started
push.0 drop
push.0 drop # TODO: remove line, see miden-vm/#1122
trace.NOTE_EXECUTION_START
# => []

# execute the note setup script
exec.note::prepare_note
# => [NOTE_SCRIPT_HASH, NOTE_ARGS]

# invoke the note script using the dyncall instruction
# run note's script
dyncall
# => [OUTPUT_3, OUTPUT_2, OUTPUT_1, OUTPUT_0]
# => [X, X, X, X]

# clean up note script outputs
# Clear the stack, the note can leave up to 4 words on the stack due to the dyncall
dropw dropw dropw dropw
# => []

# check if we have more notes to consume and should loop again
exec.note::increment_current_consumed_note_ptr
loc_load.0
neq
# => [current_consumed_note_ptr]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: I think these APIs should change to pass an explict idx, it would make testing possible.


# loop condition, exit when the memory ptr is after all input notes
loc_load.0 neq
# => [should_loop]

# TODO: we execute `push.0 drop` before `trace` as decorators are not supported without other
# instructions - see: https://github.com/0xPolygonMiden/miden-vm/issues/1122
# emit trace to signal that the note execution has ended
push.0 drop
push.0 drop # TODO: remove line, see miden-vm/#1122
trace.NOTE_EXECUTION_END
end

# execute note processing teardown
exec.note::note_processing_teardown
# => []

# TODO: we execute `push.0 drop` before `trace` as decorators are not supported without other
# instructions - see: https://github.com/0xPolygonMiden/miden-vm/issues/1122
# emit trace to signal that the notes processing has ended
push.0 drop
push.0 drop # TODO: remove line, see miden-vm/#1122
trace.NOTES_PROCESSING_END

# Transaction Script Processing
# ---------------------------------------------------------------------------------------------

# TODO: we execute `push.0 drop` before `trace` as decorators are not supported without other
# instructions - see: https://github.com/0xPolygonMiden/miden-vm/issues/1122
# emit trace to signal that the processing of the transaction script has started
push.0 drop
push.0 drop # TODO: remove line, see miden-vm/#1122
trace.TX_SCRIPT_PROCESSING_START

# execute the transaction script
Expand All @@ -205,30 +147,22 @@ proc.main.1
# => []
end

# TODO: we execute `push.0 drop` before `trace` as decorators are not supported without other
# instructions - see: https://github.com/0xPolygonMiden/miden-vm/issues/1122
# emit trace to signal that the processing of the transaction script has ended
push.0 drop
push.0 drop # TODO: remove line, see miden-vm/#1122
trace.TX_SCRIPT_PROCESSING_END

# Epilogue
# ---------------------------------------------------------------------------------------------

# TODO: we execute `push.0 drop` before `trace` as decorators are not supported without other
# instructions - see: https://github.com/0xPolygonMiden/miden-vm/issues/1122
# emit trace to signal that the execution of the epilogue has started
push.0 drop
push.0 drop # TODO: remove line, see miden-vm/#1122
trace.EPILOGUE_START

# execute the transaction epilogue
exec.epilogue::finalize_transaction
# => [CREATED_NOTES_COMMITMENT, FINAL_ACCOUNT_HASH]

# TODO: we execute `push.0 drop` before `trace` as decorators are not supported without other
# instructions - see: https://github.com/0xPolygonMiden/miden-vm/issues/1122
# emit trace to signal that the execution of the epilogue has ended
push.0 drop
push.0 drop # TODO: remove line, see miden-vm/#1122
trace.EPILOGUE_END
# => [CREATED_NOTES_COMMITMENT, FINAL_ACCOUNT_HASH]
end

begin
Expand Down
55 changes: 15 additions & 40 deletions miden-lib/asm/miden/kernels/tx/memory.masm
Original file line number Diff line number Diff line change
Expand Up @@ -141,9 +141,8 @@ const.CONSUMED_NOTE_INPUTS_HASH_OFFSET=3
const.CONSUMED_NOTE_ASSETS_HASH_OFFSET=4
const.CONSUMED_NOTE_METADATA_OFFSET=5
const.CONSUMED_NOTE_ARGS_OFFSET=6
const.CONSUMED_NOTE_NUM_INPUTS_OFFSET=7
const.CONSUMED_NOTE_NUM_ASSETS_OFFSET=8
const.CONSUMED_NOTE_ASSETS_OFFSET=9
const.CONSUMED_NOTE_NUM_ASSETS_OFFSET=7
const.CONSUMED_NOTE_ASSETS_OFFSET=8

# CREATED NOTES
# -------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -774,14 +773,15 @@ export.get_consumed_note_ptr
exec.constants::get_note_mem_size mul push.CONSUMED_NOTE_DATA_SECTION_OFFSET add
end

#! Set the hash of the consumed note at the specified memory address.
#! Set the note id of the consumed note.
#!
#! Stack: [consumed_note_ptr, H]
#! Output: [H]
#! Stack: [consumed_note_ptr, NOTE_ID]
#! Output: [NOTE_ID]
#!
#! - consumed_note_ptr is the memory address of the consumed note.
#! - H is the hash of the consumed note.
export.set_consumed_note_hash
#! Where:
#! - consumed_note_ptr, the consumed note's the memory address.
#! - NOTE_ID, the note's id.
export.set_consumed_note_id
mem_storew
end

Expand Down Expand Up @@ -871,17 +871,17 @@ export.set_consumed_note_metadata
mem_storew dropw
end

#! Returns the note args of a consumed note located at the specified memory address.
#! Returns the note's args.
#!
#! Stack: [consumed_note_ptr]
#! Output: [NOTE_ARGS]
#!
#! - consumed_note_ptr is the memory address at which the consumed note data begins.
#! - NOTE_ARGS are optional note args of the consumed note.
#! Where:
#! - consumed_note_ptr, the start memory address of the note.
#! - NOTE_ARGS, the note's args.
export.get_consumed_note_args
padw
movup.4 push.CONSUMED_NOTE_ARGS_OFFSET
add
movup.4 push.CONSUMED_NOTE_ARGS_OFFSET add
mem_loadw
end

Expand All @@ -893,35 +893,10 @@ end
#! - consumed_note_ptr is the memory address at which the consumed note data begins.
#! - NOTE_ARGS are optional note args of the consumed note.
export.set_consumed_note_args
push.CONSUMED_NOTE_ARGS_OFFSET
add
push.CONSUMED_NOTE_ARGS_OFFSET add
mem_storew dropw
end

#! Returns the number of inputs for the consumed note located at the specified memory address.
#!
#! Stack: [consumed_note_ptr]
#! Output: [num_inputs]
#!
#! - consumed_note_ptr is the memory address at which the consumed note data begins.
#! - num_inputs is the number of inputs defined for the consumed note.
export.get_consumed_note_num_inputs
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The num_inputs is now defined in the advice map, these are no longer needed

push.CONSUMED_NOTE_NUM_INPUTS_OFFSET add
mem_load
end

#! Sets the number of inputs for a consumed note located at the specified memory address.
#!
#! Stack: [consumed_note_ptr, num_inputs]
#! Output: []
#!
#! - consumed_note_ptr is the memory address at which the consumed note data begins.
#! - num_inputs is the number of inputs for the consumed note.
export.set_consumed_note_num_inputs
push.CONSUMED_NOTE_NUM_INPUTS_OFFSET add
mem_store
end

#! Returns the number of assets in the consumed note located at the specified memory address.
#!
#! Stack: [consumed_note_ptr]
Expand Down
Loading
Loading