mds1 / evm-diff

Diff EVM-compatible chains in a friendly format
https://evmdiff.com
MIT License
272 stars 27 forks source link

feat: transaction types #68

Open mds1 opened 2 months ago

mds1 commented 2 months ago

These were removed as part of #62 and should be added back. I'm not sure if there is a good way to automatically detect transaction types, so we may need to instead define a set of known transaction types, along with the test data for each (e.g. an RPC method name + associated input data)

fvictorio commented 2 months ago

I looked a bit into this, trying to find a way to detect support for EIP-1559 and EIP-4844 txs.

EIP-1559

My first attempt was to just make an eth_call with maxFeePerGas and maxPriorityFeePerGas fields, but this doesn't work: if a property is unknown, it seems to just be ignored, at least by most nodes.

What I ended up doing is sending an eth_call that executes this bytecode:

GASPRICE
PUSH1 0x00
MSTORE
PUSH1 0x20
PUSH1 0x00
RETURN

which returns the gas price. If you send a call with that input data and a gas price of 0x1234567890, then the return data is 1234567890. But if you send a call with both maxFeePerGas and maxPriorityFeePerGas of 0x1234567890, you won't get that expected value.

Now, there are two things that make this a bit harder to use in practice:

  1. The gas price used has to be bigger than the current base fee. Using a big value might be good enough to work around this problem.
  2. When I tried this in Polygon zkEVM, my first attempts were rejected because the sender didn't have enough balance. So I had to use a from address with some balance to make it work. This means that the test cases should have addressses that have enough balance and are unlikely to reduce that balance. At the moment of writing this, the zero address only has 0.077 ETH, but that coupled with a lower gas price could be enough.

EIP-4844

For this, I think it's enough to make an eth_call with {blobs: ["0x"], blobVersionedHashes: ["0x"]}. Both mainnet and optimism fail with this message: invalid argument 0: hex string has length 0, want 262144 for kzg4844.Blob.

But Arbitrum doesn't fail. Maybe this is just because they don't support EIP-4844 txs, but I'm not sure that's the case because the BLOBBASEFEE opcode is supported (at least according to evmdiff.com 😛)

Pending work

The three mainnet transaction types not currently covered are pre-EIP155 legacy txs, post-EIP155 legacy txs and access list txs. The latter might be done with estimateGas and a clever use of the access list. But I'm not sure if there's a way to detect that EIP-155 is supported without actually sending a tx.

fvictorio commented 2 months ago

Access lists are even easier than I thought: just use estimateGas with a plain call with and without an access list entry, and they will return different results, because access list entries have an extra cost.

mds1 commented 2 months ago

This is great, thank you!

EIP-1559

Could an alternative here be to use eth_estimateGas with maxFeePerGas and maxPriorityFeePerGas fields? It feels likely nodes will also ignore them here like they do with eth_call though

But if you send a call with both maxFeePerGas and maxPriorityFeePerGas of 0x1234567890, you won't get that expected value.

What do you get instead? I also wonder how this will behave on arbitrum where 1559 is a bit different, as explained here: https://github.com/mds1/evm-diff/pull/60#issuecomment-1926794404

Now, there are two things that make this a bit harder to use in practice:

We could fetch the base fee beforehand and bump it by e.g. 50% if we want to avoid hardcoding a really big value. But hardcoding something huge is probably just as good and simpler.

I've been wondering if most or all nodes support state overrides, which would be a way we can work around the insufficient balance issue

EIP-4844

Both Optimism and Arbitrum don't support blobs being posted to L2, see here for optimism and here for arbitrum. I wonder if we could also use eth_estimateGas here?

Others

For access lists, can we rely on eth_createAccessList? It seems this is not required by EIP-2930 though, so perhaps not, and I think your idea is probably preferable

fvictorio commented 2 months ago

Could an alternative here be to use eth_estimateGas with maxFeePerGas and maxPriorityFeePerGas fields?

How that would work? The gas price shouldn't affect the gas estimate in almost all cases.

What do you get instead?

You get the default gas price. Whatever that is, it's unlikely to be 0x1234567890 (or whatever number like that we use).

mds1 commented 2 months ago

How that would work? The gas price shouldn't affect the gas estimate in almost all cases.

I was thinking it would error if you try estimating gas with unsupported fields, but I have not yet tested if that's the case or if they get ignored like with eth_call

You get the default gas price. Whatever that is, it's unlikely to be 0x1234567890 (or whatever number like that we use).

Ah I see, that does make sense