@@ -103,151 +103,62 @@ func makeTopics(query ...[]interface{}) ([][]common.Hash, error) {
103103 return topics , nil
104104}
105105
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-
113106// 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!
117107func 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+ })
204113}
205114
206115// parseTopicsIntoMap converts the indexed topic field-value pairs into map key-value pairs
207116func 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 {
208129 // Sanity check that the fields and topics match up
209130 if len (fields ) != len (topics ) {
210131 return errors .New ("topic/field count mismatch" )
211132 }
212133 // Iterate over all the fields and reconstruct them from topics
213- for _ , arg := range fields {
134+ for i , arg := range fields {
214135 if ! arg .Indexed {
215136 return errors .New ("non-indexed field in topic reconstruction" )
216137 }
217-
138+ var reconstr interface {}
218139 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" )
235142 case abi .StringTy , abi .BytesTy , abi .SliceTy , abi .ArrayTy :
236143 // Array types (including strings and bytes) have their keccak256 hashes stored in the topic- not a hash
237144 // 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 ]
239146 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 ())
242149 }
243150 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+ }
248159 }
249-
250- topics = topics [ 1 :]
160+ // Use the setter function to store the value
161+ setter ( arg , reconstr )
251162 }
252163
253164 return nil
0 commit comments