Skip to content

Commit f890f71

Browse files
authored
op-chain-ops: use generic CheckNoZeroAddresses instead of struct-specific methods (#15785)
1 parent 4250bc6 commit f890f71

File tree

7 files changed

+129
-81
lines changed

7 files changed

+129
-81
lines changed

op-chain-ops/addresses/roles.go

-22
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
package addresses
22

33
import (
4-
"errors"
5-
"fmt"
6-
"reflect"
7-
84
"github.com/ethereum/go-ethereum/common"
95
)
106

@@ -36,21 +32,3 @@ type OpChainFaultProofsRoles struct {
3632
Proposer common.Address
3733
Challenger common.Address
3834
}
39-
40-
var ErrSuperchainRoleZeroAddress = errors.New("SuperchainRole is set to zero address")
41-
42-
func (s *SuperchainRoles) CheckNoZeroAddresses() error {
43-
val := reflect.ValueOf(*s)
44-
typ := reflect.TypeOf(*s)
45-
46-
// Iterate through all the fields
47-
for i := 0; i < val.NumField(); i++ {
48-
fieldValue := val.Field(i)
49-
fieldName := typ.Field(i).Name
50-
51-
if fieldValue.Interface() == (common.Address{}) {
52-
return fmt.Errorf("%w: %s", ErrSuperchainRoleZeroAddress, fieldName)
53-
}
54-
}
55-
return nil
56-
}

op-chain-ops/addresses/roles_test.go

-34
This file was deleted.

op-chain-ops/addresses/utils.go

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package addresses
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"reflect"
7+
8+
"github.com/ethereum/go-ethereum/common"
9+
)
10+
11+
var ErrZeroAddress = errors.New("found zero address")
12+
var ErrNilPointer = errors.New("nil pointer provided")
13+
var ErrNotAddressType = errors.New("field is not of type common.Address")
14+
15+
// CheckNoZeroAddresses checks that all fields in a struct are of type common.Address
16+
// and that none of them are zero addresses. Works with both struct values and pointers to structs.
17+
// Returns an error if any field is not a common.Address or if any common.Address field is zero.
18+
func CheckNoZeroAddresses(s interface{}) error {
19+
val := reflect.ValueOf(s)
20+
21+
// If we have a pointer, dereference it to get the struct
22+
if val.Kind() == reflect.Ptr {
23+
if val.IsNil() {
24+
return ErrNilPointer
25+
}
26+
val = val.Elem()
27+
}
28+
29+
// Ensure we're working with a struct
30+
if val.Kind() != reflect.Struct {
31+
return fmt.Errorf("can only check structs, but got %s", val.Kind())
32+
}
33+
34+
typ := val.Type()
35+
addressType := reflect.TypeOf(common.Address{})
36+
37+
// Iterate through all the fields
38+
for i := 0; i < val.NumField(); i++ {
39+
fieldValue := val.Field(i)
40+
fieldName := typ.Field(i).Name
41+
42+
// Verify field is a common.Address
43+
if fieldValue.Type() != addressType {
44+
return fmt.Errorf("%w: %s (type: %s)", ErrNotAddressType, fieldName, fieldValue.Type())
45+
}
46+
47+
// Check if the address is zero
48+
if fieldValue.Interface() == (common.Address{}) {
49+
return fmt.Errorf("%w: %s", ErrZeroAddress, fieldName)
50+
}
51+
}
52+
return nil
53+
}

op-chain-ops/addresses/utils_test.go

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package addresses
2+
3+
import (
4+
"testing"
5+
6+
"github.com/ethereum/go-ethereum/common"
7+
"github.com/stretchr/testify/require"
8+
)
9+
10+
func TestCheckNoZeroAddresses(t *testing.T) {
11+
t.Run("no zero addresses", func(t *testing.T) {
12+
roles := SuperchainRoles{
13+
SuperchainProxyAdminOwner: common.HexToAddress("0x1111111111111111111111111111111111111111"),
14+
SuperchainGuardian: common.HexToAddress("0x2222222222222222222222222222222222222222"),
15+
ProtocolVersionsOwner: common.HexToAddress("0x3333333333333333333333333333333333333333"),
16+
}
17+
18+
err := CheckNoZeroAddresses(roles)
19+
require.NoError(t, err)
20+
})
21+
22+
t.Run("detects zero address", func(t *testing.T) {
23+
roles := SuperchainRoles{
24+
SuperchainProxyAdminOwner: common.HexToAddress("0x1111111111111111111111111111111111111111"),
25+
ProtocolVersionsOwner: common.HexToAddress("0x3333333333333333333333333333333333333333"),
26+
}
27+
28+
require.Equal(t, roles.SuperchainGuardian, common.HexToAddress("0x0000000000000000000000000000000000000000"))
29+
err := CheckNoZeroAddresses(roles)
30+
require.Error(t, err)
31+
require.ErrorIs(t, err, ErrZeroAddress)
32+
require.Contains(t, err.Error(), "SuperchainGuardian")
33+
})
34+
35+
t.Run("error for non-address fields", func(t *testing.T) {
36+
roles := struct {
37+
SuperchainProxyAdminOwner common.Address
38+
ProtocolVersionsOwner common.Address
39+
chainId uint64
40+
}{
41+
SuperchainProxyAdminOwner: common.HexToAddress("0x1111111111111111111111111111111111111111"),
42+
ProtocolVersionsOwner: common.HexToAddress("0x3333333333333333333333333333333333333333"),
43+
chainId: 1,
44+
}
45+
46+
err := CheckNoZeroAddresses(roles)
47+
require.Error(t, err)
48+
require.ErrorIs(t, err, ErrNotAddressType)
49+
require.Contains(t, err.Error(), "chainId")
50+
})
51+
52+
t.Run("struct pointer works", func(t *testing.T) {
53+
roles := SuperchainRoles{
54+
SuperchainProxyAdminOwner: common.HexToAddress("0x1111111111111111111111111111111111111111"),
55+
SuperchainGuardian: common.HexToAddress("0x2222222222222222222222222222222222222222"),
56+
ProtocolVersionsOwner: common.HexToAddress("0x3333333333333333333333333333333333333333"),
57+
}
58+
59+
err := CheckNoZeroAddresses(&roles)
60+
require.NoError(t, err)
61+
})
62+
63+
t.Run("nil struct pointer fails", func(t *testing.T) {
64+
var roles *SuperchainRoles = nil
65+
66+
err := CheckNoZeroAddresses(roles)
67+
require.Error(t, err)
68+
require.Contains(t, err.Error(), "nil pointer provided")
69+
})
70+
}

op-deployer/pkg/deployer/state/chain_intent.go

+2-21
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@ package state
22

33
import (
44
"fmt"
5-
"reflect"
65

76
"github.com/ethereum/go-ethereum/common"
87
"github.com/ethereum/go-ethereum/common/hexutil"
98

109
"github.com/ethereum-optimism/optimism/cannon/mipsevm/versions"
10+
"github.com/ethereum-optimism/optimism/op-chain-ops/addresses"
1111
"github.com/ethereum-optimism/optimism/op-chain-ops/genesis"
1212
)
1313

@@ -86,7 +86,6 @@ type ChainRoles struct {
8686
Challenger common.Address `json:"challenger" toml:"challenger"`
8787
}
8888

89-
var ErrChainRoleZeroAddress = fmt.Errorf("ChainRole is set to zero address")
9089
var ErrFeeVaultZeroAddress = fmt.Errorf("chain has a fee vault set to zero address")
9190
var ErrNonStandardValue = fmt.Errorf("chain contains non-standard config value")
9291
var ErrEip1559ZeroValue = fmt.Errorf("eip1559 param is set to zero value")
@@ -97,7 +96,7 @@ func (c *ChainIntent) Check() error {
9796
return fmt.Errorf("id must be set")
9897
}
9998

100-
if err := c.Roles.CheckNoZeroAddresses(); err != nil {
99+
if err := addresses.CheckNoZeroAddresses(c.Roles); err != nil {
101100
return err
102101
}
103102

@@ -118,21 +117,3 @@ func (c *ChainIntent) Check() error {
118117

119118
return nil
120119
}
121-
122-
// Returns an error if any fields in ChainRoles is set to common.Address{}
123-
func (cr *ChainRoles) CheckNoZeroAddresses() error {
124-
val := reflect.ValueOf(*cr)
125-
typ := reflect.TypeOf(*cr)
126-
127-
// Iterate through all the fields
128-
for i := 0; i < val.NumField(); i++ {
129-
fieldValue := val.Field(i)
130-
fieldName := typ.Field(i).Name
131-
132-
if fieldValue.Interface() == (common.Address{}) {
133-
return fmt.Errorf("%w: %s", ErrChainRoleZeroAddress, fieldName)
134-
}
135-
}
136-
137-
return nil
138-
}

op-deployer/pkg/deployer/state/intent.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ func (c *Intent) validateCustomConfig() error {
9999
if c.SuperchainRoles == nil {
100100
return fmt.Errorf("%w: must set superchain roles if OPCM address is nil", ErrIncompatibleValue)
101101
}
102-
if err := c.SuperchainRoles.CheckNoZeroAddresses(); err != nil {
102+
if err := addresses.CheckNoZeroAddresses(c.SuperchainRoles); err != nil {
103103
return err
104104
}
105105
} else {

op-deployer/pkg/deployer/state/intent_test.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ func TestValidateStandardValues(t *testing.T) {
1414

1515
err = intent.Check()
1616
require.Error(t, err)
17-
require.ErrorIs(t, err, ErrChainRoleZeroAddress)
17+
require.ErrorIs(t, err, addresses.ErrZeroAddress)
1818

1919
setChainRoles(&intent)
2020
err = intent.Check()
@@ -110,12 +110,12 @@ func TestValidateCustomValues(t *testing.T) {
110110

111111
err = intent.Check()
112112
require.Error(t, err)
113-
require.ErrorIs(t, err, addresses.ErrSuperchainRoleZeroAddress)
113+
require.ErrorIs(t, err, addresses.ErrZeroAddress)
114114

115115
setSuperchainRoles(&intent)
116116
err = intent.Check()
117117
require.Error(t, err)
118-
require.ErrorIs(t, err, ErrChainRoleZeroAddress)
118+
require.ErrorIs(t, err, addresses.ErrZeroAddress)
119119

120120
setChainRoles(&intent)
121121
err = intent.Check()

0 commit comments

Comments
 (0)