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