accounts/abi: allow overloaded argument names (#21060)
* accounts/abi: allow overloaded argument names In solidity it is possible to create the following contract: ``` contract Overloader { struct F { uint _f; uint __f; uint f; } function f(F memory f) public {} } ``` This however resulted in a panic in the abi package. * accounts/abi fixed error handling
This commit is contained in:
parent
b8ea9042e5
commit
0b63915430
@ -57,7 +57,8 @@ const jsondata = `
|
|||||||
{ "type" : "function", "name" : "fixedArrBytes", "stateMutability" : "view", "inputs" : [ { "name" : "bytes", "type" : "bytes" }, { "name" : "fixedArr", "type" : "uint256[2]" } ] },
|
{ "type" : "function", "name" : "fixedArrBytes", "stateMutability" : "view", "inputs" : [ { "name" : "bytes", "type" : "bytes" }, { "name" : "fixedArr", "type" : "uint256[2]" } ] },
|
||||||
{ "type" : "function", "name" : "mixedArrStr", "stateMutability" : "view", "inputs" : [ { "name" : "str", "type" : "string" }, { "name" : "fixedArr", "type" : "uint256[2]" }, { "name" : "dynArr", "type" : "uint256[]" } ] },
|
{ "type" : "function", "name" : "mixedArrStr", "stateMutability" : "view", "inputs" : [ { "name" : "str", "type" : "string" }, { "name" : "fixedArr", "type" : "uint256[2]" }, { "name" : "dynArr", "type" : "uint256[]" } ] },
|
||||||
{ "type" : "function", "name" : "doubleFixedArrStr", "stateMutability" : "view", "inputs" : [ { "name" : "str", "type" : "string" }, { "name" : "fixedArr1", "type" : "uint256[2]" }, { "name" : "fixedArr2", "type" : "uint256[3]" } ] },
|
{ "type" : "function", "name" : "doubleFixedArrStr", "stateMutability" : "view", "inputs" : [ { "name" : "str", "type" : "string" }, { "name" : "fixedArr1", "type" : "uint256[2]" }, { "name" : "fixedArr2", "type" : "uint256[3]" } ] },
|
||||||
{ "type" : "function", "name" : "multipleMixedArrStr", "stateMutability" : "view", "inputs" : [ { "name" : "str", "type" : "string" }, { "name" : "fixedArr1", "type" : "uint256[2]" }, { "name" : "dynArr", "type" : "uint256[]" }, { "name" : "fixedArr2", "type" : "uint256[3]" } ] }
|
{ "type" : "function", "name" : "multipleMixedArrStr", "stateMutability" : "view", "inputs" : [ { "name" : "str", "type" : "string" }, { "name" : "fixedArr1", "type" : "uint256[2]" }, { "name" : "dynArr", "type" : "uint256[]" }, { "name" : "fixedArr2", "type" : "uint256[3]" } ] },
|
||||||
|
{ "type" : "function", "name" : "overloadedNames", "stateMutability" : "view", "inputs": [ { "components": [ { "internalType": "uint256", "name": "_f", "type": "uint256" }, { "internalType": "uint256", "name": "__f", "type": "uint256"}, { "internalType": "uint256", "name": "f", "type": "uint256"}],"internalType": "struct Overloader.F", "name": "f","type": "tuple"}]}
|
||||||
]`
|
]`
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -80,6 +81,10 @@ var (
|
|||||||
Uint256ArrNested, _ = NewType("uint256[2][2]", "", nil)
|
Uint256ArrNested, _ = NewType("uint256[2][2]", "", nil)
|
||||||
Uint8ArrNested, _ = NewType("uint8[][2]", "", nil)
|
Uint8ArrNested, _ = NewType("uint8[][2]", "", nil)
|
||||||
Uint8SliceNested, _ = NewType("uint8[][]", "", nil)
|
Uint8SliceNested, _ = NewType("uint8[][]", "", nil)
|
||||||
|
TupleF, _ = NewType("tuple", "struct Overloader.F", []ArgumentMarshaling{
|
||||||
|
{Name: "_f", Type: "uint256"},
|
||||||
|
{Name: "__f", Type: "uint256"},
|
||||||
|
{Name: "f", Type: "uint256"}})
|
||||||
)
|
)
|
||||||
|
|
||||||
var methods = map[string]Method{
|
var methods = map[string]Method{
|
||||||
@ -108,6 +113,7 @@ var methods = map[string]Method{
|
|||||||
"mixedArrStr": NewMethod("mixedArrStr", "mixedArrStr", Function, "view", false, false, []Argument{{"str", String, false}, {"fixedArr", Uint256Arr2, false}, {"dynArr", Uint256Arr, false}}, nil),
|
"mixedArrStr": NewMethod("mixedArrStr", "mixedArrStr", Function, "view", false, false, []Argument{{"str", String, false}, {"fixedArr", Uint256Arr2, false}, {"dynArr", Uint256Arr, false}}, nil),
|
||||||
"doubleFixedArrStr": NewMethod("doubleFixedArrStr", "doubleFixedArrStr", Function, "view", false, false, []Argument{{"str", String, false}, {"fixedArr1", Uint256Arr2, false}, {"fixedArr2", Uint256Arr3, false}}, nil),
|
"doubleFixedArrStr": NewMethod("doubleFixedArrStr", "doubleFixedArrStr", Function, "view", false, false, []Argument{{"str", String, false}, {"fixedArr1", Uint256Arr2, false}, {"fixedArr2", Uint256Arr3, false}}, nil),
|
||||||
"multipleMixedArrStr": NewMethod("multipleMixedArrStr", "multipleMixedArrStr", Function, "view", false, false, []Argument{{"str", String, false}, {"fixedArr1", Uint256Arr2, false}, {"dynArr", Uint256Arr, false}, {"fixedArr2", Uint256Arr3, false}}, nil),
|
"multipleMixedArrStr": NewMethod("multipleMixedArrStr", "multipleMixedArrStr", Function, "view", false, false, []Argument{{"str", String, false}, {"fixedArr1", Uint256Arr2, false}, {"dynArr", Uint256Arr, false}, {"fixedArr2", Uint256Arr3, false}}, nil),
|
||||||
|
"overloadedNames": NewMethod("overloadedNames", "overloadedNames", Function, "view", false, false, []Argument{{"f", TupleF, false}}, nil),
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestReader(t *testing.T) {
|
func TestReader(t *testing.T) {
|
||||||
@ -117,7 +123,7 @@ func TestReader(t *testing.T) {
|
|||||||
|
|
||||||
exp, err := JSON(strings.NewReader(jsondata))
|
exp, err := JSON(strings.NewReader(jsondata))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for name, expM := range exp.Methods {
|
for name, expM := range exp.Methods {
|
||||||
|
@ -163,16 +163,19 @@ func NewType(t string, internalType string, components []ArgumentMarshaling) (ty
|
|||||||
expression string // canonical parameter expression
|
expression string // canonical parameter expression
|
||||||
)
|
)
|
||||||
expression += "("
|
expression += "("
|
||||||
|
overloadedNames := make(map[string]string)
|
||||||
for idx, c := range components {
|
for idx, c := range components {
|
||||||
cType, err := NewType(c.Type, c.InternalType, c.Components)
|
cType, err := NewType(c.Type, c.InternalType, c.Components)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Type{}, err
|
return Type{}, err
|
||||||
}
|
}
|
||||||
if ToCamelCase(c.Name) == "" {
|
fieldName, err := overloadedArgName(c.Name, overloadedNames)
|
||||||
return Type{}, errors.New("abi: purely anonymous or underscored field is not supported")
|
if err != nil {
|
||||||
|
return Type{}, err
|
||||||
}
|
}
|
||||||
|
overloadedNames[fieldName] = fieldName
|
||||||
fields = append(fields, reflect.StructField{
|
fields = append(fields, reflect.StructField{
|
||||||
Name: ToCamelCase(c.Name), // reflect.StructOf will panic for any exported field.
|
Name: fieldName, // reflect.StructOf will panic for any exported field.
|
||||||
Type: cType.getType(),
|
Type: cType.getType(),
|
||||||
Tag: reflect.StructTag("json:\"" + c.Name + "\""),
|
Tag: reflect.StructTag("json:\"" + c.Name + "\""),
|
||||||
})
|
})
|
||||||
@ -246,6 +249,20 @@ func (t Type) getType() reflect.Type {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func overloadedArgName(rawName string, names map[string]string) (string, error) {
|
||||||
|
fieldName := ToCamelCase(rawName)
|
||||||
|
if fieldName == "" {
|
||||||
|
return "", errors.New("abi: purely anonymous or underscored field is not supported")
|
||||||
|
}
|
||||||
|
// Handle overloaded fieldNames
|
||||||
|
_, ok := names[fieldName]
|
||||||
|
for idx := 0; ok; idx++ {
|
||||||
|
fieldName = fmt.Sprintf("%s%d", ToCamelCase(rawName), idx)
|
||||||
|
_, ok = names[fieldName]
|
||||||
|
}
|
||||||
|
return fieldName, nil
|
||||||
|
}
|
||||||
|
|
||||||
// String implements Stringer
|
// String implements Stringer
|
||||||
func (t Type) String() (out string) {
|
func (t Type) String() (out string) {
|
||||||
return t.stringKind
|
return t.stringKind
|
||||||
|
Loading…
Reference in New Issue
Block a user