Commit be4d2f2e authored by Mark Tyneway's avatar Mark Tyneway Committed by GitHub

Merge pull request #3254 from ethereum-optimism/state-surger/bytes32

state-surgery: implement bytes32 handling
parents 815b6779 2d933448
......@@ -41,6 +41,12 @@ func EncodeStorageKeyValue(value any, entry solc.StorageLayoutEntry, storageType
encoded = append(encoded, &EncodedStorage{key, val})
case "bytes":
return nil, fmt.Errorf("%w: %s", errUnimplemented, label)
case "bytes32":
val, err := EncodeBytes32Value(value, entry.Offset)
if err != nil {
return nil, err
}
encoded = append(encoded, &EncodedStorage{key, val})
default:
switch true {
case strings.HasPrefix(label, "contract"):
......@@ -137,6 +143,42 @@ func getElementEncoder(kind string) (ElementEncoder, error) {
return nil, fmt.Errorf("unsupported type: %s", kind)
}
// EncodeBytes32Value will encode a bytes32 value. The offset
// is included so that it can implement the ElementEncoder
// interface, but the offset must always be 0.
func EncodeBytes32Value(value any, offset uint) (common.Hash, error) {
if offset != 0 {
return common.Hash{}, errors.New("offset must be 0")
}
return encodeBytes32Value(value)
}
// encodeBytes32Value implements the encoding of a bytes32
// value into a common.Hash that is suitable for storage.
func encodeBytes32Value(value any) (common.Hash, error) {
name := reflect.TypeOf(value).Name()
switch name {
case "string":
str, ok := value.(string)
if !ok {
return common.Hash{}, errInvalidType
}
val, err := hexutil.Decode(str)
if err != nil {
return common.Hash{}, err
}
return common.BytesToHash(val), nil
case "Hash":
hash, ok := value.(common.Hash)
if !ok {
return common.Hash{}, errInvalidType
}
return hash, nil
default:
return common.Hash{}, errInvalidType
}
}
// EncodeBoolValue will encode a boolean value given a storage
// offset.
func EncodeBoolValue(value any, offset uint) (common.Hash, error) {
......
......@@ -2,6 +2,7 @@ package state_test
import (
"encoding/json"
"fmt"
"math/big"
"os"
"testing"
......@@ -51,6 +52,7 @@ func TestSetAndGetStorageSlots(t *testing.T) {
values["offset3"] = uint32(0xf33d35)
values["offset4"] = uint64(0xd34dd34d00)
values["offset5"] = new(big.Int).SetUint64(0x43ad0043ad0043ad)
values["_bytes32"] = common.Hash{0xff}
addresses := make(map[any]any)
addresses[big.NewInt(1)] = common.Address{19: 0xff}
......@@ -120,6 +122,13 @@ OUTER:
res, err = contract.Offset4(&bind.CallOpts{})
case "offset5":
res, err = contract.Offset5(&bind.CallOpts{})
case "_bytes32":
res, err = contract.Bytes32(&bind.CallOpts{})
result, ok := res.([32]uint8)
require.Equal(t, ok, true)
require.Nil(t, err)
require.Equal(t, common.BytesToHash(result[:]), value)
continue OUTER
case "addresses":
addrs, ok := value.(map[any]any)
require.Equal(t, ok, true)
......@@ -130,7 +139,7 @@ OUTER:
continue OUTER
}
default:
require.Fail(t, "Unknown variable label", key)
require.Fail(t, fmt.Sprintf("Unknown variable label: %s", key))
}
require.Nil(t, err)
require.Equal(t, res, value)
......@@ -173,6 +182,10 @@ func testContractStateValuesAreEmpty(t *testing.T, contract *testdata.Testdata)
offset5, err := contract.Offset5(&bind.CallOpts{})
require.Nil(t, err)
require.Equal(t, offset5.Uint64(), uint64(0))
bytes32, err := contract.Bytes32(&bind.CallOpts{})
require.Nil(t, err)
require.Equal(t, common.BytesToHash(bytes32[:]), common.Hash{})
}
func TestMergeStorage(t *testing.T) {
......@@ -403,3 +416,25 @@ func TestEncodeAddressValue(t *testing.T) {
require.Equal(t, got, test.expect)
}
}
func TestEncodeBytes32Value(t *testing.T) {
cases := []struct {
bytes32 any
expect common.Hash
}{
{
bytes32: common.Hash{0xff},
expect: common.Hash{0xff},
},
{
bytes32: "0x11ffffff00000000000000000000000000000000000000000000000000000000",
expect: common.HexToHash("0x11ffffff00000000000000000000000000000000000000000000000000000000"),
},
}
for _, test := range cases {
got, err := state.EncodeBytes32Value(test.bytes32, 0)
require.Nil(t, err)
require.Equal(t, got, test.expect)
}
}
......@@ -30,8 +30,8 @@ var (
// TestdataMetaData contains all meta data concerning the Testdata contract.
var TestdataMetaData = &bind.MetaData{
ABI: "[{\"inputs\":[],\"name\":\"_address\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"_bool\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"_uint256\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"addresses\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"key\",\"type\":\"bytes32\"}],\"name\":\"getStorage\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"offset0\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"offset1\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"offset2\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"offset3\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"offset4\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"offset5\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"key\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"value\",\"type\":\"bytes32\"}],\"name\":\"setStorage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]",
Bin: "0x608060405234801561001057600080fd5b506102a4806100206000396000f3fe608060405234801561001057600080fd5b50600436106100b45760003560e01c8063502a6c5e11610071578063502a6c5e1461019a5780635e006859146101cc5780639b0b0fda146101d55780639e6ba9c2146101e9578063a753307d14610206578063edf26d9b1461023357600080fd5b8063099ea180146100b957806309f395f1146100dd57806318bad217146100ef57806332da25e11461011a578063350e81cc146101535780634ba664e71461017a575b600080fd5b6004546100c69060ff1681565b60405160ff90911681526020015b60405180910390f35b6004546100c690610100900460ff1681565b600054610102906001600160a01b031681565b6040516001600160a01b0390911681526020016100d4565b60045461013a9068010000000000000000900467ffffffffffffffff1681565b60405167ffffffffffffffff90911681526020016100d4565b6004546101679062010000900461ffff1681565b60405161ffff90911681526020016100d4565b61018c61018836600461025c565b5490565b6040519081526020016100d4565b6004546101b490600160801b90046001600160801b031681565b6040516001600160801b0390911681526020016100d4565b61018c60035481565b6101e76101e3366004610275565b9055565b005b6002546101f69060ff1681565b60405190151581526020016100d4565b60045461021e90640100000000900463ffffffff1681565b60405163ffffffff90911681526020016100d4565b61010261024136600461025c565b6001602052600090815260409020546001600160a01b031681565b60006020828403121561026e57600080fd5b5035919050565b6000806040838503121561028857600080fd5b5050803592602090910135915056fea164736f6c634300080f000a",
ABI: "[{\"inputs\":[],\"name\":\"_address\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"_bool\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"_bytes32\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"_string\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"_uint256\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"addresses\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"key\",\"type\":\"bytes32\"}],\"name\":\"getStorage\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"offset0\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"offset1\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"offset2\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"offset3\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"offset4\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"offset5\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"key\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"value\",\"type\":\"bytes32\"}],\"name\":\"setStorage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]",
Bin: "0x608060405234801561001057600080fd5b50610415806100206000396000f3fe608060405234801561001057600080fd5b50600436106100ea5760003560e01c80635e0068591161008c5780639b267f09116100665780639b267f09146102285780639e6ba9c21461023d578063a753307d1461025a578063edf26d9b1461028757600080fd5b80635e0068591461020257806393f2b3981461020b5780639b0b0fda1461021457600080fd5b806332da25e1116100c857806332da25e114610150578063350e81cc146101895780634ba664e7146101b0578063502a6c5e146101d057600080fd5b8063099ea180146100ef57806309f395f11461011357806318bad21714610125575b600080fd5b6004546100fc9060ff1681565b60405160ff90911681526020015b60405180910390f35b6004546100fc90610100900460ff1681565b600054610138906001600160a01b031681565b6040516001600160a01b03909116815260200161010a565b6004546101709068010000000000000000900467ffffffffffffffff1681565b60405167ffffffffffffffff909116815260200161010a565b60045461019d9062010000900461ffff1681565b60405161ffff909116815260200161010a565b6101c26101be36600461033e565b5490565b60405190815260200161010a565b6004546101ea90600160801b90046001600160801b031681565b6040516001600160801b03909116815260200161010a565b6101c260035481565b6101c260055481565b610226610222366004610357565b9055565b005b6102306102b0565b60405161010a9190610379565b60025461024a9060ff1681565b604051901515815260200161010a565b60045461027290640100000000900463ffffffff1681565b60405163ffffffff909116815260200161010a565b61013861029536600461033e565b6001602052600090815260409020546001600160a01b031681565b600680546102bd906103ce565b80601f01602080910402602001604051908101604052809291908181526020018280546102e9906103ce565b80156103365780601f1061030b57610100808354040283529160200191610336565b820191906000526020600020905b81548152906001019060200180831161031957829003601f168201915b505050505081565b60006020828403121561035057600080fd5b5035919050565b6000806040838503121561036a57600080fd5b50508035926020909101359150565b600060208083528351808285015260005b818110156103a65785810183015185820160400152820161038a565b818111156103b8576000604083870101525b50601f01601f1916929092016040019392505050565b600181811c908216806103e257607f821691505b60208210810361040257634e487b7160e01b600052602260045260246000fd5b5091905056fea164736f6c634300080f000a",
}
// TestdataABI is the input ABI used to generate the binding from.
......@@ -263,6 +263,68 @@ func (_Testdata *TestdataCallerSession) Bool() (bool, error) {
return _Testdata.Contract.Bool(&_Testdata.CallOpts)
}
// Bytes32 is a free data retrieval call binding the contract method 0x93f2b398.
//
// Solidity: function _bytes32() view returns(bytes32)
func (_Testdata *TestdataCaller) Bytes32(opts *bind.CallOpts) ([32]byte, error) {
var out []interface{}
err := _Testdata.contract.Call(opts, &out, "_bytes32")
if err != nil {
return *new([32]byte), err
}
out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte)
return out0, err
}
// Bytes32 is a free data retrieval call binding the contract method 0x93f2b398.
//
// Solidity: function _bytes32() view returns(bytes32)
func (_Testdata *TestdataSession) Bytes32() ([32]byte, error) {
return _Testdata.Contract.Bytes32(&_Testdata.CallOpts)
}
// Bytes32 is a free data retrieval call binding the contract method 0x93f2b398.
//
// Solidity: function _bytes32() view returns(bytes32)
func (_Testdata *TestdataCallerSession) Bytes32() ([32]byte, error) {
return _Testdata.Contract.Bytes32(&_Testdata.CallOpts)
}
// String is a free data retrieval call binding the contract method 0x9b267f09.
//
// Solidity: function _string() view returns(string)
func (_Testdata *TestdataCaller) String(opts *bind.CallOpts) (string, error) {
var out []interface{}
err := _Testdata.contract.Call(opts, &out, "_string")
if err != nil {
return *new(string), err
}
out0 := *abi.ConvertType(out[0], new(string)).(*string)
return out0, err
}
// String is a free data retrieval call binding the contract method 0x9b267f09.
//
// Solidity: function _string() view returns(string)
func (_Testdata *TestdataSession) String() (string, error) {
return _Testdata.Contract.String(&_Testdata.CallOpts)
}
// String is a free data retrieval call binding the contract method 0x9b267f09.
//
// Solidity: function _string() view returns(string)
func (_Testdata *TestdataCallerSession) String() (string, error) {
return _Testdata.Contract.String(&_Testdata.CallOpts)
}
// Uint256 is a free data retrieval call binding the contract method 0x5e006859.
//
// Solidity: function _uint256() view returns(uint256)
......
......@@ -79,6 +79,22 @@
"offset": 16,
"slot": "4",
"type": "t_uint128"
},
{
"astId": 25,
"contract": "contracts/HelloWorld.sol:HelloWorld",
"label": "_bytes32",
"offset": 0,
"slot": "5",
"type": "t_bytes32"
},
{
"astId": 27,
"contract": "contracts/HelloWorld.sol:HelloWorld",
"label": "_string",
"offset": 0,
"slot": "6",
"type": "t_string_storage"
}
],
"types": {
......@@ -92,6 +108,11 @@
"label": "bool",
"numberOfBytes": "1"
},
"t_bytes32": {
"encoding": "inplace",
"label": "bytes32",
"numberOfBytes": "32"
},
"t_mapping(t_uint256,t_address)": {
"encoding": "mapping",
"key": "t_uint256",
......@@ -99,6 +120,11 @@
"numberOfBytes": "32",
"value": "t_address"
},
"t_string_storage": {
"encoding": "bytes",
"label": "string",
"numberOfBytes": "32"
},
"t_uint128": {
"encoding": "inplace",
"label": "uint128",
......
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