Skip to content

execution/types/accounts, db/state/execctx: extract codeHash without a full account decode - #22468

Merged
yperbasis merged 3 commits into
mainfrom
yperbasis/codehash-extract
Jul 15, 2026
Merged

execution/types/accounts, db/state/execctx: extract codeHash without a full account decode#22468
yperbasis merged 3 commits into
mainfrom
yperbasis/codehash-extract

Conversation

@yperbasis

Copy link
Copy Markdown
Member

Split from #22159 (the #22120 StateCache review findings — finding 7's decode-cost half).

What changed

codeHashForAddr fully decoded every account record it touched — balance parse plus codeHash interning per mem hit — just to read one field. accounts.DeserialiseV3CodeHash parses the SerialiseV3 layout only up to and including the codeHash field:

  • bounds-safe on every truncation point (returns nil on malformed input; the full decoder indexes without length checks),
  • returns nil for both no-code sentinel spellings (zero hash, empty-code keccak), matching CodeHash.IsEmpty,
  • returns a subslice of enc, valid only while enc is — all four call sites in codeHashForAddr consume it synchronously within the tx, and the one retained copy (PutAddrCodeHash) goes through a fixed [32]byte.

decodeAccountCodeHash is deleted; its call sites switch to the extractor.

Testing

  • TestDeserialiseV3CodeHash cross-validates the extractor against the full DeserialiseV3 decode over a nonce × balance × codeHash × incarnation matrix.
  • TestDeserialiseV3CodeHashMalformed walks every truncation point of a record (nil at any cut into the codeHash, the hash beyond it), rejects non-32-byte codeHash fields, and pins the sentinel spellings to nil.

Verification: execution/types/accounts + db/state/execctx suites, repeated clean make lint.

Touches domain_shared.go in hunks disjoint from #22467; the two merge independently.

…a full account decode

Split from #22159 (StateCache review findings #22120, finding 7).

codeHashForAddr fully decoded every account record it touched —
balance parse plus codeHash interning per mem hit — just to read one
field. DeserialiseV3CodeHash parses the SerialiseV3 layout only up to
and including the codeHash field, is bounds-safe on truncated records
(nil on malformed input, unlike the full decoder), returns nil for the
empty and zero sentinels to match CodeHash.IsEmpty, and returns a
subslice of enc valid only while enc is — every call site consumes it
synchronously within the tx.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR optimizes the fast-path code-hash lookup by extracting the codeHash field directly from SerialiseV3-encoded account bytes, avoiding the cost of a full account decode (notably balance parsing and CodeHash interning) when only the hash is needed.

Changes:

  • Added accounts.DeserialiseV3CodeHash(enc []byte) []byte to extract the 32-byte code hash (or return nil for malformed/no-code cases) without full decoding.
  • Updated SharedDomains.codeHashForAddr to use the new extractor and removed the now-redundant decodeAccountCodeHash.
  • Added test coverage validating equivalence vs full DeserialiseV3 and ensuring bounds-safety across truncation/malformed cases.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
execution/types/accounts/account.go Adds a bounds-safe extractor for the codeHash field from SerialiseV3 account encoding.
execution/types/accounts/account_test.go Adds tests for correctness vs full decode and malformed/truncation behavior.
db/state/execctx/domain_shared.go Switches codeHashForAddr to the new extractor and removes the full-decode helper.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@yperbasis
yperbasis marked this pull request as ready for review July 14, 2026 14:09
@yperbasis
yperbasis requested a review from taratorio July 14, 2026 14:09
Comment thread execution/types/accounts/account.go Outdated
}
h := enc[pos : pos+codeHashBytes]
var zero common.Hash
if bytes.Equal(h, zero[:]) || bytes.Equal(h, empty.CodeHash[:]) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

can: if ch := common.Hash(h); ch == (common.Hash{}) || ch == empty.CodeHash {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Done in 6c04496 — switched to the direct common.Hash comparison and removed the bytes import. Thanks.

@yperbasis
yperbasis added this pull request to the merge queue Jul 15, 2026
Merged via the queue into main with commit b9ce9d8 Jul 15, 2026
96 checks passed
@yperbasis
yperbasis deleted the yperbasis/codehash-extract branch July 15, 2026 13:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants