execution/types: reduce typed-transaction Hash() allocations (no []any, no reflection) - #21858
Merged
Merged
Conversation
AskAlexSharov
force-pushed
the
alex/rlp_hash_36
branch
from
June 17, 2026 09:42
a94a960 to
a801dec
Compare
Contributor
There was a problem hiding this comment.
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 hashkeccak256(prefix || payload)where payload is written directly to the hasher. - Update
DynamicFeeTransaction.Hash()to usepayloadSize()+encodePayload(...)via the new helper instead of constructing a[]anyand calling reflection-basedrlp.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
force-pushed
the
alex/rlp_hash_36
branch
from
June 17, 2026 10:16
6a680b9 to
4473994
Compare
AskAlexSharov
force-pushed
the
alex/rlp_hash_36
branch
from
June 17, 2026 14:15
4473994 to
8f3a35f
Compare
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.
AskAlexSharov
force-pushed
the
alex/rlp_hash_36
branch
from
June 17, 2026 14:30
8f3a35f to
802cb44
Compare
awskii
approved these changes
Jun 18, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
On Bloatnet i noticed "GC stop-the-world spike"
The win is from not using
[]anycasting and not using reflection:Hash()built a[]any{...}of the tx fields (slice alloc + boxing eachuint64/pointer into an interface), thenrlp.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 anencodePayload.Results (
BenchmarkTxHash, M4 Max — allocs/op)Two behavioral notes
BlobTx.encodePayloadpreviously dereferencedTounconditionally (it had a non-nil-Toprecondition enforced by theErrNilToFieldTxguards inMarshalBinary/EncodeRLP). It now encodesToviaEncodeOptionalAddress— byte-identical for the always-presentToof a valid blob tx, and consistent with its ownpayloadSize(which already sizesTooptionally).MarshalBinary/EncodeRLPkeep theirErrNilToFieldTxguards, so their external contract is unchanged.AccountAbstractionTransaction's hash value changes. Its old[]anypath encodedSenderAddress(accounts.Address=unique.Handle, which has unexported fields) through reflection, which silently dropped the sender from the hash.Hash()now goes throughencodePayloadand equalskeccak256of the canonicalMarshalBinarybytes. AA (RIP-7560) is not live, so this is a latent-bug fix rather than a consensus change.