-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Description
This is a mischievious edge case that has gone unnoticed (AFAIK) for a few years, yet it was uncovered while investigating a report from Recall folks.
Original report
Running this script to deploy Safe on an IPC subnet fails due to an eth_call returning an empty return value. This is the error thrown by the script.
Luckily, our reporter was able to isolate and reproduce the issue with a single request:
$ curl -s https://... \
--header "Content-Type: application/json" \
--data '{
"jsonrpc": "2.0",
"method": "eth_call",
"params": [
{
"data": "0x604580600e600039806000f350fe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3"
},
"latest"
],
"id": 1
}'
{"jsonrpc":"2.0","result":"0x","id":1}
Whereas running this request against Sepolia returns the following:
{
"jsonrpc": "2.0",
"id": 1,
"result": "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3"
}
The script in question is verifying the chain's behaviour by simulating the deployment of a minimal CREATE2 factory contract via eth_call, and expecting the node to return the effectively deployed bytecode after evaluating the supplied initcode. It then goes on to perform a hash assertion on that value, which fails.
What's going on?
When a contract is deployed, the bytecode sent as data in the deployment transaction is interpreted as the "initcode". Whatever value is RETURNed from the initcode becomes the effectively deployed bytecode on-chain.
In Ethereum:
- When executed in the context of a transaction, the node elides the return value from the transaction receipt (probably for efficiency reasons).
- When executed in the context of a call, the node does not override the default behaviour and simply propagates the return value from the EVM in the response.
In Filecoin:
- The EAM (Ethereum Address Manager) doesn't return the deployed bytecode to the client.
- In our design, the EAM creates the EVM actor via the InitActor, which in turn creates the actor in the state tree and invokes its constructor supplying the initcode. The EVM constructor evaluates the initcode and stores the bytecode in its own state, i.e. all our deployment logic sits in actors and is well encapsulated, whereas in Ethereum the client is responsible for updating the state tree. Hence the client must have access to the return value.
Easy solution
The affected behaviour is not consensus-critical. The mismatch could be patched in the Eth JSON-RPC server by querying the saved bytecode after a contract deployment call for first-order contract creations. For indirect creations, there's nothing to worry about (CREATE* opcodes don't return the bytecode anyway).
I guess the hard part is querying the "intermediate" state tree from the Eth JSON-RPC server implementation in Lotus. But there's several ways to overcome that implementation detail.
Metadata
Metadata
Assignees
Labels
Type
Projects
Status