forked from TrueCloudLab/neoneo-go
rpcbinding: sort named types to stabilize output
Same input -> same output, otherwise tests fail and @AnnaShaleva is annoyed. Signed-off-by: Roman Khimov <roman@nspcc.ru>
This commit is contained in:
parent
eade327b9b
commit
4c9cd438f8
5 changed files with 226 additions and 16 deletions
|
@ -1,3 +1,3 @@
|
||||||
name: "Types"
|
name: "Types"
|
||||||
sourceurl: https://github.com/nspcc-dev/neo-go/
|
sourceurl: https://github.com/nspcc-dev/neo-go/
|
||||||
safemethods: ["bool", "int", "bytes", "string", "any", "hash160", "hash256", "publicKey", "signature", "bools", "ints", "bytess", "strings", "hash160s", "hash256s", "publicKeys", "signatures", "aAAStrings", "maps", "crazyMaps", "anyMaps"]
|
safemethods: ["bool", "int", "bytes", "string", "any", "hash160", "hash256", "publicKey", "signature", "bools", "ints", "bytess", "strings", "hash160s", "hash256s", "publicKeys", "signatures", "aAAStrings", "maps", "crazyMaps", "anyMaps", "unnamedStructs", "unnamedStructsX"]
|
||||||
|
|
|
@ -18,6 +18,17 @@ import (
|
||||||
// Hash contains contract hash.
|
// Hash contains contract hash.
|
||||||
var Hash = util.Uint160{0x33, 0x22, 0x11, 0x0, 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x0}
|
var Hash = util.Uint160{0x33, 0x22, 0x11, 0x0, 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x0}
|
||||||
|
|
||||||
|
// Unnamed is a contract-specific unnamed type used by its methods.
|
||||||
|
type Unnamed struct {
|
||||||
|
I *big.Int
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnnamedX is a contract-specific unnamedX type used by its methods.
|
||||||
|
type UnnamedX struct {
|
||||||
|
I *big.Int
|
||||||
|
B bool
|
||||||
|
}
|
||||||
|
|
||||||
// Invoker is used by ContractReader to call various safe methods.
|
// Invoker is used by ContractReader to call various safe methods.
|
||||||
type Invoker interface {
|
type Invoker interface {
|
||||||
Call(contract util.Uint160, operation string, params ...any) (*result.Invoke, error)
|
Call(contract util.Uint160, operation string, params ...any) (*result.Invoke, error)
|
||||||
|
@ -347,3 +358,87 @@ func (c *ContractReader) String(s string) (string, error) {
|
||||||
func (c *ContractReader) Strings(s []string) ([]string, error) {
|
func (c *ContractReader) Strings(s []string) ([]string, error) {
|
||||||
return unwrap.ArrayOfUTF8Strings(c.invoker.Call(c.hash, "strings", s))
|
return unwrap.ArrayOfUTF8Strings(c.invoker.Call(c.hash, "strings", s))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UnnamedStructs invokes `unnamedStructs` method of contract.
|
||||||
|
func (c *ContractReader) UnnamedStructs() (*Unnamed, error) {
|
||||||
|
return itemToUnnamed(unwrap.Item(c.invoker.Call(c.hash, "unnamedStructs")))
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnnamedStructsX invokes `unnamedStructsX` method of contract.
|
||||||
|
func (c *ContractReader) UnnamedStructsX() (*UnnamedX, error) {
|
||||||
|
return itemToUnnamedX(unwrap.Item(c.invoker.Call(c.hash, "unnamedStructsX")))
|
||||||
|
}
|
||||||
|
|
||||||
|
// itemToUnnamed converts stack item into *Unnamed.
|
||||||
|
func itemToUnnamed(item stackitem.Item, err error) (*Unnamed, error) {
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var res = new(Unnamed)
|
||||||
|
err = res.FromStackItem(item)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromStackItem retrieves fields of Unnamed from the given
|
||||||
|
// [stackitem.Item] or returns an error if it's not possible to do to so.
|
||||||
|
func (res *Unnamed) FromStackItem(item stackitem.Item) error {
|
||||||
|
arr, ok := item.Value().([]stackitem.Item)
|
||||||
|
if !ok {
|
||||||
|
return errors.New("not an array")
|
||||||
|
}
|
||||||
|
if len(arr) != 1 {
|
||||||
|
return errors.New("wrong number of structure elements")
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
index = -1
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
index++
|
||||||
|
res.I, err = arr[index].TryInteger()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("field I: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// itemToUnnamedX converts stack item into *UnnamedX.
|
||||||
|
func itemToUnnamedX(item stackitem.Item, err error) (*UnnamedX, error) {
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var res = new(UnnamedX)
|
||||||
|
err = res.FromStackItem(item)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromStackItem retrieves fields of UnnamedX from the given
|
||||||
|
// [stackitem.Item] or returns an error if it's not possible to do to so.
|
||||||
|
func (res *UnnamedX) FromStackItem(item stackitem.Item) error {
|
||||||
|
arr, ok := item.Value().([]stackitem.Item)
|
||||||
|
if !ok {
|
||||||
|
return errors.New("not an array")
|
||||||
|
}
|
||||||
|
if len(arr) != 2 {
|
||||||
|
return errors.New("wrong number of structure elements")
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
index = -1
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
index++
|
||||||
|
res.I, err = arr[index].TryInteger()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("field I: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
index++
|
||||||
|
res.B, err = arr[index].TryBool()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("field B: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -15,6 +15,17 @@ import (
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Unnamed is a contract-specific unnamed type used by its methods.
|
||||||
|
type Unnamed struct {
|
||||||
|
I *big.Int
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnnamedX is a contract-specific unnamedX type used by its methods.
|
||||||
|
type UnnamedX struct {
|
||||||
|
I *big.Int
|
||||||
|
B bool
|
||||||
|
}
|
||||||
|
|
||||||
// Invoker is used by ContractReader to call various safe methods.
|
// Invoker is used by ContractReader to call various safe methods.
|
||||||
type Invoker interface {
|
type Invoker interface {
|
||||||
Call(contract util.Uint160, operation string, params ...any) (*result.Invoke, error)
|
Call(contract util.Uint160, operation string, params ...any) (*result.Invoke, error)
|
||||||
|
@ -343,3 +354,87 @@ func (c *ContractReader) String(s string) (string, error) {
|
||||||
func (c *ContractReader) Strings(s []string) ([]string, error) {
|
func (c *ContractReader) Strings(s []string) ([]string, error) {
|
||||||
return unwrap.ArrayOfUTF8Strings(c.invoker.Call(c.hash, "strings", s))
|
return unwrap.ArrayOfUTF8Strings(c.invoker.Call(c.hash, "strings", s))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UnnamedStructs invokes `unnamedStructs` method of contract.
|
||||||
|
func (c *ContractReader) UnnamedStructs() (*Unnamed, error) {
|
||||||
|
return itemToUnnamed(unwrap.Item(c.invoker.Call(c.hash, "unnamedStructs")))
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnnamedStructsX invokes `unnamedStructsX` method of contract.
|
||||||
|
func (c *ContractReader) UnnamedStructsX() (*UnnamedX, error) {
|
||||||
|
return itemToUnnamedX(unwrap.Item(c.invoker.Call(c.hash, "unnamedStructsX")))
|
||||||
|
}
|
||||||
|
|
||||||
|
// itemToUnnamed converts stack item into *Unnamed.
|
||||||
|
func itemToUnnamed(item stackitem.Item, err error) (*Unnamed, error) {
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var res = new(Unnamed)
|
||||||
|
err = res.FromStackItem(item)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromStackItem retrieves fields of Unnamed from the given
|
||||||
|
// [stackitem.Item] or returns an error if it's not possible to do to so.
|
||||||
|
func (res *Unnamed) FromStackItem(item stackitem.Item) error {
|
||||||
|
arr, ok := item.Value().([]stackitem.Item)
|
||||||
|
if !ok {
|
||||||
|
return errors.New("not an array")
|
||||||
|
}
|
||||||
|
if len(arr) != 1 {
|
||||||
|
return errors.New("wrong number of structure elements")
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
index = -1
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
index++
|
||||||
|
res.I, err = arr[index].TryInteger()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("field I: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// itemToUnnamedX converts stack item into *UnnamedX.
|
||||||
|
func itemToUnnamedX(item stackitem.Item, err error) (*UnnamedX, error) {
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var res = new(UnnamedX)
|
||||||
|
err = res.FromStackItem(item)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromStackItem retrieves fields of UnnamedX from the given
|
||||||
|
// [stackitem.Item] or returns an error if it's not possible to do to so.
|
||||||
|
func (res *UnnamedX) FromStackItem(item stackitem.Item) error {
|
||||||
|
arr, ok := item.Value().([]stackitem.Item)
|
||||||
|
if !ok {
|
||||||
|
return errors.New("not an array")
|
||||||
|
}
|
||||||
|
if len(arr) != 2 {
|
||||||
|
return errors.New("wrong number of structure elements")
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
index = -1
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
index++
|
||||||
|
res.I, err = arr[index].TryInteger()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("field I: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
index++
|
||||||
|
res.B, err = arr[index].TryBool()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("field B: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -87,3 +87,17 @@ func CrazyMaps(m map[int][]map[string][]interop.Hash160) map[int][]map[string][]
|
||||||
func AnyMaps(m map[int]any) map[int]any {
|
func AnyMaps(m map[int]any) map[int]any {
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func UnnamedStructs() struct{ I int } {
|
||||||
|
return struct{ I int }{I: 123}
|
||||||
|
}
|
||||||
|
|
||||||
|
func UnnamedStructsX() struct {
|
||||||
|
I int
|
||||||
|
B bool
|
||||||
|
} {
|
||||||
|
return struct {
|
||||||
|
I int
|
||||||
|
B bool
|
||||||
|
}{I: 123, B: true}
|
||||||
|
}
|
||||||
|
|
|
@ -124,9 +124,9 @@ import (
|
||||||
// Hash contains contract hash.
|
// Hash contains contract hash.
|
||||||
var Hash = {{ .Hash }}
|
var Hash = {{ .Hash }}
|
||||||
{{end -}}
|
{{end -}}
|
||||||
{{- range $name, $typ := .NamedTypes }}
|
{{- range $index, $typ := .NamedTypes }}
|
||||||
// {{toTypeName $name}} is a contract-specific {{$name}} type used by its methods.
|
// {{toTypeName $typ.Name}} is a contract-specific {{$typ.Name}} type used by its methods.
|
||||||
type {{toTypeName $name}} struct {
|
type {{toTypeName $typ.Name}} struct {
|
||||||
{{- range $m := $typ.Fields}}
|
{{- range $m := $typ.Fields}}
|
||||||
{{ upperFirst .Field}} {{etTypeToStr .ExtendedType}}
|
{{ upperFirst .Field}} {{etTypeToStr .ExtendedType}}
|
||||||
{{- end}}
|
{{- end}}
|
||||||
|
@ -236,20 +236,20 @@ func New(actor Actor{{- if not (len .Hash) -}}, hash util.Uint160{{- end -}}) *C
|
||||||
{{end -}}
|
{{end -}}
|
||||||
{{- range $m := .SafeMethods }}{{template "SAFEMETHOD" $m }}{{ end -}}
|
{{- range $m := .SafeMethods }}{{template "SAFEMETHOD" $m }}{{ end -}}
|
||||||
{{- range $m := .Methods -}}{{template "METHOD" $m }}{{ end -}}
|
{{- range $m := .Methods -}}{{template "METHOD" $m }}{{ end -}}
|
||||||
{{- range $name, $typ := .NamedTypes }}
|
{{- range $index, $typ := .NamedTypes }}
|
||||||
// itemTo{{toTypeName $name}} converts stack item into *{{toTypeName $name}}.
|
// itemTo{{toTypeName $typ.Name}} converts stack item into *{{toTypeName $typ.Name}}.
|
||||||
func itemTo{{toTypeName $name}}(item stackitem.Item, err error) (*{{toTypeName $name}}, error) {
|
func itemTo{{toTypeName $typ.Name}}(item stackitem.Item, err error) (*{{toTypeName $typ.Name}}, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var res = new({{toTypeName $name}})
|
var res = new({{toTypeName $typ.Name}})
|
||||||
err = res.FromStackItem(item)
|
err = res.FromStackItem(item)
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// FromStackItem retrieves fields of {{toTypeName $name}} from the given
|
// FromStackItem retrieves fields of {{toTypeName $typ.Name}} from the given
|
||||||
// [stackitem.Item] or returns an error if it's not possible to do to so.
|
// [stackitem.Item] or returns an error if it's not possible to do to so.
|
||||||
func (res *{{toTypeName $name}}) FromStackItem(item stackitem.Item) error {
|
func (res *{{toTypeName $typ.Name}}) FromStackItem(item stackitem.Item) error {
|
||||||
arr, ok := item.Value().([]stackitem.Item)
|
arr, ok := item.Value().([]stackitem.Item)
|
||||||
if !ok {
|
if !ok {
|
||||||
return errors.New("not an array")
|
return errors.New("not an array")
|
||||||
|
@ -341,7 +341,7 @@ type (
|
||||||
|
|
||||||
SafeMethods []SafeMethodTmpl
|
SafeMethods []SafeMethodTmpl
|
||||||
CustomEvents []CustomEventTemplate
|
CustomEvents []CustomEventTemplate
|
||||||
NamedTypes map[string]binding.ExtendedType
|
NamedTypes []binding.ExtendedType
|
||||||
|
|
||||||
IsNep11D bool
|
IsNep11D bool
|
||||||
IsNep11ND bool
|
IsNep11ND bool
|
||||||
|
@ -430,7 +430,13 @@ func Generate(cfg binding.Config) error {
|
||||||
|
|
||||||
ctr.ContractTmpl = binding.TemplateFromManifest(cfg, scTypeToGo)
|
ctr.ContractTmpl = binding.TemplateFromManifest(cfg, scTypeToGo)
|
||||||
ctr = scTemplateToRPC(cfg, ctr, imports, scTypeToGo)
|
ctr = scTemplateToRPC(cfg, ctr, imports, scTypeToGo)
|
||||||
ctr.NamedTypes = cfg.NamedTypes
|
ctr.NamedTypes = make([]binding.ExtendedType, 0, len(cfg.NamedTypes))
|
||||||
|
for k := range cfg.NamedTypes {
|
||||||
|
ctr.NamedTypes = append(ctr.NamedTypes, cfg.NamedTypes[k])
|
||||||
|
}
|
||||||
|
sort.Slice(ctr.NamedTypes, func(i, j int) bool {
|
||||||
|
return strings.Compare(ctr.NamedTypes[i].Name, ctr.NamedTypes[j].Name) < 0
|
||||||
|
})
|
||||||
|
|
||||||
// Check resulting named types and events don't have duplicating field names.
|
// Check resulting named types and events don't have duplicating field names.
|
||||||
for _, t := range ctr.NamedTypes {
|
for _, t := range ctr.NamedTypes {
|
||||||
|
@ -458,7 +464,7 @@ func Generate(cfg binding.Config) error {
|
||||||
"addIndent": addIndent,
|
"addIndent": addIndent,
|
||||||
"etTypeConverter": etTypeConverter,
|
"etTypeConverter": etTypeConverter,
|
||||||
"etTypeToStr": func(et binding.ExtendedType) string {
|
"etTypeToStr": func(et binding.ExtendedType) string {
|
||||||
r, _ := extendedTypeToGo(et, ctr.NamedTypes)
|
r, _ := extendedTypeToGo(et, cfg.NamedTypes)
|
||||||
return r
|
return r
|
||||||
},
|
},
|
||||||
"toTypeName": toTypeName,
|
"toTypeName": toTypeName,
|
||||||
|
@ -719,7 +725,7 @@ func scTemplateToRPC(cfg binding.Config, ctr ContractTmpl, imports map[string]st
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, et := range cfg.NamedTypes {
|
for _, et := range cfg.NamedTypes {
|
||||||
addETImports(et, ctr.NamedTypes, imports)
|
addETImports(et, cfg.NamedTypes, imports)
|
||||||
}
|
}
|
||||||
if len(cfg.NamedTypes) > 0 {
|
if len(cfg.NamedTypes) > 0 {
|
||||||
imports["errors"] = struct{}{}
|
imports["errors"] = struct{}{}
|
||||||
|
@ -746,7 +752,7 @@ func scTemplateToRPC(cfg binding.Config, ctr ContractTmpl, imports map[string]st
|
||||||
extType = binding.ExtendedType{
|
extType = binding.ExtendedType{
|
||||||
Base: abiEvent.Parameters[i].Type,
|
Base: abiEvent.Parameters[i].Type,
|
||||||
}
|
}
|
||||||
addETImports(extType, ctr.NamedTypes, imports)
|
addETImports(extType, cfg.NamedTypes, imports)
|
||||||
}
|
}
|
||||||
eTmp.Parameters = append(eTmp.Parameters, EventParamTmpl{
|
eTmp.Parameters = append(eTmp.Parameters, EventParamTmpl{
|
||||||
ParamTmpl: binding.ParamTmpl{
|
ParamTmpl: binding.ParamTmpl{
|
||||||
|
@ -817,7 +823,7 @@ func scTemplateToRPC(cfg binding.Config, ctr ContractTmpl, imports map[string]st
|
||||||
case "keys.PublicKeys":
|
case "keys.PublicKeys":
|
||||||
ctr.SafeMethods[i].Unwrapper = "ArrayOfPublicKeys"
|
ctr.SafeMethods[i].Unwrapper = "ArrayOfPublicKeys"
|
||||||
default:
|
default:
|
||||||
addETImports(ctr.SafeMethods[i].ExtendedReturn, ctr.NamedTypes, imports)
|
addETImports(ctr.SafeMethods[i].ExtendedReturn, cfg.NamedTypes, imports)
|
||||||
ctr.SafeMethods[i].Unwrapper = "Item"
|
ctr.SafeMethods[i].Unwrapper = "Item"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue