| 
									
										
										
										
											2016-04-07 11:39:22 +02:00
										 |  |  | // Copyright 2016 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 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-11 13:21:25 +02:00
										 |  |  | import ( | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"reflect" | 
					
						
							| 
									
										
										
										
											2018-05-14 14:47:31 +02:00
										 |  |  | 	"strings" | 
					
						
							| 
									
										
										
										
											2016-05-11 13:21:25 +02:00
										 |  |  | ) | 
					
						
							| 
									
										
										
										
											2016-04-07 11:39:22 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | // indirect recursively dereferences the value until it either gets the value | 
					
						
							|  |  |  | // or finds a big.Int | 
					
						
							|  |  |  | func indirect(v reflect.Value) reflect.Value { | 
					
						
							| 
									
										
										
										
											2018-04-04 13:42:36 +02:00
										 |  |  | 	if v.Kind() == reflect.Ptr && v.Elem().Type() != derefbigT { | 
					
						
							| 
									
										
										
										
											2016-04-07 11:39:22 +02:00
										 |  |  | 		return indirect(v.Elem()) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return v | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // reflectIntKind returns the reflect using the given size and | 
					
						
							|  |  |  | // unsignedness. | 
					
						
							| 
									
										
										
										
											2017-06-27 03:05:33 -05:00
										 |  |  | func reflectIntKindAndType(unsigned bool, size int) (reflect.Kind, reflect.Type) { | 
					
						
							| 
									
										
										
										
											2016-04-07 11:39:22 +02:00
										 |  |  | 	switch size { | 
					
						
							|  |  |  | 	case 8: | 
					
						
							|  |  |  | 		if unsigned { | 
					
						
							| 
									
										
										
										
											2018-04-04 13:42:36 +02:00
										 |  |  | 			return reflect.Uint8, uint8T | 
					
						
							| 
									
										
										
										
											2016-04-07 11:39:22 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-04-04 13:42:36 +02:00
										 |  |  | 		return reflect.Int8, int8T | 
					
						
							| 
									
										
										
										
											2016-04-07 11:39:22 +02:00
										 |  |  | 	case 16: | 
					
						
							|  |  |  | 		if unsigned { | 
					
						
							| 
									
										
										
										
											2018-04-04 13:42:36 +02:00
										 |  |  | 			return reflect.Uint16, uint16T | 
					
						
							| 
									
										
										
										
											2016-04-07 11:39:22 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-04-04 13:42:36 +02:00
										 |  |  | 		return reflect.Int16, int16T | 
					
						
							| 
									
										
										
										
											2016-04-07 11:39:22 +02:00
										 |  |  | 	case 32: | 
					
						
							|  |  |  | 		if unsigned { | 
					
						
							| 
									
										
										
										
											2018-04-04 13:42:36 +02:00
										 |  |  | 			return reflect.Uint32, uint32T | 
					
						
							| 
									
										
										
										
											2016-04-07 11:39:22 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-04-04 13:42:36 +02:00
										 |  |  | 		return reflect.Int32, int32T | 
					
						
							| 
									
										
										
										
											2016-04-07 11:39:22 +02:00
										 |  |  | 	case 64: | 
					
						
							|  |  |  | 		if unsigned { | 
					
						
							| 
									
										
										
										
											2018-04-04 13:42:36 +02:00
										 |  |  | 			return reflect.Uint64, uint64T | 
					
						
							| 
									
										
										
										
											2016-04-07 11:39:22 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-04-04 13:42:36 +02:00
										 |  |  | 		return reflect.Int64, int64T | 
					
						
							| 
									
										
										
										
											2016-04-07 11:39:22 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-04-04 13:42:36 +02:00
										 |  |  | 	return reflect.Ptr, bigT | 
					
						
							| 
									
										
										
										
											2016-04-07 11:39:22 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // mustArrayToBytesSlice creates a new byte slice with the exact same size as value | 
					
						
							|  |  |  | // and copies the bytes in value to the new slice. | 
					
						
							|  |  |  | func mustArrayToByteSlice(value reflect.Value) reflect.Value { | 
					
						
							|  |  |  | 	slice := reflect.MakeSlice(reflect.TypeOf([]byte{}), value.Len(), value.Len()) | 
					
						
							|  |  |  | 	reflect.Copy(slice, value) | 
					
						
							|  |  |  | 	return slice | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2016-05-11 13:21:25 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | // set attempts to assign src to dst by either setting, copying or otherwise. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // set is a bit more lenient when it comes to assignment and doesn't force an as | 
					
						
							|  |  |  | // strict ruleset as bare `reflect` does. | 
					
						
							| 
									
										
										
										
											2019-01-10 16:59:37 +08:00
										 |  |  | func set(dst, src reflect.Value) error { | 
					
						
							|  |  |  | 	dstType, srcType := dst.Type(), src.Type() | 
					
						
							| 
									
										
										
										
											2016-05-11 13:21:25 +02:00
										 |  |  | 	switch { | 
					
						
							| 
									
										
										
										
											2019-01-23 21:36:49 +08:00
										 |  |  | 	case dstType.Kind() == reflect.Interface && dst.Elem().IsValid(): | 
					
						
							| 
									
										
										
										
											2019-01-10 16:59:37 +08:00
										 |  |  | 		return set(dst.Elem(), src) | 
					
						
							|  |  |  | 	case dstType.Kind() == reflect.Ptr && dstType.Elem() != derefbigT: | 
					
						
							|  |  |  | 		return set(dst.Elem(), src) | 
					
						
							|  |  |  | 	case srcType.AssignableTo(dstType) && dst.CanSet(): | 
					
						
							| 
									
										
										
										
											2016-05-11 13:21:25 +02:00
										 |  |  | 		dst.Set(src) | 
					
						
							| 
									
										
										
										
											2019-01-10 16:59:37 +08:00
										 |  |  | 	case dstType.Kind() == reflect.Slice && srcType.Kind() == reflect.Slice: | 
					
						
							|  |  |  | 		return setSlice(dst, src) | 
					
						
							| 
									
										
										
										
											2016-05-11 13:21:25 +02:00
										 |  |  | 	default: | 
					
						
							|  |  |  | 		return fmt.Errorf("abi: cannot unmarshal %v in to %v", src.Type(), dst.Type()) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2017-11-10 02:30:26 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-22 11:26:49 +01:00
										 |  |  | // setSlice attempts to assign src to dst when slices are not assignable by default | 
					
						
							|  |  |  | // e.g. src: [][]byte -> dst: [][15]byte | 
					
						
							| 
									
										
										
										
											2019-01-10 16:59:37 +08:00
										 |  |  | func setSlice(dst, src reflect.Value) error { | 
					
						
							| 
									
										
										
										
											2018-12-22 11:26:49 +01:00
										 |  |  | 	slice := reflect.MakeSlice(dst.Type(), src.Len(), src.Len()) | 
					
						
							|  |  |  | 	for i := 0; i < src.Len(); i++ { | 
					
						
							|  |  |  | 		v := src.Index(i) | 
					
						
							|  |  |  | 		reflect.Copy(slice.Index(i), v) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dst.Set(slice) | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-10 02:30:26 +01:00
										 |  |  | // requireAssignable assures that `dest` is a pointer and it's not an interface. | 
					
						
							|  |  |  | func requireAssignable(dst, src reflect.Value) error { | 
					
						
							|  |  |  | 	if dst.Kind() != reflect.Ptr && dst.Kind() != reflect.Interface { | 
					
						
							|  |  |  | 		return fmt.Errorf("abi: cannot unmarshal %v into %v", src.Type(), dst.Type()) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2017-12-21 16:18:37 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | // requireUnpackKind verifies preconditions for unpacking `args` into `kind` | 
					
						
							|  |  |  | func requireUnpackKind(v reflect.Value, t reflect.Type, k reflect.Kind, | 
					
						
							|  |  |  | 	args Arguments) error { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch k { | 
					
						
							|  |  |  | 	case reflect.Struct: | 
					
						
							|  |  |  | 	case reflect.Slice, reflect.Array: | 
					
						
							|  |  |  | 		if minLen := args.LengthNonIndexed(); v.Len() < minLen { | 
					
						
							|  |  |  | 			return fmt.Errorf("abi: insufficient number of elements in the list/array for unpack, want %d, got %d", | 
					
						
							|  |  |  | 				minLen, v.Len()) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		return fmt.Errorf("abi: cannot unmarshal tuple into %v", t) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-03-05 16:01:40 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-10 16:59:37 +08:00
										 |  |  | // mapArgNamesToStructFields maps a slice of argument names to struct fields. | 
					
						
							| 
									
										
										
										
											2018-05-14 14:47:31 +02:00
										 |  |  | // first round: for each Exportable field that contains a `abi:""` tag | 
					
						
							| 
									
										
										
										
											2019-01-10 16:59:37 +08:00
										 |  |  | //   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, | 
					
						
							| 
									
										
										
										
											2018-05-14 14:47:31 +02:00
										 |  |  | //   find what variable is expected to be mapped into, if it exists and has not been | 
					
						
							|  |  |  | //   used, pair them. | 
					
						
							| 
									
										
										
										
											2019-01-10 16:59:37 +08:00
										 |  |  | // Note this function assumes the given value is a struct value. | 
					
						
							|  |  |  | func mapArgNamesToStructFields(argNames []string, value reflect.Value) (map[string]string, error) { | 
					
						
							| 
									
										
										
										
											2018-05-14 14:47:31 +02:00
										 |  |  | 	typ := value.Type() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	abi2struct := make(map[string]string) | 
					
						
							|  |  |  | 	struct2abi := make(map[string]string) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// first round ~~~ | 
					
						
							|  |  |  | 	for i := 0; i < typ.NumField(); i++ { | 
					
						
							|  |  |  | 		structFieldName := typ.Field(i).Name | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// skip private struct fields. | 
					
						
							|  |  |  | 		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 | 
					
						
							| 
									
										
										
										
											2019-01-10 16:59:37 +08:00
										 |  |  | 		for _, arg := range argNames { | 
					
						
							|  |  |  | 			if arg == tagName { | 
					
						
							|  |  |  | 				if abi2struct[arg] != "" { | 
					
						
							| 
									
										
										
										
											2018-05-14 14:47:31 +02:00
										 |  |  | 					return nil, fmt.Errorf("struct: abi tag in '%s' already mapped", structFieldName) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				// pair them | 
					
						
							| 
									
										
										
										
											2019-01-10 16:59:37 +08:00
										 |  |  | 				abi2struct[arg] = structFieldName | 
					
						
							|  |  |  | 				struct2abi[structFieldName] = arg | 
					
						
							| 
									
										
										
										
											2018-05-14 14:47:31 +02:00
										 |  |  | 				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 ~~~ | 
					
						
							| 
									
										
										
										
											2019-01-10 16:59:37 +08:00
										 |  |  | 	for _, argName := range argNames { | 
					
						
							| 
									
										
										
										
											2018-05-14 14:47:31 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-10 16:59:37 +08:00
										 |  |  | 		structFieldName := ToCamelCase(argName) | 
					
						
							| 
									
										
										
										
											2018-05-14 14:47:31 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if structFieldName == "" { | 
					
						
							|  |  |  | 			return nil, fmt.Errorf("abi: purely underscored output cannot unpack to struct") | 
					
						
							| 
									
										
										
										
											2018-03-05 16:01:40 +01:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-05-14 14:47:31 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// this abi has already been paired, skip it... unless there exists another, yet unassigned | 
					
						
							|  |  |  | 		// struct field with the same field name. If so, raise an error: | 
					
						
							|  |  |  | 		//    abi: [ { "name": "value" } ] | 
					
						
							|  |  |  | 		//    struct { Value  *big.Int , Value1 *big.Int `abi:"value"`} | 
					
						
							| 
									
										
										
										
											2019-01-10 16:59:37 +08:00
										 |  |  | 		if abi2struct[argName] != "" { | 
					
						
							|  |  |  | 			if abi2struct[argName] != structFieldName && | 
					
						
							| 
									
										
										
										
											2018-05-14 14:47:31 +02:00
										 |  |  | 				struct2abi[structFieldName] == "" && | 
					
						
							|  |  |  | 				value.FieldByName(structFieldName).IsValid() { | 
					
						
							| 
									
										
										
										
											2019-01-10 16:59:37 +08:00
										 |  |  | 				return nil, fmt.Errorf("abi: multiple variables maps to the same abi field '%s'", argName) | 
					
						
							| 
									
										
										
										
											2018-05-14 14:47:31 +02:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			continue | 
					
						
							| 
									
										
										
										
											2018-03-05 16:01:40 +01:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-05-14 14:47:31 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// return an error if this struct field has already been paired. | 
					
						
							|  |  |  | 		if struct2abi[structFieldName] != "" { | 
					
						
							|  |  |  | 			return nil, fmt.Errorf("abi: multiple outputs mapping to the same struct field '%s'", structFieldName) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if value.FieldByName(structFieldName).IsValid() { | 
					
						
							|  |  |  | 			// pair them | 
					
						
							| 
									
										
										
										
											2019-01-10 16:59:37 +08:00
										 |  |  | 			abi2struct[argName] = structFieldName | 
					
						
							|  |  |  | 			struct2abi[structFieldName] = argName | 
					
						
							| 
									
										
										
										
											2018-05-14 14:47:31 +02:00
										 |  |  | 		} else { | 
					
						
							|  |  |  | 			// not paired, but annotate as used, to detect cases like | 
					
						
							|  |  |  | 			//   abi : [ { "name": "value" }, { "name": "_value" } ] | 
					
						
							|  |  |  | 			//   struct { Value *big.Int } | 
					
						
							| 
									
										
										
										
											2019-01-10 16:59:37 +08:00
										 |  |  | 			struct2abi[structFieldName] = argName | 
					
						
							| 
									
										
										
										
											2018-05-14 14:47:31 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-03-05 16:01:40 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-05-14 14:47:31 +02:00
										 |  |  | 	return abi2struct, nil | 
					
						
							| 
									
										
										
										
											2018-03-05 16:01:40 +01:00
										 |  |  | } |