go-ethereum icon indicating copy to clipboard operation
go-ethereum copied to clipboard

Native callTracer: missing CREATE2 frames where out of gas occur

Open tanmaster opened this issue 3 years ago • 5 comments

System information

Geth version: 1.10.22-unstable OS & Version: Ubuntu 20.04 LTS, 5.4.0-121-generic Commit hash : 9d76a9b94f1d4f8b8a9c212151d96d6a13cb6ead

I am trying to migrate our datasource from openethereum to geth. For obtaining the same data, we want to use the tracer API of geth. When comparing data that we got from openethereum with geth, I can observe a very small discrepancy.

Expected behaviour

In instances where CREATE2 frames error out because the execution went out of gas, this seems not to be accurately depicted by geth. According to geth, the frame in which the "out of gas" occurs is the top level call frame, rather than the CREATE2 frame (which is missing in the result entirely).

Using the example below, I would expect the result to look similar to this:

{
  "result": {
    "type": "CALL",
    "from": "0xb59bff945a74a427c74fb27ae423fcf81da27c24",
    "to": "0xffa397285ce46fb78c588a9e993286aac68c37cd",
    "value": "0x0",
    "gas": "0x267a6",
    "gasUsed": "0x267a6",
    "input": "0xfb90b320000000000000000000000000c9b0576f11635e88cc040ebf13ef57f326f553110000000000000000000000000000000000000000000000000000000000000183",
    "error": "out of gas",
    "calls":[{
      "type": "CREATE2",
      "from": "0xffa397285ce46fb78c588a9e993286aac68c37cd",
      "value": "0x0",
      "input": "0x3d602d80600a3d3981f3363d3d373d3d3d363d73059ffafdc6ef594230de44f824e2bd0a51ca5ded5af43d82803e903d91602b57fd5bf3",
      "gas": "0x1d8a7",
      "gasUsed": "0x1d8a7",
      "error": "out of gas"
    }]
  }
}

Actual behaviour

In the block range from 14992579 to 14999613 I was able to find seven such instances, all of them involving CREATE2 and out of gas:

block tx
14992579 70
14993975 100
14993997 90
14997259 62
14997534 128
14999176 209
14999613 271

Steps to reproduce the behaviour

  • nc -U geth.ipc
  • example with the first entry in the table above: {"jsonrpc": "2.0", "id": 1, "method": "debug_subscribe", "params": ["traceChain", "0xe4c4c2", "0xe4c4c3", {"tracer": "callTracer", "reexec": 2500000}]}
  • the full result can be viewed here, but the relevant part can be navigated to like this:
    • res['params']['result']['traces'][70], which in this case gives:
{
  "result": {
    "type": "CALL",
    "from": "0xb59bff945a74a427c74fb27ae423fcf81da27c24",
    "to": "0xffa397285ce46fb78c588a9e993286aac68c37cd",
    "value": "0x0",
    "gas": "0x267a6",
    "gasUsed": "0x267a6",
    "input": "0xfb90b320000000000000000000000000c9b0576f11635e88cc040ebf13ef57f326f553110000000000000000000000000000000000000000000000000000000000000183",
    "error": "out of gas"
  }
}

Let me know if there's anything else I can do to help recreate this problem.

tanmaster avatar Sep 01 '22 12:09 tanmaster

Interesting. Just to make things clear, there are several things which could be going on here, so let's first define them.

  1. The CREATE2 call goes OOG. The CREATE2 opcode costs 32000 gas up front, plus a dynamic part depending on 1) the memory expansion and 2) the size of the initcode. This is still in the outer context.
  2. The CREATE2 starts executing the initcode, but goes OOG while this is executing.
  3. The initcode executes fine, but the returned runtime_bytecode cannot be stored on-chain, because the dynamic cost of len(code) * params.CreateDataGas (200) causes OOG.

IMO the best thing to do would be to make some pretty simple testcases of these three cases, and take it from there. I can look into it at some point, but it will probably take a few weeks.

Case 1 is definitely in the outer context, case 2 is definitely in the inner context. Case 3 is not as clear-cut IMO.

holiman avatar Sep 01 '22 12:09 holiman

Kindly open this live chat link to talk to the customer service directly on your issue https://direct.lc.chat/14571264/

Jezz12-cloud avatar Oct 04 '22 07:10 Jezz12-cloud

I'll take a look into this.

jwasinger avatar Oct 20 '22 15:10 jwasinger

I'll take a look into this.

Any luck so far?

tanmaster avatar Nov 15 '22 14:11 tanmaster

I got a bit busy and forgot about this. For the reported transactions with discrepancies, I retrieved the tx hash and an opcode trace of each transaction: https://gist.github.com/jwasinger/1cda01680a5ff66bb0061f02a6a6da9a .

There are two transactions which fail during the execution of the create2 initcode. The rest fail in the parent context.

jwasinger avatar Jan 10 '23 05:01 jwasinger

for 0x666bab2c4b14cd7bd2131d29064b30343a65865e646fb57b306b0f8884c82104 and 0xb2eaa48e39a21d5a34a4474c9722d4796b701b1f84af9b0f5f816ff7db4e447d, the out of gas is caused because the init code does not have enough gas remaining to create the contract after it finishes.

I recreated this situation locally and the results using the call tracer are correct for me.

jwasinger avatar Jan 12 '23 04:01 jwasinger

out of gas was checked before entering the Create scope, so there would be no frame trigged

jsvisa avatar Apr 03 '23 03:04 jsvisa

This will be possible fixed by #27629. We are increasing the scope of CaptureExit/CaptureEnd and CaptureTxEnd to capture errors that happen during validation.

s1na avatar Aug 07 '23 16:08 s1na