topics.go 5.9 KB

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