Skip to content

RPC API Headers doesn't match actual block header #1247

@Lohann

Description

@Lohann

Description
I'm building an ethereum light-client, and one of the steps is verifying the block hash, however there's a mismatch between the block header returned by the RPC API and the actual header stored, as such I cannot recompute the block hash, preventing frontier from working with ethereum light-clients that relies on the RPC API.

After a investigation I realized this happens because of two issues:

  1. The block header stores the timestamp in milliseconds, while the API converts it to seconds: https://github.com/polkadot-evm/frontier/blob/pallet-evm-v5.0.0/client/rpc/src/eth.rs#L135
  2. The RPC API returns the baseFeePerGas field, but this field is not encoded in the header. EIP-1559 says this field MUST be part of the block header:
  1. The timestamp is important for TIMESTAMP opcode, a ethereum light-client relies on getting the contract state using eth_createAccessList and eth_getProof for executing the call locally, by returning the wrong timestamp the light-client and the real node will get different results.

Example, the eth_getBlockByNumber endpoint returns:

{
  "author": "0xf02ddb48eda520c915c0dabadc70ba12d1b49ad2",
  "baseFeePerGas": "0x1e4073dfbf",
  "difficulty": "0x0",
  "extraData": "0x",
  "gasLimit": "0xe4e1c0",
  "gasUsed": "0x4e6b11",
  "hash": "0x84471574a6645fe3c4ea4fa7fb588f53f8cea681dd92d27d2de7c23f3040a7aa",
  "logsBloom": "0x825080001000080802020000108400509000410406003440c08000402084300000021000910005c000300400022000004b000000210228020008001c31208000000008418c21101800082008c04880020408240008008c008200400ac22010448401040002820001000000080000080002030000020180030000001480988003240082802888080802200164000010208024040b0810a0004041208004200060224000400200040002b20b0409016048a1020080100210102001f12c40000ac0880144020048000603280802800014210400001001240001018022008400a100001908900000830420000018000260000800000640001040004600012c000060",
  "miner": "0xf02ddb48eda520c915c0dabadc70ba12d1b49ad2",
  "nonce": "0x0000000000000000",
  "number": "0x4a1dbd",
  "parentHash": "0x93434fec7bb917a3fdf071d43e6bda1061eab7c4d5663192ad88353925b49849",
  "receiptsRoot": "0x088e158e77aa12898ed02e3ec20f030cd18054cd56890ad56a78a7ffadd4f5f3",
  "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
  "size": "0x11f8",
  "stateRoot": "0xa7b30b5144ee34730d42b8ea7b5f240d830190ad83b098ddce0e89978ea1055a",
  "timestamp": "0x6551a2be",
  "totalDifficulty": "0x0",
  "transactions": [
	  "0xc42bbbe43ffbaa15c3f6fdd335eba12adf37520313d15b5496e77a67fbd35b1d",
	  "0x3df5b3ddaab690c68ed9e94cc086f210555d8ecc39c34aad292e8bd623b827d7",
	  "0xf708668e3002ec8a079e803e041091d8d5f2a7c3161a75c5c40592c18a9c67d2",
	  "0x5411f16773adac1f407d0161d3a0627fece66479e244d040d856e065794d4f04",
	  "0x0ba4819248cd220f1beb3f72482ef15f14121d7ab28d2deab0656452945db38b",
	  "0x9e01fd45eedbdf68665531dc9795f97c7a130b6bfbe633095b92f94a21c96adb",
	  "0xe227e458184c315517ea2c926d6505a6d53528d86acc1b29758f7c85e42a9821"
  ],
  "transactionsRoot": "0xa34082f12ca71f5b7111e910ed9fb1350e5692a09456a37edc791f055e0603e5",
  "uncles": []
}

But for correctly represent the block header, it should omit the baseFeePerGas and return the correct timestamp:

{
  "author": "0xf02ddb48eda520c915c0dabadc70ba12d1b49ad2",
  "difficulty": "0x0",
  "extraData": "0x",
  "gasLimit": "0xe4e1c0",
  "gasUsed": "0x4e6b11",
  "hash": "0x84471574a6645fe3c4ea4fa7fb588f53f8cea681dd92d27d2de7c23f3040a7aa",
  "logsBloom": "0x825080001000080802020000108400509000410406003440c08000402084300000021000910005c000300400022000004b000000210228020008001c31208000000008418c21101800082008c04880020408240008008c008200400ac22010448401040002820001000000080000080002030000020180030000001480988003240082802888080802200164000010208024040b0810a0004041208004200060224000400200040002b20b0409016048a1020080100210102001f12c40000ac0880144020048000603280802800014210400001001240001018022008400a100001908900000830420000018000260000800000640001040004600012c000060",
  "miner": "0xf02ddb48eda520c915c0dabadc70ba12d1b49ad2",
  "nonce": "0x0000000000000000",
  "number": "0x4a1dbd",
  "parentHash": "0x93434fec7bb917a3fdf071d43e6bda1061eab7c4d5663192ad88353925b49849",
  "receiptsRoot": "0x088e158e77aa12898ed02e3ec20f030cd18054cd56890ad56a78a7ffadd4f5f3",
  "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
  "size": "0x11f8",
  "stateRoot": "0xa7b30b5144ee34730d42b8ea7b5f240d830190ad83b098ddce0e89978ea1055a",
  "timestamp": "0x18bc6e3b748",
  "totalDifficulty": "0x0",
  "transactions": [
	  "0xc42bbbe43ffbaa15c3f6fdd335eba12adf37520313d15b5496e77a67fbd35b1d",
	  "0x3df5b3ddaab690c68ed9e94cc086f210555d8ecc39c34aad292e8bd623b827d7",
	  "0xf708668e3002ec8a079e803e041091d8d5f2a7c3161a75c5c40592c18a9c67d2",
	  "0x5411f16773adac1f407d0161d3a0627fece66479e244d040d856e065794d4f04",
	  "0x0ba4819248cd220f1beb3f72482ef15f14121d7ab28d2deab0656452945db38b",
	  "0x9e01fd45eedbdf68665531dc9795f97c7a130b6bfbe633095b92f94a21c96adb",
	  "0xe227e458184c315517ea2c926d6505a6d53528d86acc1b29758f7c85e42a9821"
  ],
  "transactionsRoot": "0xa34082f12ca71f5b7111e910ed9fb1350e5692a09456a37edc791f055e0603e5",
  "uncles": []
}

Steps to Reproduce

To reproduce the issue above, simply build the Header using the block returned by the eth_getBlockBy* and notice the hash doesn't match:

use ethereum::Header;
use hex_literal::hex;

let header = Header {
    parent_hash: hex!("93434fec7bb917a3fdf071d43e6bda1061eab7c4d5663192ad88353925b49849").into(),
    ommers_hash: hex!("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347").into(),,
    beneficiary: hex!("f02ddb48eda520c915c0dabadc70ba12d1b49ad2").into(),
    state_root: hex!("a7b30b5144ee34730d42b8ea7b5f240d830190ad83b098ddce0e89978ea1055a").into(),
    transactions_root: hex!("a34082f12ca71f5b7111e910ed9fb1350e5692a09456a37edc791f055e0603e5").into(),
    receipts_root: hex!("088e158e77aa12898ed02e3ec20f030cd18054cd56890ad56a78a7ffadd4f5f3").into(),
    logs_bloom: hex!("825080001000080802020000108400509000410406003440c08000402084300000021000910005c000300400022000004b000000210228020008001c31208000000008418c21101800082008c04880020408240008008c008200400ac22010448401040002820001000000080000080002030000020180030000001480988003240082802888080802200164000010208024040b0810a0004041208004200060224000400200040002b20b0409016048a1020080100210102001f12c40000ac0880144020048000603280802800014210400001001240001018022008400a100001908900000830420000018000260000800000640001040004600012c000060").into(),
    difficulty: Default::default(),
    number: 0x004a1dbd.into(),
    gas_limit: 0x00e4e1c0.into(),
    gas_used: 0x004e6b11.into(),
    timestamp: 0x6551a2be,
    extra_data: Default::default(),
    mix_hash: Default::default(),
    nonce: Default::default(),
};

let expected = hex!("84471574a6645fe3c4ea4fa7fb588f53f8cea681dd92d27d2de7c23f3040a7aa").into();
let actual = header.hash();
assert_eq(expected, actual);

For testing the baseFeePerGas example, see the reth RLP encoder as reference:
https://github.com/paradigmxyz/reth/blob/v0.1.0-alpha.10/crates/primitives/src/header.rs#L324-L391

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions