| 
									
										
										
										
											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 ( | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"reflect" | 
					
						
							|  |  |  | 	"regexp" | 
					
						
							|  |  |  | 	"strconv" | 
					
						
							| 
									
										
										
										
											2017-10-17 06:07:08 -05:00
										 |  |  | 	"strings" | 
					
						
							| 
									
										
										
										
											2015-01-27 16:19:21 +01:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-10 02:48:51 +01:00
										 |  |  | // Type enumerator | 
					
						
							| 
									
										
										
										
											2015-01-27 16:19:21 +01:00
										 |  |  | const ( | 
					
						
							|  |  |  | 	IntTy byte = iota | 
					
						
							|  |  |  | 	UintTy | 
					
						
							|  |  |  | 	BoolTy | 
					
						
							| 
									
										
										
										
											2016-02-09 13:57:00 +01:00
										 |  |  | 	StringTy | 
					
						
							| 
									
										
										
										
											2015-01-27 16:19:21 +01:00
										 |  |  | 	SliceTy | 
					
						
							| 
									
										
										
										
											2017-10-17 06:07:08 -05:00
										 |  |  | 	ArrayTy | 
					
						
							| 
									
										
										
										
											2015-01-27 16:19:21 +01:00
										 |  |  | 	AddressTy | 
					
						
							| 
									
										
										
										
											2016-02-09 13:57:00 +01:00
										 |  |  | 	FixedBytesTy | 
					
						
							|  |  |  | 	BytesTy | 
					
						
							| 
									
										
										
										
											2015-11-20 13:45:37 +01:00
										 |  |  | 	HashTy | 
					
						
							| 
									
										
										
										
											2017-06-27 03:05:33 -05:00
										 |  |  | 	FixedPointTy | 
					
						
							| 
									
										
										
										
											2017-01-05 04:46:44 -06:00
										 |  |  | 	FunctionTy | 
					
						
							| 
									
										
										
										
											2015-01-27 16:19:21 +01:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Type is the reflection of the supported argument type | 
					
						
							|  |  |  | type Type struct { | 
					
						
							| 
									
										
										
										
											2016-04-07 11:39:22 +02:00
										 |  |  | 	Elem *Type | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Kind reflect.Kind | 
					
						
							|  |  |  | 	Type reflect.Type | 
					
						
							|  |  |  | 	Size int | 
					
						
							|  |  |  | 	T    byte // Our own type checking | 
					
						
							| 
									
										
										
										
											2016-03-31 23:54:47 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-27 16:19:21 +01:00
										 |  |  | 	stringKind string // holds the unparsed string for deriving signatures | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-31 23:54:47 +02:00
										 |  |  | var ( | 
					
						
							| 
									
										
										
										
											2016-04-07 11:39:22 +02:00
										 |  |  | 	// typeRegex parses the abi sub types | 
					
						
							| 
									
										
										
										
											2016-12-19 14:10:35 +02:00
										 |  |  | 	typeRegex = regexp.MustCompile("([a-zA-Z]+)(([0-9]+)(x([0-9]+))?)?") | 
					
						
							| 
									
										
										
										
											2016-03-31 23:54:47 +02:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-07 11:39:22 +02:00
										 |  |  | // NewType creates a new reflection type of abi type given in t. | 
					
						
							| 
									
										
										
										
											2015-01-27 16:19:21 +01:00
										 |  |  | func NewType(t string) (typ Type, err error) { | 
					
						
							| 
									
										
										
										
											2017-10-17 06:07:08 -05:00
										 |  |  | 	// check that array brackets are equal if they exist | 
					
						
							|  |  |  | 	if strings.Count(t, "[") != strings.Count(t, "]") { | 
					
						
							|  |  |  | 		return Type{}, fmt.Errorf("invalid arg type in abi") | 
					
						
							| 
									
										
										
										
											2015-01-27 16:19:21 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-10-17 06:07:08 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	typ.stringKind = t | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// if there are brackets, get ready to go into slice/array mode and | 
					
						
							|  |  |  | 	// recursively create the type | 
					
						
							|  |  |  | 	if strings.Count(t, "[") != 0 { | 
					
						
							|  |  |  | 		i := strings.LastIndex(t, "[") | 
					
						
							|  |  |  | 		// recursively embed the type | 
					
						
							|  |  |  | 		embeddedType, err := NewType(t[:i]) | 
					
						
							| 
									
										
										
										
											2016-04-07 11:39:22 +02:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return Type{}, err | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-10-17 06:07:08 -05:00
										 |  |  | 		// grab the last cell and create a type from there | 
					
						
							|  |  |  | 		sliced := t[i:] | 
					
						
							|  |  |  | 		// grab the slice size with regexp | 
					
						
							|  |  |  | 		re := regexp.MustCompile("[0-9]+") | 
					
						
							|  |  |  | 		intz := re.FindAllString(sliced, -1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if len(intz) == 0 { | 
					
						
							|  |  |  | 			// is a slice | 
					
						
							|  |  |  | 			typ.T = SliceTy | 
					
						
							|  |  |  | 			typ.Kind = reflect.Slice | 
					
						
							|  |  |  | 			typ.Elem = &embeddedType | 
					
						
							|  |  |  | 			typ.Type = reflect.SliceOf(embeddedType.Type) | 
					
						
							|  |  |  | 		} else if len(intz) == 1 { | 
					
						
							|  |  |  | 			// is a array | 
					
						
							|  |  |  | 			typ.T = ArrayTy | 
					
						
							|  |  |  | 			typ.Kind = reflect.Array | 
					
						
							|  |  |  | 			typ.Elem = &embeddedType | 
					
						
							|  |  |  | 			typ.Size, err = strconv.Atoi(intz[0]) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				return Type{}, fmt.Errorf("abi: error parsing variable size: %v", err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			typ.Type = reflect.ArrayOf(typ.Size, embeddedType.Type) | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			return Type{}, fmt.Errorf("invalid formatting of array type") | 
					
						
							| 
									
										
										
										
											2016-03-31 23:54:47 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-10-17 06:07:08 -05:00
										 |  |  | 		return typ, err | 
					
						
							| 
									
										
										
										
											2017-11-10 02:48:51 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	// parse the type and size of the abi-type. | 
					
						
							|  |  |  | 	parsedType := typeRegex.FindAllStringSubmatch(t, -1)[0] | 
					
						
							|  |  |  | 	// varSize is the size of the variable | 
					
						
							|  |  |  | 	var varSize int | 
					
						
							|  |  |  | 	if len(parsedType[3]) > 0 { | 
					
						
							|  |  |  | 		var err error | 
					
						
							|  |  |  | 		varSize, err = strconv.Atoi(parsedType[2]) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return Type{}, fmt.Errorf("abi: error parsing variable size: %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-10-17 06:07:08 -05:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2017-11-10 02:48:51 +01:00
										 |  |  | 		if parsedType[0] == "uint" || parsedType[0] == "int" { | 
					
						
							|  |  |  | 			// this should fail because it means that there's something wrong with | 
					
						
							|  |  |  | 			// the abi type (the compiler should always format it to the size...always) | 
					
						
							|  |  |  | 			return Type{}, fmt.Errorf("unsupported arg type: %s", t) | 
					
						
							| 
									
										
										
										
											2017-10-17 06:07:08 -05:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-11-10 02:48:51 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	// varType is the parsed abi type | 
					
						
							|  |  |  | 	switch varType := parsedType[1]; varType { | 
					
						
							|  |  |  | 	case "int": | 
					
						
							|  |  |  | 		typ.Kind, typ.Type = reflectIntKindAndType(false, varSize) | 
					
						
							|  |  |  | 		typ.Size = varSize | 
					
						
							|  |  |  | 		typ.T = IntTy | 
					
						
							|  |  |  | 	case "uint": | 
					
						
							|  |  |  | 		typ.Kind, typ.Type = reflectIntKindAndType(true, varSize) | 
					
						
							|  |  |  | 		typ.Size = varSize | 
					
						
							|  |  |  | 		typ.T = UintTy | 
					
						
							|  |  |  | 	case "bool": | 
					
						
							|  |  |  | 		typ.Kind = reflect.Bool | 
					
						
							|  |  |  | 		typ.T = BoolTy | 
					
						
							|  |  |  | 		typ.Type = reflect.TypeOf(bool(false)) | 
					
						
							|  |  |  | 	case "address": | 
					
						
							|  |  |  | 		typ.Kind = reflect.Array | 
					
						
							| 
									
										
										
										
											2018-04-04 13:42:36 +02:00
										 |  |  | 		typ.Type = addressT | 
					
						
							| 
									
										
										
										
											2017-11-10 02:48:51 +01:00
										 |  |  | 		typ.Size = 20 | 
					
						
							|  |  |  | 		typ.T = AddressTy | 
					
						
							|  |  |  | 	case "string": | 
					
						
							|  |  |  | 		typ.Kind = reflect.String | 
					
						
							|  |  |  | 		typ.Type = reflect.TypeOf("") | 
					
						
							|  |  |  | 		typ.T = StringTy | 
					
						
							|  |  |  | 	case "bytes": | 
					
						
							|  |  |  | 		if varSize == 0 { | 
					
						
							|  |  |  | 			typ.T = BytesTy | 
					
						
							|  |  |  | 			typ.Kind = reflect.Slice | 
					
						
							|  |  |  | 			typ.Type = reflect.SliceOf(reflect.TypeOf(byte(0))) | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			typ.T = FixedBytesTy | 
					
						
							| 
									
										
										
										
											2017-10-17 06:07:08 -05:00
										 |  |  | 			typ.Kind = reflect.Array | 
					
						
							| 
									
										
										
										
											2017-11-10 02:48:51 +01:00
										 |  |  | 			typ.Size = varSize | 
					
						
							|  |  |  | 			typ.Type = reflect.ArrayOf(varSize, reflect.TypeOf(byte(0))) | 
					
						
							| 
									
										
										
										
											2016-03-30 16:22:02 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-11-10 02:48:51 +01:00
										 |  |  | 	case "function": | 
					
						
							|  |  |  | 		typ.Kind = reflect.Array | 
					
						
							|  |  |  | 		typ.T = FunctionTy | 
					
						
							|  |  |  | 		typ.Size = 24 | 
					
						
							|  |  |  | 		typ.Type = reflect.ArrayOf(24, reflect.TypeOf(byte(0))) | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		return Type{}, fmt.Errorf("unsupported arg type: %s", t) | 
					
						
							| 
									
										
										
										
											2016-03-30 16:22:02 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-01-27 16:19:21 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-07 11:39:22 +02:00
										 |  |  | // String implements Stringer | 
					
						
							| 
									
										
										
										
											2015-01-27 16:19:21 +01:00
										 |  |  | func (t Type) String() (out string) { | 
					
						
							|  |  |  | 	return t.stringKind | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-07 11:39:22 +02:00
										 |  |  | func (t Type) pack(v reflect.Value) ([]byte, error) { | 
					
						
							|  |  |  | 	// dereference pointer first if it's a pointer | 
					
						
							|  |  |  | 	v = indirect(v) | 
					
						
							| 
									
										
										
										
											2016-03-15 14:06:12 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-07 11:39:22 +02:00
										 |  |  | 	if err := typeCheck(t, v); err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-01-27 16:19:21 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-17 06:07:08 -05:00
										 |  |  | 	if t.T == SliceTy || t.T == ArrayTy { | 
					
						
							| 
									
										
										
										
											2015-01-27 16:19:21 +01:00
										 |  |  | 		var packed []byte | 
					
						
							| 
									
										
										
										
											2016-11-03 17:25:19 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-07 11:39:22 +02:00
										 |  |  | 		for i := 0; i < v.Len(); i++ { | 
					
						
							|  |  |  | 			val, err := t.Elem.pack(v.Index(i)) | 
					
						
							| 
									
										
										
										
											2016-03-30 16:22:02 +02:00
										 |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				return nil, err | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			packed = append(packed, val...) | 
					
						
							| 
									
										
										
										
											2015-01-27 16:19:21 +01:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-10-17 06:07:08 -05:00
										 |  |  | 		if t.T == SliceTy { | 
					
						
							| 
									
										
										
										
											2016-11-03 17:25:19 -05:00
										 |  |  | 			return packBytesSlice(packed, v.Len()), nil | 
					
						
							| 
									
										
										
										
											2017-10-17 06:07:08 -05:00
										 |  |  | 		} else if t.T == ArrayTy { | 
					
						
							| 
									
										
										
										
											2016-11-03 17:25:19 -05:00
										 |  |  | 			return packed, nil | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-01-27 16:19:21 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-04-07 11:39:22 +02:00
										 |  |  | 	return packElement(t, v), nil | 
					
						
							| 
									
										
										
										
											2015-01-27 16:19:21 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2016-04-20 21:30:02 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | // requireLengthPrefix returns whether the type requires any sort of length | 
					
						
							|  |  |  | // prefixing. | 
					
						
							|  |  |  | func (t Type) requiresLengthPrefix() bool { | 
					
						
							| 
									
										
										
										
											2017-10-17 06:07:08 -05:00
										 |  |  | 	return t.T == StringTy || t.T == BytesTy || t.T == SliceTy | 
					
						
							| 
									
										
										
										
											2016-04-20 21:30:02 +02:00
										 |  |  | } |