github.com/m3shine/gochain@v2.2.26+incompatible/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/gochain-io/gochain/accounts/abi" 26 "github.com/gochain-io/gochain/common" 27 "github.com/gochain-io/gochain/crypto/sha3" 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 sha3.Keccak256(topic[:32], []byte(rule)) 76 case []byte: 77 sha3.Keccak256(topic[:32], rule) 78 79 default: 80 // Attempt to generate the topic from funky types 81 val := reflect.ValueOf(rule) 82 83 switch { 84 case val.Kind() == reflect.Array && reflect.TypeOf(rule).Elem().Kind() == reflect.Uint8: 85 reflect.Copy(reflect.ValueOf(topic[common.HashLength-val.Len():]), val) 86 87 default: 88 return nil, fmt.Errorf("unsupported indexed type: %T", rule) 89 } 90 } 91 topics[i] = append(topics[i], topic) 92 } 93 } 94 return topics, nil 95 } 96 97 // Big batch of reflect types for topic reconstruction. 98 var ( 99 reflectHash = reflect.TypeOf(common.Hash{}) 100 reflectAddress = reflect.TypeOf(common.Address{}) 101 reflectBigInt = reflect.TypeOf(new(big.Int)) 102 ) 103 104 // parseTopics converts the indexed topic fields into actual log field values. 105 // 106 // Note, dynamic types cannot be reconstructed since they get mapped to Keccak256 107 // hashes as the topic value! 108 func parseTopics(out interface{}, fields abi.Arguments, topics []common.Hash) error { 109 // Sanity check that the fields and topics match up 110 if len(fields) != len(topics) { 111 return errors.New("topic/field count mismatch") 112 } 113 // Iterate over all the fields and reconstruct them from topics 114 for _, arg := range fields { 115 if !arg.Indexed { 116 return errors.New("non-indexed field in topic reconstruction") 117 } 118 field := reflect.ValueOf(out).Elem().FieldByName(capitalise(arg.Name)) 119 120 // Try to parse the topic back into the fields based on primitive types 121 switch field.Kind() { 122 case reflect.Bool: 123 if topics[0][common.HashLength-1] == 1 { 124 field.Set(reflect.ValueOf(true)) 125 } 126 case reflect.Int8: 127 num := new(big.Int).SetBytes(topics[0][:]) 128 field.Set(reflect.ValueOf(int8(num.Int64()))) 129 130 case reflect.Int16: 131 num := new(big.Int).SetBytes(topics[0][:]) 132 field.Set(reflect.ValueOf(int16(num.Int64()))) 133 134 case reflect.Int32: 135 num := new(big.Int).SetBytes(topics[0][:]) 136 field.Set(reflect.ValueOf(int32(num.Int64()))) 137 138 case reflect.Int64: 139 num := new(big.Int).SetBytes(topics[0][:]) 140 field.Set(reflect.ValueOf(num.Int64())) 141 142 case reflect.Uint8: 143 num := new(big.Int).SetBytes(topics[0][:]) 144 field.Set(reflect.ValueOf(uint8(num.Uint64()))) 145 146 case reflect.Uint16: 147 num := new(big.Int).SetBytes(topics[0][:]) 148 field.Set(reflect.ValueOf(uint16(num.Uint64()))) 149 150 case reflect.Uint32: 151 num := new(big.Int).SetBytes(topics[0][:]) 152 field.Set(reflect.ValueOf(uint32(num.Uint64()))) 153 154 case reflect.Uint64: 155 num := new(big.Int).SetBytes(topics[0][:]) 156 field.Set(reflect.ValueOf(num.Uint64())) 157 158 default: 159 // Ran out of plain primitive types, try custom types 160 switch field.Type() { 161 case reflectHash: // Also covers all dynamic types 162 field.Set(reflect.ValueOf(topics[0])) 163 164 case reflectAddress: 165 var addr common.Address 166 copy(addr[:], topics[0][common.HashLength-common.AddressLength:]) 167 field.Set(reflect.ValueOf(addr)) 168 169 case reflectBigInt: 170 num := new(big.Int).SetBytes(topics[0][:]) 171 field.Set(reflect.ValueOf(num)) 172 173 default: 174 // Ran out of custom types, try the crazies 175 switch { 176 case arg.Type.T == abi.FixedBytesTy: 177 reflect.Copy(field, reflect.ValueOf(topics[0][common.HashLength-arg.Type.Size:])) 178 179 default: 180 return fmt.Errorf("unsupported indexed type: %v", arg.Type) 181 } 182 } 183 } 184 topics = topics[1:] 185 } 186 return nil 187 }