-
Notifications
You must be signed in to change notification settings - Fork 60
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
Add block_num as a public input to the transaction kernel #1126
Add block_num as a public input to the transaction kernel #1126
Conversation
#! | ||
#! Where: | ||
#! - block_num is the number of the reference block for the transaction execution. | ||
export.get_block_num |
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.
This needs to be tested somehow. LMK best way to do this
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.
To test the memory layout generally, you can extend the global_input_memory_assertions
function in crates/miden-tx/src/tests/kernel_tests/test_prologue.rs
.
This procedure specifically will be tested implicitly by testing procedures that call it, so no extra test needed.
const.BLK_HASH_PTR=400 | ||
|
||
# The memory address at which the latest known block number is stored. | ||
const.BLK_NUM_PTR=404 |
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.
Unsure if the intention was to store this felt in the same memory slot as the account id but that is my interpretation of the instructions.
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.
Good question!
I think I would align the memory layout with the stack layout, so:
- The
BLOCK_HASH
word (4 elements) still goes intoBLK_HASH_PTR
from400..=403
(i.e. nothing to do here). - The
block_num
(1 element) goes intoBLK_NUM_PTR
at404
. - We don't do anything with the 0 input so we leave offset
405
unoccupied. - The
account_id_suffix
(1 element) goes intoACCT_ID_PTR
at406
. - The
account_id_prefix
(1 element) goes intoACCT_ID_PTR + 1
at407
.- On second thoughts, it might be best to introduce
ACCT_ID_PREFIX_PTR
andACCT_ID_SUFFIX_PTR
for these.
- On second thoughts, it might be best to introduce
So I would add a set_blk_num
procedure in memory.masm to set just the block number which is called from the prologue.
set_global_acct_id
and get_global_acct_id
must be modified to not use mem_storew/mem_loadw
but rather two mem_store/mem_load
operations on the individual felts.
Maybe @bobbinth has a different opinion, but that's how I would go about it.
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.
There is another way to do, which could potentially require fewer changes. Specifically:
- We modify
process_global_inputs
to returnblock_num
. That is,process_global_inputs
won't write it to memory but won't consume it either. - Then,
block_num
becomes an input intoprocess_block_data
procedure (i.e., the inputs will beOperand stack: [block_num]
). - Then, at the end of
process_block_data
we read theblock_num
that was written to memory and make sure it is the same as the one on the stack.
If we do this, no other MASM code needs to change, I think.
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 is the latest commit along the lines you were thinking?
So process_global_inputs
looks like this:
#! Inputs: [BLOCK_HASH, INITIAL_ACCOUNT_HASH, INPUT_NOTES_COMMITMENT, account_id_prefix, account_id_suffix, block_num]
#! Outputs: [block_num]
The test_transaction_prologue
passes with those changes so should be functional.
P.S. I'm out of context w.r.t the block_num
being written to elsewhere and why passing it in as a global input and comparing that against the one in memory is worthwhile.
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.
Yes, that's how I was thinking about it - thank you!
The overall context is: we want to include block_num
as a field in the ProvenTransaction
struct (having it there simplifies things during batch building). But if we just add this to the struct, it opens up a possibility of internal inconsistency (e.g., block_num
specified in the field may different from the block number associated with the block_hash
). So, we want to make sure that the ZKP attached to the proven transaction also verifies that block_num
and block_hash
are consistent with each other.
So, after this change, once we verify the ZKP, we can be sure that block_num
is in fact the number of the block with the specified block_hash
.
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.
Thanks for taking this on!
I left some comments inline hopefully answering your questions.
We should also add a check in prologue::process_block_data
to ensure the global block number from the public inputs matches the one from the advice provider. This could happen after the squeeze_digest
operation, for example.
This should just be a comparison between memory::get_blk_num
and memory::get_global_blk_num
and adding a new error for the assert statement.
const.BLK_HASH_PTR=400 | ||
|
||
# The memory address at which the latest known block number is stored. | ||
const.BLK_NUM_PTR=404 |
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.
Good question!
I think I would align the memory layout with the stack layout, so:
- The
BLOCK_HASH
word (4 elements) still goes intoBLK_HASH_PTR
from400..=403
(i.e. nothing to do here). - The
block_num
(1 element) goes intoBLK_NUM_PTR
at404
. - We don't do anything with the 0 input so we leave offset
405
unoccupied. - The
account_id_suffix
(1 element) goes intoACCT_ID_PTR
at406
. - The
account_id_prefix
(1 element) goes intoACCT_ID_PTR + 1
at407
.- On second thoughts, it might be best to introduce
ACCT_ID_PREFIX_PTR
andACCT_ID_SUFFIX_PTR
for these.
- On second thoughts, it might be best to introduce
So I would add a set_blk_num
procedure in memory.masm to set just the block number which is called from the prologue.
set_global_acct_id
and get_global_acct_id
must be modified to not use mem_storew/mem_loadw
but rather two mem_store/mem_load
operations on the individual felts.
Maybe @bobbinth has a different opinion, but that's how I would go about it.
#! | ||
#! Where: | ||
#! - block_num is the number of the reference block for the transaction execution. | ||
export.get_block_num |
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.
To test the memory layout generally, you can extend the global_input_memory_assertions
function in crates/miden-tx/src/tests/kernel_tests/test_prologue.rs
.
This procedure specifically will be tested implicitly by testing procedures that call it, so no extra test needed.
#! | ||
#! Where: | ||
#! - block_num is the number of the reference block for the transaction execution. | ||
export.get_block_num |
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.
We should ideally call this get_global_blk_num
(global to indicate it's the one from the public inputs and blk
for consistency, although I would personally also like us to use "block", but that's another discussion).
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.
Did not get around to a full review, but left some small comments/questions.
Not from this PR, but I noticed that some procedures in the
Can be written as:
We can do this now because after we migrated to element-addressable memory, we can read individual elements from memory rather than having to read full words and then extract the element we are interested in. cc @Fumuran |
Yep, I think a lot of memory procedures could be optimized this way. I created a corresponding issue #1132. |
64b083a
to
6fd1233
Compare
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.
All looks good! Thank you!
Closes #1119
Adds block number as a public input to the transaction kernel and validate it is consistent with the commitment block number.