abi.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. package abi
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "io"
  6. "strings"
  7. "github.com/ethereum/go-ethereum/crypto"
  8. )
  9. // Callable method given a `Name` and whether the method is a constant.
  10. // If the method is `Const` no transaction needs to be created for this
  11. // particular Method call. It can easily be simulated using a local VM.
  12. // For example a `Balance()` method only needs to retrieve something
  13. // from the storage and therefor requires no Tx to be send to the
  14. // network. A method such as `Transact` does require a Tx and thus will
  15. // be flagged `true`.
  16. // Input specifies the required input parameters for this gives method.
  17. type Method struct {
  18. Name string
  19. Const bool
  20. Input []Argument
  21. Return Type // not yet implemented
  22. }
  23. // Returns the methods string signature according to the ABI spec.
  24. //
  25. // Example
  26. //
  27. // function foo(uint32 a, int b) = "foo(uint32,int256)"
  28. //
  29. // Please note that "int" is substitute for its canonical representation "int256"
  30. func (m Method) String() (out string) {
  31. out += m.Name
  32. types := make([]string, len(m.Input))
  33. i := 0
  34. for _, input := range m.Input {
  35. types[i] = input.Type.String()
  36. i++
  37. }
  38. out += "(" + strings.Join(types, ",") + ")"
  39. return
  40. }
  41. func (m Method) Id() []byte {
  42. return crypto.Sha3([]byte(m.String()))[:4]
  43. }
  44. // Argument holds the name of the argument and the corresponding type.
  45. // Types are used when packing and testing arguments.
  46. type Argument struct {
  47. Name string
  48. Type Type
  49. }
  50. func (a *Argument) UnmarshalJSON(data []byte) error {
  51. var extarg struct {
  52. Name string
  53. Type string
  54. }
  55. err := json.Unmarshal(data, &extarg)
  56. if err != nil {
  57. return fmt.Errorf("argument json err: %v", err)
  58. }
  59. a.Type, err = NewType(extarg.Type)
  60. if err != nil {
  61. return err
  62. }
  63. a.Name = extarg.Name
  64. return nil
  65. }
  66. // The ABI holds information about a contract's context and available
  67. // invokable methods. It will allow you to type check function calls and
  68. // packs data accordingly.
  69. type ABI struct {
  70. Methods map[string]Method
  71. }
  72. // tests, tests whether the given input would result in a successful
  73. // call. Checks argument list count and matches input to `input`.
  74. func (abi ABI) pack(name string, args ...interface{}) ([]byte, error) {
  75. method := abi.Methods[name]
  76. var ret []byte
  77. for i, a := range args {
  78. input := method.Input[i]
  79. packed, err := input.Type.pack(a)
  80. if err != nil {
  81. return nil, fmt.Errorf("`%s` %v", name, err)
  82. }
  83. ret = append(ret, packed...)
  84. }
  85. return ret, nil
  86. }
  87. // Pack the given method name to conform the ABI. Method call's data
  88. // will consist of method_id, args0, arg1, ... argN. Method id consists
  89. // of 4 bytes and arguments are all 32 bytes.
  90. // Method ids are created from the first 4 bytes of the hash of the
  91. // methods string signature. (signature = baz(uint32,string32))
  92. func (abi ABI) Pack(name string, args ...interface{}) ([]byte, error) {
  93. method, exist := abi.Methods[name]
  94. if !exist {
  95. return nil, fmt.Errorf("method '%s' not found", name)
  96. }
  97. // start with argument count match
  98. if len(args) != len(method.Input) {
  99. return nil, fmt.Errorf("argument count mismatch: %d for %d", len(args), len(method.Input))
  100. }
  101. arguments, err := abi.pack(name, args...)
  102. if err != nil {
  103. return nil, err
  104. }
  105. // Set function id
  106. packed := abi.Methods[name].Id()
  107. packed = append(packed, arguments...)
  108. return packed, nil
  109. }
  110. func (abi *ABI) UnmarshalJSON(data []byte) error {
  111. var methods []Method
  112. if err := json.Unmarshal(data, &methods); err != nil {
  113. return err
  114. }
  115. abi.Methods = make(map[string]Method)
  116. for _, method := range methods {
  117. abi.Methods[method.Name] = method
  118. }
  119. return nil
  120. }
  121. func JSON(reader io.Reader) (ABI, error) {
  122. dec := json.NewDecoder(reader)
  123. var abi ABI
  124. if err := dec.Decode(&abi); err != nil {
  125. return ABI{}, err
  126. }
  127. return abi, nil
  128. }