-
Notifications
You must be signed in to change notification settings - Fork 54
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
AccountCode
refactor from MerkleTree to Sequential hash for offset based storage access
#763
Conversation
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 preliminary comments inline (mostly focusing on changes in account_code
module). Also, the overall plan makes sense.
objects/src/accounts/code.rs
Outdated
let procedures: Vec<(Digest, Felt)> = procedures | ||
.into_iter() | ||
.enumerate() | ||
.map(|(i, proc)| (proc, Felt::new(i as u64))) | ||
.collect(); |
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 would assign a unique index to each procedure, which is probably not what we want to do. Ideally, the offset would be specified within MASM (and in the future MAST) itself. For example, for the basic wallet contract, it could look something like:
use.miden::contracts::wallets::basic->basic_wallet
use.miden::contracts::auth::basic->basic_auth
@miden-storage-offset(0)
export.basic_wallet::receive_asset
@miden-storage-offset(0)
export.basic_wallet::send_asset
@miden-storage-offset(1)
export.basic_auth::auth_tx_rpo_falcon512
And the result of this would be:
[(receive_asset_hash, 0), (send_asset_hash, 0), (auth_tx_rpo_falcon512, 1)]
But we don't have support for attributes in MASM yet, and i'm not sure what would be a good interim solution (e.g., maybe we provide offsets as a construction parameter - it would be brittle but maybe OK for now).
cc @bitwalker and @plafer for another example of how we'd use annotations in MASM.
Two other things to consider:
- Should we sort the
procedures
before computing commitment? I think probably yes. - Should we somehow indicate that some procedures don't need storage access? For example, in the above
recieve_asset
andsend_asset
procedures never need to touch storage). I also think yes, but not sure how to do it yet.
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 am still thinking through how we could handle the input of the offsets, will add towards the end of the refactor once everything works correctly with dummy values.
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 still need to address some of the above questions.
daf6e06
to
cd0ef51
Compare
AccountCode
refactor from MerkleTree to Sequential hash for offset based storage access
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! Not a full review yet, but I did review pretty much everything except for tests. Left some comments inline.
objects/src/accounts/code.rs
Outdated
let procedures: Vec<(Digest, Felt)> = procedures | ||
.into_iter() | ||
.enumerate() | ||
.map(|(i, proc)| (proc, Felt::new(i as u64))) | ||
.collect(); |
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 still need to address some of the above questions.
Error:
|
TransactionEvent::AccountPushProcedureIndex => { | |
self.on_account_push_procedure_index(process) | |
}, |
on_event
calls on_account_push_procedure_index
that queries the account_procedure_index_map
using get_proc_index
with the current process (here [0,0,0,0]
).get_proc_index
queries the first word of the operand stack and searches for a value in the AccountProcedureIndexMap
matching that key.AdviceProvider
to be added to the operand stack of the VM.The problem being here that we are querying the AccountProcedureIndexMap
with [0,0,0,0]
(Digest::default
) which will return us the element at this position and not a valid procedure index in the map.
There are 2 implementations of the AccountProcedureIndexMap
a production one and a mock
one, the one that is getting called during the tests is the mock
one and has additional lines compared to the classical one stating that:
miden-base/miden-tx/src/testing/account_procs.rs
Lines 47 to 62 in 13724e9
pub fn get_proc_index<S: ProcessState>( | |
&self, | |
process: &S, | |
) -> Result<u8, TransactionKernelError> { | |
let proc_root = process.get_stack_word(0).into(); | |
// mock account method for testing from root context | |
// TODO: figure out if we can get rid of this | |
if proc_root == Digest::default() { | |
return Ok(255); | |
} | |
self.0 | |
.get(&proc_root) | |
.cloned() | |
.ok_or(TransactionKernelError::UnknownAccountProcedure(proc_root)) | |
} | |
} |
This if clause will hence push 255
on the operand stack:
if proc_root == Digest::default() {
return Ok(255);
}
Without the index out of bounds check that was added in get_procedure_info
mentioned at the top of this comment the procedure continues execution as follows:
# => [255]
push.2 mul exec.memory::get_account_procedures_section_offset add dup push.1 add
# => [1211, 1210]
# Here 2 possibilities:
# - There are elements at location 1210 and 1211 in memory and they are returned
# - There are no elements at location 1210 and 1211 in memory and 0's are returned
mem_load swap padw movup.4 mem_loadw
# => [0,0,0,0,0]
# Next we will be checking if the returned data from the memory matches the PROC_ROOT (which in this case is [0,0,0,0]
movup.4 movdn.8 assert_eqw.err=ERR_PROC_NOT_PART_OF_ACCOUNT_CODE
# => [0]
Hence we understand here that the tests would pass. Not because the logic is valid but because the caller
in the root context is [0,0,0,0]
and the returned values from the procedure in the memory are also [0,0,0,0]
.
A few questions:
- Why do we have 2 versions of the
AccountProcedureIndexMap
?classical
andmock
? - Is it normal that the
caller
here is[0,0,0,0]
? - From your answer yesterday I understand that it is because it comes from the root context, but shouldn't it be erroring out ?
I think the reason was exactly to make this tests work (i.e., to skip the real procedure authentication check).
It should not be possible to execute the But as long as there is no check, |
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 more comments inline - but they are either pretty minor or can be addressed in the next PR (when we actually integrate offsets into storage access procedures).
# move procedure data from the advice map to the advice stack and then push the number of | ||
# procedures onto the operand stack before storing it in memory | ||
adv.push_mapval adv_push.1 dup exec.memory::set_num_account_procedures | ||
# => [num_procs, CODE_COMMITMENT] |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
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 a few more nits inline. Once these are addressed, let's merge.
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 one more comment inline. Also, there seems to be a merge conflict that needs to be resolved.
In this PR I propose to refactor storage to add an offset-based storage access.
I am actively working on understanding the whole chain of dependency for this modification for now I follow this plan:
AccountCode
struct to replace theSmt
with a sequential hashcommitment
Smt
logic, replace this logic withVec<Digest, Felt>
handling (which as pointed out in the issue should be simpler and more efficient)AdviceProvider
MerkleTree
dependant codeWould be glad to have your input on this plan @bobbinth if you think I could go forward in a more efficient way.
Closes: #667