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