github.com/p202io/bor@v0.1.4/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 "encoding/binary" 21 "errors" 22 "fmt" 23 "math/big" 24 "reflect" 25 26 "github.com/maticnetwork/bor/accounts/abi" 27 "github.com/maticnetwork/bor/common" 28 "github.com/maticnetwork/bor/crypto" 29 ) 30 31 // makeTopics converts a filter query argument list into a filter topic set. 32 func makeTopics(query ...[]interface{}) ([][]common.Hash, error) { 33 topics := make([][]common.Hash, len(query)) 34 for i, filter := range query { 35 for _, rule := range filter { 36 var topic common.Hash 37 38 // Try to generate the topic based on simple types 39 switch rule := rule.(type) { 40 case common.Hash: 41 copy(topic[:], rule[:]) 42 case common.Address: 43 copy(topic[common.HashLength-common.AddressLength:], rule[:]) 44 case *big.Int: 45 blob := rule.Bytes() 46 copy(topic[common.HashLength-len(blob):], blob) 47 case bool: 48 if rule { 49 topic[common.HashLength-1] = 1 50 } 51 case int8: 52 blob := big.NewInt(int64(rule)).Bytes() 53 copy(topic[common.HashLength-len(blob):], blob) 54 case int16: 55 blob := big.NewInt(int64(rule)).Bytes() 56 copy(topic[common.HashLength-len(blob):], blob) 57 case int32: 58 blob := big.NewInt(int64(rule)).Bytes() 59 copy(topic[common.HashLength-len(blob):], blob) 60 case int64: 61 blob := big.NewInt(rule).Bytes() 62 copy(topic[common.HashLength-len(blob):], blob) 63 case uint8: 64 blob := new(big.Int).SetUint64(uint64(rule)).Bytes() 65 copy(topic[common.HashLength-len(blob):], blob) 66 case uint16: 67 blob := new(big.Int).SetUint64(uint64(rule)).Bytes() 68 copy(topic[common.HashLength-len(blob):], blob) 69 case uint32: 70 blob := new(big.Int).SetUint64(uint64(rule)).Bytes() 71 copy(topic[common.HashLength-len(blob):], blob) 72 case uint64: 73 blob := new(big.Int).SetUint64(rule).Bytes() 74 copy(topic[common.HashLength-len(blob):], blob) 75 case string: 76 hash := crypto.Keccak256Hash([]byte(rule)) 77 copy(topic[:], hash[:]) 78 case []byte: 79 hash := crypto.Keccak256Hash(rule) 80 copy(topic[:], hash[:]) 81 82 default: 83 // Attempt to generate the topic from funky types 84 val := reflect.ValueOf(rule) 85 86 switch { 87 88 // static byte array 89 case val.Kind() == reflect.Array && reflect.TypeOf(rule).Elem().Kind() == reflect.Uint8: 90 reflect.Copy(reflect.ValueOf(topic[:val.Len()]), val) 91 92 default: 93 return nil, fmt.Errorf("unsupported indexed type: %T", rule) 94 } 95 } 96 topics[i] = append(topics[i], topic) 97 } 98 } 99 return topics, nil 100 } 101 102 // Big batch of reflect types for topic reconstruction. 103 var ( 104 reflectHash = reflect.TypeOf(common.Hash{}) 105 reflectAddress = reflect.TypeOf(common.Address{}) 106 reflectBigInt = reflect.TypeOf(new(big.Int)) 107 ) 108 109 // parseTopics converts the indexed topic fields into actual log field values. 110 // 111 // Note, dynamic types cannot be reconstructed since they get mapped to Keccak256 112 // hashes as the topic value! 113 func parseTopics(out interface{}, fields abi.Arguments, topics []common.Hash) error { 114 // Sanity check that the fields and topics match up 115 if len(fields) != len(topics) { 116 return errors.New("topic/field count mismatch") 117 } 118 // Iterate over all the fields and reconstruct them from topics 119 for _, arg := range fields { 120 if !arg.Indexed { 121 return errors.New("non-indexed field in topic reconstruction") 122 } 123 field := reflect.ValueOf(out).Elem().FieldByName(capitalise(arg.Name)) 124 125 // Try to parse the topic back into the fields based on primitive types 126 switch field.Kind() { 127 case reflect.Bool: 128 if topics[0][common.HashLength-1] == 1 { 129 field.Set(reflect.ValueOf(true)) 130 } 131 case reflect.Int8: 132 num := new(big.Int).SetBytes(topics[0][:]) 133 field.Set(reflect.ValueOf(int8(num.Int64()))) 134 135 case reflect.Int16: 136 num := new(big.Int).SetBytes(topics[0][:]) 137 field.Set(reflect.ValueOf(int16(num.Int64()))) 138 139 case reflect.Int32: 140 num := new(big.Int).SetBytes(topics[0][:]) 141 field.Set(reflect.ValueOf(int32(num.Int64()))) 142 143 case reflect.Int64: 144 num := new(big.Int).SetBytes(topics[0][:]) 145 field.Set(reflect.ValueOf(num.Int64())) 146 147 case reflect.Uint8: 148 num := new(big.Int).SetBytes(topics[0][:]) 149 field.Set(reflect.ValueOf(uint8(num.Uint64()))) 150 151 case reflect.Uint16: 152 num := new(big.Int).SetBytes(topics[0][:]) 153 field.Set(reflect.ValueOf(uint16(num.Uint64()))) 154 155 case reflect.Uint32: 156 num := new(big.Int).SetBytes(topics[0][:]) 157 field.Set(reflect.ValueOf(uint32(num.Uint64()))) 158 159 case reflect.Uint64: 160 num := new(big.Int).SetBytes(topics[0][:]) 161 field.Set(reflect.ValueOf(num.Uint64())) 162 163 default: 164 // Ran out of plain primitive types, try custom types 165 switch field.Type() { 166 case reflectHash: // Also covers all dynamic types 167 field.Set(reflect.ValueOf(topics[0])) 168 169 case reflectAddress: 170 var addr common.Address 171 copy(addr[:], topics[0][common.HashLength-common.AddressLength:]) 172 field.Set(reflect.ValueOf(addr)) 173 174 case reflectBigInt: 175 num := new(big.Int).SetBytes(topics[0][:]) 176 field.Set(reflect.ValueOf(num)) 177 178 default: 179 // Ran out of custom types, try the crazies 180 switch { 181 182 // static byte array 183 case arg.Type.T == abi.FixedBytesTy: 184 reflect.Copy(field, reflect.ValueOf(topics[0][:arg.Type.Size])) 185 186 default: 187 return fmt.Errorf("unsupported indexed type: %v", arg.Type) 188 } 189 } 190 } 191 topics = topics[1:] 192 } 193 return nil 194 } 195 196 // parseTopicsIntoMap converts the indexed topic field-value pairs into map key-value pairs 197 func parseTopicsIntoMap(out map[string]interface{}, fields abi.Arguments, topics []common.Hash) error { 198 // Sanity check that the fields and topics match up 199 if len(fields) != len(topics) { 200 return errors.New("topic/field count mismatch") 201 } 202 // Iterate over all the fields and reconstruct them from topics 203 for _, arg := range fields { 204 if !arg.Indexed { 205 return errors.New("non-indexed field in topic reconstruction") 206 } 207 208 switch arg.Type.T { 209 case abi.BoolTy: 210 out[arg.Name] = topics[0][common.HashLength-1] == 1 211 case abi.IntTy, abi.UintTy: 212 num := new(big.Int).SetBytes(topics[0][:]) 213 out[arg.Name] = num 214 case abi.AddressTy: 215 var addr common.Address 216 copy(addr[:], topics[0][common.HashLength-common.AddressLength:]) 217 out[arg.Name] = addr 218 case abi.HashTy: 219 out[arg.Name] = topics[0] 220 case abi.FixedBytesTy: 221 out[arg.Name] = topics[0][:] 222 case abi.StringTy, abi.BytesTy, abi.SliceTy, abi.ArrayTy: 223 // Array types (including strings and bytes) have their keccak256 hashes stored in the topic- not a hash 224 // whose bytes can be decoded to the actual value- so the best we can do is retrieve that hash 225 out[arg.Name] = topics[0] 226 case abi.FunctionTy: 227 if garbage := binary.BigEndian.Uint64(topics[0][0:8]); garbage != 0 { 228 return fmt.Errorf("bind: got improperly encoded function type, got %v", topics[0].Bytes()) 229 } 230 var tmp [24]byte 231 copy(tmp[:], topics[0][8:32]) 232 out[arg.Name] = tmp 233 default: // Not handling tuples 234 return fmt.Errorf("unsupported indexed type: %v", arg.Type) 235 } 236 237 topics = topics[1:] 238 } 239 240 return nil 241 }