method.go 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. // Copyright 2015 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 abi
  17. import (
  18. "fmt"
  19. "reflect"
  20. "strings"
  21. "github.com/ethereum/go-ethereum/crypto"
  22. )
  23. // Callable method given a `Name` and whether the method is a constant.
  24. // If the method is `Const` no transaction needs to be created for this
  25. // particular Method call. It can easily be simulated using a local VM.
  26. // For example a `Balance()` method only needs to retrieve something
  27. // from the storage and therefor requires no Tx to be send to the
  28. // network. A method such as `Transact` does require a Tx and thus will
  29. // be flagged `true`.
  30. // Input specifies the required input parameters for this gives method.
  31. type Method struct {
  32. Name string
  33. Const bool
  34. Inputs []Argument
  35. Outputs []Argument
  36. }
  37. func (method Method) pack(args ...interface{}) ([]byte, error) {
  38. // Make sure arguments match up and pack them
  39. if len(args) != len(method.Inputs) {
  40. return nil, fmt.Errorf("argument count mismatch: %d for %d", len(args), len(method.Inputs))
  41. }
  42. // variable input is the output appended at the end of packed
  43. // output. This is used for strings and bytes types input.
  44. var variableInput []byte
  45. // input offset is the bytes offset for packed output
  46. inputOffset := 0
  47. for _, input := range method.Inputs {
  48. if input.Type.T == ArrayTy {
  49. inputOffset += (32 * input.Type.Size)
  50. } else {
  51. inputOffset += 32
  52. }
  53. }
  54. var ret []byte
  55. for i, a := range args {
  56. input := method.Inputs[i]
  57. // pack the input
  58. packed, err := input.Type.pack(reflect.ValueOf(a))
  59. if err != nil {
  60. return nil, fmt.Errorf("`%s` %v", method.Name, err)
  61. }
  62. // check for a slice type (string, bytes, slice)
  63. if input.Type.requiresLengthPrefix() {
  64. // calculate the offset
  65. offset := inputOffset + len(variableInput)
  66. // set the offset
  67. ret = append(ret, packNum(reflect.ValueOf(offset))...)
  68. // Append the packed output to the variable input. The variable input
  69. // will be appended at the end of the input.
  70. variableInput = append(variableInput, packed...)
  71. } else {
  72. // append the packed value to the input
  73. ret = append(ret, packed...)
  74. }
  75. }
  76. // append the variable input at the end of the packed input
  77. ret = append(ret, variableInput...)
  78. return ret, nil
  79. }
  80. // unpacks a method return tuple into a struct of corresponding go types
  81. //
  82. // Unpacking can be done into a struct or a slice/array.
  83. func (method Method) tupleUnpack(v interface{}, output []byte) error {
  84. // make sure the passed value is a pointer
  85. valueOf := reflect.ValueOf(v)
  86. if reflect.Ptr != valueOf.Kind() {
  87. return fmt.Errorf("abi: Unpack(non-pointer %T)", v)
  88. }
  89. var (
  90. value = valueOf.Elem()
  91. typ = value.Type()
  92. kind = value.Kind()
  93. )
  94. if err := requireUnpackKind(value, typ, kind, method.Outputs, false); err != nil {
  95. return err
  96. }
  97. j := 0
  98. for i := 0; i < len(method.Outputs); i++ {
  99. toUnpack := method.Outputs[i]
  100. marshalledValue, err := toGoType((i+j)*32, toUnpack.Type, output)
  101. if err != nil {
  102. return err
  103. }
  104. if toUnpack.Type.T == ArrayTy {
  105. // combined index ('i' + 'j') need to be adjusted only by size of array, thus
  106. // we need to decrement 'j' because 'i' was incremented
  107. j += toUnpack.Type.Size - 1
  108. }
  109. reflectValue := reflect.ValueOf(marshalledValue)
  110. switch kind {
  111. case reflect.Struct:
  112. for j := 0; j < typ.NumField(); j++ {
  113. field := typ.Field(j)
  114. // TODO read tags: `abi:"fieldName"`
  115. if field.Name == strings.ToUpper(method.Outputs[i].Name[:1])+method.Outputs[i].Name[1:] {
  116. if err := set(value.Field(j), reflectValue, method.Outputs[i]); err != nil {
  117. return err
  118. }
  119. }
  120. }
  121. case reflect.Slice, reflect.Array:
  122. v := value.Index(i)
  123. if err := requireAssignable(v, reflectValue); err != nil {
  124. return err
  125. }
  126. if err := set(v.Elem(), reflectValue, method.Outputs[i]); err != nil {
  127. return err
  128. }
  129. }
  130. }
  131. return nil
  132. }
  133. func (method Method) isTupleReturn() bool { return len(method.Outputs) > 1 }
  134. func (method Method) singleUnpack(v interface{}, output []byte) error {
  135. // make sure the passed value is a pointer
  136. valueOf := reflect.ValueOf(v)
  137. if reflect.Ptr != valueOf.Kind() {
  138. return fmt.Errorf("abi: Unpack(non-pointer %T)", v)
  139. }
  140. value := valueOf.Elem()
  141. marshalledValue, err := toGoType(0, method.Outputs[0].Type, output)
  142. if err != nil {
  143. return err
  144. }
  145. if err := set(value, reflect.ValueOf(marshalledValue), method.Outputs[0]); err != nil {
  146. return err
  147. }
  148. return nil
  149. }
  150. // Sig returns the methods string signature according to the ABI spec.
  151. //
  152. // Example
  153. //
  154. // function foo(uint32 a, int b) = "foo(uint32,int256)"
  155. //
  156. // Please note that "int" is substitute for its canonical representation "int256"
  157. func (m Method) Sig() string {
  158. types := make([]string, len(m.Inputs))
  159. i := 0
  160. for _, input := range m.Inputs {
  161. types[i] = input.Type.String()
  162. i++
  163. }
  164. return fmt.Sprintf("%v(%v)", m.Name, strings.Join(types, ","))
  165. }
  166. func (m Method) String() string {
  167. inputs := make([]string, len(m.Inputs))
  168. for i, input := range m.Inputs {
  169. inputs[i] = fmt.Sprintf("%v %v", input.Name, input.Type)
  170. }
  171. outputs := make([]string, len(m.Outputs))
  172. for i, output := range m.Outputs {
  173. if len(output.Name) > 0 {
  174. outputs[i] = fmt.Sprintf("%v ", output.Name)
  175. }
  176. outputs[i] += output.Type.String()
  177. }
  178. constant := ""
  179. if m.Const {
  180. constant = "constant "
  181. }
  182. return fmt.Sprintf("function %v(%v) %sreturns(%v)", m.Name, strings.Join(inputs, ", "), constant, strings.Join(outputs, ", "))
  183. }
  184. func (m Method) Id() []byte {
  185. return crypto.Keccak256([]byte(m.Sig()))[:4]
  186. }