aboutsummaryrefslogtreecommitdiffstats
path: root/accounts/abi/reflect.go
diff options
context:
space:
mode:
authorgary rong <garyrong0905@gmail.com>2019-01-10 16:59:37 +0800
committerGuillaume Ballet <gballet@gmail.com>2019-01-10 16:59:37 +0800
commit7ca40306af9da68a0d31439117246de8247f99d6 (patch)
treef06e5fe7050212fff1ea1e727bba4280a7d6cc2d /accounts/abi/reflect.go
parent6df3e4eeb0dda986aef3f71335151fa63c06f6d3 (diff)
downloaddexon-7ca40306af9da68a0d31439117246de8247f99d6.tar.gz
dexon-7ca40306af9da68a0d31439117246de8247f99d6.tar.zst
dexon-7ca40306af9da68a0d31439117246de8247f99d6.zip
accounts/abi: tuple support (#18406)
Diffstat (limited to 'accounts/abi/reflect.go')
-rw-r--r--accounts/abi/reflect.go63
1 files changed, 27 insertions, 36 deletions
diff --git a/accounts/abi/reflect.go b/accounts/abi/reflect.go
index f541cf3bf..1b0bb0049 100644
--- a/accounts/abi/reflect.go
+++ b/accounts/abi/reflect.go
@@ -71,18 +71,17 @@ func mustArrayToByteSlice(value reflect.Value) reflect.Value {
//
// set is a bit more lenient when it comes to assignment and doesn't force an as
// strict ruleset as bare `reflect` does.
-func set(dst, src reflect.Value, output Argument) error {
- dstType := dst.Type()
- srcType := src.Type()
+func set(dst, src reflect.Value) error {
+ dstType, srcType := dst.Type(), src.Type()
switch {
- case dstType.AssignableTo(srcType):
- dst.Set(src)
- case dstType.Kind() == reflect.Slice && srcType.Kind() == reflect.Slice:
- return setSlice(dst, src, output)
case dstType.Kind() == reflect.Interface:
+ return set(dst.Elem(), src)
+ case dstType.Kind() == reflect.Ptr && dstType.Elem() != derefbigT:
+ return set(dst.Elem(), src)
+ case srcType.AssignableTo(dstType) && dst.CanSet():
dst.Set(src)
- case dstType.Kind() == reflect.Ptr:
- return set(dst.Elem(), src, output)
+ case dstType.Kind() == reflect.Slice && srcType.Kind() == reflect.Slice:
+ return setSlice(dst, src)
default:
return fmt.Errorf("abi: cannot unmarshal %v in to %v", src.Type(), dst.Type())
}
@@ -91,7 +90,7 @@ func set(dst, src reflect.Value, output Argument) error {
// setSlice attempts to assign src to dst when slices are not assignable by default
// e.g. src: [][]byte -> dst: [][15]byte
-func setSlice(dst, src reflect.Value, output Argument) error {
+func setSlice(dst, src reflect.Value) error {
slice := reflect.MakeSlice(dst.Type(), src.Len(), src.Len())
for i := 0; i < src.Len(); i++ {
v := src.Index(i)
@@ -127,14 +126,14 @@ func requireUnpackKind(v reflect.Value, t reflect.Type, k reflect.Kind,
return nil
}
-// mapAbiToStringField maps abi to struct fields.
+// mapArgNamesToStructFields maps a slice of argument names to struct fields.
// first round: for each Exportable field that contains a `abi:""` tag
-// and this field name exists in the arguments, pair them together.
-// second round: for each argument field that has not been already linked,
+// and this field name exists in the given argument name list, pair them together.
+// second round: for each argument name that has not been already linked,
// find what variable is expected to be mapped into, if it exists and has not been
// used, pair them.
-func mapAbiToStructFields(args Arguments, value reflect.Value) (map[string]string, error) {
-
+// Note this function assumes the given value is a struct value.
+func mapArgNamesToStructFields(argNames []string, value reflect.Value) (map[string]string, error) {
typ := value.Type()
abi2struct := make(map[string]string)
@@ -148,45 +147,39 @@ func mapAbiToStructFields(args Arguments, value reflect.Value) (map[string]strin
if structFieldName[:1] != strings.ToUpper(structFieldName[:1]) {
continue
}
-
// skip fields that have no abi:"" tag.
var ok bool
var tagName string
if tagName, ok = typ.Field(i).Tag.Lookup("abi"); !ok {
continue
}
-
// check if tag is empty.
if tagName == "" {
return nil, fmt.Errorf("struct: abi tag in '%s' is empty", structFieldName)
}
-
// check which argument field matches with the abi tag.
found := false
- for _, abiField := range args.NonIndexed() {
- if abiField.Name == tagName {
- if abi2struct[abiField.Name] != "" {
+ for _, arg := range argNames {
+ if arg == tagName {
+ if abi2struct[arg] != "" {
return nil, fmt.Errorf("struct: abi tag in '%s' already mapped", structFieldName)
}
// pair them
- abi2struct[abiField.Name] = structFieldName
- struct2abi[structFieldName] = abiField.Name
+ abi2struct[arg] = structFieldName
+ struct2abi[structFieldName] = arg
found = true
}
}
-
// check if this tag has been mapped.
if !found {
return nil, fmt.Errorf("struct: abi tag '%s' defined but not found in abi", tagName)
}
-
}
// second round ~~~
- for _, arg := range args {
+ for _, argName := range argNames {
- abiFieldName := arg.Name
- structFieldName := ToCamelCase(abiFieldName)
+ structFieldName := ToCamelCase(argName)
if structFieldName == "" {
return nil, fmt.Errorf("abi: purely underscored output cannot unpack to struct")
@@ -196,11 +189,11 @@ func mapAbiToStructFields(args Arguments, value reflect.Value) (map[string]strin
// struct field with the same field name. If so, raise an error:
// abi: [ { "name": "value" } ]
// struct { Value *big.Int , Value1 *big.Int `abi:"value"`}
- if abi2struct[abiFieldName] != "" {
- if abi2struct[abiFieldName] != structFieldName &&
+ if abi2struct[argName] != "" {
+ if abi2struct[argName] != structFieldName &&
struct2abi[structFieldName] == "" &&
value.FieldByName(structFieldName).IsValid() {
- return nil, fmt.Errorf("abi: multiple variables maps to the same abi field '%s'", abiFieldName)
+ return nil, fmt.Errorf("abi: multiple variables maps to the same abi field '%s'", argName)
}
continue
}
@@ -212,16 +205,14 @@ func mapAbiToStructFields(args Arguments, value reflect.Value) (map[string]strin
if value.FieldByName(structFieldName).IsValid() {
// pair them
- abi2struct[abiFieldName] = structFieldName
- struct2abi[structFieldName] = abiFieldName
+ abi2struct[argName] = structFieldName
+ struct2abi[structFieldName] = argName
} else {
// not paired, but annotate as used, to detect cases like
// abi : [ { "name": "value" }, { "name": "_value" } ]
// struct { Value *big.Int }
- struct2abi[structFieldName] = abiFieldName
+ struct2abi[structFieldName] = argName
}
-
}
-
return abi2struct, nil
}