-
Notifications
You must be signed in to change notification settings - Fork 224
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
refactor: move hash memoization out of signed #1485
base: main
Are you sure you want to change the base?
Conversation
let mut buf = Vec::with_capacity(v.tx().encoded_len_with_signature(v.signature())); | ||
v.tx().encode_with_signature_fields(v.signature(), &mut buf); | ||
let h = keccak256(buf); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should all of those be Sealable
impls?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no, only the envelope knows the correct serialization for its components (tx types don't know their flag as it may be network dependent c.f. issue #1483)
e1b260a
to
23a5505
Compare
c5d37ef
to
2f04789
Compare
this is ready for re-review |
pub enum TxEnvelope { | ||
/// An untagged [`TxLegacy`]. | ||
Legacy(Signed<TxLegacy>), | ||
Legacy(Enveloped<TxLegacy>), | ||
/// A [`TxEip2930`] tagged with type 1. | ||
Eip2930(Signed<TxEip2930>), | ||
Eip2930(Enveloped<TxEip2930>), | ||
/// A [`TxEip1559`] tagged with type 2. | ||
Eip1559(Signed<TxEip1559>), | ||
Eip1559(Enveloped<TxEip1559>), | ||
/// A TxEip4844 tagged with type 3. | ||
/// An EIP-4844 transaction has two network representations: | ||
/// 1 - The transaction itself, which is a regular RLP-encoded transaction and used to retrieve | ||
/// historical transactions.. | ||
/// | ||
/// 2 - The transaction with a sidecar, which is the form used to | ||
/// send transactions to the network. | ||
Eip4844(Signed<TxEip4844Variant>), | ||
Eip4844(Enveloped<TxEip4844Variant>), | ||
/// A [`TxEip7702`] tagged with type 4. | ||
Eip7702(Signed<TxEip7702>), | ||
Eip7702(Enveloped<TxEip7702>), | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
excellent, but, what's the plan for alloy_consensus::TypedTransaction
now? it's essentially the same type
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TypedTransaction
is the unsigned version. As such neither signature or hash is known, and it just includes a signable version of the inner transaction and is used in the NetworkWallet::<N>::sign_transaction_from
API
actually now that you mention it, we need to apply #1489 to TypedTransaction
as well
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let mut buf = Vec::with_capacity(v.tx().encoded_len_with_signature(v.signature())); | ||
v.tx().encode_with_signature_fields(v.signature(), &mut buf); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is there no other way to get the tx hash?
if the only solution is to go through the txenvelope enum this will be very inconvenient
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
c.f. #1483. Technically it's legal for networks to make envelopes that do the following:
- use the same inner type, but a different serialization (e.g. a TxLegacy serialized borsht instead of RLP)
- use a different tx flag for the same inner type (e.g. a
TxEnvelope
containingTxEip1559
at23
instead of2
- use the same inner type at multiple tx flags (e.g. a
TxEnvelope
containingTxEip1559
at both2
and23
)
So there is no way to correctly get the hash of a transaction without wrapping it in the specific network's envelope first
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
imo if a network does this then that's on them, because the type id is even part of the eip itself, if they'd choose 23 then this would no longer be 1559
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
all of those usecases can be solved by introducing a separate inner transaction type (e.g. network can provide its own TxLegacy
)
right now it makes total sense for separate transaction types to know their full encoding because we don't yet have a case of network rolling out encoding of transaction conflicting with existing tx types. also given that most of the networks target for compatibility with ethereum I'd consider such case very unlikely
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also consider it unlikely. But it's still the only correct abstraction of an EIP-2718 envelope if we want our code to be reusable.
because the type id is even part of the eip itself
This is a fair reading of the spec. And @klkvr is right that people downstream can just duplicate 500 lines of code per tx type to change a single constant. However, it costs us very little to have the envelope drive serialization and hashing and prevents future headaches when someone inevitably does something silly here
For another interesting example, consider the extension sentinel value in eip-2718 0xff
🙃 This is also unlikely ofc, but tx-association falls down in extended envelopes
At current state of alloy transactions do know their encoding and their type byte. I've seen a lot of examples of people using IMO this edge case (Ethereum transactions with different type byte) is very unlikely and already can be solved by introducing separate types |
yes, this is the logic bug in #1483. They do, but they should not, as the type byte is an envelope feature, not a transaction feature. See #1483 and #1485 (comment) I do not know of any network that do this, but i do think that the cost of implementing it correctly now is small, while the cost of fixing it later is large
This API is broken right now, and their usage is almost certainly incorrect. It's why the encoding/decoding functions were private before #529, and why #529 hides them from users. We deliberately set out to prevent people from doing this and made it officially not part of the public API. as |
could you please elaborate a bit on that? is it broken for 4844 case? |
There's that, yes. 4844 transaction with sidecars produce incorrect
I can continue, but basically this is a broken API that confuses multiple serialization schemes and is almost impossible to correctly use The long term fix is to change the RLP derive to allow flattening and field-only serialization |
actually this is a good time to just make a cleanup PR. I'll go do that |
holding off on rebasing this as it's better with #1496 |
This is a breaking change
Motivation
See discussion in #1460 and #1483
Memoizing the hash in
Signed
is inappropriate, as the transaction does not know its full 2718 serialization without being embedded in an envelope. This breaks the hash out into aSealed
type that is produced when theEnvelope
is constructed. The sealed type is transparent to the userSolution
Enveloped
type aliasFrom<>
impls properlySeal
impl Encodable2718 for TxEnvelope
produces the correcttrie_hash
by returning the memoized hash. This previously produced incorrect hashes for 4844 txns with sidecarsPR Checklist