Statement regarding Geth v1.10.8 split

The statement of Callisto Network

The described accident was not a result of the EVM bug but a result of miscoordination in the client update. Ethereum developers introduced breaking changes in their Geth v1.10.8 release that affected consensus rules and these changes must have been implemented during the hardfork instead.

The attack

Here you can find a transaction that triggered the chain split on Ethereum mainnet: https://etherscan.io/tx/0x1cb6fb36633d270edefc04d048145b4298e67b8aa82a9e5ec4aa1435dd770ce4

Investigating the EVM exploit

Let’s analyze the “attack” to understand why this happened.

  • [0] ADDRESS
  • [1] CALLVALUE
  • [2] MSTORE
  • [4] PUSH1 0x20
  • [6] PUSH1 0x07
  • [8] PUSH1 0x20
  • [9] CALLVALUE
  • [11] PUSH1 0x04
  • [12] GAS
  • [13] STATICCALL
  • [15] PUSH1 0x20
  • [16] CALLVALUE
  • [17] CALLVALUE
  • [18] RETURNDATACOPY
  • [20] PUSH1 0x40
  • [21] CALLVALUE
  • [22] RETURN
  1. The contract is going to store the address of a newly created contract in the memory. For this matter it calls [0] ADDRESS [1] CALLVALUE and then [2] MSTORE opcodes where the first two are the inputs for the MSTORE. So the contract takes the address of a newly created contract and pushes it onto the stack. Then it pushes value 0 onto the stack (because no value is provided for CALLVALUE opcode. Then it takes the contract address from the stack and pushes it into the contract memory (the stack is cleared).
  2. Next the contract is performing the [13] STATICCALL and here are the inputs: [4] PUSH1 0x20 [6] PUSH1 0x07 [8] PUSH1 0x20 [9] CALLVALUE [11] PUSH1 0x04 [12] GAS. You can find the description of what STATICCALL is actually doing here.
    In this case STATICCALL should invoke the contract at address 0x04, it should provide all remaining GAS for this invocation, it should provide first 32 bytes of memory as input data (memory was filled at pt.1), it should take the result of the invocation and put 32 bytes into memory starting at byte 7.
    It is important to note here that the 0x04 address is a special target for this call — it’s a precompiled contract called “Identity Precompile”. It takes the data you provide it and the returns it back (can be used for some optimization reasons). You can read more about precompiled contracts here.
  3. Let’s dive into what is going on inside of the STATICCALL in Geth. Here the args variable is a pointer to the contracts memory. It is passed to the Identity Precompile and the returned value is the same pointer to the contracts memory. The important thing here is that the implementation of CALL, CALLCODE, STATICCALL and DELEGATECALL in Geth was changed on August 24, 2021 with this commit. If we take a look at the previous implementation then we can find out that it was a bit different (watch previous version of the instructions.go ). Now “old nodes” think that the value of ret variable is a pointer to the contracts memory but the “new nodes” think it is the value.
  4. At this line “old nodes” shifted the value of ret variable when trying to store this in memory (ret is a pointer to that exact memory) by 7 bytes.
  5. [15] PUSH1 0x20 [16] CALLVALUE [17] CALLVALUE [18] RETURNDATACOPY these opcodes copy 32 bytes of ret into the memory (at this point “old nodes” and “new nodes” have it different already).
  6. [20] PUSH1 0x40 [21] CALLVALUE [22] RETURN these opcodes finish the execution returning 64 bytes of the memory i.e. make the returned 64 bytes of memory a new contract’s bytecode. At this point “old nodes” and “new nodes” disagree with each other how the code of the newly created contract must look like and therefore they can’t accept each others version of a block that includes the transaction of contract creation. This is the chain split.

Conclusion

Geth v1.10.8 release contains a bugfix for the EVM exploit. This bug could not cause a chain split on its own however. What caused the chain split was a rushed fix that changed consensus rules. Ethereum developers should have called it a HardFork, but not released as a regular client update.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store