| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // Copyright 2015 The go-ethereum Authors | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // This file is part of the go-ethereum library. | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // | 
					
						
							| 
									
										
										
										
											2015-07-23 18:35:11 +02:00
										 |  |  | // The go-ethereum library is free software: you can redistribute it and/or modify | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // it under the terms of the GNU Lesser General Public License as published by | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  | // (at your option) any later version. | 
					
						
							|  |  |  | // | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // The go-ethereum library is distributed in the hope that it will be useful, | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // GNU Lesser General Public License for more details. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // You should have received a copy of the GNU Lesser General Public License | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-27 16:19:21 +01:00
										 |  |  | package abi | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"encoding/json" | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"io" | 
					
						
							|  |  |  | 	"strings" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/crypto" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Callable method given a `Name` and whether the method is a constant. | 
					
						
							|  |  |  | // If the method is `Const` no transaction needs to be created for this | 
					
						
							|  |  |  | // particular Method call. It can easily be simulated using a local VM. | 
					
						
							|  |  |  | // For example a `Balance()` method only needs to retrieve something | 
					
						
							|  |  |  | // from the storage and therefor requires no Tx to be send to the | 
					
						
							|  |  |  | // network. A method such as `Transact` does require a Tx and thus will | 
					
						
							|  |  |  | // be flagged `true`. | 
					
						
							|  |  |  | // Input specifies the required input parameters for this gives method. | 
					
						
							|  |  |  | type Method struct { | 
					
						
							|  |  |  | 	Name   string | 
					
						
							|  |  |  | 	Const  bool | 
					
						
							|  |  |  | 	Input  []Argument | 
					
						
							|  |  |  | 	Return Type // not yet implemented | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Returns the methods string signature according to the ABI spec. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // Example | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | //     function foo(uint32 a, int b)    =    "foo(uint32,int256)" | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // Please note that "int" is substitute for its canonical representation "int256" | 
					
						
							|  |  |  | func (m Method) String() (out string) { | 
					
						
							|  |  |  | 	out += m.Name | 
					
						
							|  |  |  | 	types := make([]string, len(m.Input)) | 
					
						
							|  |  |  | 	i := 0 | 
					
						
							|  |  |  | 	for _, input := range m.Input { | 
					
						
							|  |  |  | 		types[i] = input.Type.String() | 
					
						
							|  |  |  | 		i++ | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	out += "(" + strings.Join(types, ",") + ")" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (m Method) Id() []byte { | 
					
						
							|  |  |  | 	return crypto.Sha3([]byte(m.String()))[:4] | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Argument holds the name of the argument and the corresponding type. | 
					
						
							|  |  |  | // Types are used when packing and testing arguments. | 
					
						
							|  |  |  | type Argument struct { | 
					
						
							|  |  |  | 	Name string | 
					
						
							|  |  |  | 	Type Type | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (a *Argument) UnmarshalJSON(data []byte) error { | 
					
						
							|  |  |  | 	var extarg struct { | 
					
						
							|  |  |  | 		Name string | 
					
						
							|  |  |  | 		Type string | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	err := json.Unmarshal(data, &extarg) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return fmt.Errorf("argument json err: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	a.Type, err = NewType(extarg.Type) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	a.Name = extarg.Name | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // The ABI holds information about a contract's context and available | 
					
						
							|  |  |  | // invokable methods. It will allow you to type check function calls and | 
					
						
							|  |  |  | // packs data accordingly. | 
					
						
							|  |  |  | type ABI struct { | 
					
						
							|  |  |  | 	Methods map[string]Method | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // tests, tests whether the given input would result in a successful | 
					
						
							|  |  |  | // call. Checks argument list count and matches input to `input`. | 
					
						
							|  |  |  | func (abi ABI) pack(name string, args ...interface{}) ([]byte, error) { | 
					
						
							|  |  |  | 	method := abi.Methods[name] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var ret []byte | 
					
						
							|  |  |  | 	for i, a := range args { | 
					
						
							|  |  |  | 		input := method.Input[i] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		packed, err := input.Type.pack(a) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return nil, fmt.Errorf("`%s` %v", name, err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		ret = append(ret, packed...) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return ret, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Pack the given method name to conform the ABI. Method call's data | 
					
						
							|  |  |  | // will consist of method_id, args0, arg1, ... argN. Method id consists | 
					
						
							|  |  |  | // of 4 bytes and arguments are all 32 bytes. | 
					
						
							|  |  |  | // Method ids are created from the first 4 bytes of the hash of the | 
					
						
							|  |  |  | // methods string signature. (signature = baz(uint32,string32)) | 
					
						
							|  |  |  | func (abi ABI) Pack(name string, args ...interface{}) ([]byte, error) { | 
					
						
							|  |  |  | 	method, exist := abi.Methods[name] | 
					
						
							|  |  |  | 	if !exist { | 
					
						
							|  |  |  | 		return nil, fmt.Errorf("method '%s' not found", name) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// start with argument count match | 
					
						
							|  |  |  | 	if len(args) != len(method.Input) { | 
					
						
							|  |  |  | 		return nil, fmt.Errorf("argument count mismatch: %d for %d", len(args), len(method.Input)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	arguments, err := abi.pack(name, args...) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Set function id | 
					
						
							|  |  |  | 	packed := abi.Methods[name].Id() | 
					
						
							|  |  |  | 	packed = append(packed, arguments...) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return packed, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (abi *ABI) UnmarshalJSON(data []byte) error { | 
					
						
							|  |  |  | 	var methods []Method | 
					
						
							|  |  |  | 	if err := json.Unmarshal(data, &methods); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	abi.Methods = make(map[string]Method) | 
					
						
							|  |  |  | 	for _, method := range methods { | 
					
						
							|  |  |  | 		abi.Methods[method.Name] = method | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func JSON(reader io.Reader) (ABI, error) { | 
					
						
							|  |  |  | 	dec := json.NewDecoder(reader) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var abi ABI | 
					
						
							|  |  |  | 	if err := dec.Decode(&abi); err != nil { | 
					
						
							|  |  |  | 		return ABI{}, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return abi, nil | 
					
						
							|  |  |  | } |