rpcbinding: generate ASSERT for bool-returning methods

It's a common pattern.
This commit is contained in:
Roman Khimov 2022-11-07 22:13:47 +03:00
parent 2a4a5ab479
commit aeb61fb61d
3 changed files with 63 additions and 15 deletions

View file

@ -6,6 +6,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/nep11"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"math/big"
@ -153,18 +154,30 @@ func (c *Contract) SetPriceUnsigned(priceList []interface{}) (*transaction.Trans
return c.actor.MakeUnsignedCall(Hash, "setPrice", nil, priceList)
}
func scriptForRegister(name string, owner util.Uint160) ([]byte, error) {
return smartcontract.CreateCallWithAssertScript(Hash, "register", name, owner)
}
// Register creates a transaction invoking `register` method of the contract.
// This transaction is signed and immediately sent to the network.
// The values returned are its hash, ValidUntilBlock value and error if any.
func (c *Contract) Register(name string, owner util.Uint160) (util.Uint256, uint32, error) {
return c.actor.SendCall(Hash, "register", name, owner)
script, err := scriptForRegister(name, owner)
if err != nil {
return util.Uint256{}, 0, err
}
return c.actor.SendRun(script)
}
// RegisterTransaction creates a transaction invoking `register` method of the contract.
// This transaction is signed, but not sent to the network, instead it's
// returned to the caller.
func (c *Contract) RegisterTransaction(name string, owner util.Uint160) (*transaction.Transaction, error) {
return c.actor.MakeCall(Hash, "register", name, owner)
script, err := scriptForRegister(name, owner)
if err != nil {
return nil, err
}
return c.actor.MakeRun(script)
}
// RegisterUnsigned creates a transaction invoking `register` method of the contract.
@ -172,7 +185,11 @@ func (c *Contract) RegisterTransaction(name string, owner util.Uint160) (*transa
// Any fields of it that do not affect fees can be changed (ValidUntilBlock,
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
func (c *Contract) RegisterUnsigned(name string, owner util.Uint160) (*transaction.Transaction, error) {
return c.actor.MakeUnsignedCall(Hash, "register", nil, name, owner)
script, err := scriptForRegister(name, owner)
if err != nil {
return nil, err
}
return c.actor.MakeUnsignedRun(script, nil)
}
// Renew creates a transaction invoking `renew` method of the contract.

View file

@ -436,11 +436,20 @@ $ ./bin/neo-go contract generate-wrapper --manifest manifest.json --config contr
### Generating RPC contract bindings
To simplify interacting with the contract via RPC you can generate
contract-specific RPC bindings with the "generate-rpcwrapper" command. If your
contract is NEP-11 or NEP-17 that's autodetected and an appropriate package is
included as well. Notice that the type data available in the manifest is
limited, so in some cases the interface generated may use generic stackitem
types. Iterators are not supported yet.
contract-specific RPC bindings with the "generate-rpcwrapper" command. It
generates ContractReader structure for safe methods that accept appropriate
data for input and return things returned by the contract. State-changing
methods are contained in Contract structure with each contract method
represented by three wrapper methods that create/send transaction with a
script performing appropriate action. This script invokes contract method and
does not do anything else unless the method's returned value is of a boolean
type, in this case an ASSERT is added to script making it fail when the method
returns false.
If your contract is NEP-11 or NEP-17 that's autodetected and an appropriate
package is included as well. Notice that the type data available in the
manifest is limited, so in some cases the interface generated may use generic
stackitem types. Iterators are not supported yet.
```
$ ./bin/neo-go contract generate-rpcwrapper --manifest manifest.json --out rpcwrapper.go --hash 0x1b4357bff5a01bdf2a6581247cf9ed1e24629176

View file

@ -27,15 +27,26 @@ func (c *ContractReader) {{.Name}}({{range $index, $arg := .Arguments -}}
}
{{- end -}}
{{- define "METHOD" -}}
// {{.Name}} {{.Comment}}
{{- if eq .ReturnType "bool"}}func scriptFor{{.Name}}({{range $index, $arg := .Arguments -}}
{{- if ne $index 0}}, {{end}}
{{- .Name}} {{.Type}}
{{- end}}) ([]byte, error) {
return smartcontract.CreateCallWithAssertScript(Hash, "{{ .NameABI }}"{{- range $index, $arg := .Arguments -}}, {{.Name}}{{end}})
}
{{end}}// {{.Name}} {{.Comment}}
// This transaction is signed and immediately sent to the network.
// The values returned are its hash, ValidUntilBlock value and error if any.
func (c *Contract) {{.Name}}({{range $index, $arg := .Arguments -}}
{{- if ne $index 0}}, {{end}}
{{- .Name}} {{.Type}}
{{- end}}) (util.Uint256, uint32, error) {
return c.actor.SendCall(Hash, "{{ .NameABI }}"
{{- range $index, $arg := .Arguments -}}, {{.Name}}{{end}})
{{if ne .ReturnType "bool"}}return c.actor.SendCall(Hash, "{{ .NameABI }}"
{{- range $index, $arg := .Arguments -}}, {{.Name}}{{end}}){{else}}script, err := scriptFor{{.Name}}({{- range $index, $arg := .Arguments -}}{{- if ne $index 0}}, {{end}}{{.Name}}{{end}})
if err != nil {
return util.Uint256{}, 0, err
}
return c.actor.SendRun(script){{end}}
}
// {{.Name}}Transaction {{.Comment}}
@ -45,8 +56,12 @@ func (c *Contract) {{.Name}}Transaction({{range $index, $arg := .Arguments -}}
{{- if ne $index 0}}, {{end}}
{{- .Name}} {{.Type}}
{{- end}}) (*transaction.Transaction, error) {
return c.actor.MakeCall(Hash, "{{ .NameABI }}"
{{- range $index, $arg := .Arguments -}}, {{.Name}}{{end}})
{{if ne .ReturnType "bool"}}return c.actor.MakeCall(Hash, "{{ .NameABI }}"
{{- range $index, $arg := .Arguments -}}, {{.Name}}{{end}}){{else}}script, err := scriptFor{{.Name}}({{- range $index, $arg := .Arguments -}}{{- if ne $index 0}}, {{end}}{{.Name}}{{end}})
if err != nil {
return nil, err
}
return c.actor.MakeRun(script){{end}}
}
// {{.Name}}Unsigned {{.Comment}}
@ -57,8 +72,12 @@ func (c *Contract) {{.Name}}Unsigned({{range $index, $arg := .Arguments -}}
{{- if ne $index 0}}, {{end}}
{{- .Name}} {{.Type}}
{{- end}}) (*transaction.Transaction, error) {
return c.actor.MakeUnsignedCall(Hash, "{{ .NameABI }}", nil
{{- range $index, $arg := .Arguments -}}, {{.Name}}{{end}})
{{if ne .ReturnType "bool"}}return c.actor.MakeUnsignedCall(Hash, "{{ .NameABI }}", nil
{{- range $index, $arg := .Arguments -}}, {{.Name}}{{end}}){{else}}script, err := scriptFor{{.Name}}({{- range $index, $arg := .Arguments -}}{{- if ne $index 0}}, {{end}}{{.Name}}{{end}})
if err != nil {
return nil, err
}
return c.actor.MakeUnsignedRun(script, nil){{end}}
}
{{- end -}}
// Package {{.PackageName}} contains RPC wrappers for {{.ContractName}} contract.
@ -278,6 +297,9 @@ func scTemplateToRPC(cfg binding.Config, bctr binding.ContractTmpl) ContractTmpl
i--
} else {
ctr.Methods[i].Comment = fmt.Sprintf("creates a transaction invoking `%s` method of the contract.", ctr.Methods[i].NameABI)
if ctr.Methods[i].ReturnType == "bool" {
imports["github.com/nspcc-dev/neo-go/pkg/smartcontract"] = struct{}{}
}
}
}
// We're misusing CallFlag field for function name here.