mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-17 09:23:48 +00:00
accounts/abi: implement struct parsing first attempt
Signed-off-by: VoR0220 <catalanor0220@gmail.com>
This commit is contained in:
parent
86f6568f66
commit
a16610fc1e
2 changed files with 136 additions and 80 deletions
|
|
@ -29,21 +29,32 @@ type Argument struct {
|
||||||
Indexed bool // indexed is only used by events
|
Indexed bool // indexed is only used by events
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Type only used for unmarshalling json argument types
|
||||||
|
type unmarshalArg struct {
|
||||||
|
Name string
|
||||||
|
Type string
|
||||||
|
Components []unmarshalArg // used for tuples/structs
|
||||||
|
Indexed bool
|
||||||
|
}
|
||||||
|
|
||||||
func (a *Argument) UnmarshalJSON(data []byte) error {
|
func (a *Argument) UnmarshalJSON(data []byte) error {
|
||||||
var extarg struct {
|
var extarg unmarshalArg
|
||||||
Name string
|
|
||||||
Type string
|
|
||||||
Indexed bool
|
|
||||||
}
|
|
||||||
err := json.Unmarshal(data, &extarg)
|
err := json.Unmarshal(data, &extarg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("argument json err: %v", err)
|
return fmt.Errorf("argument json err: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a.Type, err = NewType(extarg.Type)
|
if len(extarg.Components) > 0 {
|
||||||
|
a.Type, err = ParseStructType(extarg.Type, extarg.Components...)
|
||||||
|
} else {
|
||||||
|
a.Type, err = NewType(extarg.Type)
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
a.Name = extarg.Name
|
a.Name = extarg.Name
|
||||||
a.Indexed = extarg.Indexed
|
a.Indexed = extarg.Indexed
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Type enumerator
|
||||||
const (
|
const (
|
||||||
IntTy byte = iota
|
IntTy byte = iota
|
||||||
UintTy
|
UintTy
|
||||||
|
|
@ -37,6 +38,7 @@ const (
|
||||||
HashTy
|
HashTy
|
||||||
FixedPointTy
|
FixedPointTy
|
||||||
FunctionTy
|
FunctionTy
|
||||||
|
StructTy
|
||||||
)
|
)
|
||||||
|
|
||||||
// Type is the reflection of the supported argument type
|
// Type is the reflection of the supported argument type
|
||||||
|
|
@ -58,21 +60,96 @@ var (
|
||||||
|
|
||||||
// NewType creates a new reflection type of abi type given in t.
|
// NewType creates a new reflection type of abi type given in t.
|
||||||
func NewType(t string) (typ Type, err error) {
|
func NewType(t string) (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
|
// if there are brackets, get ready to go into slice/array mode and
|
||||||
// recursively create the type
|
// recursively create the type
|
||||||
|
var found bool
|
||||||
|
if typ, found, err = checkForSlices(t); found == true || err != nil {
|
||||||
|
return typ, err
|
||||||
|
}
|
||||||
|
|
||||||
|
typ.stringKind = t
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
} 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 = address_t
|
||||||
|
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 "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
|
||||||
|
}
|
||||||
|
|
||||||
|
// if brackets surround the type, create it recursively, otherwise note that brackets weren't found
|
||||||
|
func checkForSlices(t string, structComponents ...unmarshalArg) (typ Type, found bool, err error) {
|
||||||
|
// check that array brackets are equal if they exist
|
||||||
|
if strings.Count(t, "[") != strings.Count(t, "]") {
|
||||||
|
return Type{}, false, fmt.Errorf("invalid arg type in abi")
|
||||||
|
}
|
||||||
|
|
||||||
if strings.Count(t, "[") != 0 {
|
if strings.Count(t, "[") != 0 {
|
||||||
i := strings.LastIndex(t, "[")
|
i := strings.LastIndex(t, "[")
|
||||||
// recursively embed the type
|
// recursively embed the type
|
||||||
embeddedType, err := NewType(t[:i])
|
var embeddedType Type
|
||||||
|
if len(structComponents) > 0 {
|
||||||
|
embeddedType, err = ParseStructType(t, structComponents...)
|
||||||
|
} else {
|
||||||
|
embeddedType, err = NewType(t[:i])
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Type{}, err
|
return Type{}, false, err
|
||||||
}
|
}
|
||||||
// grab the last cell and create a type from there
|
// grab the last cell and create a type from there
|
||||||
sliced := t[i:]
|
sliced := t[i:]
|
||||||
|
|
@ -93,78 +170,46 @@ func NewType(t string) (typ Type, err error) {
|
||||||
typ.Elem = &embeddedType
|
typ.Elem = &embeddedType
|
||||||
typ.Size, err = strconv.Atoi(intz[0])
|
typ.Size, err = strconv.Atoi(intz[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Type{}, fmt.Errorf("abi: error parsing variable size: %v", err)
|
return Type{}, false, fmt.Errorf("abi: error parsing variable size: %v", err)
|
||||||
}
|
}
|
||||||
typ.Type = reflect.ArrayOf(typ.Size, embeddedType.Type)
|
typ.Type = reflect.ArrayOf(typ.Size, embeddedType.Type)
|
||||||
} else {
|
} else {
|
||||||
return Type{}, fmt.Errorf("invalid formatting of array type")
|
return Type{}, false, fmt.Errorf("invalid formatting of array type")
|
||||||
}
|
|
||||||
return typ, err
|
|
||||||
} else {
|
|
||||||
// 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)
|
|
||||||
}
|
|
||||||
} 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
|
|
||||||
varType := parsedType[1]
|
|
||||||
|
|
||||||
switch 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 = address_t
|
|
||||||
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 "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 typ, true, err
|
||||||
}
|
}
|
||||||
|
return Type{}, false, nil
|
||||||
|
}
|
||||||
|
|
||||||
return
|
func ParseStructType(t string, components ...unmarshalArg) (typ Type, err error) {
|
||||||
|
// if there are brackets, get ready to go into slice/array mode and
|
||||||
|
// recursively create the type
|
||||||
|
var found bool
|
||||||
|
if typ, found, err = checkForSlices(t, components...); found == true || err != nil {
|
||||||
|
return typ, err
|
||||||
|
}
|
||||||
|
typ.stringKind = t
|
||||||
|
typ.T = StructTy
|
||||||
|
typ.Kind = reflect.Struct
|
||||||
|
// create the struct type
|
||||||
|
var fields []reflect.StructField
|
||||||
|
for i, component := range components {
|
||||||
|
// it's a embedded struct type
|
||||||
|
var fieldType Type
|
||||||
|
|
||||||
|
if len(component.Components) > 0 {
|
||||||
|
fieldType, err = ParseStructType(component.Type, component.Components...)
|
||||||
|
} else {
|
||||||
|
fieldType, err = NewType(component.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return Type{}, err
|
||||||
|
}
|
||||||
|
fields[i] = reflect.StructField{Name: component.Name, Type: fieldType.Type, Tag: reflect.StructTag(fmt.Sprintf(`json:"%v"`, component.Name))}
|
||||||
|
}
|
||||||
|
typ.Type = reflect.StructOf(fields)
|
||||||
|
return typ, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// String implements Stringer
|
// String implements Stringer
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue