Commit 9ad41460 authored by Mark Tyneway's avatar Mark Tyneway

op-bindings: make deterministic

parent 34a90409
...@@ -13,7 +13,9 @@ compile: ...@@ -13,7 +13,9 @@ compile:
cd $(contracts-dir) && \ cd $(contracts-dir) && \
yarn build yarn build
bindings: compile bindings: compile bindings-build
bindings-build:
go run ./gen/main.go \ go run ./gen/main.go \
-forge-artifacts ../packages/contracts-bedrock/forge-artifacts \ -forge-artifacts ../packages/contracts-bedrock/forge-artifacts \
-out ./bindings \ -out ./bindings \
......
...@@ -11,6 +11,14 @@ import ( ...@@ -11,6 +11,14 @@ import (
var remapTypeRe = regexp.MustCompile(`^(t_[\w_]+\([\w]+\))([\d]+)(_[\w]+)?$`) var remapTypeRe = regexp.MustCompile(`^(t_[\w_]+\([\w]+\))([\d]+)(_[\w]+)?$`)
// typeRemapping represents a mapping between an a type generated by solc
// and a canonicalized type. This is because solc inserts the ast id into
// certain types.
type typeRemapping struct {
oldType string
newType string
}
// CanonicalizeASTIDs canonicalizes AST IDs in storage layouts so that they // CanonicalizeASTIDs canonicalizes AST IDs in storage layouts so that they
// don't cause unnecessary conflicts/diffs. The implementation is not // don't cause unnecessary conflicts/diffs. The implementation is not
// particularly efficient, but is plenty fast enough for our purposes. // particularly efficient, but is plenty fast enough for our purposes.
...@@ -42,16 +50,26 @@ func CanonicalizeASTIDs(in *solc.StorageLayout) *solc.StorageLayout { ...@@ -42,16 +50,26 @@ func CanonicalizeASTIDs(in *solc.StorageLayout) *solc.StorageLayout {
} }
sortedOldTypes.Sort() sortedOldTypes.Sort()
seenTypes := make(map[string]bool)
for _, oldType := range sortedOldTypes { for _, oldType := range sortedOldTypes {
if seenTypes[oldType] || oldType == "" {
continue
}
matches := remapTypeRe.FindAllStringSubmatch(oldType, -1) matches := remapTypeRe.FindAllStringSubmatch(oldType, -1)
if len(matches) == 0 { if len(matches) == 0 {
continue continue
} }
if strings.Contains(oldType, "storage") {
continue
}
replaceAstID := matches[0][2] replaceAstID := matches[0][2]
newType := strings.Replace(oldType, replaceAstID, strconv.Itoa(int(lastId)), 1) newType := strings.Replace(oldType, replaceAstID, strconv.Itoa(int(lastId)), 1)
typeRemappings[oldType] = newType typeRemappings[oldType] = newType
lastId++ lastId++
seenTypes[oldType] = true
} }
outLayout := &solc.StorageLayout{ outLayout := &solc.StorageLayout{
...@@ -71,13 +89,18 @@ func CanonicalizeASTIDs(in *solc.StorageLayout) *solc.StorageLayout { ...@@ -71,13 +89,18 @@ func CanonicalizeASTIDs(in *solc.StorageLayout) *solc.StorageLayout {
for _, oldType := range sortedOldTypes { for _, oldType := range sortedOldTypes {
value := in.Types[oldType] value := in.Types[oldType]
newType := replaceType(typeRemappings, oldType) newType := replaceType(typeRemappings, oldType)
outLayout.Types[newType] = solc.StorageLayoutType{ layout := solc.StorageLayoutType{
Encoding: value.Encoding, Encoding: value.Encoding,
Label: value.Label, Label: value.Label,
NumberOfBytes: value.NumberOfBytes, NumberOfBytes: value.NumberOfBytes,
Key: replaceType(typeRemappings, value.Key), Key: replaceType(typeRemappings, value.Key),
Value: replaceType(typeRemappings, value.Value), Value: replaceType(typeRemappings, value.Value),
} }
if value.Base != "" {
layout.Base = replaceType(typeRemappings, value.Base)
}
outLayout.Types[newType] = layout
} }
return outLayout return outLayout
} }
...@@ -87,6 +110,24 @@ func replaceType(typeRemappings map[string]string, in string) string { ...@@ -87,6 +110,24 @@ func replaceType(typeRemappings map[string]string, in string) string {
return typeRemappings[in] return typeRemappings[in]
} }
// Track the number of matches
matches := []typeRemapping{}
for oldType, newType := range typeRemappings {
if strings.Contains(in, oldType) {
matches = append(matches, typeRemapping{oldType, newType})
}
}
// Sometimes types are nested, so handle the recursive case iteratively
if len(matches) > 1 {
for _, match := range matches {
in = strings.Replace(in, match.oldType, match.newType, 1)
}
return in
}
// Its safe to return on the first match here as the case with multiple
// is handled above
for oldType, newType := range typeRemappings { for oldType, newType := range typeRemappings {
if strings.Contains(in, oldType) { if strings.Contains(in, oldType) {
return strings.Replace(in, oldType, newType, 1) return strings.Replace(in, oldType, newType, 1)
......
...@@ -32,6 +32,10 @@ func TestCanonicalize(t *testing.T) { ...@@ -32,6 +32,10 @@ func TestCanonicalize(t *testing.T) {
"values in storage", "values in storage",
"values-in-storage.json", "values-in-storage.json",
}, },
{
"custom types",
"custom-types.json",
},
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
......
{
"in": {
"storage": [
{
"astId": 59243,
"contract": "contracts/dispute/DisputeGameFactory.sol:DisputeGameFactory",
"label": "_initialized",
"offset": 0,
"slot": "0",
"type": "t_uint8"
},
{
"astId": 59246,
"contract": "contracts/dispute/DisputeGameFactory.sol:DisputeGameFactory",
"label": "_initializing",
"offset": 1,
"slot": "0",
"type": "t_bool"
},
{
"astId": 59671,
"contract": "contracts/dispute/DisputeGameFactory.sol:DisputeGameFactory",
"label": "__gap",
"offset": 0,
"slot": "1",
"type": "t_array(t_uint256)50_storage"
},
{
"astId": 59115,
"contract": "contracts/dispute/DisputeGameFactory.sol:DisputeGameFactory",
"label": "_owner",
"offset": 0,
"slot": "51",
"type": "t_address"
},
{
"astId": 59235,
"contract": "contracts/dispute/DisputeGameFactory.sol:DisputeGameFactory",
"label": "__gap",
"offset": 0,
"slot": "52",
"type": "t_array(t_uint256)49_storage"
},
{
"astId": 4350,
"contract": "contracts/dispute/DisputeGameFactory.sol:DisputeGameFactory",
"label": "gameImpls",
"offset": 0,
"slot": "101",
"type": "t_mapping(t_userDefinedValueType(GameType)8945,t_contract(IDisputeGame)5664)"
},
{
"astId": 4357,
"contract": "contracts/dispute/DisputeGameFactory.sol:DisputeGameFactory",
"label": "_disputeGames",
"offset": 0,
"slot": "102",
"type": "t_mapping(t_userDefinedValueType(Hash)8927,t_userDefinedValueType(GameId)8939)"
},
{
"astId": 4362,
"contract": "contracts/dispute/DisputeGameFactory.sol:DisputeGameFactory",
"label": "_disputeGameList",
"offset": 0,
"slot": "103",
"type": "t_array(t_userDefinedValueType(GameId)8939)dyn_storage"
}
],
"types": {
"t_address": {
"encoding": "inplace",
"label": "address",
"numberOfBytes": "20"
},
"t_array(t_uint256)49_storage": {
"encoding": "inplace",
"label": "uint256[49]",
"numberOfBytes": "1568",
"base": "t_uint256"
},
"t_array(t_uint256)50_storage": {
"encoding": "inplace",
"label": "uint256[50]",
"numberOfBytes": "1600",
"base": "t_uint256"
},
"t_array(t_userDefinedValueType(GameId)8939)dyn_storage": {
"encoding": "dynamic_array",
"label": "GameId[]",
"numberOfBytes": "32",
"base": "t_userDefinedValueType(GameId)8939"
},
"t_bool": {
"encoding": "inplace",
"label": "bool",
"numberOfBytes": "1"
},
"t_contract(IDisputeGame)5664": {
"encoding": "inplace",
"label": "contract IDisputeGame",
"numberOfBytes": "20"
},
"t_mapping(t_userDefinedValueType(GameType)8945,t_contract(IDisputeGame)5664)": {
"encoding": "mapping",
"key": "t_userDefinedValueType(GameType)8945",
"label": "mapping(GameType => contract IDisputeGame)",
"numberOfBytes": "32",
"value": "t_contract(IDisputeGame)5664"
},
"t_mapping(t_userDefinedValueType(Hash)8927,t_userDefinedValueType(GameId)8939)": {
"encoding": "mapping",
"key": "t_userDefinedValueType(Hash)8927",
"label": "mapping(Hash => GameId)",
"numberOfBytes": "32",
"value": "t_userDefinedValueType(GameId)8939"
},
"t_uint256": {
"encoding": "inplace",
"label": "uint256",
"numberOfBytes": "32"
},
"t_uint8": {
"encoding": "inplace",
"label": "uint8",
"numberOfBytes": "1"
},
"t_userDefinedValueType(GameId)8939": {
"encoding": "inplace",
"label": "GameId",
"numberOfBytes": "32"
},
"t_userDefinedValueType(GameType)8945": {
"encoding": "inplace",
"label": "GameType",
"numberOfBytes": "1"
},
"t_userDefinedValueType(Hash)8927": {
"encoding": "inplace",
"label": "Hash",
"numberOfBytes": "32"
}
}
},
"out": {
"storage": [
{
"astId": 1000,
"contract": "contracts/dispute/DisputeGameFactory.sol:DisputeGameFactory",
"label": "_initialized",
"offset": 0,
"slot": "0",
"type": "t_uint8"
},
{
"astId": 1001,
"contract": "contracts/dispute/DisputeGameFactory.sol:DisputeGameFactory",
"label": "_initializing",
"offset": 1,
"slot": "0",
"type": "t_bool"
},
{
"astId": 1002,
"contract": "contracts/dispute/DisputeGameFactory.sol:DisputeGameFactory",
"label": "__gap",
"offset": 0,
"slot": "1",
"type": "t_array(t_uint256)50_storage"
},
{
"astId": 1003,
"contract": "contracts/dispute/DisputeGameFactory.sol:DisputeGameFactory",
"label": "_owner",
"offset": 0,
"slot": "51",
"type": "t_address"
},
{
"astId": 1004,
"contract": "contracts/dispute/DisputeGameFactory.sol:DisputeGameFactory",
"label": "__gap",
"offset": 0,
"slot": "52",
"type": "t_array(t_uint256)49_storage"
},
{
"astId": 1005,
"contract": "contracts/dispute/DisputeGameFactory.sol:DisputeGameFactory",
"label": "gameImpls",
"offset": 0,
"slot": "101",
"type": "t_mapping(t_userDefinedValueType(GameType)1010,t_contract(IDisputeGame)1008)"
},
{
"astId": 1006,
"contract": "contracts/dispute/DisputeGameFactory.sol:DisputeGameFactory",
"label": "_disputeGames",
"offset": 0,
"slot": "102",
"type": "t_mapping(t_userDefinedValueType(Hash)1011,t_userDefinedValueType(GameId)1009)"
},
{
"astId": 1007,
"contract": "contracts/dispute/DisputeGameFactory.sol:DisputeGameFactory",
"label": "_disputeGameList",
"offset": 0,
"slot": "103",
"type": "t_array(t_userDefinedValueType(GameId)1009)dyn_storage"
}
],
"types": {
"t_address": {
"encoding": "inplace",
"label": "address",
"numberOfBytes": "20"
},
"t_array(t_uint256)49_storage": {
"encoding": "inplace",
"label": "uint256[49]",
"numberOfBytes": "1568",
"base": "t_uint256"
},
"t_array(t_uint256)50_storage": {
"encoding": "inplace",
"label": "uint256[50]",
"numberOfBytes": "1600",
"base": "t_uint256"
},
"t_array(t_userDefinedValueType(GameId)1009)dyn_storage": {
"encoding": "dynamic_array",
"label": "GameId[]",
"numberOfBytes": "32",
"base": "t_userDefinedValueType(GameId)1009"
},
"t_bool": {
"encoding": "inplace",
"label": "bool",
"numberOfBytes": "1"
},
"t_contract(IDisputeGame)1008": {
"encoding": "inplace",
"label": "contract IDisputeGame",
"numberOfBytes": "20"
},
"t_mapping(t_userDefinedValueType(GameType)1010,t_contract(IDisputeGame)1008)": {
"encoding": "mapping",
"key": "t_userDefinedValueType(GameType)1010",
"label": "mapping(GameType => contract IDisputeGame)",
"numberOfBytes": "32",
"value": "t_contract(IDisputeGame)1008"
},
"t_mapping(t_userDefinedValueType(Hash)1011,t_userDefinedValueType(GameId)1009)": {
"encoding": "mapping",
"key": "t_userDefinedValueType(Hash)1011",
"label": "mapping(Hash => GameId)",
"numberOfBytes": "32",
"value": "t_userDefinedValueType(GameId)1009"
},
"t_uint256": {
"encoding": "inplace",
"label": "uint256",
"numberOfBytes": "32"
},
"t_uint8": {
"encoding": "inplace",
"label": "uint8",
"numberOfBytes": "1"
},
"t_userDefinedValueType(GameId)1009": {
"encoding": "inplace",
"label": "GameId",
"numberOfBytes": "32"
},
"t_userDefinedValueType(GameType)1010": {
"encoding": "inplace",
"label": "GameType",
"numberOfBytes": "1"
},
"t_userDefinedValueType(Hash)1011": {
"encoding": "inplace",
"label": "Hash",
"numberOfBytes": "32"
}
}
}
}
...@@ -64,6 +64,7 @@ type StorageLayoutType struct { ...@@ -64,6 +64,7 @@ type StorageLayoutType struct {
NumberOfBytes uint `json:"numberOfBytes,string"` NumberOfBytes uint `json:"numberOfBytes,string"`
Key string `json:"key,omitempty"` Key string `json:"key,omitempty"`
Value string `json:"value,omitempty"` Value string `json:"value,omitempty"`
Base string `json:"base,omitempty"`
} }
type CompilerOutputEvm struct { type CompilerOutputEvm struct {
......
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