compiler: store ready-to-use notification names in bindings config

Notification and its parameters may have any UTF8-compatible name
which is inappropriate for bindings configuration and for the resulting
RPC bindings file. This commit stores the prettified version of
notification's name and parameters that are ready to be used in the
resulting RPC binding without any changes.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
This commit is contained in:
Anna Shaleva 2023-05-23 14:17:39 +03:00
parent 41938ffa78
commit 19cc6c6369
6 changed files with 805 additions and 30 deletions

View file

@ -416,6 +416,7 @@ func TestAssistedRPCBindings(t *testing.T) {
checkBinding(filepath.Join("testdata", "types"))
checkBinding(filepath.Join("testdata", "structs"))
checkBinding(filepath.Join("testdata", "notifications"))
require.False(t, rewriteExpectedOutputs)
}

View file

@ -0,0 +1,7 @@
name: "Notifications"
sourceurl: https://github.com/nspcc-dev/neo-go/
events:
- name: "! complicated name %$#"
parameters:
- name: ! complicated param @#$%
type: String

View file

@ -0,0 +1,7 @@
package structs
import "github.com/nspcc-dev/neo-go/pkg/interop/runtime"
func Main() {
runtime.Notify("! complicated name %$#", "str1")
}

View file

@ -0,0 +1,748 @@
// Package structs contains RPC wrappers for Notifications contract.
package structs
import (
"crypto/elliptic"
"errors"
"fmt"
"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/util"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"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}
// LedgerBlock is a contract-specific ledger.Block type used by its methods.
type LedgerBlock struct {
Hash util.Uint256
Version *big.Int
PrevHash util.Uint256
MerkleRoot util.Uint256
Timestamp *big.Int
Nonce *big.Int
Index *big.Int
NextConsensus util.Uint160
TransactionsLength *big.Int
}
// LedgerBlockSR is a contract-specific ledger.BlockSR type used by its methods.
type LedgerBlockSR struct {
Hash util.Uint256
Version *big.Int
PrevHash util.Uint256
MerkleRoot util.Uint256
Timestamp *big.Int
Nonce *big.Int
Index *big.Int
NextConsensus util.Uint160
TransactionsLength *big.Int
PrevStateRoot util.Uint256
}
// LedgerTransaction is a contract-specific ledger.Transaction type used by its methods.
type LedgerTransaction struct {
Hash util.Uint256
Version *big.Int
Nonce *big.Int
Sender util.Uint160
SysFee *big.Int
NetFee *big.Int
ValidUntilBlock *big.Int
Script []byte
}
// LedgerTransactionSigner is a contract-specific ledger.TransactionSigner type used by its methods.
type LedgerTransactionSigner struct {
Account util.Uint160
Scopes *big.Int
AllowedContracts []util.Uint160
AllowedGroups keys.PublicKeys
Rules []*LedgerWitnessRule
}
// LedgerWitnessCondition is a contract-specific ledger.WitnessCondition type used by its methods.
type LedgerWitnessCondition struct {
Type *big.Int
Value any
}
// LedgerWitnessRule is a contract-specific ledger.WitnessRule type used by its methods.
type LedgerWitnessRule struct {
Action *big.Int
Condition *LedgerWitnessCondition
}
// ComplicatedNameEvent represents "! complicated name %$#" event emitted by the contract.
type ComplicatedNameEvent struct {
ComplicatedParam string
}
// Actor is used by Contract to call state-changing methods.
type Actor interface {
MakeCall(contract util.Uint160, method string, params ...any) (*transaction.Transaction, error)
MakeRun(script []byte) (*transaction.Transaction, error)
MakeUnsignedCall(contract util.Uint160, method string, attrs []transaction.Attribute, params ...any) (*transaction.Transaction, error)
MakeUnsignedRun(script []byte, attrs []transaction.Attribute) (*transaction.Transaction, error)
SendCall(contract util.Uint160, method string, params ...any) (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}
}
// Main creates a transaction invoking `main` 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) Main() (util.Uint256, uint32, error) {
return c.actor.SendCall(Hash, "main")
}
// MainTransaction creates a transaction invoking `main` method of the contract.
// This transaction is signed, but not sent to the network, instead it's
// returned to the caller.
func (c *Contract) MainTransaction() (*transaction.Transaction, error) {
return c.actor.MakeCall(Hash, "main")
}
// MainUnsigned creates a transaction invoking `main` 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) MainUnsigned() (*transaction.Transaction, error) {
return c.actor.MakeUnsignedCall(Hash, "main", nil)
}
// itemToLedgerBlock converts stack item into *LedgerBlock.
func itemToLedgerBlock(item stackitem.Item, err error) (*LedgerBlock, error) {
if err != nil {
return nil, err
}
var res = new(LedgerBlock)
err = res.FromStackItem(item)
return res, err
}
// FromStackItem retrieves fields of LedgerBlock from the given stack item
// and returns an error if so.
func (res *LedgerBlock) FromStackItem(item stackitem.Item) error {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 9 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
)
index++
res.Hash, err = func (item stackitem.Item) (util.Uint256, error) {
b, err := item.TryBytes()
if err != nil {
return util.Uint256{}, err
}
u, err := util.Uint256DecodeBytesBE(b)
if err != nil {
return util.Uint256{}, err
}
return u, nil
} (arr[index])
if err != nil {
return fmt.Errorf("field Hash: %w", err)
}
index++
res.Version, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field Version: %w", err)
}
index++
res.PrevHash, err = func (item stackitem.Item) (util.Uint256, error) {
b, err := item.TryBytes()
if err != nil {
return util.Uint256{}, err
}
u, err := util.Uint256DecodeBytesBE(b)
if err != nil {
return util.Uint256{}, err
}
return u, nil
} (arr[index])
if err != nil {
return fmt.Errorf("field PrevHash: %w", err)
}
index++
res.MerkleRoot, err = func (item stackitem.Item) (util.Uint256, error) {
b, err := item.TryBytes()
if err != nil {
return util.Uint256{}, err
}
u, err := util.Uint256DecodeBytesBE(b)
if err != nil {
return util.Uint256{}, err
}
return u, nil
} (arr[index])
if err != nil {
return fmt.Errorf("field MerkleRoot: %w", err)
}
index++
res.Timestamp, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field Timestamp: %w", err)
}
index++
res.Nonce, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field Nonce: %w", err)
}
index++
res.Index, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field Index: %w", err)
}
index++
res.NextConsensus, err = func (item stackitem.Item) (util.Uint160, error) {
b, err := item.TryBytes()
if err != nil {
return util.Uint160{}, err
}
u, err := util.Uint160DecodeBytesBE(b)
if err != nil {
return util.Uint160{}, err
}
return u, nil
} (arr[index])
if err != nil {
return fmt.Errorf("field NextConsensus: %w", err)
}
index++
res.TransactionsLength, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field TransactionsLength: %w", err)
}
return nil
}
// itemToLedgerBlockSR converts stack item into *LedgerBlockSR.
func itemToLedgerBlockSR(item stackitem.Item, err error) (*LedgerBlockSR, error) {
if err != nil {
return nil, err
}
var res = new(LedgerBlockSR)
err = res.FromStackItem(item)
return res, err
}
// FromStackItem retrieves fields of LedgerBlockSR from the given stack item
// and returns an error if so.
func (res *LedgerBlockSR) FromStackItem(item stackitem.Item) error {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 10 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
)
index++
res.Hash, err = func (item stackitem.Item) (util.Uint256, error) {
b, err := item.TryBytes()
if err != nil {
return util.Uint256{}, err
}
u, err := util.Uint256DecodeBytesBE(b)
if err != nil {
return util.Uint256{}, err
}
return u, nil
} (arr[index])
if err != nil {
return fmt.Errorf("field Hash: %w", err)
}
index++
res.Version, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field Version: %w", err)
}
index++
res.PrevHash, err = func (item stackitem.Item) (util.Uint256, error) {
b, err := item.TryBytes()
if err != nil {
return util.Uint256{}, err
}
u, err := util.Uint256DecodeBytesBE(b)
if err != nil {
return util.Uint256{}, err
}
return u, nil
} (arr[index])
if err != nil {
return fmt.Errorf("field PrevHash: %w", err)
}
index++
res.MerkleRoot, err = func (item stackitem.Item) (util.Uint256, error) {
b, err := item.TryBytes()
if err != nil {
return util.Uint256{}, err
}
u, err := util.Uint256DecodeBytesBE(b)
if err != nil {
return util.Uint256{}, err
}
return u, nil
} (arr[index])
if err != nil {
return fmt.Errorf("field MerkleRoot: %w", err)
}
index++
res.Timestamp, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field Timestamp: %w", err)
}
index++
res.Nonce, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field Nonce: %w", err)
}
index++
res.Index, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field Index: %w", err)
}
index++
res.NextConsensus, err = func (item stackitem.Item) (util.Uint160, error) {
b, err := item.TryBytes()
if err != nil {
return util.Uint160{}, err
}
u, err := util.Uint160DecodeBytesBE(b)
if err != nil {
return util.Uint160{}, err
}
return u, nil
} (arr[index])
if err != nil {
return fmt.Errorf("field NextConsensus: %w", err)
}
index++
res.TransactionsLength, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field TransactionsLength: %w", err)
}
index++
res.PrevStateRoot, err = func (item stackitem.Item) (util.Uint256, error) {
b, err := item.TryBytes()
if err != nil {
return util.Uint256{}, err
}
u, err := util.Uint256DecodeBytesBE(b)
if err != nil {
return util.Uint256{}, err
}
return u, nil
} (arr[index])
if err != nil {
return fmt.Errorf("field PrevStateRoot: %w", err)
}
return nil
}
// itemToLedgerTransaction converts stack item into *LedgerTransaction.
func itemToLedgerTransaction(item stackitem.Item, err error) (*LedgerTransaction, error) {
if err != nil {
return nil, err
}
var res = new(LedgerTransaction)
err = res.FromStackItem(item)
return res, err
}
// FromStackItem retrieves fields of LedgerTransaction from the given stack item
// and returns an error if so.
func (res *LedgerTransaction) FromStackItem(item stackitem.Item) error {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 8 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
)
index++
res.Hash, err = func (item stackitem.Item) (util.Uint256, error) {
b, err := item.TryBytes()
if err != nil {
return util.Uint256{}, err
}
u, err := util.Uint256DecodeBytesBE(b)
if err != nil {
return util.Uint256{}, err
}
return u, nil
} (arr[index])
if err != nil {
return fmt.Errorf("field Hash: %w", err)
}
index++
res.Version, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field Version: %w", err)
}
index++
res.Nonce, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field Nonce: %w", err)
}
index++
res.Sender, err = func (item stackitem.Item) (util.Uint160, error) {
b, err := item.TryBytes()
if err != nil {
return util.Uint160{}, err
}
u, err := util.Uint160DecodeBytesBE(b)
if err != nil {
return util.Uint160{}, err
}
return u, nil
} (arr[index])
if err != nil {
return fmt.Errorf("field Sender: %w", err)
}
index++
res.SysFee, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field SysFee: %w", err)
}
index++
res.NetFee, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field NetFee: %w", err)
}
index++
res.ValidUntilBlock, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field ValidUntilBlock: %w", err)
}
index++
res.Script, err = arr[index].TryBytes()
if err != nil {
return fmt.Errorf("field Script: %w", err)
}
return nil
}
// itemToLedgerTransactionSigner converts stack item into *LedgerTransactionSigner.
func itemToLedgerTransactionSigner(item stackitem.Item, err error) (*LedgerTransactionSigner, error) {
if err != nil {
return nil, err
}
var res = new(LedgerTransactionSigner)
err = res.FromStackItem(item)
return res, err
}
// FromStackItem retrieves fields of LedgerTransactionSigner from the given stack item
// and returns an error if so.
func (res *LedgerTransactionSigner) FromStackItem(item stackitem.Item) error {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 5 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
)
index++
res.Account, err = func (item stackitem.Item) (util.Uint160, error) {
b, err := item.TryBytes()
if err != nil {
return util.Uint160{}, err
}
u, err := util.Uint160DecodeBytesBE(b)
if err != nil {
return util.Uint160{}, err
}
return u, nil
} (arr[index])
if err != nil {
return fmt.Errorf("field Account: %w", err)
}
index++
res.Scopes, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field Scopes: %w", err)
}
index++
res.AllowedContracts, err = func (item stackitem.Item) ([]util.Uint160, error) {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return nil, errors.New("not an array")
}
res := make([]util.Uint160, len(arr))
for i := range res {
res[i], err = func (item stackitem.Item) (util.Uint160, error) {
b, err := item.TryBytes()
if err != nil {
return util.Uint160{}, err
}
u, err := util.Uint160DecodeBytesBE(b)
if err != nil {
return util.Uint160{}, err
}
return u, nil
} (arr[i])
if err != nil {
return nil, fmt.Errorf("item %d: %w", i, err)
}
}
return res, nil
} (arr[index])
if err != nil {
return fmt.Errorf("field AllowedContracts: %w", err)
}
index++
res.AllowedGroups, err = func (item stackitem.Item) (keys.PublicKeys, error) {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return nil, errors.New("not an array")
}
res := make(keys.PublicKeys, len(arr))
for i := range res {
res[i], err = func (item stackitem.Item) (*keys.PublicKey, error) {
b, err := item.TryBytes()
if err != nil {
return nil, err
}
k, err := keys.NewPublicKeyFromBytes(b, elliptic.P256())
if err != nil {
return nil, err
}
return k, nil
} (arr[i])
if err != nil {
return nil, fmt.Errorf("item %d: %w", i, err)
}
}
return res, nil
} (arr[index])
if err != nil {
return fmt.Errorf("field AllowedGroups: %w", err)
}
index++
res.Rules, err = func (item stackitem.Item) ([]*LedgerWitnessRule, error) {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return nil, errors.New("not an array")
}
res := make([]*LedgerWitnessRule, len(arr))
for i := range res {
res[i], err = itemToLedgerWitnessRule(arr[i], nil)
if err != nil {
return nil, fmt.Errorf("item %d: %w", i, err)
}
}
return res, nil
} (arr[index])
if err != nil {
return fmt.Errorf("field Rules: %w", err)
}
return nil
}
// itemToLedgerWitnessCondition converts stack item into *LedgerWitnessCondition.
func itemToLedgerWitnessCondition(item stackitem.Item, err error) (*LedgerWitnessCondition, error) {
if err != nil {
return nil, err
}
var res = new(LedgerWitnessCondition)
err = res.FromStackItem(item)
return res, err
}
// FromStackItem retrieves fields of LedgerWitnessCondition from the given stack item
// and returns an error if so.
func (res *LedgerWitnessCondition) 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.Type, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field Type: %w", err)
}
index++
res.Value, err = arr[index].Value(), error(nil)
if err != nil {
return fmt.Errorf("field Value: %w", err)
}
return nil
}
// itemToLedgerWitnessRule converts stack item into *LedgerWitnessRule.
func itemToLedgerWitnessRule(item stackitem.Item, err error) (*LedgerWitnessRule, error) {
if err != nil {
return nil, err
}
var res = new(LedgerWitnessRule)
err = res.FromStackItem(item)
return res, err
}
// FromStackItem retrieves fields of LedgerWitnessRule from the given stack item
// and returns an error if so.
func (res *LedgerWitnessRule) 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.Action, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field Action: %w", err)
}
index++
res.Condition, err = itemToLedgerWitnessCondition(arr[index], nil)
if err != nil {
return fmt.Errorf("field Condition: %w", err)
}
return nil
}
// ComplicatedNameEventsFromApplicationLog retrieves a set of all emitted events
// with "! complicated name %$#" name from the provided ApplicationLog.
func ComplicatedNameEventsFromApplicationLog(log *result.ApplicationLog) ([]*ComplicatedNameEvent, error) {
if log == nil {
return nil, errors.New("nil application log")
}
var res []*ComplicatedNameEvent
for i, ex := range log.Executions {
for j, e := range ex.Events {
if e.Name != "! complicated name %$#" {
continue
}
event := new(ComplicatedNameEvent)
err := event.FromStackItem(e.Item)
if err != nil {
return nil, fmt.Errorf("failed to deserialize ComplicatedNameEvent from stackitem (execution %d, event %d): %w", i, j, err)
}
res = append(res, event)
}
}
return res, nil
}
// FromStackItem converts provided stackitem.Array to ComplicatedNameEvent and
// returns an error if so.
func (e *ComplicatedNameEvent) FromStackItem(item *stackitem.Array) error {
if item == nil {
return errors.New("nil item")
}
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++
e.ComplicatedParam, err = func (item stackitem.Item) (string, error) {
b, err := item.TryBytes()
if err != nil {
return "", err
}
if !utf8.Valid(b) {
return "", errors.New("not a UTF-8 string")
}
return string(b), nil
} (arr[index])
if err != nil {
return fmt.Errorf("field ComplicatedParam: %w", err)
}
return nil
}

View file

@ -18,6 +18,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest/standard"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/nef"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/rpcbinding"
"github.com/nspcc-dev/neo-go/pkg/util"
"golang.org/x/tools/go/packages"
"gopkg.in/yaml.v3"
@ -339,14 +340,17 @@ func CompileAndSave(src string, o *Options) ([]byte, error) {
cfg.NamedTypes = di.NamedTypes
}
for name, et := range o.DeclaredNamedTypes {
// TODO: handle name conflict
// TODO: handle name conflict (it can happen due to invalid user input e.g.)
cfg.NamedTypes[name] = et
}
for _, e := range o.ContractEvents {
eStructName := rpcbinding.ToEventBindingName(e.Name)
for _, p := range e.Parameters {
pStructName := rpcbinding.ToParameterBindingName(p.Name)
// TODO: proper imports handling during bindings generation (see utf8 example).
// Probably, we should always add p type to the list of types.
if p.ExtendedType != nil {
pName := e.Name + "." + p.Name
pName := eStructName + "." + pStructName
cfg.Types[pName] = *p.ExtendedType
}
}
@ -354,6 +358,7 @@ func CompileAndSave(src string, o *Options) ([]byte, error) {
if o.GuessEventTypes {
if len(di.EmittedEvents) > 0 {
for eventName, eventUsages := range di.EmittedEvents {
eBindingName := rpcbinding.ToEventBindingName(eventName)
// Take into account the first usage only.
// TODO: extend it to the rest of invocations.
for typeName, extType := range eventUsages[0].ExtTypes {
@ -361,9 +366,10 @@ func CompileAndSave(src string, o *Options) ([]byte, error) {
cfg.NamedTypes[typeName] = extType
}
}
for _, p := range eventUsages[0].Params {
// TODO: prettify notification name in-place.
pname := eventName + "." + p.Name
pBindingName := rpcbinding.ToParameterBindingName(p.Name)
pname := eBindingName + "." + pBindingName
if p.RealType.TypeName != "" {
if _, ok := cfg.Overrides[pname]; !ok {
cfg.Overrides[pname] = p.RealType

View file

@ -19,10 +19,10 @@ import (
// ensure that this block has new line at the start and in the end of the block.
const (
eventDefinition = `{{ define "EVENT" }}
// {{.Name}}Event represents "{{.ManifestName}}" event emitted by the contract.
type {{.Name}}Event struct {
// {{.Name}} represents "{{.ManifestName}}" event emitted by the contract.
type {{.Name}} struct {
{{- range $index, $arg := .Parameters}}
{{toPascalCase .Name}} {{.Type}}
{{.Name}} {{.Type}}
{{- end}}
}
{{ end }}`
@ -262,23 +262,23 @@ func (res *{{toTypeName $name}}) FromStackItem(item stackitem.Item) error {
}
{{ end -}}
{{- range $e := .CustomEvents }}
// {{$e.Name}}EventsFromApplicationLog retrieves a set of all emitted events
// {{$e.Name}}sFromApplicationLog retrieves a set of all emitted events
// with "{{$e.ManifestName}}" name from the provided ApplicationLog.
func {{$e.Name}}EventsFromApplicationLog(log *result.ApplicationLog) ([]*{{$e.Name}}Event, error) {
func {{$e.Name}}sFromApplicationLog(log *result.ApplicationLog) ([]*{{$e.Name}}, error) {
if log == nil {
return nil, errors.New("nil application log")
}
var res []*{{$e.Name}}Event
var res []*{{$e.Name}}
for i, ex := range log.Executions {
for j, e := range ex.Events {
if e.Name != "{{$e.ManifestName}}" {
continue
}
event := new({{$e.Name}}Event)
event := new({{$e.Name}})
err := event.FromStackItem(e.Item)
if err != nil {
return nil, fmt.Errorf("failed to deserialize {{$e.Name}}Event from stackitem (execution %d, event %d): %w", i, j, err)
return nil, fmt.Errorf("failed to deserialize {{$e.Name}} from stackitem (execution %d, event %d): %w", i, j, err)
}
res = append(res, event)
}
@ -287,9 +287,9 @@ func {{$e.Name}}EventsFromApplicationLog(log *result.ApplicationLog) ([]*{{$e.Na
return res, nil
}
// FromStackItem converts provided stackitem.Array to {{$e.Name}}Event and
// FromStackItem converts provided stackitem.Array to {{$e.Name}} and
// returns an error if so.
func (e *{{$e.Name}}Event) FromStackItem(item *stackitem.Array) error {
func (e *{{$e.Name}}) FromStackItem(item *stackitem.Array) error {
if item == nil {
return errors.New("nil item")
}
@ -307,9 +307,9 @@ func (e *{{$e.Name}}Event) FromStackItem(item *stackitem.Array) error {
)
{{- range $p := $e.Parameters}}
index++
e.{{toPascalCase .Name}}, err = {{etTypeConverter .ExtType "arr[index]"}}
e.{{.Name}}, err = {{etTypeConverter .ExtType "arr[index]"}}
if err != nil {
return fmt.Errorf("field {{toPascalCase .Name}}: %w", err)
return fmt.Errorf("field {{.Name}}: %w", err)
}
{{end}}
{{- end}}
@ -429,7 +429,6 @@ func Generate(cfg binding.Config) error {
},
"toTypeName": toTypeName,
"cutPointer": cutPointer,
"toPascalCase": toPascalCase,
}).Parse(srcTmpl))
return srcTemplate.Execute(cfg.Output, ctr)
@ -675,23 +674,18 @@ func scTemplateToRPC(cfg binding.Config, ctr ContractTmpl, imports map[string]st
imports["errors"] = struct{}{}
}
for _, abiEvent := range cfg.Manifest.ABI.Events {
eBindingName := ToEventBindingName(abiEvent.Name)
eTmp := CustomEventTemplate{
// TODO: proper event name is better to be set right into config binding in normal form.
Name: toPascalCase(abiEvent.Name),
Name: eBindingName,
ManifestName: abiEvent.Name,
}
var varnames = make(map[string]bool)
for i := range abiEvent.Parameters {
name := abiEvent.Parameters[i].Name
fullPName := abiEvent.Name + "." + name
pBindingName := ToParameterBindingName(abiEvent.Parameters[i].Name)
fullPName := eBindingName + "." + pBindingName
typeStr, pkg := scTypeConverter(fullPName, abiEvent.Parameters[i].Type, &cfg)
if pkg != "" {
imports[pkg] = struct{}{}
}
for varnames[name] {
name = name + "_"
}
varnames[name] = true
var (
extType binding.ExtendedType
@ -699,12 +693,12 @@ func scTemplateToRPC(cfg binding.Config, ctr ContractTmpl, imports map[string]st
)
if extType, ok = cfg.Types[fullPName]; !ok {
extType = binding.ExtendedType{
Base: abiEvent.Parameters[i].Type,
Base: abiEvent.Parameters[i].Type, // TODO: properly handle imports for this case (see utf8 example)
}
}
eTmp.Parameters = append(eTmp.Parameters, EventParamTmpl{
ParamTmpl: binding.ParamTmpl{
Name: name,
Name: pBindingName,
Type: typeStr,
},
ExtType: extType,
@ -849,6 +843,18 @@ func addIndent(str string, ind string) string {
return strings.ReplaceAll(str, "\n", "\n"+ind)
}
// ToEventBindingName converts event name specified in the contract manifest to
// a valid go exported event structure name.
func ToEventBindingName(eventName string) string {
return toPascalCase(eventName) + "Event"
}
// ToParameterBindingName converts parameter name specified in the contract
// manifest to a valid go structure's exported field name.
func ToParameterBindingName(paramName string) string {
return toPascalCase(paramName)
}
// toPascalCase removes all non-unicode characters from the provided string and
// converts it to pascal case using space as delimiter.
func toPascalCase(s string) string {