rpcbinding: add GAS testcase, fix methodless wrappers
* strip NEP-XX methods before going into generator to avoid unused imports * nepXX.Invoker types already include Call * always import util, it's used for Hash
This commit is contained in:
parent
aeb61fb61d
commit
df29008a50
6 changed files with 122 additions and 66 deletions
|
@ -294,6 +294,7 @@ package myspacecontract
|
|||
import (
|
||||
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
|
@ -328,34 +329,34 @@ func TestGenerateRPCBindings(t *testing.T) {
|
|||
app := cli.NewApp()
|
||||
app.Commands = []cli.Command{generateWrapperCmd, generateRPCWrapperCmd}
|
||||
|
||||
outFile := filepath.Join(tmpDir, "out.go")
|
||||
require.NoError(t, app.Run([]string{"", "generate-rpcwrapper",
|
||||
"--manifest", filepath.Join("testdata", "nex", "nex.manifest.json"),
|
||||
"--out", outFile,
|
||||
"--hash", "0xa2a67f09e8cf22c6bfd5cea24adc0f4bf0a11aa8",
|
||||
}))
|
||||
var checkBinding = func(manifest string, hash string, good string) {
|
||||
t.Run(manifest, func(t *testing.T) {
|
||||
outFile := filepath.Join(tmpDir, "out.go")
|
||||
require.NoError(t, app.Run([]string{"", "generate-rpcwrapper",
|
||||
"--manifest", manifest,
|
||||
"--out", outFile,
|
||||
"--hash", hash,
|
||||
}))
|
||||
|
||||
data, err := os.ReadFile(outFile)
|
||||
require.NoError(t, err)
|
||||
data = bytes.ReplaceAll(data, []byte("\r"), []byte{}) // Windows.
|
||||
expected, err := os.ReadFile(filepath.Join("testdata", "nex", "nex.go"))
|
||||
require.NoError(t, err)
|
||||
expected = bytes.ReplaceAll(expected, []byte("\r"), []byte{}) // Windows.
|
||||
require.Equal(t, string(expected), string(data))
|
||||
data, err := os.ReadFile(outFile)
|
||||
require.NoError(t, err)
|
||||
data = bytes.ReplaceAll(data, []byte("\r"), []byte{}) // Windows.
|
||||
expected, err := os.ReadFile(good)
|
||||
require.NoError(t, err)
|
||||
expected = bytes.ReplaceAll(expected, []byte("\r"), []byte{}) // Windows.
|
||||
require.Equal(t, string(expected), string(data))
|
||||
})
|
||||
}
|
||||
|
||||
require.NoError(t, app.Run([]string{"", "generate-rpcwrapper",
|
||||
"--manifest", filepath.Join("testdata", "nameservice", "nns.manifest.json"),
|
||||
"--out", outFile,
|
||||
"--hash", "0x50ac1c37690cc2cfc594472833cf57505d5f46de",
|
||||
}))
|
||||
|
||||
data, err = os.ReadFile(outFile)
|
||||
require.NoError(t, err)
|
||||
data = bytes.ReplaceAll(data, []byte("\r"), []byte{}) // Windows.
|
||||
expected, err = os.ReadFile(filepath.Join("testdata", "nameservice", "nns.go"))
|
||||
require.NoError(t, err)
|
||||
expected = bytes.ReplaceAll(expected, []byte("\r"), []byte{}) // Windows.
|
||||
require.Equal(t, string(expected), string(data))
|
||||
checkBinding(filepath.Join("testdata", "nex", "nex.manifest.json"),
|
||||
"0xa2a67f09e8cf22c6bfd5cea24adc0f4bf0a11aa8",
|
||||
filepath.Join("testdata", "nex", "nex.go"))
|
||||
checkBinding(filepath.Join("testdata", "nameservice", "nns.manifest.json"),
|
||||
"0x50ac1c37690cc2cfc594472833cf57505d5f46de",
|
||||
filepath.Join("testdata", "nameservice", "nns.go"))
|
||||
checkBinding(filepath.Join("testdata", "gas", "gas.manifest.json"),
|
||||
"0xd2a4cff31913016155e38e474a2c06d08be276cf",
|
||||
filepath.Join("testdata", "gas", "gas.go"))
|
||||
}
|
||||
|
||||
func TestGenerate_Errors(t *testing.T) {
|
||||
|
|
46
cli/smartcontract/testdata/gas/gas.go
vendored
Normal file
46
cli/smartcontract/testdata/gas/gas.go
vendored
Normal file
|
@ -0,0 +1,46 @@
|
|||
// Package gastoken contains RPC wrappers for GasToken contract.
|
||||
package gastoken
|
||||
|
||||
import (
|
||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/nep17"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
)
|
||||
|
||||
// Hash contains contract hash.
|
||||
var Hash = util.Uint160{0xcf, 0x76, 0xe2, 0x8b, 0xd0, 0x6, 0x2c, 0x4a, 0x47, 0x8e, 0xe3, 0x55, 0x61, 0x1, 0x13, 0x19, 0xf3, 0xcf, 0xa4, 0xd2}
|
||||
|
||||
// Invoker is used by ContractReader to call various safe methods.
|
||||
type Invoker interface {
|
||||
nep17.Invoker
|
||||
}
|
||||
|
||||
// Actor is used by Contract to call state-changing methods.
|
||||
type Actor interface {
|
||||
Invoker
|
||||
nep17.Actor
|
||||
}
|
||||
|
||||
// ContractReader implements safe contract methods.
|
||||
type ContractReader struct {
|
||||
nep17.TokenReader
|
||||
invoker Invoker
|
||||
}
|
||||
|
||||
// Contract implements all contract methods.
|
||||
type Contract struct {
|
||||
ContractReader
|
||||
nep17.TokenWriter
|
||||
actor Actor
|
||||
}
|
||||
|
||||
// NewReader creates an instance of ContractReader using Hash and the given Invoker.
|
||||
func NewReader(invoker Invoker) *ContractReader {
|
||||
return &ContractReader{*nep17.NewReader(invoker, Hash), invoker}
|
||||
}
|
||||
|
||||
// New creates an instance of Contract using Hash and the given Actor.
|
||||
func New(actor Actor) *Contract {
|
||||
var nep17t = nep17.New(actor, Hash)
|
||||
return &Contract{ContractReader{nep17t.TokenReader, actor},nep17t.TokenWriter, actor}
|
||||
}
|
||||
|
1
cli/smartcontract/testdata/gas/gas.manifest.json
vendored
Normal file
1
cli/smartcontract/testdata/gas/gas.manifest.json
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
{"name":"GasToken","groups":[],"features":{},"supportedstandards":["NEP-17"],"abi":{"methods":[{"name":"balanceOf","parameters":[{"name":"account","type":"Hash160"}],"returntype":"Integer","offset":0,"safe":true},{"name":"decimals","parameters":[],"returntype":"Integer","offset":7,"safe":true},{"name":"symbol","parameters":[],"returntype":"String","offset":14,"safe":true},{"name":"totalSupply","parameters":[],"returntype":"Integer","offset":21,"safe":true},{"name":"transfer","parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"},{"name":"data","type":"Any"}],"returntype":"Boolean","offset":28,"safe":false}],"events":[{"name":"Transfer","parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"}]}]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":null}
|
|
@ -3,7 +3,6 @@ package nameservice
|
|||
|
||||
import (
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||
"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"
|
||||
|
@ -18,13 +17,13 @@ var Hash = util.Uint160{0xde, 0x46, 0x5f, 0x5d, 0x50, 0x57, 0xcf, 0x33, 0x28, 0x
|
|||
// Invoker is used by ContractReader to call various safe methods.
|
||||
type Invoker interface {
|
||||
nep11.Invoker
|
||||
Call(contract util.Uint160, operation string, params ...interface{}) (*result.Invoke, error)
|
||||
}
|
||||
|
||||
// Actor is used by Contract to call state-changing methods.
|
||||
type Actor interface {
|
||||
Invoker
|
||||
nep11.Actor
|
||||
|
||||
MakeCall(contract util.Uint160, method string, params ...interface{}) (*transaction.Transaction, error)
|
||||
MakeRun(script []byte) (*transaction.Transaction, error)
|
||||
MakeUnsignedCall(contract util.Uint160, method string, attrs []transaction.Attribute, params ...interface{}) (*transaction.Transaction, error)
|
||||
|
|
2
cli/smartcontract/testdata/nex/nex.go
vendored
2
cli/smartcontract/testdata/nex/nex.go
vendored
|
@ -4,7 +4,6 @@ package nextoken
|
|||
import (
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/nep17"
|
||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
|
@ -17,7 +16,6 @@ var Hash = util.Uint160{0xa8, 0x1a, 0xa1, 0xf0, 0x4b, 0xf, 0xdc, 0x4a, 0xa2, 0xc
|
|||
// Invoker is used by ContractReader to call various safe methods.
|
||||
type Invoker interface {
|
||||
nep17.Invoker
|
||||
Call(contract util.Uint160, operation string, params ...interface{}) (*result.Invoke, error)
|
||||
}
|
||||
|
||||
// Actor is used by Contract to call state-changing methods.
|
||||
|
|
|
@ -92,20 +92,18 @@ var Hash = {{ .Hash }}
|
|||
|
||||
// Invoker is used by ContractReader to call various safe methods.
|
||||
type Invoker interface {
|
||||
{{if or .IsNep11D .IsNep11ND}}nep11.Invoker
|
||||
{{end -}}
|
||||
{{if .IsNep17}}nep17.Invoker
|
||||
{{end -}}
|
||||
Call(contract util.Uint160, operation string, params ...interface{}) (*result.Invoke, error)
|
||||
{{if or .IsNep11D .IsNep11ND}} nep11.Invoker
|
||||
{{else if .IsNep17}} nep17.Invoker
|
||||
{{else if len .SafeMethods}} Call(contract util.Uint160, operation string, params ...interface{}) (*result.Invoke, error)
|
||||
{{end -}}
|
||||
}
|
||||
|
||||
{{if .HasWriter}}// Actor is used by Contract to call state-changing methods.
|
||||
type Actor interface {
|
||||
Invoker
|
||||
{{if or .IsNep11D .IsNep11ND}}nep11.Actor{{end -}}
|
||||
{{if .IsNep17}}nep17.Actor{{end -}}
|
||||
{{if len .Methods}}
|
||||
MakeCall(contract util.Uint160, method string, params ...interface{}) (*transaction.Transaction, error)
|
||||
{{if or .IsNep11D .IsNep11ND}} nep11.Actor
|
||||
{{else if .IsNep17}} nep17.Actor{{end}}
|
||||
{{if len .Methods}} MakeCall(contract util.Uint160, method string, params ...interface{}) (*transaction.Transaction, error)
|
||||
MakeRun(script []byte) (*transaction.Transaction, error)
|
||||
MakeUnsignedCall(contract util.Uint160, method string, attrs []transaction.Attribute, params ...interface{}) (*transaction.Transaction, error)
|
||||
MakeUnsignedRun(script []byte, attrs []transaction.Attribute) (*transaction.Transaction, error)
|
||||
|
@ -198,19 +196,50 @@ func NewConfig() binding.Config {
|
|||
|
||||
// Generate writes Go file containing smartcontract bindings to the `cfg.Output`.
|
||||
func Generate(cfg binding.Config) error {
|
||||
// Avoid changing *cfg.Manifest.
|
||||
mfst := *cfg.Manifest
|
||||
mfst.ABI.Methods = make([]manifest.Method, len(mfst.ABI.Methods))
|
||||
copy(mfst.ABI.Methods, cfg.Manifest.ABI.Methods)
|
||||
cfg.Manifest = &mfst
|
||||
|
||||
var imports = make(map[string]struct{})
|
||||
var ctr ContractTmpl
|
||||
|
||||
// Strip standard methods from NEP-XX packages.
|
||||
for _, std := range cfg.Manifest.SupportedStandards {
|
||||
if std == manifest.NEP11StandardName {
|
||||
imports["github.com/nspcc-dev/neo-go/pkg/rpcclient/nep11"] = struct{}{}
|
||||
if standard.ComplyABI(cfg.Manifest, standard.Nep11Divisible) == nil {
|
||||
mfst.ABI.Methods = dropStdMethods(mfst.ABI.Methods, standard.Nep11Divisible)
|
||||
ctr.IsNep11D = true
|
||||
} else if standard.ComplyABI(cfg.Manifest, standard.Nep11NonDivisible) == nil {
|
||||
mfst.ABI.Methods = dropStdMethods(mfst.ABI.Methods, standard.Nep11NonDivisible)
|
||||
ctr.IsNep11ND = true
|
||||
}
|
||||
break // Can't be NEP-17 at the same time.
|
||||
}
|
||||
if std == manifest.NEP17StandardName && standard.ComplyABI(cfg.Manifest, standard.Nep17) == nil {
|
||||
mfst.ABI.Methods = dropStdMethods(mfst.ABI.Methods, standard.Nep17)
|
||||
imports["github.com/nspcc-dev/neo-go/pkg/rpcclient/nep17"] = struct{}{}
|
||||
ctr.IsNep17 = true
|
||||
break // Can't be NEP-11 at the same time.
|
||||
}
|
||||
}
|
||||
|
||||
bctr, err := binding.TemplateFromManifest(cfg, scTypeToGo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ctr := scTemplateToRPC(cfg, bctr)
|
||||
ctr.ContractTmpl = bctr
|
||||
ctr = scTemplateToRPC(cfg, ctr, imports)
|
||||
|
||||
return srcTemplate.Execute(cfg.Output, ctr)
|
||||
}
|
||||
|
||||
func dropManifestMethods(meths []binding.MethodTmpl, manifested []manifest.Method) []binding.MethodTmpl {
|
||||
func dropManifestMethods(meths []manifest.Method, manifested []manifest.Method) []manifest.Method {
|
||||
for _, m := range manifested {
|
||||
for i := 0; i < len(meths); i++ {
|
||||
if meths[i].NameABI == m.Name && len(meths[i].Arguments) == len(m.Parameters) {
|
||||
if meths[i].Name == m.Name && len(meths[i].Parameters) == len(m.Parameters) {
|
||||
meths = append(meths[:i], meths[i+1:]...)
|
||||
i--
|
||||
}
|
||||
|
@ -219,7 +248,7 @@ func dropManifestMethods(meths []binding.MethodTmpl, manifested []manifest.Metho
|
|||
return meths
|
||||
}
|
||||
|
||||
func dropStdMethods(meths []binding.MethodTmpl, std *standard.Standard) []binding.MethodTmpl {
|
||||
func dropStdMethods(meths []manifest.Method, std *standard.Standard) []manifest.Method {
|
||||
meths = dropManifestMethods(meths, std.Manifest.ABI.Methods)
|
||||
if std.Optional != nil {
|
||||
meths = dropManifestMethods(meths, std.Optional)
|
||||
|
@ -263,32 +292,11 @@ func scTypeToGo(name string, typ smartcontract.ParamType, overrides map[string]b
|
|||
}
|
||||
}
|
||||
|
||||
func scTemplateToRPC(cfg binding.Config, bctr binding.ContractTmpl) ContractTmpl {
|
||||
var imports = make(map[string]struct{})
|
||||
var ctr = ContractTmpl{ContractTmpl: bctr}
|
||||
func scTemplateToRPC(cfg binding.Config, ctr ContractTmpl, imports map[string]struct{}) ContractTmpl {
|
||||
for i := range ctr.Imports {
|
||||
imports[ctr.Imports[i]] = struct{}{}
|
||||
}
|
||||
ctr.Hash = fmt.Sprintf("%#v", cfg.Hash)
|
||||
for _, std := range cfg.Manifest.SupportedStandards {
|
||||
if std == manifest.NEP11StandardName {
|
||||
imports["github.com/nspcc-dev/neo-go/pkg/rpcclient/nep11"] = struct{}{}
|
||||
if standard.ComplyABI(cfg.Manifest, standard.Nep11Divisible) == nil {
|
||||
ctr.Methods = dropStdMethods(ctr.Methods, standard.Nep11Divisible)
|
||||
ctr.IsNep11D = true
|
||||
} else if standard.ComplyABI(cfg.Manifest, standard.Nep11NonDivisible) == nil {
|
||||
ctr.Methods = dropStdMethods(ctr.Methods, standard.Nep11NonDivisible)
|
||||
ctr.IsNep11ND = true
|
||||
}
|
||||
break // Can't be NEP-17 at the same time.
|
||||
}
|
||||
if std == manifest.NEP17StandardName && standard.ComplyABI(cfg.Manifest, standard.Nep17) == nil {
|
||||
ctr.Methods = dropStdMethods(ctr.Methods, standard.Nep17)
|
||||
imports["github.com/nspcc-dev/neo-go/pkg/rpcclient/nep17"] = struct{}{}
|
||||
ctr.IsNep17 = true
|
||||
break // Can't be NEP-11 at the same time.
|
||||
}
|
||||
}
|
||||
for i := 0; i < len(ctr.Methods); i++ {
|
||||
abim := cfg.Manifest.ABI.GetMethod(ctr.Methods[i].NameABI, len(ctr.Methods[i].Arguments))
|
||||
if abim.Safe {
|
||||
|
@ -332,9 +340,12 @@ func scTemplateToRPC(cfg binding.Config, bctr binding.ContractTmpl) ContractTmpl
|
|||
}
|
||||
}
|
||||
|
||||
imports["github.com/nspcc-dev/neo-go/pkg/neorpc/result"] = struct{}{}
|
||||
imports["github.com/nspcc-dev/neo-go/pkg/util"] = struct{}{}
|
||||
if len(ctr.SafeMethods) > 0 {
|
||||
imports["github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"] = struct{}{}
|
||||
if !(ctr.IsNep17 || ctr.IsNep11D || ctr.IsNep11ND) {
|
||||
imports["github.com/nspcc-dev/neo-go/pkg/neorpc/result"] = struct{}{}
|
||||
}
|
||||
}
|
||||
if len(ctr.Methods) > 0 {
|
||||
imports["github.com/nspcc-dev/neo-go/pkg/core/transaction"] = struct{}{}
|
||||
|
|
Loading…
Reference in a new issue