feat: decode rlp directly from tx_input - #2653
Conversation
PR Reviewer Guide 🔍(Review updated until commit 6b243b5)Here are some key observations to aid the review process:
|
PR Code Suggestions ✨Latest suggestions up to 6b243b5
Previous suggestionsSuggestions up to commit 7db6dee
|
There was a problem hiding this comment.
Summary
Nice refactor overall: decoding now builds TransactionInput directly from TxEnvelope, and the new signature_hash() path is covered by a focused consistency test against to_tx_envelope().signature_hash() across tx types 0–4.
I reviewed for correctness around signer recovery and hash derivation, and the implementation stays behaviorally aligned with the previous envelope-based hash flow for the fields currently persisted in TransactionInput.
|
Persistent review updated to latest commit 6b243b5 |
There was a problem hiding this comment.
Wrong idea. The idea is to decode transaction input directly from the received rlp. This means that we never even create the alloy types in the first place, the rlp gets decoded directly to TransactionInput, this means we don't ever even decode to TxEnvelope.
Before doing this however, a better issue to solve first is #2548 . Since then when receiving an eth_sendRawTransaction we wouldn't have to do any conversions with alloy at all.
There was a problem hiding this comment.
Thanks for the refactor — moving decode toward TransactionInput directly is a good direction. I found one blocking correctness issue in signer recovery:
Blocking: signature_hash() now reconstructs typed txs with fields that are not persisted in TransactionInput (access list, 1559 priority fee, 4844 blob fields, 7702 authorization list) using defaults. For any real tx where those fields are non-default, recovered prehash will differ from the original signed prehash, so signer recovery can fail or recover the wrong address.
Concretely in this diff:
- type 1/2:
access_list: AccessList::default() - type 2/3/4:
max_priority_fee_per_gas = gas_price - type 3:
blob_versioned_hashes = [],max_fee_per_blob_gas = 0 - type 4:
authorization_list = []
Because build_transaction_input_from_envelope() now calls recover_signer_address() (which uses this new hash path), this can break immediately on decode of valid raw txs carrying those fields.
Suggested fix options:
- Keep using envelope-native signing hash for recovery when decoding from raw tx (
envelope.signature_hash()), and only use field-derived hash where you can guarantee complete persisted fields; or - Extend
TransactionInput/ExecutionInfoto store all signing-relevant fields per tx type, then compute hash from fully faithful data.
Also, current test only checks signature_hash() vs to_tx_envelope() built from the same reduced fields, so it can’t catch this class of mismatch. Please add a test with a real typed tx (e.g. 1559 with non-empty access list / different priority fee, and/or 4844 with blob hashes) and assert recovered signer matches the signer from the original envelope/raw tx.
PR Type
Enhancement, Tests
Description
Add
signature_hash()method toTransactionInputRefactor RLP decoding flow
build_transaction_input_from_envelope()try_from_alloy_transaction()logicRemove redundant transaction conversion code
Add unit tests for
signature_hash()correctnessDiagram Walkthrough
File Walkthrough
transaction_input.rs
Add signature_hash and refactor decodingsrc/eth/types/transaction/transaction_input.rs
signature_hash()computing B256 from stored fieldsbuild_transaction_input_from_envelope()try_from_alloy_transaction()conversion path