Skip to content

fix: new account map delta#2077

Merged
bobbinth merged 8 commits intomainfrom
pgackst-fix-new-account-map-delta
Nov 8, 2025
Merged

fix: new account map delta#2077
bobbinth merged 8 commits intomainfrom
pgackst-fix-new-account-map-delta

Conversation

@PhilippGackstatter
Copy link
Contributor

@PhilippGackstatter PhilippGackstatter commented Nov 7, 2025

Fixes the representation of empty map slots in full state deltas (i.e. deltas representing new accounts).

This is done by:

  • inserting an empty StorageMapDelta into the AccountStorageDelta to represent the presence of an empty map.
  • skipping normalization of storage map deltas when the account is new
  • changing the delta commitment to include map headers even if num_changed_entries == 0

Despite what the docs on AccountDelta::to_commitment said previously, I believe an entry with num_changed_entries == 0 should be fine. I updated the docs, primarily because I wanted to convince myself this was ok.

This should work overall, but makes the AccountDelta more subtle to use, which is not great. Meaning, there is now an implicit expectation that an AccountDelta is correctly constructed, e.g. a full state delta should be constructed with an empty StorageMapDelta to represent the presence of an empty map and it will be included in the commitment if it is present, not otherwise. In other words, constructing an account delta manually would currently likely result in some edge case being incorrect. So as long as the delta is taken from ExecutedTransaction or ProvenTransaction, this should work out, but otherwise the delta has increased its complexity more than I had hoped for.

I think we should revisit this fix more broadly when we implement general support for inserting or removing storage slots to an account, e.g. "account storage upgrade". The problem here really is representing a slot that is being newly inserted, while the delta was previously designed for representing only changes to existing slots, and the fix here is to make use of this existing design in subtle ways, which is not the best.

closes #2076

Comment on lines +216 to +219
/// - Append `[[domain = 3, slot_idx, num_changed_entries, 0], 0, 0, 0, 0]`.
/// - For partial state deltas, the map header must only be included if
/// `num_changed_entries` is not zero.
/// - For full state deltas, the map header must always be included.
Copy link
Collaborator

Choose a reason for hiding this comment

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

I can't remember whether full state deltas ALWAYS implies the account is new? Or can we have full state delta for an existing account, too?
I'm bringing this up because there's a small inconsistency in the naming for this fix vs. for #2075.
Here, we make special adjustments "for full state deltas" (always include the map header, analogous to always including the value entry even if empty).
In #2075, we make special adjustments "for new accounts".

So if full state deltas =ALWAYS= new account, then maybe we could refer to new account vs. existing accounts here, too?
lmk if this makes sense or whether I missed the point completely :D

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, full state delta always means new account - so, we should have probably used "new account" here as well. But I also think it is fine as is because we'll rework it relatively soon with #2078.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I agree the terminology is inconsistent here, mostly a result of doing these PRs as "quick fixes" and in sequence instead of as one unified feature.

So if full state deltas =ALWAYS= new account, then maybe we could refer to new account vs. existing accounts here, too?

I added your comments to #2078 (comment), thanks for raising it! We could refer to new/existing accounts, but as mentioned in the issue comment, full state and partial state is more well-defined in the delta context than new/existing account, so this seems a bit better. Also open to a rename of the full / partial state notion, but can't think of anything better immediately.

Comment on lines +101 to +103
pub fn insert_empty_map_delta(&mut self, slot_index: u8) {
self.maps.entry(slot_index).or_default();
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Does the logic of this method align with its name?
If we want to insert an empty map, should we always use default(), rather than first trying to access by slot index?

Base automatically changed from pgackst-fix-new-account-delta to main November 8, 2025 07:07
Copy link
Contributor

@bobbinth bobbinth left a 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'll merge this as is, and any outstanding comments we could address in a separate PR, or maybe just tackle as a part of #2078.

@bobbinth bobbinth merged commit b9e68d4 into main Nov 8, 2025
17 checks passed
@bobbinth bobbinth deleted the pgackst-fix-new-account-map-delta branch November 8, 2025 07:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants