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. }
  83. decodedArg := decodedArgument{
  84. soltype: argument,
  85. value: v[n],
  86. }
  87. decoded.inputs = append(decoded.inputs, decodedArg)
  88. }
  89. // We're finished decoding the data. At this point, we encode the decoded data to see if it matches with the
  90. // original data. If we didn't do that, it would e.g. be possible to stuff extra data into the arguments, which
  91. // is not detected by merely decoding the data.
  92. var (
  93. encoded []byte
  94. )
  95. encoded, err = method.Inputs.PackValues(v)
  96. if err != nil {
  97. return nil, err
  98. }
  99. if !bytes.Equal(encoded, argdata) {
  100. was := common.Bytes2Hex(encoded)
  101. exp := common.Bytes2Hex(argdata)
  102. return nil, fmt.Errorf("WARNING: Supplied data is stuffed with extra data. \nWant %s\nHave %s\nfor method %v", exp, was, method.Sig())
  103. }
  104. return &decoded, nil
  105. }
  106. // MethodSelectorToAbi converts a method selector into an ABI struct. The returned data is a valid json string
  107. // which can be consumed by the standard abi package.
  108. func MethodSelectorToAbi(selector string) ([]byte, error) {
  109. re := regexp.MustCompile(`^([^\)]+)\(([a-z0-9,\[\]]*)\)`)
  110. type fakeArg struct {
  111. Type string `json:"type"`
  112. }
  113. type fakeABI struct {
  114. Name string `json:"name"`
  115. Type string `json:"type"`
  116. Inputs []fakeArg `json:"inputs"`
  117. }
  118. groups := re.FindStringSubmatch(selector)
  119. if len(groups) != 3 {
  120. return nil, fmt.Errorf("Did not match: %v (%v matches)", selector, len(groups))
  121. }
  122. name := groups[1]
  123. args := groups[2]
  124. arguments := make([]fakeArg, 0)
  125. if len(args) > 0 {
  126. for _, arg := range strings.Split(args, ",") {
  127. arguments = append(arguments, fakeArg{arg})
  128. }
  129. }
  130. abicheat := fakeABI{
  131. name, "function", arguments,
  132. }
  133. return json.Marshal([]fakeABI{abicheat})
  134. }
  135. type AbiDb struct {
  136. db map[string]string
  137. customdb map[string]string
  138. customdbPath string
  139. }
  140. // NewEmptyAbiDB exists for test purposes
  141. func NewEmptyAbiDB() (*AbiDb, error) {
  142. return &AbiDb{make(map[string]string), make(map[string]string), ""}, nil
  143. }
  144. // NewAbiDBFromFile loads signature database from file, and
  145. // errors if the file is not valid json. Does no other validation of contents
  146. func NewAbiDBFromFile(path string) (*AbiDb, error) {
  147. raw, err := ioutil.ReadFile(path)
  148. if err != nil {
  149. return nil, err
  150. }
  151. db, err := NewEmptyAbiDB()
  152. if err != nil {
  153. return nil, err
  154. }
  155. json.Unmarshal(raw, &db.db)
  156. return db, nil
  157. }
  158. // NewAbiDBFromFiles loads both the standard signature database and a custom database. The latter will be used
  159. // to write new values into if they are submitted via the API
  160. func NewAbiDBFromFiles(standard, custom string) (*AbiDb, error) {
  161. db := &AbiDb{make(map[string]string), make(map[string]string), custom}
  162. db.customdbPath = custom
  163. raw, err := ioutil.ReadFile(standard)
  164. if err != nil {
  165. return nil, err
  166. }
  167. json.Unmarshal(raw, &db.db)
  168. // Custom file may not exist. Will be created during save, if needed
  169. if _, err := os.Stat(custom); err == nil {
  170. raw, err = ioutil.ReadFile(custom)
  171. if err != nil {
  172. return nil, err
  173. }
  174. json.Unmarshal(raw, &db.customdb)
  175. }
  176. return db, nil
  177. }
  178. // LookupMethodSelector checks the given 4byte-sequence against the known ABI methods.
  179. // OBS: This method does not validate the match, it's assumed the caller will do so
  180. func (db *AbiDb) LookupMethodSelector(id []byte) (string, error) {
  181. if len(id) < 4 {
  182. return "", fmt.Errorf("Expected 4-byte id, got %d", len(id))
  183. }
  184. sig := common.ToHex(id[:4])
  185. if key, exists := db.db[sig]; exists {
  186. return key, nil
  187. }
  188. if key, exists := db.customdb[sig]; exists {
  189. return key, nil
  190. }
  191. return "", fmt.Errorf("Signature %v not found", sig)
  192. }
  193. func (db *AbiDb) Size() int {
  194. return len(db.db)
  195. }
  196. // saveCustomAbi saves a signature ephemerally. If custom file is used, also saves to disk
  197. func (db *AbiDb) saveCustomAbi(selector, signature string) error {
  198. db.customdb[signature] = selector
  199. if db.customdbPath == "" {
  200. return nil //Not an error per se, just not used
  201. }
  202. d, err := json.Marshal(db.customdb)
  203. if err != nil {
  204. return err
  205. }
  206. err = ioutil.WriteFile(db.customdbPath, d, 0600)
  207. return err
  208. }
  209. // AddSignature to the database, if custom database saving is enabled.
  210. // OBS: This method does _not_ validate the correctness of the data,
  211. // it is assumed that the caller has already done so
  212. func (db *AbiDb) AddSignature(selector string, data []byte) error {
  213. if len(data) < 4 {
  214. return nil
  215. }
  216. _, err := db.LookupMethodSelector(data[:4])
  217. if err == nil {
  218. return nil
  219. }
  220. sig := common.ToHex(data[:4])
  221. return db.saveCustomAbi(selector, sig)
  222. }