feat: implement API changes for named storage slots#2025
feat: implement API changes for named storage slots#2025PhilippGackstatter merged 171 commits intonextfrom
Conversation
mmagician
left a comment
There was a problem hiding this comment.
Minor comments left, otherwise LGTM ✅
I think overall this is a much needed feature, and the PRs do a great job at implementing the necessary changes as well as showing, via examples, how to use it.
LFG 🔥
| /// [/* no fungible asset delta */], | ||
| /// [/* no non-fungible asset delta */], | ||
| /// [[domain = 2, slot_idx = 1, 0, 0], NEW_VALUE] | ||
| /// [[domain = 2, 0, name_id_suffix = 0, name_id_prefix = 0], NEW_VALUE] |
There was a problem hiding this comment.
for another PR: I don't think this example is meaningful anymore, since we're extremely unlikely to get name_id_suffix = 0, name_id_prefix = 0.
Which makes me wonder whether we can simplify a bit and remove the domain element completely, and just use the name_id_{prefix/suffix} - it effectively functions as a domain separator
There was a problem hiding this comment.
Thanks for the comment! The kernel only deals with slot IDs, and technically users are free to use prefix = 0 and suffix = 0 as their slot ID. They wouldn't be able to use our Rust APIs, but from a protocol perspective, it's allowed. Because of that, we still need the domain separators afaict.
This made me realize a potential problem with slot names not being committed to by the kernel, though not sure it's a problem at this stage.
Main points:
- We have a
SlotName(String)from which we derive aSlotId([Felt; 2])using BLAKE3. - The transaction kernel only deals with slot IDs; it doesn't know about slot names at all.
- All Rust APIs use a
SlotName, e.g. the account storage or the account delta. They all assume the slot name is available. - Relevant when decentralizing Miden, but, afaict, a state update to L1 (Ethereum) in our case would basically consist of:
- The block proof.
- The public inputs/outputs of the block kernel (needed for proof verification).
- The chain data required to reconstruct the new Miden state (e.g., accumulated account deltas, new notes, etc.).
- This is what other nodes would use to construct the new public state of the chain.
- The only way to guarantee that the preimage of a slot ID (= the slot name) is available, is by committing to it through the chain data. Since the delta commits only to the slot ID, we currently don't have that guarantee.
- Without this, Rust nodes assuming the slot name is available/provided would crash or go out of sync.
- Solutions
- L1 verifier contract needs to ensure that the slot name for each slot ID is provided. This means we can deal with this later (as in after mainnet).
- Commit to the slot name via the kernel somehow. This means we need to deal with it now (as in before mainnet).
- I think the same is relevant for the account code in the delta, where only the MAST root is committed to, but the actual code would not be guaranteed to be available without further validation, e.g. on L1.
I believe we can go the L1 verifier route, but would be good to get another perspective on this.
Fumuran
left a comment
There was a problem hiding this comment.
Looks great, thank you! I left just a few little comments.
|
|
||
| push.PUBLIC_KEYS_MAP_SLOT | ||
| # => [pub_key_slot_idx, num_of_approvers, TX_SUMMARY_COMMITMENT, default_threshold] | ||
| push.APPROVER_PUBLIC_KEYS_SLOT[0..2] |
There was a problem hiding this comment.
We are using push.SLOT_NAME[0..2] quite often, so I'm wondering should we create a new syntax for the slot names, which will work similar to the word(...) or event(...), but will hold just two first elements of the resulting hash. That way it will be more clear what in fact this constant is holding.
Probably it's an overkill, this feature will require some changes in the VM, but could be nice to have something like that.
There was a problem hiding this comment.
I kind of agree, yes. I think it would already be sufficient to be able to define a sliced constant:
const APPROVER_PUBLIC_KEYS_SLOT = word("miden::standards::auth::ecdsa_k256_keccak_multisig::approver_public_keys")[0..2]
And then you could simply do:
push.APPROVER_PUBLIC_KEYS_SLOT
But not sure it's worth adding.
I think merging them now makes sense since that's the bulk of the work and avoids the feature branch getting out of sync too much. |
Implements the user-facing API changes for named storage slots, building on top of #1987.
This is a big PR, because it refactors a core part of accounts and as a result, the PR needs to touch many corners of the codebase. The only significant part that was deactivated instead of refactored in this PR are
AccountComponentTemplates, which will be dealt with in a separate PR.Also, the majority of changes in this PR are simple: They replace a slot index with a slot name. See the "PR Review" section for what a good focus for a review might be.
Choices
SlotName::from_static_strand leave only the non-constnewconstructor. Theconststuff is pretty sad to remove again, but I now think it's an overall better approach. There are quite a few places where we use theOrdimplementation ofSlotName, e.g. in everyBTreeMap<SlotName, _>and currently this recomputes theSlotNameIdmany times.PR Review
I think there are really only two bigger areas that need a detailed review:
find_storage_slotAPI is used in a lot of places now, and it returning aslot_ptrcaused refactorings to storage-related APIs, e.g. set_map_item, set_item, get_item, etc. This also meant changes to the transaction host event handlers. These would be good to review in detail.AccountStorageHeader, mostly as a way to support the transaction host to react to events.$kernel::account.slot_idxbut now includes the slot name ID.AccountStorage. So, I think this makes the delta architecture more consistent with account storage, but I still realized this too late, so this could maybe have been a separate PR - sorry about that.AccountStorageDelta::append_delta_elements. I implemented a minimal way to deal with the necessary changes.AccountStorageDeltaso it contains a singleBTreeMap<SlotName, StorageSlotDelta>, but as always, this comes with trade-offs.Notes on Changes
test_account_code_procedure_offset_out_of_boundsbecause this will be removed in a follow-up PR together with offset and storage size of account procedures and fixing the test would've been non-trivial.impl TryFrom<Package> for AccountComponentTemplatewas moved unchanged to a more appropriate place. That made deactivating the template code easier.Follow-Ups to this PR
TODO(named_slots).AccountComponentMetadata(Implement Named Storage Slots #1724 (comment))SlotName::from_static_str(priority, to avoid stabilizing an API we'll remove anyway).SlotNameIdpart ofSlotNameto avoid recomputing it in various cases (feat: implement API changes for named storage slots #2025 (comment))ERR_ACCOUNT_UNKNOWN_STORAGE_SLOT_NAME.StorageSlot->StorageSlotContent(feat: implement API changes for named storage slots #2025 (comment))NamedStorageSlot->StorageSlot(https://github.com/0xMiden/miden-base/pull/1987#discussion_r2575545109)
SlotNameId->StorageSlotId(feat: Implement named storage slots in the transaction kernel #1987 (comment)).name_id_prefix->slot_id_prefix(same for suffix) (feat: implement API changes for named storage slots #2025 (comment))NEW_VALUEandOLD_MAP_VALUEconsistent inset_map_itemfeat: implement API changes for named storage slots #2025 (comment).get_kernel_mem_elementto use updatedMemory::read_elementfeat: implement API changes for named storage slots #2025 (comment)part of #1724