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
17package abi
18
19import (
20	"errors"
21	"fmt"
22	"reflect"
23	"regexp"
24	"strconv"
25	"strings"
26
27	"github.com/ethereum/go-ethereum/common"
28)
29
30// Type enumerator
31const (
32	IntTy byte = iota
33	UintTy
34	BoolTy
35	StringTy
36	SliceTy
37	ArrayTy
38	TupleTy
39	AddressTy
40	FixedBytesTy
41	BytesTy
42	HashTy
43	FixedPointTy
44	FunctionTy
45)
46
47// Type is the reflection of the supported argument type.
48type Type struct {
49	Elem *Type
50	Size int
51	T    byte // Our own type checking
52
53	stringKind string // holds the unparsed string for deriving signatures
54
55	// Tuple relative fields
56	TupleRawName  string       // Raw struct name defined in source code, may be empty.
57	TupleElems    []*Type      // Type information of all tuple fields
58	TupleRawNames []string     // Raw field name of all tuple fields
59	TupleType     reflect.Type // Underlying struct of the tuple
60}
61
62var (
63	// typeRegex parses the abi sub types
64	typeRegex = regexp.MustCompile("([a-zA-Z]+)(([0-9]+)(x([0-9]+))?)?")
65)
66
67// NewType creates a new reflection type of abi type given in t.
68func NewType(t string, internalType string, components []ArgumentMarshaling) (typ Type, err error) {
69	// check that array brackets are equal if they exist
70	if strings.Count(t, "[") != strings.Count(t, "]") {
71		return Type{}, fmt.Errorf("invalid arg type in abi")
72	}
73	typ.stringKind = t
74
75	// if there are brackets, get ready to go into slice/array mode and
76	// recursively create the type
77	if strings.Count(t, "[") != 0 {
78		// Note internalType can be empty here.
79		subInternal := internalType
80		if i := strings.LastIndex(internalType, "["); i != -1 {
81			subInternal = subInternal[:i]
82		}
83		// recursively embed the type
84		i := strings.LastIndex(t, "[")
85		embeddedType, err := NewType(t[:i], subInternal, components)
86		if err != nil {
87			return Type{}, err
88		}
89		// grab the last cell and create a type from there
90		sliced := t[i:]
91		// grab the slice size with regexp
92		re := regexp.MustCompile("[0-9]+")
93		intz := re.FindAllString(sliced, -1)
94
95		if len(intz) == 0 {
96			// is a slice
97			typ.T = SliceTy
98			typ.Elem = &embeddedType
99			typ.stringKind = embeddedType.stringKind + sliced
100		} else if len(intz) == 1 {
101			// is an array
102			typ.T = ArrayTy
103			typ.Elem = &embeddedType
104			typ.Size, err = strconv.Atoi(intz[0])
105			if err != nil {
106				return Type{}, fmt.Errorf("abi: error parsing variable size: %v", err)
107			}
108			typ.stringKind = embeddedType.stringKind + sliced
109		} else {
110			return Type{}, fmt.Errorf("invalid formatting of array type")
111		}
112		return typ, err
113	}
114	// parse the type and size of the abi-type.
115	matches := typeRegex.FindAllStringSubmatch(t, -1)
116	if len(matches) == 0 {
117		return Type{}, fmt.Errorf("invalid type '%v'", t)
118	}
119	parsedType := matches[0]
120
121	// varSize is the size of the variable
122	var varSize int
123	if len(parsedType[3]) > 0 {
124		var err error
125		varSize, err = strconv.Atoi(parsedType[2])
126		if err != nil {
127			return Type{}, fmt.Errorf("abi: error parsing variable size: %v", err)
128		}
129	} else {
130		if parsedType[0] == "uint" || parsedType[0] == "int" {
131			// this should fail because it means that there's something wrong with
132			// the abi type (the compiler should always format it to the size...always)
133			return Type{}, fmt.Errorf("unsupported arg type: %s", t)
134		}
135	}
136	// varType is the parsed abi type
137	switch varType := parsedType[1]; varType {
138	case "int":
139		typ.Size = varSize
140		typ.T = IntTy
141	case "uint":
142		typ.Size = varSize
143		typ.T = UintTy
144	case "bool":
145		typ.T = BoolTy
146	case "address":
147		typ.Size = 20
148		typ.T = AddressTy
149	case "string":
150		typ.T = StringTy
151	case "bytes":
152		if varSize == 0 {
153			typ.T = BytesTy
154		} else {
155			typ.T = FixedBytesTy
156			typ.Size = varSize
157		}
158	case "tuple":
159		var (
160			fields     []reflect.StructField
161			elems      []*Type
162			names      []string
163			expression string // canonical parameter expression
164		)
165		expression += "("
166		overloadedNames := make(map[string]string)
167		for idx, c := range components {
168			cType, err := NewType(c.Type, c.InternalType, c.Components)
169			if err != nil {
170				return Type{}, err
171			}
172			fieldName, err := overloadedArgName(c.Name, overloadedNames)
173			if err != nil {
174				return Type{}, err
175			}
176			overloadedNames[fieldName] = fieldName
177			fields = append(fields, reflect.StructField{
178				Name: fieldName, // reflect.StructOf will panic for any exported field.
179				Type: cType.GetType(),
180				Tag:  reflect.StructTag("json:\"" + c.Name + "\""),
181			})
182			elems = append(elems, &cType)
183			names = append(names, c.Name)
184			expression += cType.stringKind
185			if idx != len(components)-1 {
186				expression += ","
187			}
188		}
189		expression += ")"
190
191		typ.TupleType = reflect.StructOf(fields)
192		typ.TupleElems = elems
193		typ.TupleRawNames = names
194		typ.T = TupleTy
195		typ.stringKind = expression
196
197		const structPrefix = "struct "
198		// After solidity 0.5.10, a new field of abi "internalType"
199		// is introduced. From that we can obtain the struct name
200		// user defined in the source code.
201		if internalType != "" && strings.HasPrefix(internalType, structPrefix) {
202			// Foo.Bar type definition is not allowed in golang,
203			// convert the format to FooBar
204			typ.TupleRawName = strings.Replace(internalType[len(structPrefix):], ".", "", -1)
205		}
206
207	case "function":
208		typ.T = FunctionTy
209		typ.Size = 24
210	default:
211		return Type{}, fmt.Errorf("unsupported arg type: %s", t)
212	}
213
214	return
215}
216
217// GetType returns the reflection type of the ABI type.
218func (t Type) GetType() reflect.Type {
219	switch t.T {
220	case IntTy:
221		return reflectIntType(false, t.Size)
222	case UintTy:
223		return reflectIntType(true, t.Size)
224	case BoolTy:
225		return reflect.TypeOf(false)
226	case StringTy:
227		return reflect.TypeOf("")
228	case SliceTy:
229		return reflect.SliceOf(t.Elem.GetType())
230	case ArrayTy:
231		return reflect.ArrayOf(t.Size, t.Elem.GetType())
232	case TupleTy:
233		return t.TupleType
234	case AddressTy:
235		return reflect.TypeOf(common.Address{})
236	case FixedBytesTy:
237		return reflect.ArrayOf(t.Size, reflect.TypeOf(byte(0)))
238	case BytesTy:
239		return reflect.SliceOf(reflect.TypeOf(byte(0)))
240	case HashTy:
241		// hashtype currently not used
242		return reflect.ArrayOf(32, reflect.TypeOf(byte(0)))
243	case FixedPointTy:
244		// fixedpoint type currently not used
245		return reflect.ArrayOf(32, reflect.TypeOf(byte(0)))
246	case FunctionTy:
247		return reflect.ArrayOf(24, reflect.TypeOf(byte(0)))
248	default:
249		panic("Invalid type")
250	}
251}
252
253func overloadedArgName(rawName string, names map[string]string) (string, error) {
254	fieldName := ToCamelCase(rawName)
255	if fieldName == "" {
256		return "", errors.New("abi: purely anonymous or underscored field is not supported")
257	}
258	// Handle overloaded fieldNames
259	_, ok := names[fieldName]
260	for idx := 0; ok; idx++ {
261		fieldName = fmt.Sprintf("%s%d", ToCamelCase(rawName), idx)
262		_, ok = names[fieldName]
263	}
264	return fieldName, nil
265}
266
267// String implements Stringer.
268func (t Type) String() (out string) {
269	return t.stringKind
270}
271
272func (t Type) pack(v reflect.Value) ([]byte, error) {
273	// dereference pointer first if it's a pointer
274	v = indirect(v)
275	if err := typeCheck(t, v); err != nil {
276		return nil, err
277	}
278
279	switch t.T {
280	case SliceTy, ArrayTy:
281		var ret []byte
282
283		if t.requiresLengthPrefix() {
284			// append length
285			ret = append(ret, packNum(reflect.ValueOf(v.Len()))...)
286		}
287
288		// calculate offset if any
289		offset := 0
290		offsetReq := isDynamicType(*t.Elem)
291		if offsetReq {
292			offset = getTypeSize(*t.Elem) * v.Len()
293		}
294		var tail []byte
295		for i := 0; i < v.Len(); i++ {
296			val, err := t.Elem.pack(v.Index(i))
297			if err != nil {
298				return nil, err
299			}
300			if !offsetReq {
301				ret = append(ret, val...)
302				continue
303			}
304			ret = append(ret, packNum(reflect.ValueOf(offset))...)
305			offset += len(val)
306			tail = append(tail, val...)
307		}
308		return append(ret, tail...), nil
309	case TupleTy:
310		// (T1,...,Tk) for k >= 0 and any types T1, …, Tk
311		// enc(X) = head(X(1)) ... head(X(k)) tail(X(1)) ... tail(X(k))
312		// where X = (X(1), ..., X(k)) and head and tail are defined for Ti being a static
313		// type as
314		//     head(X(i)) = enc(X(i)) and tail(X(i)) = "" (the empty string)
315		// and as
316		//     head(X(i)) = enc(len(head(X(1)) ... head(X(k)) tail(X(1)) ... tail(X(i-1))))
317		//     tail(X(i)) = enc(X(i))
318		// otherwise, i.e. if Ti is a dynamic type.
319		fieldmap, err := mapArgNamesToStructFields(t.TupleRawNames, v)
320		if err != nil {
321			return nil, err
322		}
323		// Calculate prefix occupied size.
324		offset := 0
325		for _, elem := range t.TupleElems {
326			offset += getTypeSize(*elem)
327		}
328		var ret, tail []byte
329		for i, elem := range t.TupleElems {
330			field := v.FieldByName(fieldmap[t.TupleRawNames[i]])
331			if !field.IsValid() {
332				return nil, fmt.Errorf("field %s for tuple not found in the given struct", t.TupleRawNames[i])
333			}
334			val, err := elem.pack(field)
335			if err != nil {
336				return nil, err
337			}
338			if isDynamicType(*elem) {
339				ret = append(ret, packNum(reflect.ValueOf(offset))...)
340				tail = append(tail, val...)
341				offset += len(val)
342			} else {
343				ret = append(ret, val...)
344			}
345		}
346		return append(ret, tail...), nil
347
348	default:
349		return packElement(t, v)
350	}
351}
352
353// requireLengthPrefix returns whether the type requires any sort of length
354// prefixing.
355func (t Type) requiresLengthPrefix() bool {
356	return t.T == StringTy || t.T == BytesTy || t.T == SliceTy
357}
358
359// isDynamicType returns true if the type is dynamic.
360// The following types are called “dynamic”:
361// * bytes
362// * string
363// * T[] for any T
364// * T[k] for any dynamic T and any k >= 0
365// * (T1,...,Tk) if Ti is dynamic for some 1 <= i <= k
366func isDynamicType(t Type) bool {
367	if t.T == TupleTy {
368		for _, elem := range t.TupleElems {
369			if isDynamicType(*elem) {
370				return true
371			}
372		}
373		return false
374	}
375	return t.T == StringTy || t.T == BytesTy || t.T == SliceTy || (t.T == ArrayTy && isDynamicType(*t.Elem))
376}
377
378// getTypeSize returns the size that this type needs to occupy.
379// We distinguish static and dynamic types. Static types are encoded in-place
380// and dynamic types are encoded at a separately allocated location after the
381// current block.
382// So for a static variable, the size returned represents the size that the
383// variable actually occupies.
384// For a dynamic variable, the returned size is fixed 32 bytes, which is used
385// to store the location reference for actual value storage.
386func getTypeSize(t Type) int {
387	if t.T == ArrayTy && !isDynamicType(*t.Elem) {
388		// Recursively calculate type size if it is a nested array
389		if t.Elem.T == ArrayTy || t.Elem.T == TupleTy {
390			return t.Size * getTypeSize(*t.Elem)
391		}
392		return t.Size * 32
393	} else if t.T == TupleTy && !isDynamicType(t) {
394		total := 0
395		for _, elem := range t.TupleElems {
396			total += getTypeSize(*elem)
397		}
398		return total
399	}
400	return 32
401}
402