mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-11-29 03:41:45 +00:00
rpcbinding: export any unexported fields of structures/events
Perform private -> public transformation at the last step of RPC binding generation so that it works not only with NeoGo contracts, but with any other contracts. Close #3083. Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
This commit is contained in:
parent
11c0f13d06
commit
1356721862
11 changed files with 358 additions and 24 deletions
|
@ -17,3 +17,7 @@ events:
|
|||
parameters:
|
||||
- name: a
|
||||
type: Array
|
||||
- name: "SomeUnexportedField"
|
||||
parameters:
|
||||
- name: s
|
||||
type: Struct
|
|
@ -36,6 +36,13 @@ events:
|
|||
base: Array
|
||||
value:
|
||||
base: Integer
|
||||
- name: "SomeUnexportedField"
|
||||
parameters:
|
||||
- name: s
|
||||
type: Struct
|
||||
extendedtype:
|
||||
base: Struct
|
||||
name: simpleStruct
|
||||
namedtypes:
|
||||
crazyStruct:
|
||||
base: Struct
|
||||
|
@ -45,3 +52,9 @@ namedtypes:
|
|||
base: Integer
|
||||
- field: B
|
||||
base: Boolean
|
||||
simpleStruct:
|
||||
base: Struct
|
||||
name: simpleStruct
|
||||
fields:
|
||||
- field: i
|
||||
base: Integer
|
|
@ -17,3 +17,7 @@ events:
|
|||
parameters:
|
||||
- name: a
|
||||
type: Array
|
||||
- name: "SomeUnexportedField"
|
||||
parameters:
|
||||
- name: s
|
||||
type: Struct
|
|
@ -23,3 +23,11 @@ func Struct() {
|
|||
func Array() {
|
||||
runtime.Notify("SomeArray", [][]int{})
|
||||
}
|
||||
|
||||
// UnexportedField emits notification with unexported field that must be converted
|
||||
// to exported in the resulting RPC binding.
|
||||
func UnexportedField() {
|
||||
runtime.Notify("SomeUnexportedField", struct {
|
||||
i int
|
||||
}{i: 123})
|
||||
}
|
||||
|
|
|
@ -97,6 +97,11 @@ type SomeArrayEvent struct {
|
|||
A []any
|
||||
}
|
||||
|
||||
// SomeUnexportedFieldEvent represents "SomeUnexportedField" event emitted by the contract.
|
||||
type SomeUnexportedFieldEvent struct {
|
||||
S []any
|
||||
}
|
||||
|
||||
// Actor is used by Contract to call state-changing methods.
|
||||
type Actor interface {
|
||||
MakeCall(contract util.Uint160, method string, params ...any) (*transaction.Transaction, error)
|
||||
|
@ -207,6 +212,28 @@ func (c *Contract) StructUnsigned() (*transaction.Transaction, error) {
|
|||
return c.actor.MakeUnsignedCall(c.hash, "struct", nil)
|
||||
}
|
||||
|
||||
// UnexportedField creates a transaction invoking `unexportedField` 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) UnexportedField() (util.Uint256, uint32, error) {
|
||||
return c.actor.SendCall(c.hash, "unexportedField")
|
||||
}
|
||||
|
||||
// UnexportedFieldTransaction creates a transaction invoking `unexportedField` method of the contract.
|
||||
// This transaction is signed, but not sent to the network, instead it's
|
||||
// returned to the caller.
|
||||
func (c *Contract) UnexportedFieldTransaction() (*transaction.Transaction, error) {
|
||||
return c.actor.MakeCall(c.hash, "unexportedField")
|
||||
}
|
||||
|
||||
// UnexportedFieldUnsigned creates a transaction invoking `unexportedField` 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) UnexportedFieldUnsigned() (*transaction.Transaction, error) {
|
||||
return c.actor.MakeUnsignedCall(c.hash, "unexportedField", nil)
|
||||
}
|
||||
|
||||
// itemToLedgerBlock converts stack item into *LedgerBlock.
|
||||
func itemToLedgerBlock(item stackitem.Item, err error) (*LedgerBlock, error) {
|
||||
if err != nil {
|
||||
|
@ -1030,3 +1057,68 @@ func (e *SomeArrayEvent) FromStackItem(item *stackitem.Array) error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SomeUnexportedFieldEventsFromApplicationLog retrieves a set of all emitted events
|
||||
// with "SomeUnexportedField" name from the provided [result.ApplicationLog].
|
||||
func SomeUnexportedFieldEventsFromApplicationLog(log *result.ApplicationLog) ([]*SomeUnexportedFieldEvent, error) {
|
||||
if log == nil {
|
||||
return nil, errors.New("nil application log")
|
||||
}
|
||||
|
||||
var res []*SomeUnexportedFieldEvent
|
||||
for i, ex := range log.Executions {
|
||||
for j, e := range ex.Events {
|
||||
if e.Name != "SomeUnexportedField" {
|
||||
continue
|
||||
}
|
||||
event := new(SomeUnexportedFieldEvent)
|
||||
err := event.FromStackItem(e.Item)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to deserialize SomeUnexportedFieldEvent from stackitem (execution #%d, event #%d): %w", i, j, err)
|
||||
}
|
||||
res = append(res, event)
|
||||
}
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// FromStackItem converts provided [stackitem.Array] to SomeUnexportedFieldEvent or
|
||||
// returns an error if it's not possible to do to so.
|
||||
func (e *SomeUnexportedFieldEvent) 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.S, err = func (item stackitem.Item) ([]any, error) {
|
||||
arr, ok := item.Value().([]stackitem.Item)
|
||||
if !ok {
|
||||
return nil, errors.New("not an array")
|
||||
}
|
||||
res := make([]any, len(arr))
|
||||
for i := range res {
|
||||
res[i], err = arr[i].Value(), error(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 S: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -83,6 +83,11 @@ type LedgerWitnessRule struct {
|
|||
Condition *LedgerWitnessCondition
|
||||
}
|
||||
|
||||
// SimpleStruct is a contract-specific simpleStruct type used by its methods.
|
||||
type SimpleStruct struct {
|
||||
I *big.Int
|
||||
}
|
||||
|
||||
// ComplicatedNameEvent represents "! complicated name %$#" event emitted by the contract.
|
||||
type ComplicatedNameEvent struct {
|
||||
ComplicatedParam string
|
||||
|
@ -103,6 +108,11 @@ type SomeArrayEvent struct {
|
|||
A [][]*big.Int
|
||||
}
|
||||
|
||||
// SomeUnexportedFieldEvent represents "SomeUnexportedField" event emitted by the contract.
|
||||
type SomeUnexportedFieldEvent struct {
|
||||
S *SimpleStruct
|
||||
}
|
||||
|
||||
// Actor is used by Contract to call state-changing methods.
|
||||
type Actor interface {
|
||||
MakeCall(contract util.Uint160, method string, params ...any) (*transaction.Transaction, error)
|
||||
|
@ -213,6 +223,28 @@ func (c *Contract) StructUnsigned() (*transaction.Transaction, error) {
|
|||
return c.actor.MakeUnsignedCall(c.hash, "struct", nil)
|
||||
}
|
||||
|
||||
// UnexportedField creates a transaction invoking `unexportedField` 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) UnexportedField() (util.Uint256, uint32, error) {
|
||||
return c.actor.SendCall(c.hash, "unexportedField")
|
||||
}
|
||||
|
||||
// UnexportedFieldTransaction creates a transaction invoking `unexportedField` method of the contract.
|
||||
// This transaction is signed, but not sent to the network, instead it's
|
||||
// returned to the caller.
|
||||
func (c *Contract) UnexportedFieldTransaction() (*transaction.Transaction, error) {
|
||||
return c.actor.MakeCall(c.hash, "unexportedField")
|
||||
}
|
||||
|
||||
// UnexportedFieldUnsigned creates a transaction invoking `unexportedField` 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) UnexportedFieldUnsigned() (*transaction.Transaction, error) {
|
||||
return c.actor.MakeUnsignedCall(c.hash, "unexportedField", nil)
|
||||
}
|
||||
|
||||
// itemToCrazyStruct converts stack item into *CrazyStruct.
|
||||
func itemToCrazyStruct(item stackitem.Item, err error) (*CrazyStruct, error) {
|
||||
if err != nil {
|
||||
|
@ -816,6 +848,40 @@ func (res *LedgerWitnessRule) FromStackItem(item stackitem.Item) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// itemToSimpleStruct converts stack item into *SimpleStruct.
|
||||
func itemToSimpleStruct(item stackitem.Item, err error) (*SimpleStruct, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var res = new(SimpleStruct)
|
||||
err = res.FromStackItem(item)
|
||||
return res, err
|
||||
}
|
||||
|
||||
// FromStackItem retrieves fields of SimpleStruct from the given
|
||||
// [stackitem.Item] or returns an error if it's not possible to do to so.
|
||||
func (res *SimpleStruct) FromStackItem(item stackitem.Item) error {
|
||||
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++
|
||||
res.I, err = arr[index].TryInteger()
|
||||
if err != nil {
|
||||
return fmt.Errorf("field I: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ComplicatedNameEventsFromApplicationLog retrieves a set of all emitted events
|
||||
// with "! complicated name %$#" name from the provided [result.ApplicationLog].
|
||||
func ComplicatedNameEventsFromApplicationLog(log *result.ApplicationLog) ([]*ComplicatedNameEvent, error) {
|
||||
|
@ -1126,3 +1192,55 @@ func (e *SomeArrayEvent) FromStackItem(item *stackitem.Array) error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SomeUnexportedFieldEventsFromApplicationLog retrieves a set of all emitted events
|
||||
// with "SomeUnexportedField" name from the provided [result.ApplicationLog].
|
||||
func SomeUnexportedFieldEventsFromApplicationLog(log *result.ApplicationLog) ([]*SomeUnexportedFieldEvent, error) {
|
||||
if log == nil {
|
||||
return nil, errors.New("nil application log")
|
||||
}
|
||||
|
||||
var res []*SomeUnexportedFieldEvent
|
||||
for i, ex := range log.Executions {
|
||||
for j, e := range ex.Events {
|
||||
if e.Name != "SomeUnexportedField" {
|
||||
continue
|
||||
}
|
||||
event := new(SomeUnexportedFieldEvent)
|
||||
err := event.FromStackItem(e.Item)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to deserialize SomeUnexportedFieldEvent from stackitem (execution #%d, event #%d): %w", i, j, err)
|
||||
}
|
||||
res = append(res, event)
|
||||
}
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// FromStackItem converts provided [stackitem.Array] to SomeUnexportedFieldEvent or
|
||||
// returns an error if it's not possible to do to so.
|
||||
func (e *SomeUnexportedFieldEvent) 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.S, err = itemToSimpleStruct(arr[index], nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("field S: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -103,6 +103,11 @@ type SomeArrayEvent struct {
|
|||
A [][]*big.Int
|
||||
}
|
||||
|
||||
// SomeUnexportedFieldEvent represents "SomeUnexportedField" event emitted by the contract.
|
||||
type SomeUnexportedFieldEvent struct {
|
||||
S *Unnamed
|
||||
}
|
||||
|
||||
// Actor is used by Contract to call state-changing methods.
|
||||
type Actor interface {
|
||||
MakeCall(contract util.Uint160, method string, params ...any) (*transaction.Transaction, error)
|
||||
|
@ -213,6 +218,28 @@ func (c *Contract) StructUnsigned() (*transaction.Transaction, error) {
|
|||
return c.actor.MakeUnsignedCall(c.hash, "struct", nil)
|
||||
}
|
||||
|
||||
// UnexportedField creates a transaction invoking `unexportedField` 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) UnexportedField() (util.Uint256, uint32, error) {
|
||||
return c.actor.SendCall(c.hash, "unexportedField")
|
||||
}
|
||||
|
||||
// UnexportedFieldTransaction creates a transaction invoking `unexportedField` method of the contract.
|
||||
// This transaction is signed, but not sent to the network, instead it's
|
||||
// returned to the caller.
|
||||
func (c *Contract) UnexportedFieldTransaction() (*transaction.Transaction, error) {
|
||||
return c.actor.MakeCall(c.hash, "unexportedField")
|
||||
}
|
||||
|
||||
// UnexportedFieldUnsigned creates a transaction invoking `unexportedField` 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) UnexportedFieldUnsigned() (*transaction.Transaction, error) {
|
||||
return c.actor.MakeUnsignedCall(c.hash, "unexportedField", nil)
|
||||
}
|
||||
|
||||
// itemToLedgerBlock converts stack item into *LedgerBlock.
|
||||
func itemToLedgerBlock(item stackitem.Item, err error) (*LedgerBlock, error) {
|
||||
if err != nil {
|
||||
|
@ -1139,3 +1166,55 @@ func (e *SomeArrayEvent) FromStackItem(item *stackitem.Array) error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SomeUnexportedFieldEventsFromApplicationLog retrieves a set of all emitted events
|
||||
// with "SomeUnexportedField" name from the provided [result.ApplicationLog].
|
||||
func SomeUnexportedFieldEventsFromApplicationLog(log *result.ApplicationLog) ([]*SomeUnexportedFieldEvent, error) {
|
||||
if log == nil {
|
||||
return nil, errors.New("nil application log")
|
||||
}
|
||||
|
||||
var res []*SomeUnexportedFieldEvent
|
||||
for i, ex := range log.Executions {
|
||||
for j, e := range ex.Events {
|
||||
if e.Name != "SomeUnexportedField" {
|
||||
continue
|
||||
}
|
||||
event := new(SomeUnexportedFieldEvent)
|
||||
err := event.FromStackItem(e.Item)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to deserialize SomeUnexportedFieldEvent from stackitem (execution #%d, event #%d): %w", i, j, err)
|
||||
}
|
||||
res = append(res, event)
|
||||
}
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// FromStackItem converts provided [stackitem.Array] to SomeUnexportedFieldEvent or
|
||||
// returns an error if it's not possible to do to so.
|
||||
func (e *SomeUnexportedFieldEvent) 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.S, err = itemToUnnamed(arr[index], nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("field S: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -152,6 +152,7 @@ type StructsInternal struct {
|
|||
ArrOfH160 []util.Uint160
|
||||
Map map[*big.Int]keys.PublicKeys
|
||||
Struct *StructsInternal
|
||||
UnexportedField *big.Int
|
||||
}
|
||||
|
||||
// Invoker is used by ContractReader to call various safe methods.
|
||||
|
@ -1410,7 +1411,7 @@ func (res *StructsInternal) FromStackItem(item stackitem.Item) error {
|
|||
if !ok {
|
||||
return errors.New("not an array")
|
||||
}
|
||||
if len(arr) != 13 {
|
||||
if len(arr) != 14 {
|
||||
return errors.New("wrong number of structure elements")
|
||||
}
|
||||
|
||||
|
@ -1622,5 +1623,11 @@ func (res *StructsInternal) FromStackItem(item stackitem.Item) error {
|
|||
return fmt.Errorf("field Struct: %w", err)
|
||||
}
|
||||
|
||||
index++
|
||||
res.UnexportedField, err = arr[index].TryInteger()
|
||||
if err != nil {
|
||||
return fmt.Errorf("field UnexportedField: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -149,6 +149,7 @@ type StructsInternal struct {
|
|||
ArrOfH160 []util.Uint160
|
||||
Map map[*big.Int]keys.PublicKeys
|
||||
Struct *StructsInternal
|
||||
UnexportedField *big.Int
|
||||
}
|
||||
|
||||
// Invoker is used by ContractReader to call various safe methods.
|
||||
|
@ -1406,7 +1407,7 @@ func (res *StructsInternal) FromStackItem(item stackitem.Item) error {
|
|||
if !ok {
|
||||
return errors.New("not an array")
|
||||
}
|
||||
if len(arr) != 13 {
|
||||
if len(arr) != 14 {
|
||||
return errors.New("wrong number of structure elements")
|
||||
}
|
||||
|
||||
|
@ -1618,5 +1619,11 @@ func (res *StructsInternal) FromStackItem(item stackitem.Item) error {
|
|||
return fmt.Errorf("field Struct: %w", err)
|
||||
}
|
||||
|
||||
index++
|
||||
res.UnexportedField, err = arr[index].TryInteger()
|
||||
if err != nil {
|
||||
return fmt.Errorf("field UnexportedField: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ type Internal struct {
|
|||
ArrOfH160 []interop.Hash160
|
||||
Map map[int][]interop.PublicKey
|
||||
Struct *Internal
|
||||
unexportedField int // this one should be exported in the resulting RPC binding.
|
||||
}
|
||||
|
||||
func Contract(mc management.Contract) management.Contract {
|
||||
|
|
|
@ -23,7 +23,7 @@ const (
|
|||
// {{.Name}} represents "{{.ManifestName}}" event emitted by the contract.
|
||||
type {{.Name}} struct {
|
||||
{{- range $index, $arg := .Parameters}}
|
||||
{{.Name}} {{.Type}}
|
||||
{{ upperFirst .Name}} {{.Type}}
|
||||
{{- end}}
|
||||
}
|
||||
{{ end }}`
|
||||
|
@ -126,7 +126,7 @@ var Hash = {{ .Hash }}
|
|||
// {{toTypeName $name}} is a contract-specific {{$name}} type used by its methods.
|
||||
type {{toTypeName $name}} struct {
|
||||
{{- range $m := $typ.Fields}}
|
||||
{{.Field}} {{etTypeToStr .ExtendedType}}
|
||||
{{ upperFirst .Field}} {{etTypeToStr .ExtendedType}}
|
||||
{{- end}}
|
||||
}
|
||||
{{end}}
|
||||
|
@ -262,9 +262,9 @@ func (res *{{toTypeName $name}}) FromStackItem(item stackitem.Item) error {
|
|||
)
|
||||
{{- range $m := $typ.Fields}}
|
||||
index++
|
||||
res.{{.Field}}, err = {{etTypeConverter .ExtendedType "arr[index]"}}
|
||||
res.{{ upperFirst .Field}}, err = {{etTypeConverter .ExtendedType "arr[index]"}}
|
||||
if err != nil {
|
||||
return fmt.Errorf("field {{.Field}}: %w", err)
|
||||
return fmt.Errorf("field {{ upperFirst .Field}}: %w", err)
|
||||
}
|
||||
{{end}}
|
||||
{{- end}}
|
||||
|
@ -317,9 +317,9 @@ func (e *{{$e.Name}}) FromStackItem(item *stackitem.Array) error {
|
|||
)
|
||||
{{- range $p := $e.Parameters}}
|
||||
index++
|
||||
e.{{.Name}}, err = {{etTypeConverter .ExtType "arr[index]"}}
|
||||
e.{{ upperFirst .Name}}, err = {{etTypeConverter .ExtType "arr[index]"}}
|
||||
if err != nil {
|
||||
return fmt.Errorf("field {{.Name}}: %w", err)
|
||||
return fmt.Errorf("field {{ upperFirst .Name}}: %w", err)
|
||||
}
|
||||
{{end}}
|
||||
{{- end}}
|
||||
|
@ -439,6 +439,7 @@ func Generate(cfg binding.Config) error {
|
|||
},
|
||||
"toTypeName": toTypeName,
|
||||
"cutPointer": cutPointer,
|
||||
"upperFirst": upperFirst,
|
||||
}).Parse(srcTmpl))
|
||||
|
||||
return srcTemplate.Execute(cfg.Output, ctr)
|
||||
|
|
Loading…
Reference in a new issue