From b3ad4c6014f8c35d4839edc563cb9006840193d0 Mon Sep 17 00:00:00 2001 From: Aaron Buchwald Date: Fri, 17 Mar 2023 14:01:51 -0400 Subject: [PATCH 1/9] abi: add err handling for UnpackLog with zero topics on log --- accounts/abi/bind/base.go | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/accounts/abi/bind/base.go b/accounts/abi/bind/base.go index df3f52a403e7..680c735a21c1 100644 --- a/accounts/abi/bind/base.go +++ b/accounts/abi/bind/base.go @@ -34,6 +34,11 @@ import ( const basefeeWiggleMultiplier = 2 +var ( + errNoEventSignature = errors.New("no event signature") + errEventSignatureMismatch = errors.New("event signature mismatch") +) + // SignerFn is a signer function callback when a contract requires a method to // sign the transaction before submission. type SignerFn func(common.Address, *types.Transaction) (*types.Transaction, error) @@ -488,8 +493,11 @@ func (c *BoundContract) WatchLogs(opts *WatchOpts, name string, query ...[]inter // UnpackLog unpacks a retrieved log into the provided output structure. func (c *BoundContract) UnpackLog(out interface{}, event string, log types.Log) error { + if len(log.Topics) == 0 { + return errNoEventSignature + } if log.Topics[0] != c.abi.Events[event].ID { - return fmt.Errorf("event signature mismatch") + return errEventSignatureMismatch } if len(log.Data) > 0 { if err := c.abi.UnpackIntoInterface(out, event, log.Data); err != nil { @@ -507,8 +515,11 @@ func (c *BoundContract) UnpackLog(out interface{}, event string, log types.Log) // UnpackLogIntoMap unpacks a retrieved log into the provided map. func (c *BoundContract) UnpackLogIntoMap(out map[string]interface{}, event string, log types.Log) error { + if len(log.Topics) == 0 { + return errNoEventSignature + } if log.Topics[0] != c.abi.Events[event].ID { - return fmt.Errorf("event signature mismatch") + return errEventSignatureMismatch } if len(log.Data) > 0 { if err := c.abi.UnpackIntoMap(out, event, log.Data); err != nil { From 04beca9ab31cd1952797dc733ded3739e166c855 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Tue, 28 Mar 2023 16:27:47 +0200 Subject: [PATCH 2/9] add test for unpacking log0 --- accounts/abi/bind/base_test.go | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/accounts/abi/bind/base_test.go b/accounts/abi/bind/base_test.go index 2307b9874b18..abd8673f7be5 100644 --- a/accounts/abi/bind/base_test.go +++ b/accounts/abi/bind/base_test.go @@ -186,6 +186,23 @@ func TestUnpackIndexedStringTyLogIntoMap(t *testing.T) { unpackAndCheck(t, bc, expectedReceivedMap, mockLog) } +func TestUnpackAnonomousLogIntoMap(t *testing.T) { + mockLog := newMockLog(nil, common.HexToHash("0x0")) + + abiString := `[{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"received","type":"event"}]` + parsedAbi, _ := abi.JSON(strings.NewReader(abiString)) + bc := bind.NewBoundContract(common.HexToAddress("0x0"), parsedAbi, nil, nil, nil) + + var received map[string]interface{} + err := bc.UnpackLogIntoMap(received, "received", mockLog) + if err == nil { + t.Error("unpacking LOG0 is not supported") + } + if err.Error() != "no event signature" { + t.Errorf("expected error 'no event signature', got '%s'", err) + } +} + func TestUnpackIndexedSliceTyLogIntoMap(t *testing.T) { sliceBytes, err := rlp.EncodeToBytes([]string{"name1", "name2", "name3", "name4"}) if err != nil { From becc64c8febcb577ac04f730c523cee3846af701 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Tue, 28 Mar 2023 18:54:02 +0200 Subject: [PATCH 3/9] Handle anonymous and LOG0 logs --- accounts/abi/bind/base.go | 40 +++++++++++++++++++++++++++------- accounts/abi/bind/base_test.go | 32 +++++++++++++-------------- 2 files changed, 47 insertions(+), 25 deletions(-) diff --git a/accounts/abi/bind/base.go b/accounts/abi/bind/base.go index 680c735a21c1..5af7ce0354ab 100644 --- a/accounts/abi/bind/base.go +++ b/accounts/abi/bind/base.go @@ -493,11 +493,23 @@ func (c *BoundContract) WatchLogs(opts *WatchOpts, name string, query ...[]inter // UnpackLog unpacks a retrieved log into the provided output structure. func (c *BoundContract) UnpackLog(out interface{}, event string, log types.Log) error { + // Happens in case of LOG0 or an anonymous event with + // no indexed arg. Only parse the data. if len(log.Topics) == 0 { - return errNoEventSignature + if len(log.Data) > 0 { + if err := c.abi.UnpackIntoInterface(out, event, log.Data); err != nil { + return err + } + } + return nil } - if log.Topics[0] != c.abi.Events[event].ID { - return errEventSignatureMismatch + // All the topics for an anonymous event are indexed inputs. + topics := log.Topics + if !c.abi.Events[event].Anonymous { + if log.Topics[0] != c.abi.Events[event].ID { + return errEventSignatureMismatch + } + topics = log.Topics[1:] } if len(log.Data) > 0 { if err := c.abi.UnpackIntoInterface(out, event, log.Data); err != nil { @@ -510,16 +522,28 @@ func (c *BoundContract) UnpackLog(out interface{}, event string, log types.Log) indexed = append(indexed, arg) } } - return abi.ParseTopics(out, indexed, log.Topics[1:]) + return abi.ParseTopics(out, indexed, topics) } // UnpackLogIntoMap unpacks a retrieved log into the provided map. func (c *BoundContract) UnpackLogIntoMap(out map[string]interface{}, event string, log types.Log) error { + // Happens in case of LOG0 or an anonymous event with + // no indexed arg. Only parse the data. if len(log.Topics) == 0 { - return errNoEventSignature + if len(log.Data) > 0 { + if err := c.abi.UnpackIntoMap(out, event, log.Data); err != nil { + return err + } + } + return nil } - if log.Topics[0] != c.abi.Events[event].ID { - return errEventSignatureMismatch + // All the topics for an anonymous event are indexed inputs. + topics := log.Topics + if !c.abi.Events[event].Anonymous { + if log.Topics[0] != c.abi.Events[event].ID { + return errEventSignatureMismatch + } + topics = log.Topics[1:] } if len(log.Data) > 0 { if err := c.abi.UnpackIntoMap(out, event, log.Data); err != nil { @@ -532,7 +556,7 @@ func (c *BoundContract) UnpackLogIntoMap(out map[string]interface{}, event strin indexed = append(indexed, arg) } } - return abi.ParseTopicsIntoMap(out, indexed, log.Topics[1:]) + return abi.ParseTopicsIntoMap(out, indexed, topics) } // ensureContext is a helper method to ensure a context is not nil, even if the diff --git a/accounts/abi/bind/base_test.go b/accounts/abi/bind/base_test.go index abd8673f7be5..08e11775cfc3 100644 --- a/accounts/abi/bind/base_test.go +++ b/accounts/abi/bind/base_test.go @@ -171,7 +171,7 @@ func TestUnpackIndexedStringTyLogIntoMap(t *testing.T) { crypto.Keccak256Hash([]byte("received(string,address,uint256,bytes)")), hash, } - mockLog := newMockLog(topics, common.HexToHash("0x0")) + mockLog := newMockLog(topics, common.HexToHash("0x0"), hexData) abiString := `[{"anonymous":false,"inputs":[{"indexed":true,"name":"name","type":"string"},{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"memo","type":"bytes"}],"name":"received","type":"event"}]` parsedAbi, _ := abi.JSON(strings.NewReader(abiString)) @@ -186,21 +186,19 @@ func TestUnpackIndexedStringTyLogIntoMap(t *testing.T) { unpackAndCheck(t, bc, expectedReceivedMap, mockLog) } -func TestUnpackAnonomousLogIntoMap(t *testing.T) { - mockLog := newMockLog(nil, common.HexToHash("0x0")) +func TestUnpackAnonymousLogIntoMap(t *testing.T) { + // Anonymous event + mockLog := newMockLog(nil, common.HexToHash("0x0"), "0x0000000000000000000000000000000000000000000000000000000000000001") - abiString := `[{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"received","type":"event"}]` + abiString := `[{"anonymous":true,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"received","type":"event"}]` parsedAbi, _ := abi.JSON(strings.NewReader(abiString)) bc := bind.NewBoundContract(common.HexToAddress("0x0"), parsedAbi, nil, nil, nil) - var received map[string]interface{} - err := bc.UnpackLogIntoMap(received, "received", mockLog) - if err == nil { - t.Error("unpacking LOG0 is not supported") - } - if err.Error() != "no event signature" { - t.Errorf("expected error 'no event signature', got '%s'", err) + expectedReceivedMap := map[string]interface{}{ + "amount": big.NewInt(1), } + + unpackAndCheck(t, bc, expectedReceivedMap, mockLog) } func TestUnpackIndexedSliceTyLogIntoMap(t *testing.T) { @@ -213,7 +211,7 @@ func TestUnpackIndexedSliceTyLogIntoMap(t *testing.T) { crypto.Keccak256Hash([]byte("received(string[],address,uint256,bytes)")), hash, } - mockLog := newMockLog(topics, common.HexToHash("0x0")) + mockLog := newMockLog(topics, common.HexToHash("0x0"), hexData) abiString := `[{"anonymous":false,"inputs":[{"indexed":true,"name":"names","type":"string[]"},{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"memo","type":"bytes"}],"name":"received","type":"event"}]` parsedAbi, _ := abi.JSON(strings.NewReader(abiString)) @@ -238,7 +236,7 @@ func TestUnpackIndexedArrayTyLogIntoMap(t *testing.T) { crypto.Keccak256Hash([]byte("received(address[2],address,uint256,bytes)")), hash, } - mockLog := newMockLog(topics, common.HexToHash("0x0")) + mockLog := newMockLog(topics, common.HexToHash("0x0"), hexData) abiString := `[{"anonymous":false,"inputs":[{"indexed":true,"name":"addresses","type":"address[2]"},{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"memo","type":"bytes"}],"name":"received","type":"event"}]` parsedAbi, _ := abi.JSON(strings.NewReader(abiString)) @@ -265,7 +263,7 @@ func TestUnpackIndexedFuncTyLogIntoMap(t *testing.T) { crypto.Keccak256Hash([]byte("received(function,address,uint256,bytes)")), common.BytesToHash(functionTyBytes), } - mockLog := newMockLog(topics, common.HexToHash("0x5c698f13940a2153440c6d19660878bc90219d9298fdcf37365aa8d88d40fc42")) + mockLog := newMockLog(topics, common.HexToHash("0x5c698f13940a2153440c6d19660878bc90219d9298fdcf37365aa8d88d40fc42"), hexData) abiString := `[{"anonymous":false,"inputs":[{"indexed":true,"name":"function","type":"function"},{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"memo","type":"bytes"}],"name":"received","type":"event"}]` parsedAbi, _ := abi.JSON(strings.NewReader(abiString)) bc := bind.NewBoundContract(common.HexToAddress("0x0"), parsedAbi, nil, nil, nil) @@ -286,7 +284,7 @@ func TestUnpackIndexedBytesTyLogIntoMap(t *testing.T) { crypto.Keccak256Hash([]byte("received(bytes,address,uint256,bytes)")), hash, } - mockLog := newMockLog(topics, common.HexToHash("0x5c698f13940a2153440c6d19660878bc90219d9298fdcf37365aa8d88d40fc42")) + mockLog := newMockLog(topics, common.HexToHash("0x5c698f13940a2153440c6d19660878bc90219d9298fdcf37365aa8d88d40fc42"), hexData) abiString := `[{"anonymous":false,"inputs":[{"indexed":true,"name":"content","type":"bytes"},{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"memo","type":"bytes"}],"name":"received","type":"event"}]` parsedAbi, _ := abi.JSON(strings.NewReader(abiString)) @@ -362,11 +360,11 @@ func unpackAndCheck(t *testing.T, bc *bind.BoundContract, expected map[string]in } } -func newMockLog(topics []common.Hash, txHash common.Hash) types.Log { +func newMockLog(topics []common.Hash, txHash common.Hash, data string) types.Log { return types.Log{ Address: common.HexToAddress("0x0"), Topics: topics, - Data: hexutil.MustDecode(hexData), + Data: hexutil.MustDecode(data), BlockNumber: uint64(26), TxHash: txHash, TxIndex: 111, From 251a8e330511b54f62a03071c3a749370903e5c7 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Wed, 29 Mar 2023 12:18:01 +0200 Subject: [PATCH 4/9] add more test --- accounts/abi/bind/base_test.go | 58 ++++++++++++++++++++++++++++++++-- 1 file changed, 55 insertions(+), 3 deletions(-) diff --git a/accounts/abi/bind/base_test.go b/accounts/abi/bind/base_test.go index 08e11775cfc3..89d921e8ba88 100644 --- a/accounts/abi/bind/base_test.go +++ b/accounts/abi/bind/base_test.go @@ -186,8 +186,42 @@ func TestUnpackIndexedStringTyLogIntoMap(t *testing.T) { unpackAndCheck(t, bc, expectedReceivedMap, mockLog) } +func TestLog0AndAnonymousLogIntoMap(t *testing.T) { + for i, tc := range []struct { + abiString string + topics []common.Hash + expected map[string]interface{} + }{ + { + `[{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"received","type":"event"}]`, + nil, + map[string]interface{}{ + "amount": big.NewInt(1), + }, + }, + } { + mockLog := newMockLog(tc.topics, common.HexToHash("0x0"), "0x0000000000000000000000000000000000000000000000000000000000000001") + parsedAbi, _ := abi.JSON(strings.NewReader(tc.abiString)) + bc := bind.NewBoundContract(common.HexToAddress("0x0"), parsedAbi, nil, nil, nil) + unpackAndCheck(t, bc, tc.expected, mockLog) + } +} + +func TestUnpackLog0IntoMap(t *testing.T) { + mockLog := newMockLog(nil, common.HexToHash("0x0"), "0x0000000000000000000000000000000000000000000000000000000000000001") + + abiString := `[{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"received","type":"event"}]` + parsedAbi, _ := abi.JSON(strings.NewReader(abiString)) + bc := bind.NewBoundContract(common.HexToAddress("0x0"), parsedAbi, nil, nil, nil) + + expectedReceivedMap := map[string]interface{}{ + "amount": big.NewInt(1), + } + + unpackAndCheck(t, bc, expectedReceivedMap, mockLog) +} + func TestUnpackAnonymousLogIntoMap(t *testing.T) { - // Anonymous event mockLog := newMockLog(nil, common.HexToHash("0x0"), "0x0000000000000000000000000000000000000000000000000000000000000001") abiString := `[{"anonymous":true,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"received","type":"event"}]` @@ -201,6 +235,25 @@ func TestUnpackAnonymousLogIntoMap(t *testing.T) { unpackAndCheck(t, bc, expectedReceivedMap, mockLog) } +func TestUnpackIndexedAnonymousLogIntoMap(t *testing.T) { + hash := crypto.Keccak256Hash([]byte{1, 2, 3, 4, 5}) + topics := []common.Hash{ + hash, + } + + mockLog := newMockLog(topics, common.HexToHash("0x0"), "0x0000000000000000000000000000000000000000000000000000000000000001") + abiString := `[{"anonymous":true,"inputs":[{"indexed":true,"name":"content","type":"bytes"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"received","type":"event"}]` + parsedAbi, _ := abi.JSON(strings.NewReader(abiString)) + bc := bind.NewBoundContract(common.HexToAddress("0x0"), parsedAbi, nil, nil, nil) + + expectedReceivedMap := map[string]interface{}{ + "content": hash, + "amount": big.NewInt(1), + } + + unpackAndCheck(t, bc, expectedReceivedMap, mockLog) +} + func TestUnpackIndexedSliceTyLogIntoMap(t *testing.T) { sliceBytes, err := rlp.EncodeToBytes([]string{"name1", "name2", "name3", "name4"}) if err != nil { @@ -278,8 +331,7 @@ func TestUnpackIndexedFuncTyLogIntoMap(t *testing.T) { } func TestUnpackIndexedBytesTyLogIntoMap(t *testing.T) { - bytes := []byte{1, 2, 3, 4, 5} - hash := crypto.Keccak256Hash(bytes) + hash := crypto.Keccak256Hash([]byte{1, 2, 3, 4, 5}) topics := []common.Hash{ crypto.Keccak256Hash([]byte("received(bytes,address,uint256,bytes)")), hash, From d955576ea4ae2bc51cdc75b4844e12e2e98b25a2 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Thu, 30 Mar 2023 17:04:05 +0200 Subject: [PATCH 5/9] rm unnecessary log0 handling --- accounts/abi/bind/base.go | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/accounts/abi/bind/base.go b/accounts/abi/bind/base.go index 5af7ce0354ab..7c7dc97de140 100644 --- a/accounts/abi/bind/base.go +++ b/accounts/abi/bind/base.go @@ -493,16 +493,6 @@ func (c *BoundContract) WatchLogs(opts *WatchOpts, name string, query ...[]inter // UnpackLog unpacks a retrieved log into the provided output structure. func (c *BoundContract) UnpackLog(out interface{}, event string, log types.Log) error { - // Happens in case of LOG0 or an anonymous event with - // no indexed arg. Only parse the data. - if len(log.Topics) == 0 { - if len(log.Data) > 0 { - if err := c.abi.UnpackIntoInterface(out, event, log.Data); err != nil { - return err - } - } - return nil - } // All the topics for an anonymous event are indexed inputs. topics := log.Topics if !c.abi.Events[event].Anonymous { @@ -527,16 +517,6 @@ func (c *BoundContract) UnpackLog(out interface{}, event string, log types.Log) // UnpackLogIntoMap unpacks a retrieved log into the provided map. func (c *BoundContract) UnpackLogIntoMap(out map[string]interface{}, event string, log types.Log) error { - // Happens in case of LOG0 or an anonymous event with - // no indexed arg. Only parse the data. - if len(log.Topics) == 0 { - if len(log.Data) > 0 { - if err := c.abi.UnpackIntoMap(out, event, log.Data); err != nil { - return err - } - } - return nil - } // All the topics for an anonymous event are indexed inputs. topics := log.Topics if !c.abi.Events[event].Anonymous { From 3ef2f7d13b865a539381af68fa8421e88852bfe5 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Thu, 30 Mar 2023 17:04:29 +0200 Subject: [PATCH 6/9] table test --- accounts/abi/bind/base_test.go | 80 ++++++++++------------------------ 1 file changed, 22 insertions(+), 58 deletions(-) diff --git a/accounts/abi/bind/base_test.go b/accounts/abi/bind/base_test.go index 89d921e8ba88..c760331a6061 100644 --- a/accounts/abi/bind/base_test.go +++ b/accounts/abi/bind/base_test.go @@ -19,6 +19,7 @@ package bind_test import ( "context" "errors" + "fmt" "math/big" "reflect" "strings" @@ -183,75 +184,38 @@ func TestUnpackIndexedStringTyLogIntoMap(t *testing.T) { "amount": big.NewInt(1), "memo": []byte{88}, } - unpackAndCheck(t, bc, expectedReceivedMap, mockLog) + unpackAndCheck(t, bc, expectedReceivedMap, mockLog, "") } -func TestLog0AndAnonymousLogIntoMap(t *testing.T) { +func TestAnonymousLogIntoMap(t *testing.T) { for i, tc := range []struct { abiString string topics []common.Hash expected map[string]interface{} }{ + // Anonymous event with no indexed parameters { - `[{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"received","type":"event"}]`, + `[{"anonymous":true,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"received","type":"event"}]`, nil, map[string]interface{}{ "amount": big.NewInt(1), }, }, + // Anonymous event with indexed parameters + { + `[{"anonymous":true,"inputs":[{"indexed":true,"name":"content","type":"bytes"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"received","type":"event"}]`, + []common.Hash{crypto.Keccak256Hash([]byte{1, 2, 3, 4, 5})}, + map[string]interface{}{ + "content": crypto.Keccak256Hash([]byte{1, 2, 3, 4, 5}), + "amount": big.NewInt(1), + }, + }, } { mockLog := newMockLog(tc.topics, common.HexToHash("0x0"), "0x0000000000000000000000000000000000000000000000000000000000000001") parsedAbi, _ := abi.JSON(strings.NewReader(tc.abiString)) bc := bind.NewBoundContract(common.HexToAddress("0x0"), parsedAbi, nil, nil, nil) - unpackAndCheck(t, bc, tc.expected, mockLog) - } -} - -func TestUnpackLog0IntoMap(t *testing.T) { - mockLog := newMockLog(nil, common.HexToHash("0x0"), "0x0000000000000000000000000000000000000000000000000000000000000001") - - abiString := `[{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"received","type":"event"}]` - parsedAbi, _ := abi.JSON(strings.NewReader(abiString)) - bc := bind.NewBoundContract(common.HexToAddress("0x0"), parsedAbi, nil, nil, nil) - - expectedReceivedMap := map[string]interface{}{ - "amount": big.NewInt(1), + unpackAndCheck(t, bc, tc.expected, mockLog, fmt.Sprintf("test case %d: ", i)) } - - unpackAndCheck(t, bc, expectedReceivedMap, mockLog) -} - -func TestUnpackAnonymousLogIntoMap(t *testing.T) { - mockLog := newMockLog(nil, common.HexToHash("0x0"), "0x0000000000000000000000000000000000000000000000000000000000000001") - - abiString := `[{"anonymous":true,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"received","type":"event"}]` - parsedAbi, _ := abi.JSON(strings.NewReader(abiString)) - bc := bind.NewBoundContract(common.HexToAddress("0x0"), parsedAbi, nil, nil, nil) - - expectedReceivedMap := map[string]interface{}{ - "amount": big.NewInt(1), - } - - unpackAndCheck(t, bc, expectedReceivedMap, mockLog) -} - -func TestUnpackIndexedAnonymousLogIntoMap(t *testing.T) { - hash := crypto.Keccak256Hash([]byte{1, 2, 3, 4, 5}) - topics := []common.Hash{ - hash, - } - - mockLog := newMockLog(topics, common.HexToHash("0x0"), "0x0000000000000000000000000000000000000000000000000000000000000001") - abiString := `[{"anonymous":true,"inputs":[{"indexed":true,"name":"content","type":"bytes"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"received","type":"event"}]` - parsedAbi, _ := abi.JSON(strings.NewReader(abiString)) - bc := bind.NewBoundContract(common.HexToAddress("0x0"), parsedAbi, nil, nil, nil) - - expectedReceivedMap := map[string]interface{}{ - "content": hash, - "amount": big.NewInt(1), - } - - unpackAndCheck(t, bc, expectedReceivedMap, mockLog) } func TestUnpackIndexedSliceTyLogIntoMap(t *testing.T) { @@ -276,7 +240,7 @@ func TestUnpackIndexedSliceTyLogIntoMap(t *testing.T) { "amount": big.NewInt(1), "memo": []byte{88}, } - unpackAndCheck(t, bc, expectedReceivedMap, mockLog) + unpackAndCheck(t, bc, expectedReceivedMap, mockLog, "") } func TestUnpackIndexedArrayTyLogIntoMap(t *testing.T) { @@ -301,7 +265,7 @@ func TestUnpackIndexedArrayTyLogIntoMap(t *testing.T) { "amount": big.NewInt(1), "memo": []byte{88}, } - unpackAndCheck(t, bc, expectedReceivedMap, mockLog) + unpackAndCheck(t, bc, expectedReceivedMap, mockLog, "") } func TestUnpackIndexedFuncTyLogIntoMap(t *testing.T) { @@ -327,7 +291,7 @@ func TestUnpackIndexedFuncTyLogIntoMap(t *testing.T) { "amount": big.NewInt(1), "memo": []byte{88}, } - unpackAndCheck(t, bc, expectedReceivedMap, mockLog) + unpackAndCheck(t, bc, expectedReceivedMap, mockLog, "") } func TestUnpackIndexedBytesTyLogIntoMap(t *testing.T) { @@ -348,7 +312,7 @@ func TestUnpackIndexedBytesTyLogIntoMap(t *testing.T) { "amount": big.NewInt(1), "memo": []byte{88}, } - unpackAndCheck(t, bc, expectedReceivedMap, mockLog) + unpackAndCheck(t, bc, expectedReceivedMap, mockLog, "") } func TestTransactGasFee(t *testing.T) { @@ -396,18 +360,18 @@ func TestTransactGasFee(t *testing.T) { assert.True(mt.suggestGasPriceCalled) } -func unpackAndCheck(t *testing.T, bc *bind.BoundContract, expected map[string]interface{}, mockLog types.Log) { +func unpackAndCheck(t *testing.T, bc *bind.BoundContract, expected map[string]interface{}, mockLog types.Log, errPrefix string) { received := make(map[string]interface{}) if err := bc.UnpackLogIntoMap(received, "received", mockLog); err != nil { t.Error(err) } if len(received) != len(expected) { - t.Fatalf("unpacked map length %v not equal expected length of %v", len(received), len(expected)) + t.Fatalf("%sunpacked map length %v not equal expected length of %v", errPrefix, len(received), len(expected)) } for name, elem := range expected { if !reflect.DeepEqual(elem, received[name]) { - t.Errorf("field %v does not match expected, want %v, got %v", name, elem, received[name]) + t.Errorf("%sfield %v does not match expected, want %v, got %v", errPrefix, name, elem, received[name]) } } } From f0775925465dbf79520fe13cd7404ea685d4f513 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Thu, 30 Mar 2023 18:12:20 +0200 Subject: [PATCH 7/9] revert commits --- accounts/abi/bind/base.go | 28 ++++++------- accounts/abi/bind/base_test.go | 76 ++++++++++++++-------------------- 2 files changed, 43 insertions(+), 61 deletions(-) diff --git a/accounts/abi/bind/base.go b/accounts/abi/bind/base.go index 7c7dc97de140..680c735a21c1 100644 --- a/accounts/abi/bind/base.go +++ b/accounts/abi/bind/base.go @@ -493,13 +493,11 @@ func (c *BoundContract) WatchLogs(opts *WatchOpts, name string, query ...[]inter // UnpackLog unpacks a retrieved log into the provided output structure. func (c *BoundContract) UnpackLog(out interface{}, event string, log types.Log) error { - // All the topics for an anonymous event are indexed inputs. - topics := log.Topics - if !c.abi.Events[event].Anonymous { - if log.Topics[0] != c.abi.Events[event].ID { - return errEventSignatureMismatch - } - topics = log.Topics[1:] + if len(log.Topics) == 0 { + return errNoEventSignature + } + if log.Topics[0] != c.abi.Events[event].ID { + return errEventSignatureMismatch } if len(log.Data) > 0 { if err := c.abi.UnpackIntoInterface(out, event, log.Data); err != nil { @@ -512,18 +510,16 @@ func (c *BoundContract) UnpackLog(out interface{}, event string, log types.Log) indexed = append(indexed, arg) } } - return abi.ParseTopics(out, indexed, topics) + return abi.ParseTopics(out, indexed, log.Topics[1:]) } // UnpackLogIntoMap unpacks a retrieved log into the provided map. func (c *BoundContract) UnpackLogIntoMap(out map[string]interface{}, event string, log types.Log) error { - // All the topics for an anonymous event are indexed inputs. - topics := log.Topics - if !c.abi.Events[event].Anonymous { - if log.Topics[0] != c.abi.Events[event].ID { - return errEventSignatureMismatch - } - topics = log.Topics[1:] + if len(log.Topics) == 0 { + return errNoEventSignature + } + if log.Topics[0] != c.abi.Events[event].ID { + return errEventSignatureMismatch } if len(log.Data) > 0 { if err := c.abi.UnpackIntoMap(out, event, log.Data); err != nil { @@ -536,7 +532,7 @@ func (c *BoundContract) UnpackLogIntoMap(out map[string]interface{}, event strin indexed = append(indexed, arg) } } - return abi.ParseTopicsIntoMap(out, indexed, topics) + return abi.ParseTopicsIntoMap(out, indexed, log.Topics[1:]) } // ensureContext is a helper method to ensure a context is not nil, even if the diff --git a/accounts/abi/bind/base_test.go b/accounts/abi/bind/base_test.go index c760331a6061..abd8673f7be5 100644 --- a/accounts/abi/bind/base_test.go +++ b/accounts/abi/bind/base_test.go @@ -19,7 +19,6 @@ package bind_test import ( "context" "errors" - "fmt" "math/big" "reflect" "strings" @@ -172,7 +171,7 @@ func TestUnpackIndexedStringTyLogIntoMap(t *testing.T) { crypto.Keccak256Hash([]byte("received(string,address,uint256,bytes)")), hash, } - mockLog := newMockLog(topics, common.HexToHash("0x0"), hexData) + mockLog := newMockLog(topics, common.HexToHash("0x0")) abiString := `[{"anonymous":false,"inputs":[{"indexed":true,"name":"name","type":"string"},{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"memo","type":"bytes"}],"name":"received","type":"event"}]` parsedAbi, _ := abi.JSON(strings.NewReader(abiString)) @@ -184,37 +183,23 @@ func TestUnpackIndexedStringTyLogIntoMap(t *testing.T) { "amount": big.NewInt(1), "memo": []byte{88}, } - unpackAndCheck(t, bc, expectedReceivedMap, mockLog, "") + unpackAndCheck(t, bc, expectedReceivedMap, mockLog) } -func TestAnonymousLogIntoMap(t *testing.T) { - for i, tc := range []struct { - abiString string - topics []common.Hash - expected map[string]interface{} - }{ - // Anonymous event with no indexed parameters - { - `[{"anonymous":true,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"received","type":"event"}]`, - nil, - map[string]interface{}{ - "amount": big.NewInt(1), - }, - }, - // Anonymous event with indexed parameters - { - `[{"anonymous":true,"inputs":[{"indexed":true,"name":"content","type":"bytes"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"received","type":"event"}]`, - []common.Hash{crypto.Keccak256Hash([]byte{1, 2, 3, 4, 5})}, - map[string]interface{}{ - "content": crypto.Keccak256Hash([]byte{1, 2, 3, 4, 5}), - "amount": big.NewInt(1), - }, - }, - } { - mockLog := newMockLog(tc.topics, common.HexToHash("0x0"), "0x0000000000000000000000000000000000000000000000000000000000000001") - parsedAbi, _ := abi.JSON(strings.NewReader(tc.abiString)) - bc := bind.NewBoundContract(common.HexToAddress("0x0"), parsedAbi, nil, nil, nil) - unpackAndCheck(t, bc, tc.expected, mockLog, fmt.Sprintf("test case %d: ", i)) +func TestUnpackAnonomousLogIntoMap(t *testing.T) { + mockLog := newMockLog(nil, common.HexToHash("0x0")) + + abiString := `[{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"received","type":"event"}]` + parsedAbi, _ := abi.JSON(strings.NewReader(abiString)) + bc := bind.NewBoundContract(common.HexToAddress("0x0"), parsedAbi, nil, nil, nil) + + var received map[string]interface{} + err := bc.UnpackLogIntoMap(received, "received", mockLog) + if err == nil { + t.Error("unpacking LOG0 is not supported") + } + if err.Error() != "no event signature" { + t.Errorf("expected error 'no event signature', got '%s'", err) } } @@ -228,7 +213,7 @@ func TestUnpackIndexedSliceTyLogIntoMap(t *testing.T) { crypto.Keccak256Hash([]byte("received(string[],address,uint256,bytes)")), hash, } - mockLog := newMockLog(topics, common.HexToHash("0x0"), hexData) + mockLog := newMockLog(topics, common.HexToHash("0x0")) abiString := `[{"anonymous":false,"inputs":[{"indexed":true,"name":"names","type":"string[]"},{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"memo","type":"bytes"}],"name":"received","type":"event"}]` parsedAbi, _ := abi.JSON(strings.NewReader(abiString)) @@ -240,7 +225,7 @@ func TestUnpackIndexedSliceTyLogIntoMap(t *testing.T) { "amount": big.NewInt(1), "memo": []byte{88}, } - unpackAndCheck(t, bc, expectedReceivedMap, mockLog, "") + unpackAndCheck(t, bc, expectedReceivedMap, mockLog) } func TestUnpackIndexedArrayTyLogIntoMap(t *testing.T) { @@ -253,7 +238,7 @@ func TestUnpackIndexedArrayTyLogIntoMap(t *testing.T) { crypto.Keccak256Hash([]byte("received(address[2],address,uint256,bytes)")), hash, } - mockLog := newMockLog(topics, common.HexToHash("0x0"), hexData) + mockLog := newMockLog(topics, common.HexToHash("0x0")) abiString := `[{"anonymous":false,"inputs":[{"indexed":true,"name":"addresses","type":"address[2]"},{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"memo","type":"bytes"}],"name":"received","type":"event"}]` parsedAbi, _ := abi.JSON(strings.NewReader(abiString)) @@ -265,7 +250,7 @@ func TestUnpackIndexedArrayTyLogIntoMap(t *testing.T) { "amount": big.NewInt(1), "memo": []byte{88}, } - unpackAndCheck(t, bc, expectedReceivedMap, mockLog, "") + unpackAndCheck(t, bc, expectedReceivedMap, mockLog) } func TestUnpackIndexedFuncTyLogIntoMap(t *testing.T) { @@ -280,7 +265,7 @@ func TestUnpackIndexedFuncTyLogIntoMap(t *testing.T) { crypto.Keccak256Hash([]byte("received(function,address,uint256,bytes)")), common.BytesToHash(functionTyBytes), } - mockLog := newMockLog(topics, common.HexToHash("0x5c698f13940a2153440c6d19660878bc90219d9298fdcf37365aa8d88d40fc42"), hexData) + mockLog := newMockLog(topics, common.HexToHash("0x5c698f13940a2153440c6d19660878bc90219d9298fdcf37365aa8d88d40fc42")) abiString := `[{"anonymous":false,"inputs":[{"indexed":true,"name":"function","type":"function"},{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"memo","type":"bytes"}],"name":"received","type":"event"}]` parsedAbi, _ := abi.JSON(strings.NewReader(abiString)) bc := bind.NewBoundContract(common.HexToAddress("0x0"), parsedAbi, nil, nil, nil) @@ -291,16 +276,17 @@ func TestUnpackIndexedFuncTyLogIntoMap(t *testing.T) { "amount": big.NewInt(1), "memo": []byte{88}, } - unpackAndCheck(t, bc, expectedReceivedMap, mockLog, "") + unpackAndCheck(t, bc, expectedReceivedMap, mockLog) } func TestUnpackIndexedBytesTyLogIntoMap(t *testing.T) { - hash := crypto.Keccak256Hash([]byte{1, 2, 3, 4, 5}) + bytes := []byte{1, 2, 3, 4, 5} + hash := crypto.Keccak256Hash(bytes) topics := []common.Hash{ crypto.Keccak256Hash([]byte("received(bytes,address,uint256,bytes)")), hash, } - mockLog := newMockLog(topics, common.HexToHash("0x5c698f13940a2153440c6d19660878bc90219d9298fdcf37365aa8d88d40fc42"), hexData) + mockLog := newMockLog(topics, common.HexToHash("0x5c698f13940a2153440c6d19660878bc90219d9298fdcf37365aa8d88d40fc42")) abiString := `[{"anonymous":false,"inputs":[{"indexed":true,"name":"content","type":"bytes"},{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"memo","type":"bytes"}],"name":"received","type":"event"}]` parsedAbi, _ := abi.JSON(strings.NewReader(abiString)) @@ -312,7 +298,7 @@ func TestUnpackIndexedBytesTyLogIntoMap(t *testing.T) { "amount": big.NewInt(1), "memo": []byte{88}, } - unpackAndCheck(t, bc, expectedReceivedMap, mockLog, "") + unpackAndCheck(t, bc, expectedReceivedMap, mockLog) } func TestTransactGasFee(t *testing.T) { @@ -360,27 +346,27 @@ func TestTransactGasFee(t *testing.T) { assert.True(mt.suggestGasPriceCalled) } -func unpackAndCheck(t *testing.T, bc *bind.BoundContract, expected map[string]interface{}, mockLog types.Log, errPrefix string) { +func unpackAndCheck(t *testing.T, bc *bind.BoundContract, expected map[string]interface{}, mockLog types.Log) { received := make(map[string]interface{}) if err := bc.UnpackLogIntoMap(received, "received", mockLog); err != nil { t.Error(err) } if len(received) != len(expected) { - t.Fatalf("%sunpacked map length %v not equal expected length of %v", errPrefix, len(received), len(expected)) + t.Fatalf("unpacked map length %v not equal expected length of %v", len(received), len(expected)) } for name, elem := range expected { if !reflect.DeepEqual(elem, received[name]) { - t.Errorf("%sfield %v does not match expected, want %v, got %v", errPrefix, name, elem, received[name]) + t.Errorf("field %v does not match expected, want %v, got %v", name, elem, received[name]) } } } -func newMockLog(topics []common.Hash, txHash common.Hash, data string) types.Log { +func newMockLog(topics []common.Hash, txHash common.Hash) types.Log { return types.Log{ Address: common.HexToAddress("0x0"), Topics: topics, - Data: hexutil.MustDecode(data), + Data: hexutil.MustDecode(hexData), BlockNumber: uint64(26), TxHash: txHash, TxIndex: 111, From 509737b5a081aa24262861b66c7f30234c0c42ca Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Thu, 30 Mar 2023 18:14:39 +0200 Subject: [PATCH 8/9] add comment --- accounts/abi/bind/base.go | 2 ++ accounts/abi/bind/base_test.go | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/accounts/abi/bind/base.go b/accounts/abi/bind/base.go index 680c735a21c1..b03f431f7717 100644 --- a/accounts/abi/bind/base.go +++ b/accounts/abi/bind/base.go @@ -493,6 +493,7 @@ func (c *BoundContract) WatchLogs(opts *WatchOpts, name string, query ...[]inter // UnpackLog unpacks a retrieved log into the provided output structure. func (c *BoundContract) UnpackLog(out interface{}, event string, log types.Log) error { + // Anonymous events are not supported. if len(log.Topics) == 0 { return errNoEventSignature } @@ -515,6 +516,7 @@ func (c *BoundContract) UnpackLog(out interface{}, event string, log types.Log) // UnpackLogIntoMap unpacks a retrieved log into the provided map. func (c *BoundContract) UnpackLogIntoMap(out map[string]interface{}, event string, log types.Log) error { + // Anonymous events are not supported. if len(log.Topics) == 0 { return errNoEventSignature } diff --git a/accounts/abi/bind/base_test.go b/accounts/abi/bind/base_test.go index abd8673f7be5..1766014b9987 100644 --- a/accounts/abi/bind/base_test.go +++ b/accounts/abi/bind/base_test.go @@ -186,7 +186,7 @@ func TestUnpackIndexedStringTyLogIntoMap(t *testing.T) { unpackAndCheck(t, bc, expectedReceivedMap, mockLog) } -func TestUnpackAnonomousLogIntoMap(t *testing.T) { +func TestUnpackAnonymousLogIntoMap(t *testing.T) { mockLog := newMockLog(nil, common.HexToHash("0x0")) abiString := `[{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"received","type":"event"}]` From fc11c9f93d0ea0b9e69b6b037bb7ed44c22294ed Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Thu, 30 Mar 2023 18:15:35 +0200 Subject: [PATCH 9/9] minor --- accounts/abi/bind/base_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accounts/abi/bind/base_test.go b/accounts/abi/bind/base_test.go index 1766014b9987..ca0128148ffa 100644 --- a/accounts/abi/bind/base_test.go +++ b/accounts/abi/bind/base_test.go @@ -196,7 +196,7 @@ func TestUnpackAnonymousLogIntoMap(t *testing.T) { var received map[string]interface{} err := bc.UnpackLogIntoMap(received, "received", mockLog) if err == nil { - t.Error("unpacking LOG0 is not supported") + t.Error("unpacking anonymous event is not supported") } if err.Error() != "no event signature" { t.Errorf("expected error 'no event signature', got '%s'", err)