abihelper.go 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. // Copyright 2018 The go-ethereum Authors
  2. // This file is part of go-ethereum.
  3. //
  4. // go-ethereum is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU 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. // go-ethereum 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 General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License
  15. // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
  16. package core
  17. import (
  18. "encoding/json"
  19. "fmt"
  20. "io/ioutil"
  21. "strings"
  22. "github.com/ethereum/go-ethereum/accounts/abi"
  23. "github.com/ethereum/go-ethereum/common"
  24. "bytes"
  25. "os"
  26. "regexp"
  27. )
  28. type decodedArgument struct {
  29. soltype abi.Argument
  30. value interface{}
  31. }
  32. type decodedCallData struct {
  33. signature string
  34. name string
  35. inputs []decodedArgument
  36. }
  37. // String implements stringer interface, tries to use the underlying value-type
  38. func (arg decodedArgument) String() string {
  39. var value string
  40. switch arg.value.(type) {
  41. case fmt.Stringer:
  42. value = arg.value.(fmt.Stringer).String()
  43. default:
  44. value = fmt.Sprintf("%v", arg.value)
  45. }
  46. return fmt.Sprintf("%v: %v", arg.soltype.Type.String(), value)
  47. }
  48. // String implements stringer interface for decodedCallData
  49. func (cd decodedCallData) String() string {
  50. args := make([]string, len(cd.inputs))
  51. for i, arg := range cd.inputs {
  52. args[i] = arg.String()
  53. }
  54. return fmt.Sprintf("%s(%s)", cd.name, strings.Join(args, ","))
  55. }
  56. // parseCallData matches the provided call data against the abi definition,
  57. // and returns a struct containing the actual go-typed values
  58. func parseCallData(calldata []byte, abidata string) (*decodedCallData, error) {
  59. if len(calldata) < 4 {
  60. return nil, fmt.Errorf("Invalid ABI-data, incomplete method signature of (%d bytes)", len(calldata))
  61. }
  62. sigdata, argdata := calldata[:4], calldata[4:]
  63. if len(argdata)%32 != 0 {
  64. return nil, fmt.Errorf("Not ABI-encoded data; length should be a multiple of 32 (was %d)", len(argdata))
  65. }
  66. abispec, err := abi.JSON(strings.NewReader(abidata))
  67. if err != nil {
  68. return nil, fmt.Errorf("Failed parsing JSON ABI: %v, abidata: %v", err, abidata)
  69. }
  70. method, err := abispec.MethodById(sigdata)
  71. if err != nil {
  72. return nil, err
  73. }
  74. v, err := method.Inputs.UnpackValues(argdata)
  75. if err != nil {
  76. return nil, err
  77. }
  78. decoded := decodedCallData{signature: method.Sig(), name: method.Name}
  79. for n, argument := range method.Inputs {
  80. if err != nil {
  81. return nil, fmt.Errorf("Failed to decode argument %d (signature %v): %v", n, method.Sig(), err)
  82. } else {
  83. decodedArg := decodedArgument{
  84. soltype: argument,
  85. value: v[n],
  86. }
  87. decoded.inputs = append(decoded.inputs, decodedArg)
  88. }
  89. }
  90. // We're finished decoding the data. At this point, we encode the decoded data to see if it matches with the
  91. // original data. If we didn't do that, it would e.g. be possible to stuff extra data into the arguments, which
  92. // is not detected by merely decoding the data.
  93. var (
  94. encoded []byte
  95. )
  96. encoded, err = method.Inputs.PackValues(v)
  97. if err != nil {
  98. return nil, err
  99. }
  100. if !bytes.Equal(encoded, argdata) {
  101. was := common.Bytes2Hex(encoded)
  102. exp := common.Bytes2Hex(argdata)
  103. return nil, fmt.Errorf("WARNING: Supplied data is stuffed with extra data. \nWant %s\nHave %s\nfor method %v", exp, was, method.Sig())
  104. }
  105. return &decoded, nil
  106. }
  107. // MethodSelectorToAbi converts a method selector into an ABI struct. The returned data is a valid json string
  108. // which can be consumed by the standard abi package.
  109. func MethodSelectorToAbi(selector string) ([]byte, error) {
  110. re := regexp.MustCompile(`^([^\)]+)\(([a-z0-9,\[\]]*)\)`)
  111. type fakeArg struct {
  112. Type string `json:"type"`
  113. }
  114. type fakeABI struct {
  115. Name string `json:"name"`
  116. Type string `json:"type"`
  117. Inputs []fakeArg `json:"inputs"`
  118. }
  119. groups := re.FindStringSubmatch(selector)
  120. if len(groups) != 3 {
  121. return nil, fmt.Errorf("Did not match: %v (%v matches)", selector, len(groups))
  122. }
  123. name := groups[1]
  124. args := groups[2]
  125. arguments := make([]fakeArg, 0)
  126. if len(args) > 0 {
  127. for _, arg := range strings.Split(args, ",") {
  128. arguments = append(arguments, fakeArg{arg})
  129. }
  130. }
  131. abicheat := fakeABI{
  132. name, "function", arguments,
  133. }
  134. return json.Marshal([]fakeABI{abicheat})
  135. }
  136. type AbiDb struct {
  137. db map[string]string
  138. customdb map[string]string
  139. customdbPath string
  140. }
  141. // NewEmptyAbiDB exists for test purposes
  142. func NewEmptyAbiDB() (*AbiDb, error) {
  143. return &AbiDb{make(map[string]string), make(map[string]string), ""}, nil
  144. }
  145. // NewAbiDBFromFile loads signature database from file, and
  146. // errors if the file is not valid json. Does no other validation of contents
  147. func NewAbiDBFromFile(path string) (*AbiDb, error) {
  148. raw, err := ioutil.ReadFile(path)
  149. if err != nil {
  150. return nil, err
  151. }
  152. db, err := NewEmptyAbiDB()
  153. if err != nil {
  154. return nil, err
  155. }
  156. json.Unmarshal(raw, &db.db)
  157. return db, nil
  158. }
  159. // NewAbiDBFromFiles loads both the standard signature database and a custom database. The latter will be used
  160. // to write new values into if they are submitted via the API
  161. func NewAbiDBFromFiles(standard, custom string) (*AbiDb, error) {
  162. db := &AbiDb{make(map[string]string), make(map[string]string), custom}
  163. db.customdbPath = custom
  164. raw, err := ioutil.ReadFile(standard)
  165. if err != nil {
  166. return nil, err
  167. }
  168. json.Unmarshal(raw, &db.db)
  169. // Custom file may not exist. Will be created during save, if needed
  170. if _, err := os.Stat(custom); err == nil {
  171. raw, err = ioutil.ReadFile(custom)
  172. if err != nil {
  173. return nil, err
  174. }
  175. json.Unmarshal(raw, &db.customdb)
  176. }
  177. return db, nil
  178. }
  179. // LookupMethodSelector checks the given 4byte-sequence against the known ABI methods.
  180. // OBS: This method does not validate the match, it's assumed the caller will do so
  181. func (db *AbiDb) LookupMethodSelector(id []byte) (string, error) {
  182. if len(id) < 4 {
  183. return "", fmt.Errorf("Expected 4-byte id, got %d", len(id))
  184. }
  185. sig := common.ToHex(id[:4])
  186. if key, exists := db.db[sig]; exists {
  187. return key, nil
  188. }
  189. if key, exists := db.customdb[sig]; exists {
  190. return key, nil
  191. }
  192. return "", fmt.Errorf("Signature %v not found", sig)
  193. }
  194. func (db *AbiDb) Size() int {
  195. return len(db.db)
  196. }
  197. // saveCustomAbi saves a signature ephemerally. If custom file is used, also saves to disk
  198. func (db *AbiDb) saveCustomAbi(selector, signature string) error {
  199. db.customdb[signature] = selector
  200. if db.customdbPath == "" {
  201. return nil //Not an error per se, just not used
  202. }
  203. d, err := json.Marshal(db.customdb)
  204. if err != nil {
  205. return err
  206. }
  207. err = ioutil.WriteFile(db.customdbPath, d, 0600)
  208. return err
  209. }
  210. // Adds a signature to the database, if custom database saving is enabled.
  211. // OBS: This method does _not_ validate the correctness of the data,
  212. // it is assumed that the caller has already done so
  213. func (db *AbiDb) AddSignature(selector string, data []byte) error {
  214. if len(data) < 4 {
  215. return nil
  216. }
  217. _, err := db.LookupMethodSelector(data[:4])
  218. if err == nil {
  219. return nil
  220. }
  221. sig := common.ToHex(data[:4])
  222. return db.saveCustomAbi(selector, sig)
  223. }