-
Notifications
You must be signed in to change notification settings - Fork 20.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
accounts/abi: allow abi: tags when unpacking structs #16648
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,6 +19,7 @@ package abi | |
import ( | ||
"fmt" | ||
"reflect" | ||
"strings" | ||
) | ||
|
||
// indirect recursively dereferences the value until it either gets the value | ||
|
@@ -111,18 +112,99 @@ func requireUnpackKind(v reflect.Value, t reflect.Type, k reflect.Kind, | |
return nil | ||
} | ||
|
||
// requireUniqueStructFieldNames makes sure field names don't collide | ||
func requireUniqueStructFieldNames(args Arguments) error { | ||
exists := make(map[string]bool) | ||
// mapAbiToStringField maps abi 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, | ||
// find what variable is expected to be mapped into, if exists and has not been | ||
// used, pair them. | ||
func mapAbiToStructFields(args Arguments, value reflect.Value) (map[string]string, error) { | ||
|
||
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 has not `abi:""` tag. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. skip fileds that have no |
||
var ok bool | ||
var tagName string | ||
if tagName, ok = typ.Field(i).Tag.Lookup("abi"); !ok { | ||
continue | ||
} | ||
|
||
// check if tag is emmpty. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 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] != "" { | ||
return nil, fmt.Errorf("struct: abi tag in '%s' already mapped", structFieldName) | ||
} | ||
// pair them | ||
abi2struct[abiField.Name] = structFieldName | ||
struct2abi[structFieldName] = abiField.Name | ||
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 { | ||
field := capitalise(arg.Name) | ||
if field == "" { | ||
return fmt.Errorf("abi: purely underscored output cannot unpack to struct") | ||
|
||
abiFieldName := arg.Name | ||
structFieldName := capitalise(abiFieldName) | ||
|
||
if structFieldName == "" { | ||
return nil, fmt.Errorf("abi: purely underscored output cannot unpack to struct") | ||
} | ||
if exists[field] { | ||
return fmt.Errorf("abi: multiple outputs mapping to the same struct field '%s'", field) | ||
|
||
// this abi been already paired, skip | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this abi has already been paired, skip... |
||
if abi2struct[abiFieldName] != "" { | ||
// unless if exists another not still assigned struct field with the same name | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. unless there is another yet unassigned struct field with the same name I think you mean mean "the same "abi" name", right? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, I will add a clarification there. |
||
if abi2struct[abiFieldName] != structFieldName && | ||
struct2abi[structFieldName] == "" && | ||
value.FieldByName(structFieldName).IsValid() { | ||
return nil, fmt.Errorf("abi: multiple variables maps to the same abi field '%s'", abiFieldName) | ||
} | ||
continue | ||
} | ||
exists[field] = true | ||
|
||
// error if this struct field been already paired. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. return an error if this struct field has already been paired |
||
if struct2abi[structFieldName] != "" { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. could you move this before line 181? It would simplify the condition check on line 184 |
||
return nil, fmt.Errorf("abi: multiple outputs mapping to the same struct field '%s'", structFieldName) | ||
} | ||
|
||
if value.FieldByName(structFieldName).IsValid() { | ||
// pair them | ||
abi2struct[abiFieldName] = structFieldName | ||
struct2abi[structFieldName] = abiFieldName | ||
} else { | ||
// not paired, but annotate as used, to detect cases like | ||
// abi : [ { "name": "value" }, { "name": "_value" } ] | ||
// struct { Value *big.Int } | ||
struct2abi[structFieldName] = abiFieldName | ||
} | ||
|
||
} | ||
return nil | ||
|
||
return abi2struct, nil | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if it exists