github.com/luckypickle/go-ethereum-vet@v1.14.2/accounts/abi/bind/topics.go (about) 1 // Copyright 2018 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package bind 18 19 import ( 20 "errors" 21 "fmt" 22 "math/big" 23 "reflect" 24 25 "github.com/luckypickle/go-ethereum-vet/accounts/abi" 26 "github.com/luckypickle/go-ethereum-vet/common" 27 "github.com/luckypickle/go-ethereum-vet/crypto" 28 ) 29 30 // makeTopics converts a filter query argument list into a filter topic set. 31 func makeTopics(query ...[]interface{}) ([][]common.Hash, error) { 32 topics := make([][]common.Hash, len(query)) 33 for i, filter := range query { 34 for _, rule := range filter { 35 var topic common.Hash 36 37 // Try to generate the topic based on simple types 38 switch rule := rule.(type) { 39 case common.Hash: 40 copy(topic[:], rule[:]) 41 case common.Address: 42 copy(topic[common.HashLength-common.AddressLength:], rule[:]) 43 case *big.Int: 44 blob := rule.Bytes() 45 copy(topic[common.HashLength-len(blob):], blob) 46 case bool: 47 if rule { 48 topic[common.HashLength-1] = 1 49 } 50 case int8: 51 blob := big.NewInt(int64(rule)).Bytes() 52 copy(topic[common.HashLength-len(blob):], blob) 53 case int16: 54 blob := big.NewInt(int64(rule)).Bytes() 55 copy(topic[common.HashLength-len(blob):], blob) 56 case int32: 57 blob := big.NewInt(int64(rule)).Bytes() 58 copy(topic[common.HashLength-len(blob):], blob) 59 case int64: 60 blob := big.NewInt(rule).Bytes() 61 copy(topic[common.HashLength-len(blob):], blob) 62 case uint8: 63 blob := new(big.Int).SetUint64(uint64(rule)).Bytes() 64 copy(topic[common.HashLength-len(blob):], blob) 65 case uint16: 66 blob := new(big.Int).SetUint64(uint64(rule)).Bytes() 67 copy(topic[common.HashLength-len(blob):], blob) 68 case uint32: 69 blob := new(big.Int).SetUint64(uint64(rule)).Bytes() 70 copy(topic[common.HashLength-len(blob):], blob) 71 case uint64: 72 blob := new(big.Int).SetUint64(rule).Bytes() 73 copy(topic[common.HashLength-len(blob):], blob) 74 case string: 75 hash := crypto.Keccak256Hash([]byte(rule)) 76 copy(topic[:], hash[:]) 77 case []byte: 78 hash := crypto.Keccak256Hash(rule) 79 copy(topic[:], hash[:]) 80 81 default: 82 // Attempt to generate the topic from funky types 83 val := reflect.ValueOf(rule) 84 85 switch { 86 case val.Kind() == reflect.Array && reflect.TypeOf(rule).Elem().Kind() == reflect.Uint8: 87 reflect.Copy(reflect.ValueOf(topic[common.HashLength-val.Len():]), val) 88 89 default: 90 return nil, fmt.Errorf("unsupported indexed type: %T", rule) 91 } 92 } 93 topics[i] = append(topics[i], topic) 94 } 95 } 96 return topics, nil 97 } 98 99 // Big batch of reflect types for topic reconstruction. 100 var ( 101 reflectHash = reflect.TypeOf(common.Hash{}) 102 reflectAddress = reflect.TypeOf(common.Address{}) 103 reflectBigInt = reflect.TypeOf(new(big.Int)) 104 ) 105 106 // parseTopics converts the indexed topic fields into actual log field values. 107 // 108 // Note, dynamic types cannot be reconstructed since they get mapped to Keccak256 109 // hashes as the topic value! 110 func parseTopics(out interface{}, fields abi.Arguments, topics []common.Hash) error { 111 // Sanity check that the fields and topics match up 112 if len(fields) != len(topics) { 113 return errors.New("topic/field count mismatch") 114 } 115 // Iterate over all the fields and reconstruct them from topics 116 for _, arg := range fields { 117 if !arg.Indexed { 118 return errors.New("non-indexed field in topic reconstruction") 119 } 120 field := reflect.ValueOf(out).Elem().FieldByName(capitalise(arg.Name)) 121 122 // Try to parse the topic back into the fields based on primitive types 123 switch field.Kind() { 124 case reflect.Bool: 125 if topics[0][common.HashLength-1] == 1 { 126 field.Set(reflect.ValueOf(true)) 127 } 128 case reflect.Int8: 129 num := new(big.Int).SetBytes(topics[0][:]) 130 field.Set(reflect.ValueOf(int8(num.Int64()))) 131 132 case reflect.Int16: 133 num := new(big.Int).SetBytes(topics[0][:]) 134 field.Set(reflect.ValueOf(int16(num.Int64()))) 135 136 case reflect.Int32: 137 num := new(big.Int).SetBytes(topics[0][:]) 138 field.Set(reflect.ValueOf(int32(num.Int64()))) 139 140 case reflect.Int64: 141 num := new(big.Int).SetBytes(topics[0][:]) 142 field.Set(reflect.ValueOf(num.Int64())) 143 144 case reflect.Uint8: 145 num := new(big.Int).SetBytes(topics[0][:]) 146 field.Set(reflect.ValueOf(uint8(num.Uint64()))) 147 148 case reflect.Uint16: 149 num := new(big.Int).SetBytes(topics[0][:]) 150 field.Set(reflect.ValueOf(uint16(num.Uint64()))) 151 152 case reflect.Uint32: 153 num := new(big.Int).SetBytes(topics[0][:]) 154 field.Set(reflect.ValueOf(uint32(num.Uint64()))) 155 156 case reflect.Uint64: 157 num := new(big.Int).SetBytes(topics[0][:]) 158 field.Set(reflect.ValueOf(num.Uint64())) 159 160 default: 161 // Ran out of plain primitive types, try custom types 162 switch field.Type() { 163 case reflectHash: // Also covers all dynamic types 164 field.Set(reflect.ValueOf(topics[0])) 165 166 case reflectAddress: 167 var addr common.Address 168 copy(addr[:], topics[0][common.HashLength-common.AddressLength:]) 169 field.Set(reflect.ValueOf(addr)) 170 171 case reflectBigInt: 172 num := new(big.Int).SetBytes(topics[0][:]) 173 field.Set(reflect.ValueOf(num)) 174 175 default: 176 // Ran out of custom types, try the crazies 177 switch { 178 case arg.Type.T == abi.FixedBytesTy: 179 reflect.Copy(field, reflect.ValueOf(topics[0][common.HashLength-arg.Type.Size:])) 180 181 default: 182 return fmt.Errorf("unsupported indexed type: %v", arg.Type) 183 } 184 } 185 } 186 topics = topics[1:] 187 } 188 return nil 189 }