-
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
fix: Remove caller ID workaround for root contexts #857
Conversation
// ERR_FUNGIBLE_ASSET_MISMATCH | ||
assert_execution_errored(process, 0x00020039); |
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'm not entirely sure all these error codes are correct and in line of what was being returned originally. I mean to double check this soon
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 confirmed this by going back and checking the expected error codes for these tests
|
||
# double check that on storage slot is indeed the new map | ||
push.{item_index} | ||
exec.account::get_item | ||
call.account::get_map_item | ||
end | ||
", | ||
item_index = storage_item.index, |
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 test is the only failing one. Not sure what it is, seems to be related to the stack state after set_map_item
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 was fixed, but I'm not entirely sure how the fix is valid. Something in the interplay between get_item
and set_map_item
is likely not correct
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.
get_item()
reads the word in a given slot, regardless of the underlying type of the slot. Currently, we have two types of slots: simple values and maps. When the type of a slat is map
, its value is actually the commitment to the map (i.e., its root).
So, if we update the map via set_map_item
and then do get_item
for the same storage slot, we'll get the root of the updated storage map back.
Let me know if this clarifies 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.
set_map_item
returns [OLD_VALUE, NEW_ROOT]
hence in this test OLD_VALUE
is asserted for but NEW_ROOT
is not as of now.
We should add the following assertion:
assert_eq!(
new_storage_map.root(),
RpoDigest::from(process.get_stack_word(2)),
"The returned updated value doesn't match the stored updated value",
);
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.
get_item()
reads the word in a given slot, regardless of the underlying type of the slot. Currently, we have two types of slots: simple values and maps. When the type of a slat ismap
, its value is actually the commitment to the map (i.e., its root).So, if we update the map via
set_map_item
and then doget_item
for the same storage slot, we'll get the root of the updated storage map back.Let me know if this clarifies it.
I get the difference, but this is how I had to define get_item
on the mock account code for it to work:
export.get_item
exec.account::get_item
movup.8 drop movup.8 drop movup.8 drop
end
set_map_item returns [OLD_VALUE, NEW_ROOT] hence in this test OLD_VALUE is asserted for but NEW_ROOT is not as of now.
It seems that ::miden::account::set_map_item
returns [OLD_MAP_ROOT, OLD_MAP_VALUE]
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 get the difference, but this is how I had to define
get_item
on the mock account code for it to work:export.get_item exec.account::get_item movup.8 drop movup.8 drop movup.8 drop end
This is related to #685. Basically, we expect the above procedure to be call
-ed and so it must leave exactly 16 items on the stack. But when we call exec.account::get_item
it pushes 3 items onto the stack and so we need to drop them before returning from the call
.
As discussed in #685, we should probably adapt an ABI that makes these things explicit. One general solution to this is that at the end of an account interface procedure, we should always call std::sys::truncate_stack
. This is a little bit more expensive (in this case would take 28 cycles) - but probably not a big price to pay for a solution that would work every time.
This is also possibly a breaking change (under |
Some tests were failing with incorrect errors (missing note types in note-creation scripts, etc.). Changing this PR to draft until all are fixed. |
Looking into the PR, I think this is the right solution, though previously when trying this method we hit limitations with the assembler erroring out on |
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.
Thank you! Looks good! I left a few comments/questions inline.
|
||
# double check that on storage slot is indeed the new map | ||
push.{item_index} | ||
exec.account::get_item | ||
call.account::get_map_item | ||
end | ||
", | ||
item_index = storage_item.index, |
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.
get_item()
reads the word in a given slot, regardless of the underlying type of the slot. Currently, we have two types of slots: simple values and maps. When the type of a slat is map
, its value is actually the commitment to the map (i.e., its root).
So, if we update the map via set_map_item
and then do get_item
for the same storage slot, we'll get the root of the updated storage map back.
Let me know if this clarifies 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.
Great work!
Love to see the workaround be removed.
A few proposed changes.
@@ -565,24 +558,11 @@ export.authenticate_procedure | |||
|
|||
# get procedure info (PROC_ELEMENTS, storage_offset) from memory stored at index | |||
exec.get_procedure_info | |||
# In production: | |||
# => [PROC_ELEMENTS, storage_offset, PROC_ROOT] |
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 would change the return naming here from PROC_ELEMENTS
to PROC_ROOT
and in the above comment.
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.
Done
@@ -368,6 +368,7 @@ proc.validate_new_account | |||
# empty SMT) | |||
exec.constants::get_empty_smt_root assert_eqw.err=ERR_PROLOGUE_NEW_NON_FUNGIBLE_FAUCET_INVALID_RESERVED_SLOT | |||
# => [] | |||
push.1001 drop # TODO: remove line, see miden-vm/#1122 |
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.
Why do we need to add this here specifically? Did we have an error with decorators previously?
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.
Yeah, it's what Bobbin mentioned yesterday (and related to the error mentioned in the comment). Essentially for asserts with errors the MAST root would be the same and thus the error returned by the VM could be unrelated to the actual error happening in the execution. I do not know the inner workings but adding this push and drop fixes it and we can assert for the actual error in the test.
|
||
# double check that on storage slot is indeed the new map | ||
push.{item_index} | ||
exec.account::get_item | ||
call.account::get_map_item | ||
end | ||
", | ||
item_index = storage_item.index, |
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.
set_map_item
returns [OLD_VALUE, NEW_ROOT]
hence in this test OLD_VALUE
is asserted for but NEW_ROOT
is not as of now.
We should add the following assertion:
assert_eq!(
new_storage_map.root(),
RpoDigest::from(process.get_stack_word(2)),
"The returned updated value doesn't match the stored updated value",
);
fn test_authenticate_procedure() { | ||
let tx_context = TransactionContextBuilder::with_standard_account(ONE).build(); | ||
let account = tx_context.tx_inputs().account(); | ||
fn test_procedure_in_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.
I would keep the naming of this test test_authenticate_procedure
because authenticate_procedure
is a kernel proc.
And it is the one that we are trying to test the logic of here.
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 changed it back, but there's a subtle distinction I think: Even though authenticate_procedure
is the actually called procedure, it errors immediately where the push_procedure
event is emitted instead of the check for comparing roots and authenticating against the account code.
export.authenticate_procedure
# load procedure index
emit.ACCOUNT_PUSH_PROCEDURE_INDEX_EVENT adv_push.1 <- Execution fails here
# => [index, PROC_ROOT]
# get procedure info (PROC_ROOT, storage_offset) from memory stored at index
exec.get_procedure_info
# => [PROC_ROOT, storage_offset, PROC_ROOT]
# verify that PROC_ROOT exists in memory at index
movup.4 movdn.8 assert_eqw.err=ERR_PROC_NOT_PART_OF_ACCOUNT_CODE
# => [storage_offset]
end
If I'm not wrong the account code could contain the procedure, but if the procedure is not in the advice provider, the execution would fail anyway (with the same error it throws now) and the test would pass anyway, which is why I thought the other name was a tiny bit more appropriate. In any case the positive cases do test the whole proc for valid cases.
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.
Looks good! Thank you! I left some small comments inline.
|
||
# double check that on storage slot is indeed the new map | ||
push.{item_index} | ||
exec.account::get_item | ||
call.account::get_map_item | ||
end | ||
", | ||
item_index = storage_item.index, |
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 get the difference, but this is how I had to define
get_item
on the mock account code for it to work:export.get_item exec.account::get_item movup.8 drop movup.8 drop movup.8 drop end
This is related to #685. Basically, we expect the above procedure to be call
-ed and so it must leave exactly 16 items on the stack. But when we call exec.account::get_item
it pushes 3 items onto the stack and so we need to drop them before returning from the call
.
As discussed in #685, we should probably adapt an ABI that makes these things explicit. One general solution to this is that at the end of an account interface procedure, we should always call std::sys::truncate_stack
. This is a little bit more expensive (in this case would take 28 cycles) - but probably not a big price to pay for a solution that would work every time.
45e16cf
to
5db5c7c
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!
88d9f44
to
ce66581
Compare
Closes #851
Also refactors tests to check against VM error codes. This resulted in some tests being slightly modified to account for things that were out of place (eg, some
create_notes
did not have parameters up to date and theprocess.is_err()
would make the tests pass anyway).Also adds some missing kernel errors to the kernel errors array.