From 793642e2dd6e75f8928362abf7ac3b9458cfec25 Mon Sep 17 00:00:00 2001 From: Chawin Aiemvaravutigul Date: Tue, 16 May 2023 14:37:20 +0700 Subject: [PATCH 1/6] accounts/abi: add ErrorById --- accounts/abi/abi.go | 14 ++++++++++++++ accounts/abi/abi_test.go | 36 ++++++++++++++++++++++++++++++++++++ accounts/abi/error.go | 7 +++---- 3 files changed, 53 insertions(+), 4 deletions(-) diff --git a/accounts/abi/abi.go b/accounts/abi/abi.go index 62b860e18c77..6db235e56eb2 100644 --- a/accounts/abi/abi.go +++ b/accounts/abi/abi.go @@ -222,6 +222,20 @@ func (abi *ABI) EventByID(topic common.Hash) (*Event, error) { return nil, fmt.Errorf("no event with id: %#x", topic.Hex()) } +// ErrorById looks up an error by the 4-byte id, +// returns nil if none found. +func (abi *ABI) ErrorById(sigdata []byte) (*Error, error) { + if len(sigdata) < 4 { + return nil, fmt.Errorf("data too short (%d bytes) for abi error lookup", len(sigdata)) + } + for _, errABI := range abi.Errors { + if bytes.Equal(errABI.ID, sigdata[:4]) { + return &errABI, nil + } + } + return nil, fmt.Errorf("no error with id: %#x", sigdata[:4]) +} + // HasFallback returns an indicator whether a fallback function is included. func (abi *ABI) HasFallback() bool { return abi.Fallback.Type == Fallback diff --git a/accounts/abi/abi_test.go b/accounts/abi/abi_test.go index 96c11e096462..9bd0939c7a25 100644 --- a/accounts/abi/abi_test.go +++ b/accounts/abi/abi_test.go @@ -1057,6 +1057,42 @@ func TestABI_EventById(t *testing.T) { } } +func TestABI_ErrorById(t *testing.T) { + abi, err := JSON(strings.NewReader(`[ + {"inputs":[{"internalType":"uint256","name":"x","type":"uint256"}],"name":"MyError1","type":"error"}, + {"inputs":[{"components":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"string","name":"b","type":"string"},{"internalType":"address","name":"c","type":"address"}],"internalType":"struct MyError.MyStruct","name":"x","type":"tuple"},{"internalType":"address","name":"y","type":"address"},{"components":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"string","name":"b","type":"string"},{"internalType":"address","name":"c","type":"address"}],"internalType":"struct MyError.MyStruct","name":"z","type":"tuple"}],"name":"MyError2","type":"error"}, + {"inputs":[{"internalType":"uint256[]","name":"x","type":"uint256[]"}],"name":"MyError3","type":"error"} + ]`)) + if err != nil { + t.Fatal(err) + } + for name, m := range abi.Errors { + a := fmt.Sprintf("%v", &m) + m2, err := abi.ErrorById(m.ID) + if err != nil { + t.Fatalf("Failed to look up ABI error: %v", err) + } + b := fmt.Sprintf("%v", m2) + if a != b { + t.Errorf("Error %v (id %x) not 'findable' by id in ABI", name, m.ID) + } + } + // test unsuccessful lookups + if _, err = abi.ErrorById(crypto.Keccak256()); err == nil { + t.Error("Expected error: no error with this id") + } + // Also test empty + if _, err := abi.ErrorById([]byte{0x00}); err == nil { + t.Errorf("Expected error, too short to decode data") + } + if _, err := abi.ErrorById([]byte{}); err == nil { + t.Errorf("Expected error, too short to decode data") + } + if _, err := abi.ErrorById(nil); err == nil { + t.Errorf("Expected error, nil is short to decode data") + } +} + // TestDoubleDuplicateMethodNames checks that if transfer0 already exists, there won't be a name // conflict and that the second transfer method will be renamed transfer1. func TestDoubleDuplicateMethodNames(t *testing.T) { diff --git a/accounts/abi/error.go b/accounts/abi/error.go index f53c996def14..67ef922e4e9b 100644 --- a/accounts/abi/error.go +++ b/accounts/abi/error.go @@ -22,7 +22,6 @@ import ( "fmt" "strings" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" ) @@ -38,7 +37,7 @@ type Error struct { // ID returns the canonical representation of the error's signature used by the // abi definition to identify event names and types. - ID common.Hash + ID []byte } func NewError(name string, inputs Arguments) Error { @@ -67,7 +66,7 @@ func NewError(name string, inputs Arguments) Error { str := fmt.Sprintf("error %v(%v)", name, strings.Join(names, ", ")) sig := fmt.Sprintf("%v(%v)", name, strings.Join(types, ",")) - id := common.BytesToHash(crypto.Keccak256([]byte(sig))) + id := crypto.Keccak256([]byte(sig))[:4] return Error{ Name: name, @@ -78,7 +77,7 @@ func NewError(name string, inputs Arguments) Error { } } -func (e *Error) String() string { +func (e Error) String() string { return e.str } From 057b8494f03c1bf2eed8b59c6e3b90a57111e1bc Mon Sep 17 00:00:00 2001 From: Chawin Aiemvaravutigul Date: Wed, 17 May 2023 16:37:42 +0700 Subject: [PATCH 2/6] accounts/abi: change sigdata to `[4]byte` --- accounts/abi/abi.go | 7 ++----- accounts/abi/abi_test.go | 12 +----------- accounts/abi/error.go | 4 ++-- 3 files changed, 5 insertions(+), 18 deletions(-) diff --git a/accounts/abi/abi.go b/accounts/abi/abi.go index 6db235e56eb2..9404ec71344a 100644 --- a/accounts/abi/abi.go +++ b/accounts/abi/abi.go @@ -224,12 +224,9 @@ func (abi *ABI) EventByID(topic common.Hash) (*Event, error) { // ErrorById looks up an error by the 4-byte id, // returns nil if none found. -func (abi *ABI) ErrorById(sigdata []byte) (*Error, error) { - if len(sigdata) < 4 { - return nil, fmt.Errorf("data too short (%d bytes) for abi error lookup", len(sigdata)) - } +func (abi *ABI) ErrorById(sigdata [4]byte) (*Error, error) { for _, errABI := range abi.Errors { - if bytes.Equal(errABI.ID, sigdata[:4]) { + if errABI.ID == sigdata { return &errABI, nil } } diff --git a/accounts/abi/abi_test.go b/accounts/abi/abi_test.go index 9bd0939c7a25..41648e20a60a 100644 --- a/accounts/abi/abi_test.go +++ b/accounts/abi/abi_test.go @@ -1078,19 +1078,9 @@ func TestABI_ErrorById(t *testing.T) { } } // test unsuccessful lookups - if _, err = abi.ErrorById(crypto.Keccak256()); err == nil { + if _, err = abi.ErrorById([4]byte{}); err == nil { t.Error("Expected error: no error with this id") } - // Also test empty - if _, err := abi.ErrorById([]byte{0x00}); err == nil { - t.Errorf("Expected error, too short to decode data") - } - if _, err := abi.ErrorById([]byte{}); err == nil { - t.Errorf("Expected error, too short to decode data") - } - if _, err := abi.ErrorById(nil); err == nil { - t.Errorf("Expected error, nil is short to decode data") - } } // TestDoubleDuplicateMethodNames checks that if transfer0 already exists, there won't be a name diff --git a/accounts/abi/error.go b/accounts/abi/error.go index 67ef922e4e9b..da34929d4b56 100644 --- a/accounts/abi/error.go +++ b/accounts/abi/error.go @@ -37,7 +37,7 @@ type Error struct { // ID returns the canonical representation of the error's signature used by the // abi definition to identify event names and types. - ID []byte + ID [4]byte } func NewError(name string, inputs Arguments) Error { @@ -66,7 +66,7 @@ func NewError(name string, inputs Arguments) Error { str := fmt.Sprintf("error %v(%v)", name, strings.Join(names, ", ")) sig := fmt.Sprintf("%v(%v)", name, strings.Join(types, ",")) - id := crypto.Keccak256([]byte(sig))[:4] + id := *(*[4]byte)(crypto.Keccak256([]byte(sig))[:4]) return Error{ Name: name, From 7425fa630b7b1fe8c42acca62119042aee9c4232 Mon Sep 17 00:00:00 2001 From: Chawin Aiemvaravutigul Date: Thu, 18 May 2023 11:19:45 +0700 Subject: [PATCH 3/6] accounts/abi: change `ID` to `common.Hash` --- accounts/abi/error.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/accounts/abi/error.go b/accounts/abi/error.go index da34929d4b56..f65f0d2cc278 100644 --- a/accounts/abi/error.go +++ b/accounts/abi/error.go @@ -22,6 +22,7 @@ import ( "fmt" "strings" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" ) @@ -37,7 +38,7 @@ type Error struct { // ID returns the canonical representation of the error's signature used by the // abi definition to identify event names and types. - ID [4]byte + ID common.Hash } func NewError(name string, inputs Arguments) Error { @@ -66,7 +67,7 @@ func NewError(name string, inputs Arguments) Error { str := fmt.Sprintf("error %v(%v)", name, strings.Join(names, ", ")) sig := fmt.Sprintf("%v(%v)", name, strings.Join(types, ",")) - id := *(*[4]byte)(crypto.Keccak256([]byte(sig))[:4]) + id := common.BytesToHash(crypto.Keccak256([]byte(sig))) return Error{ Name: name, From 21f2959eb30afe9986891715e2a9b6782740e211 Mon Sep 17 00:00:00 2001 From: Chawin Aiemvaravutigul Date: Thu, 18 May 2023 11:20:35 +0700 Subject: [PATCH 4/6] accounts/abi: rename `ErrorById `to `ErrorByID` --- accounts/abi/abi.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/accounts/abi/abi.go b/accounts/abi/abi.go index 9404ec71344a..55576070a4ae 100644 --- a/accounts/abi/abi.go +++ b/accounts/abi/abi.go @@ -222,15 +222,15 @@ func (abi *ABI) EventByID(topic common.Hash) (*Event, error) { return nil, fmt.Errorf("no event with id: %#x", topic.Hex()) } -// ErrorById looks up an error by the 4-byte id, +// ErrorByID looks up an error by the 4-byte id, // returns nil if none found. -func (abi *ABI) ErrorById(sigdata [4]byte) (*Error, error) { +func (abi *ABI) ErrorByID(sigdata [4]byte) (*Error, error) { for _, errABI := range abi.Errors { - if errABI.ID == sigdata { + if bytes.Equal(errABI.ID[:4], sigdata[:]) { return &errABI, nil } } - return nil, fmt.Errorf("no error with id: %#x", sigdata[:4]) + return nil, fmt.Errorf("no error with id: %#x", sigdata[:]) } // HasFallback returns an indicator whether a fallback function is included. From a9123e5feab11a174ad76a073551cbb752487dec Mon Sep 17 00:00:00 2001 From: Chawin Aiemvaravutigul Date: Thu, 18 May 2023 11:21:41 +0700 Subject: [PATCH 5/6] accounts/abi: fix test `ErrorByID` --- accounts/abi/abi_test.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/accounts/abi/abi_test.go b/accounts/abi/abi_test.go index 41648e20a60a..da686a92c1ab 100644 --- a/accounts/abi/abi_test.go +++ b/accounts/abi/abi_test.go @@ -1057,7 +1057,7 @@ func TestABI_EventById(t *testing.T) { } } -func TestABI_ErrorById(t *testing.T) { +func TestABI_ErrorByID(t *testing.T) { abi, err := JSON(strings.NewReader(`[ {"inputs":[{"internalType":"uint256","name":"x","type":"uint256"}],"name":"MyError1","type":"error"}, {"inputs":[{"components":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"string","name":"b","type":"string"},{"internalType":"address","name":"c","type":"address"}],"internalType":"struct MyError.MyStruct","name":"x","type":"tuple"},{"internalType":"address","name":"y","type":"address"},{"components":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"string","name":"b","type":"string"},{"internalType":"address","name":"c","type":"address"}],"internalType":"struct MyError.MyStruct","name":"z","type":"tuple"}],"name":"MyError2","type":"error"}, @@ -1068,17 +1068,18 @@ func TestABI_ErrorById(t *testing.T) { } for name, m := range abi.Errors { a := fmt.Sprintf("%v", &m) - m2, err := abi.ErrorById(m.ID) + id := *(*[4]byte)(m.ID[:4]) + m2, err := abi.ErrorByID(id) if err != nil { t.Fatalf("Failed to look up ABI error: %v", err) } b := fmt.Sprintf("%v", m2) if a != b { - t.Errorf("Error %v (id %x) not 'findable' by id in ABI", name, m.ID) + t.Errorf("Error %v (id %x) not 'findable' by id in ABI", name, id) } } // test unsuccessful lookups - if _, err = abi.ErrorById([4]byte{}); err == nil { + if _, err = abi.ErrorByID([4]byte{}); err == nil { t.Error("Expected error: no error with this id") } } From 50e43aed9d675558018f8c342d3ef22bae46b3f1 Mon Sep 17 00:00:00 2001 From: Chawin Aiemvaravutigul Date: Sat, 20 May 2023 14:05:45 +0700 Subject: [PATCH 6/6] accounts/abi: assign `[4]byte` using copy --- accounts/abi/abi_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/accounts/abi/abi_test.go b/accounts/abi/abi_test.go index da686a92c1ab..3486ffd1a517 100644 --- a/accounts/abi/abi_test.go +++ b/accounts/abi/abi_test.go @@ -1068,7 +1068,8 @@ func TestABI_ErrorByID(t *testing.T) { } for name, m := range abi.Errors { a := fmt.Sprintf("%v", &m) - id := *(*[4]byte)(m.ID[:4]) + var id [4]byte + copy(id[:], m.ID[:4]) m2, err := abi.ErrorByID(id) if err != nil { t.Fatalf("Failed to look up ABI error: %v", err)