github.com/jeffallen/go-ethereum@v1.1.4-0.20150910155051-571d3236c49c/accounts/abi/abi.go (about)

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