Try   HackMD

Besu Hive Test UncleFromSideChain Analysis

Analysis of failure of UncleFromSideChain_Merge and UncleFromSideChain_Shanghai. They have the same cause but will take an in-depth dive of UncleFromSideChain_Shanghai as an illustration.

Test Description

  • Import block 1 through 8 in order.
  • Block 1 - 3 corresponds to blocknumber 1 through 3 on chainname='A'
  • Block 4 - 8 are on chainname='B'. blocknumber for these blocks is 1, 2, 3, 4, 4 in the respective order
  • Block 7 is intentially be a bad block
  • Timestamp of block 8 is greater than block 3
  • Expected outcome upon calling eth_getBlockByNumber for the latest block should be block 8 but Besu returns block 3

Observation

Link to the Hive test containing the blocks used

Relevant Log:

last block hash mismatch:
  want 0x020a8cc6958317b1abc36780cd99e108c39955224714e48fcbd0df9f43e77a0c
   got 0x79fdf23dcf96d045cd41127ee3f0d061e70d9558212682c29142f9fc49a83842
block response: {
  "baseFeePerGas": "0xc",
  "difficulty": "0x0",
  "extraData": "0x42",
  "gasLimit": "0x2fefd8",
  "gasUsed": "0x5208",
  "hash": "0x79fdf23dcf96d045cd41127ee3f0d061e70d9558212682c29142f9fc49a83842",
  "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  "miner": "0x8888f1f195afa192cfee860698584c030f4c9db1",
  "mixHash": "0x0000000000000000000000000000000000000000000000000000000000020000",
  "nonce": "0x0000000000000000",
  "number": "0x3",
  "parentHash": "0x928172cd14600429d6057b2ff2366ecd32e694311f0d81b1cddbd8529b82ebed",
  "receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2",
  "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
  "size": "0x286",
  "stateRoot": "0x6f448c8c35eaff8ed4f1e1df9f0f39577c5bd60fbea662d7bbcb9d87b461888a",
  "timestamp": "0x54c99839",
  "totalDifficulty": "0x0",
  "transactions": [
    "0x3fdff461f477669637750436e50082c5c7d3a71765521045eef506363a0f31ab"
  ],
  "transactionsRoot": "0x8c8775e959d553f9f991a21a8502dbe6819c53c518711f2cbbbd7ed998f65647",
  "uncles": [],
  "withdrawals": [],
  "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"
}

Code Analysis

Latest eth_getBlockByNumber looks up the head block of the DefaultBlockChain here, which has block 3 as the head block, and hence returning the undesired result.

When importing block 4-8, the DefaultBlockChain's head block (chainHeader) was never switched, because handleChainReorg() was never triggered due to condition blockChoiceRule.compare(newBlock.getHeader(), chainHeader) > 0 was never met here.

The above condition was failed, not because of the total difficulty (They both have same total difficult ie. 0), but because the blockChoiceRule was overwritten here. This is triggered by PostMergeContext.setIsPostMerge during createController() in BlocksSubCommand()