topics.go 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  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. "encoding/binary"
  19. "errors"
  20. "fmt"
  21. "math/big"
  22. "reflect"
  23. "github.com/ethereum/go-ethereum/accounts/abi"
  24. "github.com/ethereum/go-ethereum/common"
  25. "github.com/ethereum/go-ethereum/crypto"
  26. )
  27. // makeTopics converts a filter query argument list into a filter topic set.
  28. func makeTopics(query ...[]interface{}) ([][]common.Hash, error) {
  29. topics := make([][]common.Hash, len(query))
  30. for i, filter := range query {
  31. for _, rule := range filter {
  32. var topic common.Hash
  33. // Try to generate the topic based on simple types
  34. switch rule := rule.(type) {
  35. case common.Hash:
  36. copy(topic[:], rule[:])
  37. case common.Address:
  38. copy(topic[common.HashLength-common.AddressLength:], rule[:])
  39. case *big.Int:
  40. blob := rule.Bytes()
  41. copy(topic[common.HashLength-len(blob):], blob)
  42. case bool:
  43. if rule {
  44. topic[common.HashLength-1] = 1
  45. }
  46. case int8:
  47. copy(topic[:], genIntType(int64(rule), 1))
  48. case int16:
  49. copy(topic[:], genIntType(int64(rule), 2))
  50. case int32:
  51. copy(topic[:], genIntType(int64(rule), 4))
  52. case int64:
  53. copy(topic[:], genIntType(rule, 8))
  54. case uint8:
  55. blob := new(big.Int).SetUint64(uint64(rule)).Bytes()
  56. copy(topic[common.HashLength-len(blob):], blob)
  57. case uint16:
  58. blob := new(big.Int).SetUint64(uint64(rule)).Bytes()
  59. copy(topic[common.HashLength-len(blob):], blob)
  60. case uint32:
  61. blob := new(big.Int).SetUint64(uint64(rule)).Bytes()
  62. copy(topic[common.HashLength-len(blob):], blob)
  63. case uint64:
  64. blob := new(big.Int).SetUint64(rule).Bytes()
  65. copy(topic[common.HashLength-len(blob):], blob)
  66. case string:
  67. hash := crypto.Keccak256Hash([]byte(rule))
  68. copy(topic[:], hash[:])
  69. case []byte:
  70. hash := crypto.Keccak256Hash(rule)
  71. copy(topic[:], hash[:])
  72. default:
  73. // todo(rjl493456442) according solidity documentation, indexed event
  74. // parameters that are not value types i.e. arrays and structs are not
  75. // stored directly but instead a keccak256-hash of an encoding is stored.
  76. //
  77. // We only convert stringS and bytes to hash, still need to deal with
  78. // array(both fixed-size and dynamic-size) and struct.
  79. // Attempt to generate the topic from funky types
  80. val := reflect.ValueOf(rule)
  81. switch {
  82. // static byte array
  83. case val.Kind() == reflect.Array && reflect.TypeOf(rule).Elem().Kind() == reflect.Uint8:
  84. reflect.Copy(reflect.ValueOf(topic[:val.Len()]), val)
  85. default:
  86. return nil, fmt.Errorf("unsupported indexed type: %T", rule)
  87. }
  88. }
  89. topics[i] = append(topics[i], topic)
  90. }
  91. }
  92. return topics, nil
  93. }
  94. func genIntType(rule int64, size uint) []byte {
  95. var topic [common.HashLength]byte
  96. if rule < 0 {
  97. // if a rule is negative, we need to put it into two's complement.
  98. // extended to common.Hashlength bytes.
  99. topic = [common.HashLength]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}
  100. }
  101. for i := uint(0); i < size; i++ {
  102. topic[common.HashLength-i-1] = byte(rule >> (i * 8))
  103. }
  104. return topic[:]
  105. }
  106. // parseTopics converts the indexed topic fields into actual log field values.
  107. func parseTopics(out interface{}, fields abi.Arguments, topics []common.Hash) error {
  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. })
  113. }
  114. // parseTopicsIntoMap converts the indexed topic field-value pairs into map key-value pairs
  115. func parseTopicsIntoMap(out map[string]interface{}, fields abi.Arguments, topics []common.Hash) error {
  116. return parseTopicWithSetter(fields, topics,
  117. func(arg abi.Argument, reconstr interface{}) {
  118. out[arg.Name] = reconstr
  119. })
  120. }
  121. // parseTopicWithSetter converts the indexed topic field-value pairs and stores them using the
  122. // provided set function.
  123. //
  124. // Note, dynamic types cannot be reconstructed since they get mapped to Keccak256
  125. // hashes as the topic value!
  126. func parseTopicWithSetter(fields abi.Arguments, topics []common.Hash, setter func(abi.Argument, interface{})) error {
  127. // Sanity check that the fields and topics match up
  128. if len(fields) != len(topics) {
  129. return errors.New("topic/field count mismatch")
  130. }
  131. // Iterate over all the fields and reconstruct them from topics
  132. for i, arg := range fields {
  133. if !arg.Indexed {
  134. return errors.New("non-indexed field in topic reconstruction")
  135. }
  136. var reconstr interface{}
  137. switch arg.Type.T {
  138. case abi.TupleTy:
  139. return errors.New("tuple type in topic reconstruction")
  140. case abi.StringTy, abi.BytesTy, abi.SliceTy, abi.ArrayTy:
  141. // Array types (including strings and bytes) have their keccak256 hashes stored in the topic- not a hash
  142. // whose bytes can be decoded to the actual value- so the best we can do is retrieve that hash
  143. reconstr = topics[i]
  144. case abi.FunctionTy:
  145. if garbage := binary.BigEndian.Uint64(topics[i][0:8]); garbage != 0 {
  146. return fmt.Errorf("bind: got improperly encoded function type, got %v", topics[i].Bytes())
  147. }
  148. var tmp [24]byte
  149. copy(tmp[:], topics[i][8:32])
  150. reconstr = tmp
  151. default:
  152. var err error
  153. reconstr, err = abi.ToGoType(0, arg.Type, topics[i].Bytes())
  154. if err != nil {
  155. return err
  156. }
  157. }
  158. // Use the setter function to store the value
  159. setter(arg, reconstr)
  160. }
  161. return nil
  162. }