Fixes a rather rare state root computation edge case that affected Ethereum mainnet block 20527346.
The contract deployed at 0xfd8C3ACD4187aA14FE7D7e28E498dd6e5Df4A1D0 had exactly 3 storage slots used before this block. All these slots shared no prefix, and therefore sit on the root branch node as 3 child nodes.
The block cleared 2 out of the 3 storage slots, leaving only one slot behind. This slot then becomes a root leaf node. That is, the root node turns from a branch node into a leaf node. In general, this bug is triggered when the only one child of the root branch node is left.
This process of turning a parent branch node into a leaf node has been implemented with #7. However, the very condition of checking whether such a conversion is needed stayed incorrect. When checking for the existence of a lower (left) neighbour, the code checks for whether the last inserted key shares the same parent as the current node. This check gives false positive for the first node, as both the "last inserted key" and "parent key" are empty, so the "starts with" check is always true.
The fix is simple - we just have to check whether the last inserted key is empty when checking the existence of a lower neighbour. When the last key is empty there's no left (lower) neighbour and it should always be false.
As usual, a new test case has been added to target this bug.
Fixes a rather rare state root computation edge case that affected Ethereum mainnet block
20527346
.The contract deployed at
0xfd8C3ACD4187aA14FE7D7e28E498dd6e5Df4A1D0
had exactly 3 storage slots used before this block. All these slots shared no prefix, and therefore sit on the root branch node as 3 child nodes.The block cleared 2 out of the 3 storage slots, leaving only one slot behind. This slot then becomes a root leaf node. That is, the root node turns from a branch node into a leaf node. In general, this bug is triggered when the only one child of the root branch node is left.
This process of turning a parent branch node into a leaf node has been implemented with #7. However, the very condition of checking whether such a conversion is needed stayed incorrect. When checking for the existence of a lower (left) neighbour, the code checks for whether the last inserted key shares the same parent as the current node. This check gives false positive for the first node, as both the "last inserted key" and "parent key" are empty, so the "starts with" check is always
true
.The fix is simple - we just have to check whether the last inserted key is empty when checking the existence of a lower neighbour. When the last key is empty there's no left (lower) neighbour and it should always be
false
.As usual, a new test case has been added to target this bug.