Commit 692ca3ff authored by Mark Tyneway's avatar Mark Tyneway Committed by GitHub

state-surgery: handle empty label bug (#3262)

Someplace in foundry it seems to not populate the
key value correctly in the compiler storage layout type.
Unclear why its not always populated, it is in some cases
but not all. It could be anywhere between solc, foundry and
the foundry hardhat plugin.

The information is still there, it just needs to be parsed
from a different field. This PR uses a regex to parse the value
to pull it out. It recursively calls itself and we can be sure
that it will not infinitely recurse because a non empty string
is passed in the second time.

With this PR, I am able to successfully build the L2 genesis
state.

bugfix

fix
Co-authored-by: default avatarmergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
parent 1c42c5f7
...@@ -5,6 +5,7 @@ import ( ...@@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"math/big" "math/big"
"reflect" "reflect"
"regexp"
"strings" "strings"
"github.com/ethereum-optimism/optimism/state-surgery/solc" "github.com/ethereum-optimism/optimism/state-surgery/solc"
...@@ -24,7 +25,6 @@ func EncodeStorageKeyValue(value any, entry solc.StorageLayoutEntry, storageType ...@@ -24,7 +25,6 @@ func EncodeStorageKeyValue(value any, entry solc.StorageLayoutEntry, storageType
encoded := make([]*EncodedStorage, 0) encoded := make([]*EncodedStorage, 0)
key := encodeSlotKey(entry) key := encodeSlotKey(entry)
switch storageType.Encoding { switch storageType.Encoding {
case "inplace": case "inplace":
switch label { switch label {
...@@ -90,11 +90,11 @@ func EncodeStorageKeyValue(value any, entry solc.StorageLayoutEntry, storageType ...@@ -90,11 +90,11 @@ func EncodeStorageKeyValue(value any, entry solc.StorageLayoutEntry, storageType
} }
keyEncoder, err := getElementEncoder(storageType.Key) keyEncoder, err := getElementEncoder(storageType, "key")
if err != nil { if err != nil {
return nil, err return nil, err
} }
valueEncoder, err := getElementEncoder(storageType.Value) valueEncoder, err := getElementEncoder(storageType, "value")
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -114,6 +114,7 @@ func EncodeStorageKeyValue(value any, entry solc.StorageLayoutEntry, storageType ...@@ -114,6 +114,7 @@ func EncodeStorageKeyValue(value any, entry solc.StorageLayoutEntry, storageType
hash := crypto.Keccak256(preimage[:]) hash := crypto.Keccak256(preimage[:])
key := common.BytesToHash(hash) key := common.BytesToHash(hash)
val, err := valueEncoder(rawVal, 0) val, err := valueEncoder(rawVal, 0)
if err != nil { if err != nil {
return nil, err return nil, err
...@@ -138,19 +139,53 @@ func encodeSlotKey(entry solc.StorageLayoutEntry) common.Hash { ...@@ -138,19 +139,53 @@ func encodeSlotKey(entry solc.StorageLayoutEntry) common.Hash {
type ElementEncoder func(value any, offset uint) (common.Hash, error) type ElementEncoder func(value any, offset uint) (common.Hash, error)
// getElementEncoder will return the correct ElementEncoder // getElementEncoder will return the correct ElementEncoder
// given a solidity type. // given a solidity type. The kind refers to the key or the value
func getElementEncoder(kind string) (ElementEncoder, error) { // when getting an encoder for a mapping. This is only useful
switch kind { // if the key itself is not populated for some reason.
func getElementEncoder(storageType solc.StorageLayoutType, kind string) (ElementEncoder, error) {
var target string
if kind == "key" {
target = storageType.Key
} else if kind == "value" {
target = storageType.Value
} else {
return nil, fmt.Errorf("unknown storage %s", kind)
}
switch target {
case "t_address": case "t_address":
return EncodeAddressValue, nil return EncodeAddressValue, nil
case "t_bool": case "t_bool":
return EncodeBoolValue, nil return EncodeBoolValue, nil
default: default:
if strings.HasPrefix(kind, "t_uint") { if strings.HasPrefix(target, "t_uint") {
return EncodeUintValue, nil return EncodeUintValue, nil
} }
} }
return nil, fmt.Errorf("unsupported type: %s", kind)
// Special case fallback if the target is empty, pull it
// from the label. This requires knowledge of whether we want
// the key or the value in the label.
if target == "" {
r := regexp.MustCompile(`mapping\((?P<key>[[:alnum:]]*) => (?P<value>[[:alnum:]]*)\)`)
result := r.FindStringSubmatch(storageType.Label)
for i, key := range r.SubexpNames() {
if kind == key {
res := "t_" + result[i]
layout := solc.StorageLayoutType{}
if kind == "key" {
layout.Key = res
} else if kind == "value" {
layout.Value = res
} else {
return nil, fmt.Errorf("unknown storage %s", kind)
}
return getElementEncoder(layout, kind)
}
}
}
return nil, fmt.Errorf("unsupported type: %s", target)
} }
// EncodeBytes32Value will encode a bytes32 value. The offset // EncodeBytes32Value will encode a bytes32 value. The offset
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment