rpcbinding: support writer-only wrappers

"verify" contract doesn't have any safe methods.
This commit is contained in:
Roman Khimov 2022-11-08 16:36:38 +03:00
parent df29008a50
commit 130608ac67
6 changed files with 127 additions and 12 deletions

View file

@ -357,6 +357,9 @@ func TestGenerateRPCBindings(t *testing.T) {
checkBinding(filepath.Join("testdata", "gas", "gas.manifest.json"), checkBinding(filepath.Join("testdata", "gas", "gas.manifest.json"),
"0xd2a4cff31913016155e38e474a2c06d08be276cf", "0xd2a4cff31913016155e38e474a2c06d08be276cf",
filepath.Join("testdata", "gas", "gas.go")) filepath.Join("testdata", "gas", "gas.go"))
checkBinding(filepath.Join("testdata", "verify.manifest.json"),
"0x00112233445566778899aabbccddeeff00112233",
filepath.Join("testdata", "verifyrpc", "verify.go"))
} }
func TestGenerate_Errors(t *testing.T) { func TestGenerate_Errors(t *testing.T) {

View file

@ -17,6 +17,7 @@ type Invoker interface {
// Actor is used by Contract to call state-changing methods. // Actor is used by Contract to call state-changing methods.
type Actor interface { type Actor interface {
Invoker Invoker
nep17.Actor nep17.Actor
} }
@ -41,6 +42,6 @@ func NewReader(invoker Invoker) *ContractReader {
// New creates an instance of Contract using Hash and the given Actor. // New creates an instance of Contract using Hash and the given Actor.
func New(actor Actor) *Contract { func New(actor Actor) *Contract {
var nep17t = nep17.New(actor, Hash) var nep17t = nep17.New(actor, Hash)
return &Contract{ContractReader{nep17t.TokenReader, actor},nep17t.TokenWriter, actor} return &Contract{ContractReader{nep17t.TokenReader, actor}, nep17t.TokenWriter, actor}
} }

View file

@ -22,6 +22,7 @@ type Invoker interface {
// Actor is used by Contract to call state-changing methods. // Actor is used by Contract to call state-changing methods.
type Actor interface { type Actor interface {
Invoker Invoker
nep11.Actor nep11.Actor
MakeCall(contract util.Uint160, method string, params ...interface{}) (*transaction.Transaction, error) MakeCall(contract util.Uint160, method string, params ...interface{}) (*transaction.Transaction, error)
@ -53,7 +54,7 @@ func NewReader(invoker Invoker) *ContractReader {
// New creates an instance of Contract using Hash and the given Actor. // New creates an instance of Contract using Hash and the given Actor.
func New(actor Actor) *Contract { func New(actor Actor) *Contract {
var nep11ndt = nep11.NewNonDivisible(actor, Hash) var nep11ndt = nep11.NewNonDivisible(actor, Hash)
return &Contract{ContractReader{nep11ndt.NonDivisibleReader, actor},nep11ndt.BaseWriter, actor} return &Contract{ContractReader{nep11ndt.NonDivisibleReader, actor}, nep11ndt.BaseWriter, actor}
} }

View file

@ -21,7 +21,9 @@ type Invoker interface {
// Actor is used by Contract to call state-changing methods. // Actor is used by Contract to call state-changing methods.
type Actor interface { type Actor interface {
Invoker Invoker
nep17.Actor nep17.Actor
MakeCall(contract util.Uint160, method string, params ...interface{}) (*transaction.Transaction, error) MakeCall(contract util.Uint160, method string, params ...interface{}) (*transaction.Transaction, error)
MakeRun(script []byte) (*transaction.Transaction, error) MakeRun(script []byte) (*transaction.Transaction, error)
MakeUnsignedCall(contract util.Uint160, method string, attrs []transaction.Attribute, params ...interface{}) (*transaction.Transaction, error) MakeUnsignedCall(contract util.Uint160, method string, attrs []transaction.Attribute, params ...interface{}) (*transaction.Transaction, error)
@ -51,7 +53,7 @@ func NewReader(invoker Invoker) *ContractReader {
// New creates an instance of Contract using Hash and the given Actor. // New creates an instance of Contract using Hash and the given Actor.
func New(actor Actor) *Contract { func New(actor Actor) *Contract {
var nep17t = nep17.New(actor, Hash) var nep17t = nep17.New(actor, Hash)
return &Contract{ContractReader{nep17t.TokenReader, actor},nep17t.TokenWriter, actor} return &Contract{ContractReader{nep17t.TokenReader, actor}, nep17t.TokenWriter, actor}
} }

View file

@ -0,0 +1,93 @@
// Package verify contains RPC wrappers for verify contract.
package verify
import (
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/util"
"math/big"
)
// 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}
// Actor is used by Contract to call state-changing methods.
type Actor interface {
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)
SendCall(contract util.Uint160, method string, params ...interface{}) (util.Uint256, uint32, error)
SendRun(script []byte) (util.Uint256, uint32, error)
}
// Contract implements all contract methods.
type Contract struct {
actor Actor
}
// New creates an instance of Contract using Hash and the given Actor.
func New(actor Actor) *Contract {
return &Contract{actor}
}
func scriptForVerify() ([]byte, error) {
return smartcontract.CreateCallWithAssertScript(Hash, "verify")
}
// Verify creates a transaction invoking `verify` 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) Verify() (util.Uint256, uint32, error) {
script, err := scriptForVerify()
if err != nil {
return util.Uint256{}, 0, err
}
return c.actor.SendRun(script)
}
// VerifyTransaction creates a transaction invoking `verify` method of the contract.
// This transaction is signed, but not sent to the network, instead it's
// returned to the caller.
func (c *Contract) VerifyTransaction() (*transaction.Transaction, error) {
script, err := scriptForVerify()
if err != nil {
return nil, err
}
return c.actor.MakeRun(script)
}
// VerifyUnsigned creates a transaction invoking `verify` method of the contract.
// This transaction is not signed, it's simply returned to the caller.
// 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) VerifyUnsigned() (*transaction.Transaction, error) {
script, err := scriptForVerify()
if err != nil {
return nil, err
}
return c.actor.MakeUnsignedRun(script, nil)
}
// OnNEP17Payment creates a transaction invoking `onNEP17Payment` 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) OnNEP17Payment(from []byte, amount *big.Int, data interface{}) (util.Uint256, uint32, error) {
return c.actor.SendCall(Hash, "onNEP17Payment", from, amount, data)
}
// OnNEP17PaymentTransaction creates a transaction invoking `onNEP17Payment` method of the contract.
// This transaction is signed, but not sent to the network, instead it's
// returned to the caller.
func (c *Contract) OnNEP17PaymentTransaction(from []byte, amount *big.Int, data interface{}) (*transaction.Transaction, error) {
return c.actor.MakeCall(Hash, "onNEP17Payment", from, amount, data)
}
// OnNEP17PaymentUnsigned creates a transaction invoking `onNEP17Payment` method of the contract.
// This transaction is not signed, it's simply returned to the caller.
// 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) OnNEP17PaymentUnsigned(from []byte, amount *big.Int, data interface{}) (*transaction.Transaction, error) {
return c.actor.MakeUnsignedCall(Hash, "onNEP17Payment", nil, from, amount, data)
}

View file

@ -90,7 +90,7 @@ import (
// Hash contains contract hash. // Hash contains contract hash.
var Hash = {{ .Hash }} var Hash = {{ .Hash }}
// Invoker is used by ContractReader to call various safe methods. {{if .HasReader}}// Invoker is used by ContractReader to call various safe methods.
type Invoker interface { type Invoker interface {
{{if or .IsNep11D .IsNep11ND}} nep11.Invoker {{if or .IsNep11D .IsNep11ND}} nep11.Invoker
{{else if .IsNep17}} nep17.Invoker {{else if .IsNep17}} nep17.Invoker
@ -98,12 +98,19 @@ type Invoker interface {
{{end -}} {{end -}}
} }
{{end -}}
{{if .HasWriter}}// Actor is used by Contract to call state-changing methods. {{if .HasWriter}}// Actor is used by Contract to call state-changing methods.
type Actor interface { type Actor interface {
{{- if .HasReader}}
Invoker Invoker
{{if or .IsNep11D .IsNep11ND}} nep11.Actor {{end}}
{{else if .IsNep17}} nep17.Actor{{end}} {{- if or .IsNep11D .IsNep11ND}}
{{if len .Methods}} MakeCall(contract util.Uint160, method string, params ...interface{}) (*transaction.Transaction, error) 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) MakeRun(script []byte) (*transaction.Transaction, error)
MakeUnsignedCall(contract util.Uint160, method string, attrs []transaction.Attribute, params ...interface{}) (*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) MakeUnsignedRun(script []byte, attrs []transaction.Attribute) (*transaction.Transaction, error)
@ -113,7 +120,7 @@ type Actor interface {
} }
{{end -}} {{end -}}
// ContractReader implements safe contract methods. {{if .HasReader}}// ContractReader implements safe contract methods.
type ContractReader struct { type ContractReader struct {
{{if .IsNep11D}}nep11.DivisibleReader {{if .IsNep11D}}nep11.DivisibleReader
{{end -}} {{end -}}
@ -124,9 +131,11 @@ type ContractReader struct {
invoker Invoker invoker Invoker
} }
{{end -}}
{{if .HasWriter}}// Contract implements all contract methods. {{if .HasWriter}}// Contract implements all contract methods.
type Contract struct { type Contract struct {
ContractReader {{if .HasReader}}ContractReader
{{end -}}
{{if .IsNep11D}}nep11.DivisibleWriter {{if .IsNep11D}}nep11.DivisibleWriter
{{end -}} {{end -}}
{{if .IsNep11ND}}nep11.BaseWriter {{if .IsNep11ND}}nep11.BaseWriter
@ -137,7 +146,7 @@ type Contract struct {
} }
{{end -}} {{end -}}
// NewReader creates an instance of ContractReader using Hash and the given Invoker. {{if .HasReader}}// NewReader creates an instance of ContractReader using Hash and the given Invoker.
func NewReader(invoker Invoker) *ContractReader { func NewReader(invoker Invoker) *ContractReader {
return &ContractReader{ return &ContractReader{
{{- if .IsNep11D}}*nep11.NewDivisibleReader(invoker, Hash), {{end}} {{- if .IsNep11D}}*nep11.NewDivisibleReader(invoker, Hash), {{end}}
@ -146,6 +155,7 @@ func NewReader(invoker Invoker) *ContractReader {
invoker} invoker}
} }
{{end -}}
{{if .HasWriter}}// New creates an instance of Contract using Hash and the given Actor. {{if .HasWriter}}// New creates an instance of Contract using Hash and the given Actor.
func New(actor Actor) *Contract { func New(actor Actor) *Contract {
{{if .IsNep11D}}var nep11dt = nep11.NewDivisible(actor, Hash) {{if .IsNep11D}}var nep11dt = nep11.NewDivisible(actor, Hash)
@ -154,11 +164,12 @@ func New(actor Actor) *Contract {
{{end -}} {{end -}}
{{if .IsNep17}}var nep17t = nep17.New(actor, Hash) {{if .IsNep17}}var nep17t = nep17.New(actor, Hash)
{{end -}} {{end -}}
return &Contract{ContractReader{ return &Contract{
{{- if .HasReader}}ContractReader{
{{- if .IsNep11D}}nep11dt.DivisibleReader, {{end -}} {{- if .IsNep11D}}nep11dt.DivisibleReader, {{end -}}
{{- if .IsNep11ND}}nep11ndt.NonDivisibleReader, {{end -}} {{- if .IsNep11ND}}nep11ndt.NonDivisibleReader, {{end -}}
{{- if .IsNep17}}nep17t.TokenReader, {{end -}} {{- if .IsNep17}}nep17t.TokenReader, {{end -}}
actor}, actor}, {{end -}}
{{- if .IsNep11D}}nep11dt.DivisibleWriter, {{end -}} {{- if .IsNep11D}}nep11dt.DivisibleWriter, {{end -}}
{{- if .IsNep11ND}}nep11ndt.BaseWriter, {{end -}} {{- if .IsNep11ND}}nep11ndt.BaseWriter, {{end -}}
{{- if .IsNep17}}nep17t.TokenWriter, {{end -}} {{- if .IsNep17}}nep17t.TokenWriter, {{end -}}
@ -185,6 +196,7 @@ type (
IsNep11ND bool IsNep11ND bool
IsNep17 bool IsNep17 bool
HasReader bool
HasWriter bool HasWriter bool
} }
) )
@ -353,6 +365,9 @@ func scTemplateToRPC(cfg binding.Config, ctr ContractTmpl, imports map[string]st
if len(ctr.Methods) > 0 || ctr.IsNep17 || ctr.IsNep11D || ctr.IsNep11ND { if len(ctr.Methods) > 0 || ctr.IsNep17 || ctr.IsNep11D || ctr.IsNep11ND {
ctr.HasWriter = true ctr.HasWriter = true
} }
if len(ctr.SafeMethods) > 0 || ctr.IsNep17 || ctr.IsNep11D || ctr.IsNep11ND {
ctr.HasReader = true
}
ctr.Imports = ctr.Imports[:0] ctr.Imports = ctr.Imports[:0]
for imp := range imports { for imp := range imports {
ctr.Imports = append(ctr.Imports, imp) ctr.Imports = append(ctr.Imports, imp)