Skip to content

Commit

Permalink
ParseSignatures should add a number to duplicated names
Browse files Browse the repository at this point in the history
  • Loading branch information
MDobak committed Nov 20, 2023
1 parent 0f2b5b2 commit a72ca3b
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 3 deletions.
22 changes: 19 additions & 3 deletions abi/contract.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,9 @@ func (a *ABI) MustParseJSON(data []byte) *Contract {
// ParseSignatures parses list of signatures and returns a Contract instance.
// Signatures must be prefixed with the kind, e.g. "constructor" or "event".
// For functions, the "function" prefix can be omitted.
//
// In case of duplicate function, event or error names, a counter will be
// appended to the name starting from 2.
func (a *ABI) ParseSignatures(signatures ...string) (*Contract, error) {
c := &Contract{
Methods: make(map[string]*Method),
Expand Down Expand Up @@ -268,7 +271,7 @@ func (a *ABI) ParseSignatures(signatures ...string) (*Contract, error) {
if err != nil {
return nil, err
}
c.Methods[method.Name()] = method
appendWithCounter(c.Methods, method.Name(), method)
c.MethodsBySignature[method.Signature()] = method
case sigparser.EventSignatureInput:
sig, err := sigparser.ParseSignatureAs(sigparser.EventKind, s)
Expand All @@ -279,7 +282,7 @@ func (a *ABI) ParseSignatures(signatures ...string) (*Contract, error) {
if err != nil {
return nil, err
}
c.Events[event.Name()] = event
appendWithCounter(c.Events, event.Name(), event)
case sigparser.ErrorSignatureInput:
sig, err := sigparser.ParseSignatureAs(sigparser.ErrorKind, s)
if err != nil {
Expand All @@ -289,7 +292,7 @@ func (a *ABI) ParseSignatures(signatures ...string) (*Contract, error) {
if err != nil {
return nil, err
}
c.Errors[errsig.Name()] = errsig
appendWithCounter(c.Errors, errsig.Name(), errsig)
default:
return nil, fmt.Errorf("invalid signature: %s", s)
}
Expand Down Expand Up @@ -553,3 +556,16 @@ func parseInternalType(typ string) (int, string, string) {
}
return kind, intName, intNamespace
}

// appendWithCounter appends a value to a map. If the key already exists, it
// will be suffixed with a number.
func appendWithCounter[T any](m map[string]T, key string, value T) {
nextKey := key
for i := 0; ; i++ {
if _, ok := m[nextKey]; !ok {
m[nextKey] = value
return
}
nextKey = key + strconv.Itoa(i+2)
}
}
28 changes: 28 additions & 0 deletions abi/contract_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ func TestABI_ParseSignatures(t *testing.T) {
`constructor(CustomUint a)`,
`function Foo(CustomUint a) nonpayable returns (CustomUint)`,
`function Bar(Struct[2][2] a) nonpayable returns (uint8[2][2])`,
`function Bar()`, // Should be added as Bar2 because Bar already exists
)

require.NoError(t, err)
Expand All @@ -72,6 +73,7 @@ func TestABI_ParseSignatures(t *testing.T) {
require.NotNil(t, abi.Constructor)
require.NotNil(t, abi.Methods["Foo"])
require.NotNil(t, abi.Methods["Bar"])
require.NotNil(t, abi.Methods["Bar2"])

assert.Equal(t, "Status", abi.Types["Status"].String())
assert.Equal(t, "Struct", abi.Types["Struct"].String())
Expand Down Expand Up @@ -277,3 +279,29 @@ func Fuzz_parseArrays(f *testing.F) {
_, _, _ = parseArrays(typ)
})
}

func Test_appendWithCounter(t *testing.T) {
t.Run("add same key", func(t *testing.T) {
m := make(map[string]int)

appendWithCounter(m, "test", 1)
appendWithCounter(m, "test", 2)
appendWithCounter(m, "test", 3)
assert.Equal(t, 3, len(m))
assert.Equal(t, 1, m["test"])
assert.Equal(t, 2, m["test2"])
assert.Equal(t, 3, m["test3"])
})

t.Run("add same key with number", func(t *testing.T) {
m := make(map[string]int)

appendWithCounter(m, "test", 1)
appendWithCounter(m, "test", 2)
appendWithCounter(m, "test2", 3)
assert.Equal(t, 3, len(m))
assert.Equal(t, 1, m["test"])
assert.Equal(t, 2, m["test2"])
assert.Equal(t, 3, m["test22"])
})
}

0 comments on commit a72ca3b

Please sign in to comment.