@@ -103,151 +103,62 @@ func makeTopics(query ...[]interface{}) ([][]common.Hash, error) {
103
103
return topics , nil
104
104
}
105
105
106
- // Big batch of reflect types for topic reconstruction.
107
- var (
108
- reflectHash = reflect .TypeOf (common.Hash {})
109
- reflectAddress = reflect .TypeOf (common.Address {})
110
- reflectBigInt = reflect .TypeOf (new (big.Int ))
111
- )
112
-
113
106
// parseTopics converts the indexed topic fields into actual log field values.
114
- //
115
- // Note, dynamic types cannot be reconstructed since they get mapped to Keccak256
116
- // hashes as the topic value!
117
107
func parseTopics (out interface {}, fields abi.Arguments , topics []common.Hash ) error {
118
- // Sanity check that the fields and topics match up
119
- if len (fields ) != len (topics ) {
120
- return errors .New ("topic/field count mismatch" )
121
- }
122
- // Iterate over all the fields and reconstruct them from topics
123
- for _ , arg := range fields {
124
- if ! arg .Indexed {
125
- return errors .New ("non-indexed field in topic reconstruction" )
126
- }
127
- field := reflect .ValueOf (out ).Elem ().FieldByName (capitalise (arg .Name ))
128
-
129
- // Try to parse the topic back into the fields based on primitive types
130
- switch field .Kind () {
131
- case reflect .Bool :
132
- if topics [0 ][common .HashLength - 1 ] == 1 {
133
- field .Set (reflect .ValueOf (true ))
134
- }
135
- case reflect .Int8 :
136
- num := new (big.Int ).SetBytes (topics [0 ][:])
137
- field .Set (reflect .ValueOf (int8 (num .Int64 ())))
138
-
139
- case reflect .Int16 :
140
- num := new (big.Int ).SetBytes (topics [0 ][:])
141
- field .Set (reflect .ValueOf (int16 (num .Int64 ())))
142
-
143
- case reflect .Int32 :
144
- num := new (big.Int ).SetBytes (topics [0 ][:])
145
- field .Set (reflect .ValueOf (int32 (num .Int64 ())))
146
-
147
- case reflect .Int64 :
148
- num := new (big.Int ).SetBytes (topics [0 ][:])
149
- field .Set (reflect .ValueOf (num .Int64 ()))
150
-
151
- case reflect .Uint8 :
152
- num := new (big.Int ).SetBytes (topics [0 ][:])
153
- field .Set (reflect .ValueOf (uint8 (num .Uint64 ())))
154
-
155
- case reflect .Uint16 :
156
- num := new (big.Int ).SetBytes (topics [0 ][:])
157
- field .Set (reflect .ValueOf (uint16 (num .Uint64 ())))
158
-
159
- case reflect .Uint32 :
160
- num := new (big.Int ).SetBytes (topics [0 ][:])
161
- field .Set (reflect .ValueOf (uint32 (num .Uint64 ())))
162
-
163
- case reflect .Uint64 :
164
- num := new (big.Int ).SetBytes (topics [0 ][:])
165
- field .Set (reflect .ValueOf (num .Uint64 ()))
166
-
167
- default :
168
- // Ran out of plain primitive types, try custom types
169
-
170
- switch field .Type () {
171
- case reflectHash : // Also covers all dynamic types
172
- field .Set (reflect .ValueOf (topics [0 ]))
173
-
174
- case reflectAddress :
175
- var addr common.Address
176
- copy (addr [:], topics [0 ][common .HashLength - common .AddressLength :])
177
- field .Set (reflect .ValueOf (addr ))
178
-
179
- case reflectBigInt :
180
- num := new (big.Int ).SetBytes (topics [0 ][:])
181
- if arg .Type .T == abi .IntTy {
182
- if num .Cmp (abi .MaxInt256 ) > 0 {
183
- num .Add (abi .MaxUint256 , big .NewInt (0 ).Neg (num ))
184
- num .Add (num , big .NewInt (1 ))
185
- num .Neg (num )
186
- }
187
- }
188
- field .Set (reflect .ValueOf (num ))
189
-
190
- default :
191
- // Ran out of custom types, try the crazies
192
- switch {
193
- // static byte array
194
- case arg .Type .T == abi .FixedBytesTy :
195
- reflect .Copy (field , reflect .ValueOf (topics [0 ][:arg .Type .Size ]))
196
- default :
197
- return fmt .Errorf ("unsupported indexed type: %v" , arg .Type )
198
- }
199
- }
200
- }
201
- topics = topics [1 :]
202
- }
203
- return nil
108
+ return parseTopicWithSetter (fields , topics ,
109
+ func (arg abi.Argument , reconstr interface {}) {
110
+ field := reflect .ValueOf (out ).Elem ().FieldByName (capitalise (arg .Name ))
111
+ field .Set (reflect .ValueOf (reconstr ))
112
+ })
204
113
}
205
114
206
115
// parseTopicsIntoMap converts the indexed topic field-value pairs into map key-value pairs
207
116
func parseTopicsIntoMap (out map [string ]interface {}, fields abi.Arguments , topics []common.Hash ) error {
117
+ return parseTopicWithSetter (fields , topics ,
118
+ func (arg abi.Argument , reconstr interface {}) {
119
+ out [arg .Name ] = reconstr
120
+ })
121
+ }
122
+
123
+ // parseTopicWithSetter converts the indexed topic field-value pairs and stores them using the
124
+ // provided set function.
125
+ //
126
+ // Note, dynamic types cannot be reconstructed since they get mapped to Keccak256
127
+ // hashes as the topic value!
128
+ func parseTopicWithSetter (fields abi.Arguments , topics []common.Hash , setter func (abi.Argument , interface {})) error {
208
129
// Sanity check that the fields and topics match up
209
130
if len (fields ) != len (topics ) {
210
131
return errors .New ("topic/field count mismatch" )
211
132
}
212
133
// Iterate over all the fields and reconstruct them from topics
213
- for _ , arg := range fields {
134
+ for i , arg := range fields {
214
135
if ! arg .Indexed {
215
136
return errors .New ("non-indexed field in topic reconstruction" )
216
137
}
217
-
138
+ var reconstr interface {}
218
139
switch arg .Type .T {
219
- case abi .BoolTy :
220
- out [arg .Name ] = topics [0 ][common .HashLength - 1 ] == 1
221
- case abi .IntTy , abi .UintTy :
222
- out [arg .Name ] = abi .ReadInteger (arg .Type .T , arg .Type .Kind , topics [0 ].Bytes ())
223
- case abi .AddressTy :
224
- var addr common.Address
225
- copy (addr [:], topics [0 ][common .HashLength - common .AddressLength :])
226
- out [arg .Name ] = addr
227
- case abi .HashTy :
228
- out [arg .Name ] = topics [0 ]
229
- case abi .FixedBytesTy :
230
- array , err := abi .ReadFixedBytes (arg .Type , topics [0 ].Bytes ())
231
- if err != nil {
232
- return err
233
- }
234
- out [arg .Name ] = array
140
+ case abi .TupleTy :
141
+ return errors .New ("tuple type in topic reconstruction" )
235
142
case abi .StringTy , abi .BytesTy , abi .SliceTy , abi .ArrayTy :
236
143
// Array types (including strings and bytes) have their keccak256 hashes stored in the topic- not a hash
237
144
// whose bytes can be decoded to the actual value- so the best we can do is retrieve that hash
238
- out [ arg . Name ] = topics [0 ]
145
+ reconstr = topics [i ]
239
146
case abi .FunctionTy :
240
- if garbage := binary .BigEndian .Uint64 (topics [0 ][0 :8 ]); garbage != 0 {
241
- return fmt .Errorf ("bind: got improperly encoded function type, got %v" , topics [0 ].Bytes ())
147
+ if garbage := binary .BigEndian .Uint64 (topics [i ][0 :8 ]); garbage != 0 {
148
+ return fmt .Errorf ("bind: got improperly encoded function type, got %v" , topics [i ].Bytes ())
242
149
}
243
150
var tmp [24 ]byte
244
- copy (tmp [:], topics [0 ][8 :32 ])
245
- out [arg .Name ] = tmp
246
- default : // Not handling tuples
247
- return fmt .Errorf ("unsupported indexed type: %v" , arg .Type )
151
+ copy (tmp [:], topics [i ][8 :32 ])
152
+ reconstr = tmp
153
+ default :
154
+ var err error
155
+ reconstr , err = abi .ToGoType (0 , arg .Type , topics [i ].Bytes ())
156
+ if err != nil {
157
+ return err
158
+ }
248
159
}
249
-
250
- topics = topics [ 1 :]
160
+ // Use the setter function to store the value
161
+ setter ( arg , reconstr )
251
162
}
252
163
253
164
return nil
0 commit comments