From 0214628127c2bc354860ace7c764331ead9ead0e Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Fri, 25 Nov 2022 13:04:24 +0300 Subject: [PATCH] rpcbinding: generate bindings using new extended type data --- cli/smartcontract/generate_test.go | 1 + cli/smartcontract/testdata/structs/config.yml | 3 + .../testdata/structs/rpcbindings.out | 1423 +++++++++++++++++ cli/smartcontract/testdata/structs/structs.go | 39 + docs/compiler.md | 5 +- pkg/smartcontract/binding/generate.go | 10 +- pkg/smartcontract/rpcbinding/binding.go | 244 ++- 7 files changed, 1687 insertions(+), 38 deletions(-) create mode 100644 cli/smartcontract/testdata/structs/config.yml create mode 100644 cli/smartcontract/testdata/structs/rpcbindings.out create mode 100644 cli/smartcontract/testdata/structs/structs.go diff --git a/cli/smartcontract/generate_test.go b/cli/smartcontract/generate_test.go index ed0e32157..47328dbcc 100644 --- a/cli/smartcontract/generate_test.go +++ b/cli/smartcontract/generate_test.go @@ -401,6 +401,7 @@ func TestAssistedRPCBindings(t *testing.T) { } checkBinding(filepath.Join("testdata", "types")) + checkBinding(filepath.Join("testdata", "structs")) } func TestGenerate_Errors(t *testing.T) { diff --git a/cli/smartcontract/testdata/structs/config.yml b/cli/smartcontract/testdata/structs/config.yml new file mode 100644 index 000000000..04192ba7b --- /dev/null +++ b/cli/smartcontract/testdata/structs/config.yml @@ -0,0 +1,3 @@ +name: "Types" +sourceurl: https://github.com/nspcc-dev/neo-go/ +safemethods: ["contract", "block", "transaction", "struct"] diff --git a/cli/smartcontract/testdata/structs/rpcbindings.out b/cli/smartcontract/testdata/structs/rpcbindings.out new file mode 100644 index 000000000..aa1bf2e77 --- /dev/null +++ b/cli/smartcontract/testdata/structs/rpcbindings.out @@ -0,0 +1,1423 @@ +// Package structs contains RPC wrappers for Types contract. +package structs + +import ( + "crypto/elliptic" + "errors" + "fmt" + "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/unwrap" + "github.com/nspcc-dev/neo-go/pkg/util" + "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" + "math/big" + "unicode/utf8" +) + +// 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 interface{} +} + +// LedgerWitnessRule is a contract-specific ledger.WitnessRule type used by its methods. +type LedgerWitnessRule struct { + Action *big.Int + Condition *LedgerWitnessCondition +} + +// ManagementABI is a contract-specific management.ABI type used by its methods. +type ManagementABI struct { + Methods []*ManagementMethod + Events []*ManagementEvent +} + +// ManagementContract is a contract-specific management.Contract type used by its methods. +type ManagementContract struct { + ID *big.Int + UpdateCounter *big.Int + Hash util.Uint160 + NEF []byte + Manifest *ManagementManifest +} + +// ManagementEvent is a contract-specific management.Event type used by its methods. +type ManagementEvent struct { + Name string + Params []*ManagementParameter +} + +// ManagementGroup is a contract-specific management.Group type used by its methods. +type ManagementGroup struct { + PublicKey *keys.PublicKey + Signature []byte +} + +// ManagementManifest is a contract-specific management.Manifest type used by its methods. +type ManagementManifest struct { + Name string + Groups []*ManagementGroup + Features *stackitem.Map + SupportedStandards []string + ABI *ManagementABI + Permissions []*ManagementPermission + Trusts []util.Uint160 + Extra interface{} +} + +// ManagementMethod is a contract-specific management.Method type used by its methods. +type ManagementMethod struct { + Name string + Params []*ManagementParameter + ReturnType *big.Int + Offset *big.Int + Safe bool +} + +// ManagementParameter is a contract-specific management.Parameter type used by its methods. +type ManagementParameter struct { + Name string + Type *big.Int +} + +// ManagementPermission is a contract-specific management.Permission type used by its methods. +type ManagementPermission struct { + Contract util.Uint160 + Methods []string +} + +// StructsInternal is a contract-specific structs.Internal type used by its methods. +type StructsInternal struct { + Bool bool + Int *big.Int + Bytes []byte + String string + H160 util.Uint160 + H256 util.Uint256 + PK *keys.PublicKey + PubKey *keys.PublicKey + Sign []byte + ArrOfBytes [][]byte + ArrOfH160 []util.Uint160 + Map *stackitem.Map + Struct *StructsInternal +} +// Invoker is used by ContractReader to call various safe methods. +type Invoker interface { + Call(contract util.Uint160, operation string, params ...interface{}) (*result.Invoke, error) +} + +// ContractReader implements safe contract methods. +type ContractReader struct { + invoker Invoker +} + +// NewReader creates an instance of ContractReader using Hash and the given Invoker. +func NewReader(invoker Invoker) *ContractReader { + return &ContractReader{invoker} +} + + +// Block invokes `block` method of contract. +func (c *ContractReader) Block(b *LedgerBlock) (*LedgerBlock, error) { + return itemToLedgerBlock(unwrap.Item(c.invoker.Call(Hash, "block", b))) +} + +// Contract invokes `contract` method of contract. +func (c *ContractReader) Contract(mc *ManagementContract) (*ManagementContract, error) { + return itemToManagementContract(unwrap.Item(c.invoker.Call(Hash, "contract", mc))) +} + +// Struct invokes `struct` method of contract. +func (c *ContractReader) Struct(s *StructsInternal) (*StructsInternal, error) { + return itemToStructsInternal(unwrap.Item(c.invoker.Call(Hash, "struct", s))) +} + +// Transaction invokes `transaction` method of contract. +func (c *ContractReader) Transaction(t *LedgerTransaction) (*LedgerTransaction, error) { + return itemToLedgerTransaction(unwrap.Item(c.invoker.Call(Hash, "transaction", t))) +} + +// itemToLedgerBlock converts stack item into *LedgerBlock. +func itemToLedgerBlock(item stackitem.Item, err error) (*LedgerBlock, error) { + if err != nil { + return nil, err + } + arr, ok := item.Value().([]stackitem.Item) + if !ok { + return nil, errors.New("not an array") + } + if len(arr) != 9 { + return nil, errors.New("wrong number of structure elements") + } + + var res = new(LedgerBlock) + var index = -1 + 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 nil, err + } + + index++ + res.Version, err = arr[index].TryInteger() + if err != nil { + return nil, 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 nil, 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 nil, err + } + + index++ + res.Timestamp, err = arr[index].TryInteger() + if err != nil { + return nil, err + } + + index++ + res.Nonce, err = arr[index].TryInteger() + if err != nil { + return nil, err + } + + index++ + res.Index, err = arr[index].TryInteger() + if err != nil { + return nil, 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 nil, err + } + + index++ + res.TransactionsLength, err = arr[index].TryInteger() + if err != nil { + return nil, err + } + + + return res, err +} + +// itemToLedgerBlockSR converts stack item into *LedgerBlockSR. +func itemToLedgerBlockSR(item stackitem.Item, err error) (*LedgerBlockSR, error) { + if err != nil { + return nil, err + } + arr, ok := item.Value().([]stackitem.Item) + if !ok { + return nil, errors.New("not an array") + } + if len(arr) != 10 { + return nil, errors.New("wrong number of structure elements") + } + + var res = new(LedgerBlockSR) + var index = -1 + 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 nil, err + } + + index++ + res.Version, err = arr[index].TryInteger() + if err != nil { + return nil, 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 nil, 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 nil, err + } + + index++ + res.Timestamp, err = arr[index].TryInteger() + if err != nil { + return nil, err + } + + index++ + res.Nonce, err = arr[index].TryInteger() + if err != nil { + return nil, err + } + + index++ + res.Index, err = arr[index].TryInteger() + if err != nil { + return nil, 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 nil, err + } + + index++ + res.TransactionsLength, err = arr[index].TryInteger() + if err != nil { + return nil, 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 nil, err + } + + + return res, err +} + +// itemToLedgerTransaction converts stack item into *LedgerTransaction. +func itemToLedgerTransaction(item stackitem.Item, err error) (*LedgerTransaction, error) { + if err != nil { + return nil, err + } + arr, ok := item.Value().([]stackitem.Item) + if !ok { + return nil, errors.New("not an array") + } + if len(arr) != 8 { + return nil, errors.New("wrong number of structure elements") + } + + var res = new(LedgerTransaction) + var index = -1 + 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 nil, err + } + + index++ + res.Version, err = arr[index].TryInteger() + if err != nil { + return nil, err + } + + index++ + res.Nonce, err = arr[index].TryInteger() + if err != nil { + return nil, 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 nil, err + } + + index++ + res.SysFee, err = arr[index].TryInteger() + if err != nil { + return nil, err + } + + index++ + res.NetFee, err = arr[index].TryInteger() + if err != nil { + return nil, err + } + + index++ + res.ValidUntilBlock, err = arr[index].TryInteger() + if err != nil { + return nil, err + } + + index++ + res.Script, err = arr[index].TryBytes() + if err != nil { + return nil, err + } + + + return res, err +} + +// itemToLedgerTransactionSigner converts stack item into *LedgerTransactionSigner. +func itemToLedgerTransactionSigner(item stackitem.Item, err error) (*LedgerTransactionSigner, error) { + if err != nil { + return nil, err + } + arr, ok := item.Value().([]stackitem.Item) + if !ok { + return nil, errors.New("not an array") + } + if len(arr) != 5 { + return nil, errors.New("wrong number of structure elements") + } + + var res = new(LedgerTransactionSigner) + var index = -1 + 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 nil, err + } + + index++ + res.Scopes, err = arr[index].TryInteger() + if err != nil { + return nil, 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, err + } + } + return res, nil + } (arr[index]) + if err != nil { + return nil, 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, err + } + } + return res, nil + } (arr[index]) + if err != nil { + return nil, 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, err + } + } + return res, nil + } (arr[index]) + if err != nil { + return nil, err + } + + + return res, err +} + +// itemToLedgerWitnessCondition converts stack item into *LedgerWitnessCondition. +func itemToLedgerWitnessCondition(item stackitem.Item, err error) (*LedgerWitnessCondition, error) { + if err != nil { + return nil, err + } + arr, ok := item.Value().([]stackitem.Item) + if !ok { + return nil, errors.New("not an array") + } + if len(arr) != 2 { + return nil, errors.New("wrong number of structure elements") + } + + var res = new(LedgerWitnessCondition) + var index = -1 + index++ + res.Type, err = arr[index].TryInteger() + if err != nil { + return nil, err + } + + index++ + res.Value, err = arr[index].Value(), nil + if err != nil { + return nil, err + } + + + return res, err +} + +// itemToLedgerWitnessRule converts stack item into *LedgerWitnessRule. +func itemToLedgerWitnessRule(item stackitem.Item, err error) (*LedgerWitnessRule, error) { + if err != nil { + return nil, err + } + arr, ok := item.Value().([]stackitem.Item) + if !ok { + return nil, errors.New("not an array") + } + if len(arr) != 2 { + return nil, errors.New("wrong number of structure elements") + } + + var res = new(LedgerWitnessRule) + var index = -1 + index++ + res.Action, err = arr[index].TryInteger() + if err != nil { + return nil, err + } + + index++ + res.Condition, err = itemToLedgerWitnessCondition(arr[index], nil) + if err != nil { + return nil, err + } + + + return res, err +} + +// itemToManagementABI converts stack item into *ManagementABI. +func itemToManagementABI(item stackitem.Item, err error) (*ManagementABI, error) { + if err != nil { + return nil, err + } + arr, ok := item.Value().([]stackitem.Item) + if !ok { + return nil, errors.New("not an array") + } + if len(arr) != 2 { + return nil, errors.New("wrong number of structure elements") + } + + var res = new(ManagementABI) + var index = -1 + index++ + res.Methods, err = func (item stackitem.Item) ([]*ManagementMethod, error) { + arr, ok := item.Value().([]stackitem.Item) + if !ok { + return nil, errors.New("not an array") + } + res := make([]*ManagementMethod, len(arr)) + for i := range res { + res[i], err = itemToManagementMethod(arr[i], nil) + if err != nil { + return nil, err + } + } + return res, nil + } (arr[index]) + if err != nil { + return nil, err + } + + index++ + res.Events, err = func (item stackitem.Item) ([]*ManagementEvent, error) { + arr, ok := item.Value().([]stackitem.Item) + if !ok { + return nil, errors.New("not an array") + } + res := make([]*ManagementEvent, len(arr)) + for i := range res { + res[i], err = itemToManagementEvent(arr[i], nil) + if err != nil { + return nil, err + } + } + return res, nil + } (arr[index]) + if err != nil { + return nil, err + } + + + return res, err +} + +// itemToManagementContract converts stack item into *ManagementContract. +func itemToManagementContract(item stackitem.Item, err error) (*ManagementContract, error) { + if err != nil { + return nil, err + } + arr, ok := item.Value().([]stackitem.Item) + if !ok { + return nil, errors.New("not an array") + } + if len(arr) != 5 { + return nil, errors.New("wrong number of structure elements") + } + + var res = new(ManagementContract) + var index = -1 + index++ + res.ID, err = arr[index].TryInteger() + if err != nil { + return nil, err + } + + index++ + res.UpdateCounter, err = arr[index].TryInteger() + if err != nil { + return nil, err + } + + index++ + res.Hash, 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 nil, err + } + + index++ + res.NEF, err = arr[index].TryBytes() + if err != nil { + return nil, err + } + + index++ + res.Manifest, err = itemToManagementManifest(arr[index], nil) + if err != nil { + return nil, err + } + + + return res, err +} + +// itemToManagementEvent converts stack item into *ManagementEvent. +func itemToManagementEvent(item stackitem.Item, err error) (*ManagementEvent, error) { + if err != nil { + return nil, err + } + arr, ok := item.Value().([]stackitem.Item) + if !ok { + return nil, errors.New("not an array") + } + if len(arr) != 2 { + return nil, errors.New("wrong number of structure elements") + } + + var res = new(ManagementEvent) + var index = -1 + index++ + res.Name, 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 nil, err + } + + index++ + res.Params, err = func (item stackitem.Item) ([]*ManagementParameter, error) { + arr, ok := item.Value().([]stackitem.Item) + if !ok { + return nil, errors.New("not an array") + } + res := make([]*ManagementParameter, len(arr)) + for i := range res { + res[i], err = itemToManagementParameter(arr[i], nil) + if err != nil { + return nil, err + } + } + return res, nil + } (arr[index]) + if err != nil { + return nil, err + } + + + return res, err +} + +// itemToManagementGroup converts stack item into *ManagementGroup. +func itemToManagementGroup(item stackitem.Item, err error) (*ManagementGroup, error) { + if err != nil { + return nil, err + } + arr, ok := item.Value().([]stackitem.Item) + if !ok { + return nil, errors.New("not an array") + } + if len(arr) != 2 { + return nil, errors.New("wrong number of structure elements") + } + + var res = new(ManagementGroup) + var index = -1 + index++ + res.PublicKey, 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[index]) + if err != nil { + return nil, err + } + + index++ + res.Signature, err = arr[index].TryBytes() + if err != nil { + return nil, err + } + + + return res, err +} + +// itemToManagementManifest converts stack item into *ManagementManifest. +func itemToManagementManifest(item stackitem.Item, err error) (*ManagementManifest, error) { + if err != nil { + return nil, err + } + arr, ok := item.Value().([]stackitem.Item) + if !ok { + return nil, errors.New("not an array") + } + if len(arr) != 8 { + return nil, errors.New("wrong number of structure elements") + } + + var res = new(ManagementManifest) + var index = -1 + index++ + res.Name, 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 nil, err + } + + index++ + res.Groups, err = func (item stackitem.Item) ([]*ManagementGroup, error) { + arr, ok := item.Value().([]stackitem.Item) + if !ok { + return nil, errors.New("not an array") + } + res := make([]*ManagementGroup, len(arr)) + for i := range res { + res[i], err = itemToManagementGroup(arr[i], nil) + if err != nil { + return nil, err + } + } + return res, nil + } (arr[index]) + if err != nil { + return nil, err + } + + index++ + res.Features, err = func (item stackitem.Item) (*stackitem.Map, error) { + if t := item.Type(); t != stackitem.MapT { + return nil, fmt.Errorf("%s is not a map", t.String()) + } + return item.(*stackitem.Map), nil + } (arr[index]) + if err != nil { + return nil, err + } + + index++ + res.SupportedStandards, err = func (item stackitem.Item) ([]string, error) { + arr, ok := item.Value().([]stackitem.Item) + if !ok { + return nil, errors.New("not an array") + } + res := make([]string, len(arr)) + for i := range res { + res[i], 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[i]) + if err != nil { + return nil, err + } + } + return res, nil + } (arr[index]) + if err != nil { + return nil, err + } + + index++ + res.ABI, err = itemToManagementABI(arr[index], nil) + if err != nil { + return nil, err + } + + index++ + res.Permissions, err = func (item stackitem.Item) ([]*ManagementPermission, error) { + arr, ok := item.Value().([]stackitem.Item) + if !ok { + return nil, errors.New("not an array") + } + res := make([]*ManagementPermission, len(arr)) + for i := range res { + res[i], err = itemToManagementPermission(arr[i], nil) + if err != nil { + return nil, err + } + } + return res, nil + } (arr[index]) + if err != nil { + return nil, err + } + + index++ + res.Trusts, 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, err + } + } + return res, nil + } (arr[index]) + if err != nil { + return nil, err + } + + index++ + res.Extra, err = arr[index].Value(), nil + if err != nil { + return nil, err + } + + + return res, err +} + +// itemToManagementMethod converts stack item into *ManagementMethod. +func itemToManagementMethod(item stackitem.Item, err error) (*ManagementMethod, error) { + if err != nil { + return nil, err + } + arr, ok := item.Value().([]stackitem.Item) + if !ok { + return nil, errors.New("not an array") + } + if len(arr) != 5 { + return nil, errors.New("wrong number of structure elements") + } + + var res = new(ManagementMethod) + var index = -1 + index++ + res.Name, 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 nil, err + } + + index++ + res.Params, err = func (item stackitem.Item) ([]*ManagementParameter, error) { + arr, ok := item.Value().([]stackitem.Item) + if !ok { + return nil, errors.New("not an array") + } + res := make([]*ManagementParameter, len(arr)) + for i := range res { + res[i], err = itemToManagementParameter(arr[i], nil) + if err != nil { + return nil, err + } + } + return res, nil + } (arr[index]) + if err != nil { + return nil, err + } + + index++ + res.ReturnType, err = arr[index].TryInteger() + if err != nil { + return nil, err + } + + index++ + res.Offset, err = arr[index].TryInteger() + if err != nil { + return nil, err + } + + index++ + res.Safe, err = arr[index].TryBool() + if err != nil { + return nil, err + } + + + return res, err +} + +// itemToManagementParameter converts stack item into *ManagementParameter. +func itemToManagementParameter(item stackitem.Item, err error) (*ManagementParameter, error) { + if err != nil { + return nil, err + } + arr, ok := item.Value().([]stackitem.Item) + if !ok { + return nil, errors.New("not an array") + } + if len(arr) != 2 { + return nil, errors.New("wrong number of structure elements") + } + + var res = new(ManagementParameter) + var index = -1 + index++ + res.Name, 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 nil, err + } + + index++ + res.Type, err = arr[index].TryInteger() + if err != nil { + return nil, err + } + + + return res, err +} + +// itemToManagementPermission converts stack item into *ManagementPermission. +func itemToManagementPermission(item stackitem.Item, err error) (*ManagementPermission, error) { + if err != nil { + return nil, err + } + arr, ok := item.Value().([]stackitem.Item) + if !ok { + return nil, errors.New("not an array") + } + if len(arr) != 2 { + return nil, errors.New("wrong number of structure elements") + } + + var res = new(ManagementPermission) + var index = -1 + index++ + res.Contract, 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 nil, err + } + + index++ + res.Methods, err = func (item stackitem.Item) ([]string, error) { + arr, ok := item.Value().([]stackitem.Item) + if !ok { + return nil, errors.New("not an array") + } + res := make([]string, len(arr)) + for i := range res { + res[i], 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[i]) + if err != nil { + return nil, err + } + } + return res, nil + } (arr[index]) + if err != nil { + return nil, err + } + + + return res, err +} + +// itemToStructsInternal converts stack item into *StructsInternal. +func itemToStructsInternal(item stackitem.Item, err error) (*StructsInternal, error) { + if err != nil { + return nil, err + } + arr, ok := item.Value().([]stackitem.Item) + if !ok { + return nil, errors.New("not an array") + } + if len(arr) != 13 { + return nil, errors.New("wrong number of structure elements") + } + + var res = new(StructsInternal) + var index = -1 + index++ + res.Bool, err = arr[index].TryBool() + if err != nil { + return nil, err + } + + index++ + res.Int, err = arr[index].TryInteger() + if err != nil { + return nil, err + } + + index++ + res.Bytes, err = arr[index].TryBytes() + if err != nil { + return nil, err + } + + index++ + res.String, 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 nil, err + } + + index++ + res.H160, 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 nil, err + } + + index++ + res.H256, 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 nil, err + } + + index++ + res.PK, 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[index]) + if err != nil { + return nil, err + } + + index++ + res.PubKey, 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[index]) + if err != nil { + return nil, err + } + + index++ + res.Sign, err = arr[index].TryBytes() + if err != nil { + return nil, err + } + + index++ + res.ArrOfBytes, err = func (item stackitem.Item) ([][]byte, error) { + arr, ok := item.Value().([]stackitem.Item) + if !ok { + return nil, errors.New("not an array") + } + res := make([][]byte, len(arr)) + for i := range res { + res[i], err = arr[i].TryBytes() + if err != nil { + return nil, err + } + } + return res, nil + } (arr[index]) + if err != nil { + return nil, err + } + + index++ + res.ArrOfH160, 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, err + } + } + return res, nil + } (arr[index]) + if err != nil { + return nil, err + } + + index++ + res.Map, err = func (item stackitem.Item) (*stackitem.Map, error) { + if t := item.Type(); t != stackitem.MapT { + return nil, fmt.Errorf("%s is not a map", t.String()) + } + return item.(*stackitem.Map), nil + } (arr[index]) + if err != nil { + return nil, err + } + + index++ + res.Struct, err = itemToStructsInternal(arr[index], nil) + if err != nil { + return nil, err + } + + + return res, err +} diff --git a/cli/smartcontract/testdata/structs/structs.go b/cli/smartcontract/testdata/structs/structs.go new file mode 100644 index 000000000..5a54fb224 --- /dev/null +++ b/cli/smartcontract/testdata/structs/structs.go @@ -0,0 +1,39 @@ +package structs + +import ( + "github.com/nspcc-dev/neo-go/pkg/interop" + "github.com/nspcc-dev/neo-go/pkg/interop/native/ledger" + "github.com/nspcc-dev/neo-go/pkg/interop/native/management" +) + +type Internal struct { + Bool bool + Int int + Bytes []byte + String string + H160 interop.Hash160 + H256 interop.Hash256 + PK interop.PublicKey + PubKey interop.PublicKey + Sign interop.Signature + ArrOfBytes [][]byte + ArrOfH160 []interop.Hash160 + Map map[int][]interop.PublicKey + Struct *Internal +} + +func Contract(mc management.Contract) management.Contract { + return mc +} + +func Block(b *ledger.Block) *ledger.Block { + return b +} + +func Transaction(t *ledger.Transaction) *ledger.Transaction { + return t +} + +func Struct(s *Internal) *Internal { + return s +} diff --git a/docs/compiler.md b/docs/compiler.md index 3d7edd638..7675ba4a6 100644 --- a/docs/compiler.md +++ b/docs/compiler.md @@ -459,8 +459,9 @@ result. This pair can then be used in Invoker `TraverseIterator` method to retrieve actual resulting items. Go contracts can also make use of additional type data from bindings -configuration file generated during compilation. At the moment it allows to -generate proper wrappers for simple array types, but doesn't cover structures: +configuration file generated during compilation. This can cover arrays, maps +and structures. Notice that structured types returned by methods can't be Null +at the moment (see #2795). ``` $ ./bin/neo-go contract compile -i contract.go --config contract.yml -o contract.nef --manifest manifest.json --bindings contract.bindings.yml diff --git a/pkg/smartcontract/binding/generate.go b/pkg/smartcontract/binding/generate.go index 48ba4b4ec..62733b7ac 100644 --- a/pkg/smartcontract/binding/generate.go +++ b/pkg/smartcontract/binding/generate.go @@ -119,8 +119,8 @@ func Generate(cfg Config) error { return srcTemplate.Execute(cfg.Output, ctr) } -func scTypeToGo(name string, typ smartcontract.ParamType, overrides map[string]Override) (string, string) { - if over, ok := overrides[name]; ok { +func scTypeToGo(name string, typ smartcontract.ParamType, cfg *Config) (string, string) { + if over, ok := cfg.Overrides[name]; ok { return over.TypeName, over.Package } @@ -159,7 +159,7 @@ func scTypeToGo(name string, typ smartcontract.ParamType, overrides map[string]O // TemplateFromManifest create a contract template using the given configuration // and type conversion function. It assumes manifest to be present in the // configuration and assumes it to be correct (passing IsValid check). -func TemplateFromManifest(cfg Config, scTypeConverter func(string, smartcontract.ParamType, map[string]Override) (string, string)) ContractTmpl { +func TemplateFromManifest(cfg Config, scTypeConverter func(string, smartcontract.ParamType, *Config) (string, string)) ContractTmpl { hStr := "" for _, b := range cfg.Hash.BytesBE() { hStr += fmt.Sprintf("\\x%02x", b) @@ -221,7 +221,7 @@ func TemplateFromManifest(cfg Config, scTypeConverter func(string, smartcontract var varnames = make(map[string]bool) for i := range m.Parameters { name := m.Parameters[i].Name - typeStr, pkg := scTypeConverter(m.Name+"."+name, m.Parameters[i].Type, cfg.Overrides) + typeStr, pkg := scTypeConverter(m.Name+"."+name, m.Parameters[i].Type, &cfg) if pkg != "" { imports[pkg] = struct{}{} } @@ -238,7 +238,7 @@ func TemplateFromManifest(cfg Config, scTypeConverter func(string, smartcontract }) } - typeStr, pkg := scTypeConverter(m.Name, m.ReturnType, cfg.Overrides) + typeStr, pkg := scTypeConverter(m.Name, m.ReturnType, &cfg) if pkg != "" { imports[pkg] = struct{}{} } diff --git a/pkg/smartcontract/rpcbinding/binding.go b/pkg/smartcontract/rpcbinding/binding.go index 6c330cab3..1bfda8417 100644 --- a/pkg/smartcontract/rpcbinding/binding.go +++ b/pkg/smartcontract/rpcbinding/binding.go @@ -3,6 +3,7 @@ package rpcbinding import ( "fmt" "sort" + "strings" "text/template" "github.com/nspcc-dev/neo-go/pkg/smartcontract" @@ -18,8 +19,12 @@ func (c *ContractReader) {{.Name}}({{range $index, $arg := .Arguments -}} {{- if ne $index 0}}, {{end}} {{- .Name}} {{.Type}} {{- end}}) {{if .ReturnType }}({{ .ReturnType }}, error) { - return unwrap.{{.CallFlag}}(c.invoker.Call(Hash, "{{ .NameABI }}"{{/* CallFlag field is used for function name */}} - {{- range $arg := .Arguments -}}, {{.Name}}{{end}})) + return {{if .CallFlag -}} + unwrap.{{.CallFlag}}(c.invoker.Call(Hash, "{{ .NameABI }}"{{/* CallFlag field is used for function name */}} + {{- else -}} + itemTo{{ cutPointer .ReturnType }}(unwrap.Item(c.invoker.Call(Hash, "{{ .NameABI }}"{{/* CallFlag field is used for function name */}} + {{- end -}} + {{- range $arg := .Arguments -}}, {{.Name}}{{end}})){{if not .CallFlag}}){{end}} {{- else -}} (*result.Invoke, error) { c.invoker.Call(Hash, "{{ .NameABI }}" {{- range $arg := .Arguments -}}, {{.Name}}{{end}}) @@ -101,6 +106,14 @@ import ( // Hash contains contract hash. var Hash = {{ .Hash }} +{{range $name, $typ := .NamedTypes}} +// {{toTypeName $name}} is a contract-specific {{$name}} type used by its methods. +type {{toTypeName $name}} struct { +{{- range $m := $typ.Fields}} + {{.Field}} {{etTypeToStr .ExtendedType}} +{{- end}} +} +{{end -}} {{if .HasReader}}// Invoker is used by ContractReader to call various safe methods. type Invoker interface { {{if or .IsNep11D .IsNep11ND}} nep11.Invoker @@ -199,15 +212,41 @@ func New(actor Actor) *Contract { {{end}} {{- range $m := .Methods}} {{template "METHOD" $m }} -{{end}}` +{{end}} +{{- range $name, $typ := .NamedTypes}} +// itemTo{{toTypeName $name}} converts stack item into *{{toTypeName $name}}. +func itemTo{{toTypeName $name}}(item stackitem.Item, err error) (*{{toTypeName $name}}, error) { + if err != nil { + return nil, err + } + arr, ok := item.Value().([]stackitem.Item) + if !ok { + return nil, errors.New("not an array") + } + if len(arr) != {{len $typ.Fields}} { + return nil, errors.New("wrong number of structure elements") + } -var srcTemplate = template.Must(template.New("generate").Parse(srcTmpl)) + var res = new({{toTypeName $name}}) +{{if len .Fields}} var index = -1 +{{- range $m := $typ.Fields}} + index++ + res.{{.Field}}, err = {{etTypeConverter .ExtendedType "arr[index]"}} + if err != nil { + return nil, err + } +{{end}} +{{end}} + return res, err +} +{{end}}` type ( ContractTmpl struct { binding.ContractTmpl SafeMethods []binding.MethodTmpl + NamedTypes map[string]binding.ExtendedType IsNep11D bool IsNep11ND bool @@ -268,6 +307,17 @@ func Generate(cfg binding.Config) error { ctr.ContractTmpl = binding.TemplateFromManifest(cfg, scTypeToGo) ctr = scTemplateToRPC(cfg, ctr, imports) + ctr.NamedTypes = cfg.NamedTypes + + var srcTemplate = template.Must(template.New("generate").Funcs(template.FuncMap{ + "etTypeConverter": etTypeConverter, + "etTypeToStr": func(et binding.ExtendedType) string { + r, _ := extendedTypeToGo(et, ctr.NamedTypes) + return r + }, + "toTypeName": toTypeName, + "cutPointer": cutPointer, + }).Parse(srcTmpl)) return srcTemplate.Execute(cfg.Output, ctr) } @@ -295,31 +345,8 @@ func dropStdMethods(meths []manifest.Method, std *standard.Standard) []manifest. return meths } -func scTypeToGo(name string, typ smartcontract.ParamType, overrides map[string]binding.Override) (string, string) { - over, ok := overrides[name] - if ok { - switch over.TypeName { - case "[]bool": - return "[]bool", "" - case "[]int", "[]uint", "[]int8", "[]uint8", "[]int16", - "[]uint16", "[]int32", "[]uint32", "[]int64", "[]uint64": - return "[]*big.Int", "math/big" - case "[][]byte": - return "[][]byte", "" - case "[]string": - return "[]string", "" - case "[]interop.Hash160": - return "[]util.Uint160", "github.com/nspcc-dev/neo-go/pkg/util" - case "[]interop.Hash256": - return "[]util.Uint256", "github.com/nspcc-dev/neo-go/pkg/util" - case "[]interop.PublicKey": - return "keys.PublicKeys", "github.com/nspcc-dev/neo-go/pkg/crypto/keys" - case "[]interop.Signature": - return "[][]byte", "" - } - } - - switch typ { +func extendedTypeToGo(et binding.ExtendedType, named map[string]binding.ExtendedType) (string, string) { + switch et.Base { case smartcontract.AnyType: return "interface{}", "" case smartcontract.BoolType: @@ -339,16 +366,132 @@ func scTypeToGo(name string, typ smartcontract.ParamType, overrides map[string]b case smartcontract.SignatureType: return "[]byte", "" case smartcontract.ArrayType: + if len(et.Name) > 0 { + return "*" + toTypeName(et.Name), "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" + } else if et.Value != nil { + if et.Value.Base == smartcontract.PublicKeyType { // Special array wrapper. + return "keys.PublicKeys", "github.com/nspcc-dev/neo-go/pkg/crypto/keys" + } + sub, pkg := extendedTypeToGo(*et.Value, named) + return "[]" + sub, pkg + } return "[]interface{}", "" + case smartcontract.MapType: return "*stackitem.Map", "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" case smartcontract.InteropInterfaceType: return "interface{}", "" case smartcontract.VoidType: return "", "" - default: - panic("unreachable") } + panic("unreachable") +} + +func etTypeConverter(et binding.ExtendedType, v string) string { + switch et.Base { + case smartcontract.AnyType: + return v + ".Value(), nil" + case smartcontract.BoolType: + return v + ".TryBool()" + case smartcontract.IntegerType: + return v + ".TryInteger()" + case smartcontract.ByteArrayType, smartcontract.SignatureType: + return v + ".TryBytes()" + case smartcontract.StringType: + return `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 + } (` + v + `)` + case smartcontract.Hash160Type: + return `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 + } (` + v + `)` + case smartcontract.Hash256Type: + return `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 + } (` + v + `)` + case smartcontract.PublicKeyType: + return `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 + } (` + v + `)` + case smartcontract.ArrayType: + if len(et.Name) > 0 { + return "itemTo" + toTypeName(et.Name) + "(" + v + ", nil)" + } else if et.Value != nil { + at, _ := extendedTypeToGo(et, nil) + return `func (item stackitem.Item) (` + at + `, error) { + arr, ok := item.Value().([]stackitem.Item) + if !ok { + return nil, errors.New("not an array") + } + res := make(` + at + `, len(arr)) + for i := range res { + res[i], err = ` + etTypeConverter(*et.Value, "arr[i]") + ` + if err != nil { + return nil, err + } + } + return res, nil + } (` + v + `)` + } + return etTypeConverter(binding.ExtendedType{ + Base: smartcontract.ArrayType, + Value: &binding.ExtendedType{ + Base: smartcontract.AnyType, + }, + }, v) + + case smartcontract.MapType: + return `func (item stackitem.Item) (*stackitem.Map, error) { + if t := item.Type(); t != stackitem.MapT { + return nil, fmt.Errorf("%s is not a map", t.String()) + } + return item.(*stackitem.Map), nil + } (` + v + `)` + case smartcontract.InteropInterfaceType: + return "item.Value(), nil" + case smartcontract.VoidType: + return "" + } + panic("unreachable") +} + +func scTypeToGo(name string, typ smartcontract.ParamType, cfg *binding.Config) (string, string) { + et, ok := cfg.Types[name] + if !ok { + et = binding.ExtendedType{Base: typ} + } + return extendedTypeToGo(et, cfg.NamedTypes) } func scTemplateToRPC(cfg binding.Config, ctr ContractTmpl, imports map[string]struct{}) ContractTmpl { @@ -369,6 +512,27 @@ func scTemplateToRPC(cfg binding.Config, ctr ContractTmpl, imports map[string]st } } } + for _, et := range cfg.NamedTypes { + for _, fet := range et.Fields { + _, pkg := extendedTypeToGo(fet.ExtendedType, ctr.NamedTypes) + if pkg != "" { + imports[pkg] = struct{}{} + } + // Additional packages used during decoding. + switch fet.Base { + case smartcontract.StringType: + imports["unicode/utf8"] = struct{}{} + case smartcontract.PublicKeyType: + imports["crypto/elliptic"] = struct{}{} + case smartcontract.MapType: + imports["fmt"] = struct{}{} + } + } + } + if len(cfg.NamedTypes) > 0 { + imports["errors"] = struct{}{} + } + // We're misusing CallFlag field for function name here. for i := range ctr.SafeMethods { switch ctr.SafeMethods[i].ReturnType { @@ -420,6 +584,8 @@ func scTemplateToRPC(cfg binding.Config, ctr ContractTmpl, imports map[string]st ctr.SafeMethods[i].CallFlag = "ArrayOfUint256" case "keys.PublicKeys": ctr.SafeMethods[i].CallFlag = "ArrayOfPublicKeys" + default: + ctr.SafeMethods[i].CallFlag = "" } } @@ -446,3 +612,19 @@ func scTemplateToRPC(cfg binding.Config, ctr ContractTmpl, imports map[string]st sort.Strings(ctr.Imports) return ctr } + +func cutPointer(s string) string { + if s[0] == '*' { + return s[1:] + } + return s +} + +func toTypeName(s string) string { + return strings.Map(func(c rune) rune { + if c == '.' { + return -1 + } + return c + }, strings.ToUpper(s[0:1])+s[1:]) +}