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/neorpc/result"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/nep11" "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/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/util"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"math/big" "math/big"
@ -153,18 +154,30 @@ func (c *Contract) SetPriceUnsigned(priceList []interface{}) (*transaction.Trans
return c.actor.MakeUnsignedCall(Hash, "setPrice", nil, priceList) 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. // Register creates a transaction invoking `register` method of the contract.
// This transaction is signed and immediately sent to the network. // This transaction is signed and immediately sent to the network.
// The values returned are its hash, ValidUntilBlock value and error if any. // 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) { 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. // RegisterTransaction creates a transaction invoking `register` method of the contract.
// This transaction is signed, but not sent to the network, instead it's // This transaction is signed, but not sent to the network, instead it's
// returned to the caller. // returned to the caller.
func (c *Contract) RegisterTransaction(name string, owner util.Uint160) (*transaction.Transaction, error) { 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. // 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, // Any fields of it that do not affect fees can be changed (ValidUntilBlock,
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well. // Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
func (c *Contract) RegisterUnsigned(name string, owner util.Uint160) (*transaction.Transaction, error) { 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. // 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 ### Generating RPC contract bindings
To simplify interacting with the contract via RPC you can generate To simplify interacting with the contract via RPC you can generate
contract-specific RPC bindings with the "generate-rpcwrapper" command. If your contract-specific RPC bindings with the "generate-rpcwrapper" command. It
contract is NEP-11 or NEP-17 that's autodetected and an appropriate package is generates ContractReader structure for safe methods that accept appropriate
included as well. Notice that the type data available in the manifest is data for input and return things returned by the contract. State-changing
limited, so in some cases the interface generated may use generic stackitem methods are contained in Contract structure with each contract method
types. Iterators are not supported yet. 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 $ ./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 -}} {{- end -}}
{{- define "METHOD" -}} {{- 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. // This transaction is signed and immediately sent to the network.
// The values returned are its hash, ValidUntilBlock value and error if any. // The values returned are its hash, ValidUntilBlock value and error if any.
func (c *Contract) {{.Name}}({{range $index, $arg := .Arguments -}} func (c *Contract) {{.Name}}({{range $index, $arg := .Arguments -}}
{{- if ne $index 0}}, {{end}} {{- if ne $index 0}}, {{end}}
{{- .Name}} {{.Type}} {{- .Name}} {{.Type}}
{{- end}}) (util.Uint256, uint32, error) { {{- end}}) (util.Uint256, uint32, error) {
return c.actor.SendCall(Hash, "{{ .NameABI }}" {{if ne .ReturnType "bool"}}return c.actor.SendCall(Hash, "{{ .NameABI }}"
{{- range $index, $arg := .Arguments -}}, {{.Name}}{{end}}) {{- 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}} // {{.Name}}Transaction {{.Comment}}
@ -45,8 +56,12 @@ func (c *Contract) {{.Name}}Transaction({{range $index, $arg := .Arguments -}}
{{- if ne $index 0}}, {{end}} {{- if ne $index 0}}, {{end}}
{{- .Name}} {{.Type}} {{- .Name}} {{.Type}}
{{- end}}) (*transaction.Transaction, error) { {{- end}}) (*transaction.Transaction, error) {
return c.actor.MakeCall(Hash, "{{ .NameABI }}" {{if ne .ReturnType "bool"}}return c.actor.MakeCall(Hash, "{{ .NameABI }}"
{{- range $index, $arg := .Arguments -}}, {{.Name}}{{end}}) {{- 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}} // {{.Name}}Unsigned {{.Comment}}
@ -57,8 +72,12 @@ func (c *Contract) {{.Name}}Unsigned({{range $index, $arg := .Arguments -}}
{{- if ne $index 0}}, {{end}} {{- if ne $index 0}}, {{end}}
{{- .Name}} {{.Type}} {{- .Name}} {{.Type}}
{{- end}}) (*transaction.Transaction, error) { {{- end}}) (*transaction.Transaction, error) {
return c.actor.MakeUnsignedCall(Hash, "{{ .NameABI }}", nil {{if ne .ReturnType "bool"}}return c.actor.MakeUnsignedCall(Hash, "{{ .NameABI }}", nil
{{- range $index, $arg := .Arguments -}}, {{.Name}}{{end}}) {{- 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 -}} {{- end -}}
// Package {{.PackageName}} contains RPC wrappers for {{.ContractName}} contract. // Package {{.PackageName}} contains RPC wrappers for {{.ContractName}} contract.
@ -278,6 +297,9 @@ func scTemplateToRPC(cfg binding.Config, bctr binding.ContractTmpl) ContractTmpl
i-- i--
} else { } else {
ctr.Methods[i].Comment = fmt.Sprintf("creates a transaction invoking `%s` method of the contract.", ctr.Methods[i].NameABI) 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. // We're misusing CallFlag field for function name here.