plugeth/accounts/abi/type.go

211 lines
5.2 KiB
Go
Raw Normal View History

2015-07-07 00:54:22 +00:00
// Copyright 2015 The go-ethereum Authors
// This file is part of the go-ethereum library.
2015-07-07 00:54:22 +00:00
//
// The go-ethereum library is free software: you can redistribute it and/or modify
2015-07-07 00:54:22 +00: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.
//
// The go-ethereum library is distributed in the hope that it will be useful,
2015-07-07 00:54:22 +00:00
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2015-07-07 00:54:22 +00:00
// 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/>.
2015-07-07 00:54:22 +00:00
2015-01-27 15:19:21 +00:00
package abi
import (
"fmt"
"reflect"
"regexp"
"strconv"
)
const (
IntTy byte = iota
UintTy
BoolTy
StringTy
2015-01-27 15:19:21 +00:00
SliceTy
AddressTy
FixedBytesTy
BytesTy
HashTy
accounts/abi: reorganizing package with small fixes (#14610) * accounts/abi: reorganizing package and some notes and a quick correction of name. Signed-off-by: RJ Catalano <rj@monax.io> get rid of some imports Signed-off-by: RJ Catalano <rj@monax.io> * accounts/abi: move file names Signed-off-by: RJ Catalano <rj@monax.io> * accounts/abi: fix boolean decode function Signed-off-by: RJ Catalano <rj@monax.io> * accounts/abi: fix for the array set and for creating a bool Signed-off-by: RJ Catalano <rj@monax.io> * accounts/abi: be very very very correct Signed-off-by: RJ Catalano <rj@monax.io> * accounts/abi: fix up error message and variable names Signed-off-by: RJ Catalano <rj@monax.io> * accounts/abi: take out unnecessary argument in pack method Signed-off-by: RJ Catalano <rj@monax.io> * accounts/abi: add bool unpack test and add a panic to readBool function Signed-off-by: RJ Catalano <rj@monax.io> * accounts/abi: fix panic message Signed-off-by: RJ Catalano <rj@monax.io> * accounts/abi: change from panic to basic error Signed-off-by: RJ Catalano <rj@monax.io> * accounts/abi: fix nil to false Signed-off-by: RJ Catalano <rj@monax.io> * accounts/abi: fill out type regex tests and fill with the correct type for integers Signed-off-by: RJ Catalano <rj@monax.io> * accounts/abi: move packNumbers into pack.go. Signed-off-by: RJ Catalano <rj@monax.io> * accounts/abi: separation of the testing suite into appropriately named files. Signed-off-by: RJ Catalano <rj@monax.io> * account/abi: change to hex string tests. Signed-off-by: RJ Catalano <rj@monax.io> * account/abi: fix up rest of tests to hex Signed-off-by: RJ Catalano <rj@monax.io> * accounts/abi: declare bool at the package level Signed-off-by: RJ Catalano <rj@monax.io> * accounts/abi: use errors package in the error file. Signed-off-by: RJ Catalano <rj@monax.io> * accounts/abi: fix ugly hack and fix error type declaration. Signed-off-by: RJ Catalano <rj@monax.io>
2017-06-27 08:05:33 +00:00
FixedPointTy
FunctionTy
2015-01-27 15:19:21 +00:00
)
// Type is the reflection of the supported argument type
type Type struct {
IsSlice, IsArray bool
SliceSize int
Elem *Type
Kind reflect.Kind
Type reflect.Type
Size int
T byte // Our own type checking
2015-01-27 15:19:21 +00:00
stringKind string // holds the unparsed string for deriving signatures
}
var (
// fullTypeRegex parses the abi types
//
// Types can be in the format of:
//
// Input = Type [ "[" [ Number ] "]" ] Name .
// Type = [ "u" ] "int" [ Number ] [ x ] [ Number ].
//
// Examples:
//
// string int uint fixed
// string32 int8 uint8 uint[]
// address int256 uint256 fixed128x128[2]
fullTypeRegex = regexp.MustCompile(`([a-zA-Z0-9]+)(\[([0-9]*)\])?`)
// 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.
2015-01-27 15:19:21 +00:00
func NewType(t string) (typ Type, err error) {
res := fullTypeRegex.FindAllStringSubmatch(t, -1)[0]
// check if type is slice and parse type.
2015-01-27 15:19:21 +00:00
switch {
case res[3] != "":
// err is ignored. Already checked for number through the regexp
typ.SliceSize, _ = strconv.Atoi(res[3])
typ.IsArray = true
2015-01-27 15:19:21 +00:00
case res[2] != "":
typ.IsSlice, typ.SliceSize = true, -1
2015-01-27 15:19:21 +00:00
case res[0] == "":
return Type{}, fmt.Errorf("abi: type parse error: %s", t)
2015-01-27 15:19:21 +00:00
}
if typ.IsArray || typ.IsSlice {
sliceType, err := NewType(res[1])
if err != nil {
return Type{}, err
}
typ.Elem = &sliceType
typ.stringKind = sliceType.stringKind + t[len(res[1]):]
// Although we know that this is an array, we cannot return
2016-12-14 22:34:27 +00:00
// as we don't know the type of the element, however, if it
// is still an array, then don't determine the type.
if typ.Elem.IsArray || typ.Elem.IsSlice {
return typ, nil
}
}
2015-01-27 15:19:21 +00:00
// parse the type and size of the abi-type.
parsedType := typeRegex.FindAllStringSubmatch(res[1], -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)
}
2015-01-27 15:19:21 +00:00
}
// varType is the parsed abi type
varType := parsedType[1]
// substitute canonical integer
if varSize == 0 && (varType == "int" || varType == "uint") {
varSize = 256
2015-01-27 15:19:21 +00:00
t += "256"
}
// only set stringKind if not array or slice, as for those,
// the correct string type has been set
if !(typ.IsArray || typ.IsSlice) {
typ.stringKind = t
}
2015-01-27 15:19:21 +00:00
switch varType {
case "int":
accounts/abi: reorganizing package with small fixes (#14610) * accounts/abi: reorganizing package and some notes and a quick correction of name. Signed-off-by: RJ Catalano <rj@monax.io> get rid of some imports Signed-off-by: RJ Catalano <rj@monax.io> * accounts/abi: move file names Signed-off-by: RJ Catalano <rj@monax.io> * accounts/abi: fix boolean decode function Signed-off-by: RJ Catalano <rj@monax.io> * accounts/abi: fix for the array set and for creating a bool Signed-off-by: RJ Catalano <rj@monax.io> * accounts/abi: be very very very correct Signed-off-by: RJ Catalano <rj@monax.io> * accounts/abi: fix up error message and variable names Signed-off-by: RJ Catalano <rj@monax.io> * accounts/abi: take out unnecessary argument in pack method Signed-off-by: RJ Catalano <rj@monax.io> * accounts/abi: add bool unpack test and add a panic to readBool function Signed-off-by: RJ Catalano <rj@monax.io> * accounts/abi: fix panic message Signed-off-by: RJ Catalano <rj@monax.io> * accounts/abi: change from panic to basic error Signed-off-by: RJ Catalano <rj@monax.io> * accounts/abi: fix nil to false Signed-off-by: RJ Catalano <rj@monax.io> * accounts/abi: fill out type regex tests and fill with the correct type for integers Signed-off-by: RJ Catalano <rj@monax.io> * accounts/abi: move packNumbers into pack.go. Signed-off-by: RJ Catalano <rj@monax.io> * accounts/abi: separation of the testing suite into appropriately named files. Signed-off-by: RJ Catalano <rj@monax.io> * account/abi: change to hex string tests. Signed-off-by: RJ Catalano <rj@monax.io> * account/abi: fix up rest of tests to hex Signed-off-by: RJ Catalano <rj@monax.io> * accounts/abi: declare bool at the package level Signed-off-by: RJ Catalano <rj@monax.io> * accounts/abi: use errors package in the error file. Signed-off-by: RJ Catalano <rj@monax.io> * accounts/abi: fix ugly hack and fix error type declaration. Signed-off-by: RJ Catalano <rj@monax.io>
2017-06-27 08:05:33 +00:00
typ.Kind, typ.Type = reflectIntKindAndType(false, varSize)
typ.Size = varSize
typ.T = IntTy
case "uint":
accounts/abi: reorganizing package with small fixes (#14610) * accounts/abi: reorganizing package and some notes and a quick correction of name. Signed-off-by: RJ Catalano <rj@monax.io> get rid of some imports Signed-off-by: RJ Catalano <rj@monax.io> * accounts/abi: move file names Signed-off-by: RJ Catalano <rj@monax.io> * accounts/abi: fix boolean decode function Signed-off-by: RJ Catalano <rj@monax.io> * accounts/abi: fix for the array set and for creating a bool Signed-off-by: RJ Catalano <rj@monax.io> * accounts/abi: be very very very correct Signed-off-by: RJ Catalano <rj@monax.io> * accounts/abi: fix up error message and variable names Signed-off-by: RJ Catalano <rj@monax.io> * accounts/abi: take out unnecessary argument in pack method Signed-off-by: RJ Catalano <rj@monax.io> * accounts/abi: add bool unpack test and add a panic to readBool function Signed-off-by: RJ Catalano <rj@monax.io> * accounts/abi: fix panic message Signed-off-by: RJ Catalano <rj@monax.io> * accounts/abi: change from panic to basic error Signed-off-by: RJ Catalano <rj@monax.io> * accounts/abi: fix nil to false Signed-off-by: RJ Catalano <rj@monax.io> * accounts/abi: fill out type regex tests and fill with the correct type for integers Signed-off-by: RJ Catalano <rj@monax.io> * accounts/abi: move packNumbers into pack.go. Signed-off-by: RJ Catalano <rj@monax.io> * accounts/abi: separation of the testing suite into appropriately named files. Signed-off-by: RJ Catalano <rj@monax.io> * account/abi: change to hex string tests. Signed-off-by: RJ Catalano <rj@monax.io> * account/abi: fix up rest of tests to hex Signed-off-by: RJ Catalano <rj@monax.io> * accounts/abi: declare bool at the package level Signed-off-by: RJ Catalano <rj@monax.io> * accounts/abi: use errors package in the error file. Signed-off-by: RJ Catalano <rj@monax.io> * accounts/abi: fix ugly hack and fix error type declaration. Signed-off-by: RJ Catalano <rj@monax.io>
2017-06-27 08:05:33 +00:00
typ.Kind, typ.Type = reflectIntKindAndType(true, varSize)
typ.Size = varSize
typ.T = UintTy
case "bool":
typ.Kind = reflect.Bool
typ.T = BoolTy
case "address":
typ.Kind = reflect.Array
typ.Type = address_t
typ.Size = 20
typ.T = AddressTy
case "string":
typ.Kind = reflect.String
typ.Size = -1
typ.T = StringTy
case "bytes":
sliceType, _ := NewType("uint8")
typ.Elem = &sliceType
if varSize == 0 {
typ.IsSlice = true
typ.T = BytesTy
typ.SliceSize = -1
} else {
typ.IsArray = true
typ.T = FixedBytesTy
typ.SliceSize = varSize
}
case "function":
sliceType, _ := NewType("uint8")
typ.Elem = &sliceType
typ.IsArray = true
typ.T = FunctionTy
typ.SliceSize = 24
default:
return Type{}, fmt.Errorf("unsupported arg type: %s", t)
}
2015-01-27 15:19:21 +00:00
return
}
// String implements Stringer
2015-01-27 15:19:21 +00:00
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
}
2015-01-27 15:19:21 +00:00
if (t.IsSlice || t.IsArray) && t.T != BytesTy && t.T != FixedBytesTy && t.T != FunctionTy {
2015-01-27 15:19:21 +00:00
var packed []byte
for i := 0; i < v.Len(); i++ {
val, err := t.Elem.pack(v.Index(i))
if err != nil {
return nil, err
}
packed = append(packed, val...)
2015-01-27 15:19:21 +00:00
}
if t.IsSlice {
return packBytesSlice(packed, v.Len()), nil
} else if t.IsArray {
return packed, nil
}
2015-01-27 15:19:21 +00:00
}
return packElement(t, v), nil
2015-01-27 15:19:21 +00:00
}
// requireLengthPrefix returns whether the type requires any sort of length
// prefixing.
func (t Type) requiresLengthPrefix() bool {
return t.T != FixedBytesTy && (t.T == StringTy || t.T == BytesTy || t.IsSlice)
}