Skip to content

execution/types: reduce typed-transaction Hash() allocations (no []any, no reflection) - #21858

Merged
awskii merged 1 commit into
mainfrom
alex/rlp_hash_36
Jun 18, 2026
Merged

awskii merged 1 commit into
mainfrom
alex/rlp_hash_36

Conversation

@AskAlexSharov

@AskAlexSharov AskAlexSharov commented Jun 17, 2026 •

Copy link
Copy Markdown
Collaborator

On Bloatnet i noticed "GC stop-the-world spike"

The win is from not using []any casting and not using reflection:

  • the old Hash() built a []any{...} of the tx fields (slice alloc + boxing each uint64/pointer into an interface), then
  • handed it to the reflection-based rlp.Encode, which walks the values dynamically and allocates as it goes.

Applied to

LegacyTx, AccessListTx, DynamicFeeTransaction, BlobTx, SetCodeTransaction, AccountAbstractionTransaction — every tx type that already has an encodePayload.

Results (BenchmarkTxHash, M4 Max — allocs/op)

type before after
legacy 8 1
accesslist 9 1
dynamicfee 9 1
blob 10 1
setcode 22 1
aa 13 1

Two behavioral notes

  • BlobTx.encodePayload previously dereferenced To unconditionally (it had a non-nil-To precondition enforced by the ErrNilToFieldTx guards in MarshalBinary/EncodeRLP). It now encodes To via EncodeOptionalAddress — byte-identical for the always-present To of a valid blob tx, and consistent with its own payloadSize (which already sizes To optionally). MarshalBinary/EncodeRLP keep their ErrNilToFieldTx guards, so their external contract is unchanged.
  • AccountAbstractionTransaction's hash value changes. Its old []any path encoded SenderAddress (accounts.Address = unique.Handle, which has unexported fields) through reflection, which silently dropped the sender from the hash. Hash() now goes through encodePayload and equals keccak256 of the canonical MarshalBinary bytes. AA (RIP-7560) is not live, so this is a latent-bug fix rather than a consensus change.

@AskAlexSharov AskAlexSharov changed the title [wip] execution/types: reduce DynamicFeeTransaction.Hash() allocations execution/types: reduce DynamicFeeTransaction.Hash() allocations Jun 17, 2026
@AskAlexSharov
AskAlexSharov requested a review from Copilot June 17, 2026 09:57

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

Reduces allocations and reflection overhead in EIP-1559 (DynamicFeeTransaction) hashing by hashing the typed-transaction prefix plus the already hand-written RLP payload encoding, avoiding []any boxing and rlp.Encode reflection.

Changes:

  • Add prefixedPayloadHash(prefix, encode) helper to hash keccak256(prefix || payload) where payload is written directly to the hasher.
  • Update DynamicFeeTransaction.Hash() to use payloadSize() + encodePayload(...) via the new helper instead of constructing a []any and calling reflection-based rlp.Encode.

Reviewed changes

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

File Description
execution/types/hashing.go Adds prefixedPayloadHash to hash typed-tx prefix + caller-written payload using pooled keccak + pooled RLP scratch buffer.
execution/types/dynamic_fee_tx.go Switches DynamicFeeTransaction.Hash() to hash the existing hand-written payload encoding (no []any, no reflection).

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

@AskAlexSharov AskAlexSharov changed the title execution/types: reduce DynamicFeeTransaction.Hash() allocations [wip] execution/types: reduce typed-transaction Hash() allocations (no []any, no reflection) Jun 17, 2026
@AskAlexSharov AskAlexSharov changed the title [wip] execution/types: reduce typed-transaction Hash() allocations (no []any, no reflection) execution/types: reduce typed-transaction Hash() allocations (no []any, no reflection) Jun 17, 2026
@AskAlexSharov
AskAlexSharov requested a review from Copilot June 17, 2026 10:20

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

Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.

Comment thread execution/types/hashing.go Outdated

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

Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.

Comment thread execution/types/transaction_hash_opt_test.go
Hash() built a []any of the transaction fields and ran it through the
reflection-based rlp encoder. Add typed helpers rlpPayloadHash and
prefixedPayloadHash that hash into a pooled keccak state and let each
transaction encode through its existing hand-written encodePayload, so
there is no []any boxing and no reflection.

Applied to LegacyTx, AccessListTx, DynamicFeeTransaction, BlobTx,
SetCodeTransaction and AccountAbstractionTransaction. For the first five
the hash is unchanged, verified byte-for-byte against the old reflection
path. BlobTx.encodePayload now encodes To via EncodeOptionalAddress
(byte-identical for the always-present To of a valid blob tx), matching
its own payloadSize and the reflection path instead of dereferencing a
possibly-nil To.

AccountAbstractionTransaction's hash changes: its old []any path encoded
SenderAddress (accounts.Address = unique.Handle) via reflection, which
skips the unexported handle field and dropped the sender from the hash.
The encodePayload path matches MarshalBinary, so Hash() now equals
keccak256 of the canonical wire bytes.

Also fix a pool-leak-on-panic in prefixedRlpHash (return the hasher via
defer). Per-call allocations drop to 1 (the cached-hash pointer): e.g.
SetCode 22->1, AA 13->1, Blob 10->1.

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

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

@awskii
awskii added this pull request to the merge queue Jun 18, 2026
Merged via the queue into main with commit 9c149fb Jun 18, 2026
95 checks passed
@awskii
awskii deleted the alex/rlp_hash_36 branch June 18, 2026 04:29
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.

4 participants