aboutsummaryrefslogtreecommitdiff
path: root/accounts/abi/type.go
diff options
context:
space:
mode:
Diffstat (limited to 'accounts/abi/type.go')
-rw-r--r--accounts/abi/type.go348
1 files changed, 0 insertions, 348 deletions
diff --git a/accounts/abi/type.go b/accounts/abi/type.go
deleted file mode 100644
index 597d314..0000000
--- a/accounts/abi/type.go
+++ /dev/null
@@ -1,348 +0,0 @@
-// Copyright 2015 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// 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.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
-
-package abi
-
-import (
- "errors"
- "fmt"
- "reflect"
- "regexp"
- "strconv"
- "strings"
-)
-
-// Type enumerator
-const (
- IntTy byte = iota
- UintTy
- BoolTy
- StringTy
- SliceTy
- ArrayTy
- TupleTy
- AddressTy
- FixedBytesTy
- BytesTy
- HashTy
- FixedPointTy
- FunctionTy
-)
-
-// Type is the reflection of the supported argument type
-type Type struct {
- Elem *Type
- Kind reflect.Kind
- Type reflect.Type
- Size int
- T byte // Our own type checking
-
- stringKind string // holds the unparsed string for deriving signatures
-
- // Tuple relative fields
- TupleElems []*Type // Type information of all tuple fields
- TupleRawNames []string // Raw field name of all tuple fields
-}
-
-var (
- // typeRegex parses the abi sub types
- typeRegex = regexp.MustCompile("([a-zA-Z]+)(([0-9]+)(x([0-9]+))?)?")
-)
-
-// NewType creates a new reflection type of abi type given in t.
-func NewType(t string, components []ArgumentMarshaling) (typ Type, err error) {
- // 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")
- }
- 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], components)
- if err != nil {
- return Type{}, err
- }
- // 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)
- typ.stringKind = embeddedType.stringKind + sliced
- } 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)
- typ.stringKind = embeddedType.stringKind + sliced
- } else {
- return Type{}, fmt.Errorf("invalid formatting of array type")
- }
- return typ, err
- }
- // parse the type and size of the abi-type.
- matches := typeRegex.FindAllStringSubmatch(t, -1)
- if len(matches) == 0 {
- return Type{}, fmt.Errorf("invalid type '%v'", t)
- }
- parsedType := matches[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)
- }
- } else {
- 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)
- }
- }
- // 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
- typ.Type = addressT
- 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
- typ.Kind = reflect.Array
- typ.Size = varSize
- typ.Type = reflect.ArrayOf(varSize, reflect.TypeOf(byte(0)))
- }
- case "tuple":
- var (
- fields []reflect.StructField
- elems []*Type
- names []string
- expression string // canonical parameter expression
- )
- expression += "("
- for idx, c := range components {
- cType, err := NewType(c.Type, c.Components)
- if err != nil {
- return Type{}, err
- }
- if ToCamelCase(c.Name) == "" {
- return Type{}, errors.New("abi: purely anonymous or underscored field is not supported")
- }
- fields = append(fields, reflect.StructField{
- Name: ToCamelCase(c.Name), // reflect.StructOf will panic for any exported field.
- Type: cType.Type,
- Tag: reflect.StructTag("json:\"" + c.Name + "\""),
- })
- elems = append(elems, &cType)
- names = append(names, c.Name)
- expression += cType.stringKind
- if idx != len(components)-1 {
- expression += ","
- }
- }
- expression += ")"
- typ.Kind = reflect.Struct
- typ.Type = reflect.StructOf(fields)
- typ.TupleElems = elems
- typ.TupleRawNames = names
- typ.T = TupleTy
- typ.stringKind = expression
- 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)
- }
-
- return
-}
-
-// String implements Stringer
-func (t Type) String() (out string) {
- return t.stringKind
-}
-
-func (t Type) pack(v reflect.Value) ([]byte, error) {
- // dereference pointer first if it's a pointer
- v = indirect(v)
- if err := typeCheck(t, v); err != nil {
- return nil, err
- }
-
- switch t.T {
- case SliceTy, ArrayTy:
- var ret []byte
-
- if t.requiresLengthPrefix() {
- // append length
- ret = append(ret, packNum(reflect.ValueOf(v.Len()))...)
- }
-
- // calculate offset if any
- offset := 0
- offsetReq := isDynamicType(*t.Elem)
- if offsetReq {
- offset = getTypeSize(*t.Elem) * v.Len()
- }
- var tail []byte
- for i := 0; i < v.Len(); i++ {
- val, err := t.Elem.pack(v.Index(i))
- if err != nil {
- return nil, err
- }
- if !offsetReq {
- ret = append(ret, val...)
- continue
- }
- ret = append(ret, packNum(reflect.ValueOf(offset))...)
- offset += len(val)
- tail = append(tail, val...)
- }
- return append(ret, tail...), nil
- case TupleTy:
- // (T1,...,Tk) for k >= 0 and any types T1, …, Tk
- // enc(X) = head(X(1)) ... head(X(k)) tail(X(1)) ... tail(X(k))
- // where X = (X(1), ..., X(k)) and head and tail are defined for Ti being a static
- // type as
- // head(X(i)) = enc(X(i)) and tail(X(i)) = "" (the empty string)
- // and as
- // head(X(i)) = enc(len(head(X(1)) ... head(X(k)) tail(X(1)) ... tail(X(i-1))))
- // tail(X(i)) = enc(X(i))
- // otherwise, i.e. if Ti is a dynamic type.
- fieldmap, err := mapArgNamesToStructFields(t.TupleRawNames, v)
- if err != nil {
- return nil, err
- }
- // Calculate prefix occupied size.
- offset := 0
- for _, elem := range t.TupleElems {
- offset += getTypeSize(*elem)
- }
- var ret, tail []byte
- for i, elem := range t.TupleElems {
- field := v.FieldByName(fieldmap[t.TupleRawNames[i]])
- if !field.IsValid() {
- return nil, fmt.Errorf("field %s for tuple not found in the given struct", t.TupleRawNames[i])
- }
- val, err := elem.pack(field)
- if err != nil {
- return nil, err
- }
- if isDynamicType(*elem) {
- ret = append(ret, packNum(reflect.ValueOf(offset))...)
- tail = append(tail, val...)
- offset += len(val)
- } else {
- ret = append(ret, val...)
- }
- }
- return append(ret, tail...), nil
-
- default:
- return packElement(t, v), nil
- }
-}
-
-// requireLengthPrefix returns whether the type requires any sort of length
-// prefixing.
-func (t Type) requiresLengthPrefix() bool {
- return t.T == StringTy || t.T == BytesTy || t.T == SliceTy
-}
-
-// isDynamicType returns true if the type is dynamic.
-// The following types are called “dynamic”:
-// * bytes
-// * string
-// * T[] for any T
-// * T[k] for any dynamic T and any k >= 0
-// * (T1,...,Tk) if Ti is dynamic for some 1 <= i <= k
-func isDynamicType(t Type) bool {
- if t.T == TupleTy {
- for _, elem := range t.TupleElems {
- if isDynamicType(*elem) {
- return true
- }
- }
- return false
- }
- return t.T == StringTy || t.T == BytesTy || t.T == SliceTy || (t.T == ArrayTy && isDynamicType(*t.Elem))
-}
-
-// getTypeSize returns the size that this type needs to occupy.
-// We distinguish static and dynamic types. Static types are encoded in-place
-// and dynamic types are encoded at a separately allocated location after the
-// current block.
-// So for a static variable, the size returned represents the size that the
-// variable actually occupies.
-// For a dynamic variable, the returned size is fixed 32 bytes, which is used
-// to store the location reference for actual value storage.
-func getTypeSize(t Type) int {
- if t.T == ArrayTy && !isDynamicType(*t.Elem) {
- // Recursively calculate type size if it is a nested array
- if t.Elem.T == ArrayTy {
- return t.Size * getTypeSize(*t.Elem)
- }
- return t.Size * 32
- } else if t.T == TupleTy && !isDynamicType(t) {
- total := 0
- for _, elem := range t.TupleElems {
- total += getTypeSize(*elem)
- }
- return total
- }
- return 32
-}