-
Notifications
You must be signed in to change notification settings - Fork 773
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
Tx: New supports(capability) method #1315
Conversation
…supported EIPs as input and otherwise throwing
…tsEIP() calls, fixed bug in deprecated generateTxReceipt() method
Codecov Report
Flags with carried forward coverage won't be shown. Click here to find out more. |
throw new Error( | ||
`Unsupported transaction type ${'transactionType' in tx ? tx.transactionType : 'NaN'}` | ||
) | ||
} as PostByzantiumTxReceipt |
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 have simplified here since I think this is not very future proof if we bring out some new tx type within a new non-breaking tx release and this would be run on a new VM (this would then break here without the change) and at the same time I am not really seeing the use for these dedicated receipt types.
Hope that I am not overlooking some side effects here though, eventually also give this some additional thought if you think this is ok.
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.
(and if there will be some future tx type changing the receipt format once again we can still then think about how we react and eventually add a specific new receipt type here)
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 believe the reason this was implemented with dedicated receipt names for each EIP is due to EIP-2718 saying:
Receipt
is eitherTransactionType || ReceiptPayload
orLegacyReceipt
ReceiptPayload
is an opaque byte array whose interpretation is dependent on theTransactionType
and defined in future EIPsLegacyReceipt
isrlp([status, cumulativeGasUsed, logsBloom, logs])
EIP-2930:
The EIP-2718
ReceiptPayload
for this transaction isrlp([status, cumulativeGasUsed, logsBloom, logs])
.
EIP-1559:
The EIP-2718
ReceiptPayload
for this transaction isrlp([status, cumulativeGasUsed, logsBloom, logs])
.
So although the receipts are aligned so far, they might deviate in the future. That said, I think your code improvements and reasoning here are great and we can introduce a new receipt type when the time comes.
…P() calls, deprecated EIP2930Receipt and EIP1559Receipt types and improve forwards-compatibility for EIP-2718 receipt generation by omit specific receipt assignment and dispense on throwing for unsupported tx types
e3c267a
to
8004517
Compare
Ok, this is now ready for review. 😄 |
My one thought here is do we need both |
Yes, I first (or actually: on a second or third iteration 😋) had this thought too: couldn't we just use the information we already have in the Common. But actually we can not, this is something different. While common reflects the network state, this method is dedicatedly targeted to describe the capabilities of a specific tx type. This becomes apparent if you take a legacy tx running on |
Got it. That makes sense now that you explain it. I'm approving though don't take that as 100% guarantee that it should be merged. I'll defer to @ryanio for a knowledgeable review. |
// EIP-1559 spec: | ||
// The signer must be able to afford the transaction | ||
// `assert balance >= gas_limit * max_fee_per_gas` | ||
const cost = tx.gasLimit.mul(tx.maxFeePerGas) | ||
const cost = tx.gasLimit.mul((tx as FeeMarketEIP1559Transaction).maxFeePerGas) |
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.
It might be interesting to consider turning the supportsEIP
method into a TypeScript typeguard. This would allow automatic inference of the transaction type (no as FeeMarketEIP1559Transaction
would then be necessary).
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.
Oh that's a really cool idea, could you commit it to this branch or sketch out how we may do that? I am just reading about it, super interesting: https://www.typescriptlang.org/docs/handbook/advanced-types.html#using-type-predicates
I agree with trying to reduce as many as x
as possible, I have tried to resolve them on a per case basis in PR reviews since it makes a huge difference in readability before/ after.
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.
The idea is really cool yeah! 😄 It doesn't apply on this context though I would very much say. The supportsEIP()
(or however we call it) method is explicitly not about the tx type but about some certain capability. So for 2930 (access lists) it is just not decidable on what to cast (lowest common denominator AccessListEIP2930Transaction
or FeeMarketEIP1559Transaction
). I would assume it is rather not good to make assumptions here (e.g.: let's cast to the lowest common denominator) since this might not be appropriate for the specific usage context. And at the end there is no such thing as "transaction hierarchy", tx types are at the end completely independent entities, so it might even be wrong to talk about "lowest common denominator" in this context at all.
And with a potential EIP-155 addition this concept breaks completely.
Alternative ideas:
Might it be possible to either:
a) add this to the type
getter instead, this then gets deterministic on a call of this method and this would also be more consistent from a usage context perspective I guess (if someone wants to assume a 1559 tx in e.g. an if
clause one can also use a tx.type === 2
switch)
b) if possible likely optimal: add this typeguard after the constructor is called (no idea if this is technically possible, also have no insights on typeguards)
An additional thought: could we also refactor the _signedTxImplementsEIP155 (packages\tx\src\legacyTransaction.ts) boolean to use that supportsEIP method also?
Yes, I will add this along the rework, makes super-much sense, txs working in a EIP-155 context is a super-important tx capability and we are dealing with this in a far too implicit manner for my taste right now. I guess we need to go the way here to deprecate _signedTxImplementsEIP155()
methods - even if considered private - since there is some higher chance that people are calling this specific one for various custom reasons.
An additional thought: could we also refactor the |
Thanks for not merging this in yet and continue on the discussion, I also had some additional thoughts on this and think this is better off with some rework (@acolytec3 so far with: merging early is always/mostly good, lol 😛). I think the semantics on this is really tricky here. I thought a bit more on this confusion Andrew had - and I initially had as well - with the similarity to the Common The naming I've chosen here with tx.active(Capabilities.EIP1559_FEE_MARKET) I guess that's a lot more accurate and descriptive (I first had Side note: I will finally try out enums in JavaScript to be on the safe side here. Long story short (not really possible any more, lol 😜): I am so convinced here that I will directly give this a rework. Will make a local copy of my branch though in case anyone has strong arguments to revert. |
Ok, I finally made the enum test for JavaScript (not sure if this ever was an issue for you, but for me it was). So I did the following TypeScript script: export enum Hello {
World = "world",
Everyone = "everyone",
}
export function hello(to: Hello) {
return `Hello ${to}`
} This can be used from another TypeScript file like this: import { Hello } from './hello'
import { hello } from './hello'
hello(Hello.World) // 'Hello world' Then I have compiled the first "library" (lol) file with const Hello = require('./hello').Hello
const hello = require('./hello').hello
hello(Hello.World) // 'Hello world' This works pretty well, call syntax is the same, so I guess we are fine to use here (and for other use cases). 😄 |
Update: argh, sorry for this back-and-forth, but when seeing this transaction signature usage a bit I was first thinking "hmm, and then again the |
…rts(capability: Capabilities)
…bility switch, refactored EIP-155 related signature code, deprecated (private) _signedTxImplementsEIP155() and _unsignedTxImplementsEIP155() methods
…x after spuriousDragon with a non-EIP155 conforming signature and want to recreate the signature
Ok, also added EIP-155 as a capability in 505c856, this comes along with some substantial reworking of the code. Generally I am pretty happy with this, nevertheless would need a somewhat thorough review. One test was failing on this and I had to add a somewhat ugly hack in 1c29006 to get this fixed. This is for a very questionable special case, the test is Phew. On first thought I wonder if Would be interested to hear a short statement from @alcuadrado on this, Patricio, wonder if this test actually also has been added by you? In doubt I guess we could live with this hack though. The overall EIP-155 related signing code is a lot cheaper now in return and the hack is very much isolated. Ok. Ready for review. 😄 |
… restrict too much on tx customization/subclassing
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.
A lot of the details here are new to me so I would certainly defer to @ryanio and others for official approval, but the tx.supports()
and Capabilities
enum pattern makes sense to me, and none of the code changes jumped out to me as problematic. 👍
looks really great, I didn't have time to do a full review tonight but will do in the morning! |
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.
looks awesome, love how this PR ended up and really enjoying the improved code and readability.
Fixes #1242 respectively addresses #1313
Ok, this is now addressing the
tx.transactionType
,tx.type
and - especiallytx instance of
comparison issue (browser compatibility & being future proof on feature vs tx type comparison).I thought a bit longer about comparing with enum strings vs. comparing with EIP numbers. At the end I gave comparing with EIP numbers a preference since this aligns relatively well with existing Common syntax on lines like
if (opts.tx.supportsEIP(2718) && this._common.isActivatedEIP(2718)) {
and I personally find this simpler for this very much limited set of EIPs (which will also likely grow very slowly) since one is avoiding an additional import. Last reason: I am still not so sure if JavaScript works so well with enums (but was also too lazy to properly look this up TBH since I already had these previously stated reasons).@ryanio let me know if you go along, we can also still change with a limited amount of additional work for changing.
Still WIP, need to replace some more occurrences, just wanted to push early to see if tests - especially on the VM - will pass.