smartcontract: add test for user-defined extended event types configuration
config_extended.yml contains an example of user-defined configuration file with extended event types. User-defined event types are allowed to be named and complicated, i.e. properly support extended types notation. Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
This commit is contained in:
parent
a0d991a500
commit
3e2755e66d
6 changed files with 1288 additions and 5 deletions
|
@ -379,14 +379,24 @@ func TestAssistedRPCBindings(t *testing.T) {
|
|||
app := cli.NewApp()
|
||||
app.Commands = NewCommands()
|
||||
|
||||
var checkBinding = func(source string) {
|
||||
t.Run(source, func(t *testing.T) {
|
||||
var checkBinding = func(source string, suffix ...string) {
|
||||
testName := source
|
||||
if len(suffix) != 0 {
|
||||
testName += suffix[0]
|
||||
}
|
||||
t.Run(testName, func(t *testing.T) {
|
||||
configFile := filepath.Join(source, "config.yml")
|
||||
expectedFile := filepath.Join(source, "rpcbindings.out")
|
||||
if len(suffix) != 0 {
|
||||
configFile = filepath.Join(source, "config"+suffix[0]+".yml")
|
||||
expectedFile = filepath.Join(source, "rpcbindings"+suffix[0]+".out")
|
||||
}
|
||||
manifestF := filepath.Join(tmpDir, "manifest.json")
|
||||
bindingF := filepath.Join(tmpDir, "binding.yml")
|
||||
nefF := filepath.Join(tmpDir, "out.nef")
|
||||
require.NoError(t, app.Run([]string{"", "contract", "compile",
|
||||
"--in", source,
|
||||
"--config", filepath.Join(source, "config.yml"),
|
||||
"--config", configFile,
|
||||
"--manifest", manifestF,
|
||||
"--bindings", bindingF,
|
||||
"--out", nefF,
|
||||
|
@ -402,7 +412,6 @@ func TestAssistedRPCBindings(t *testing.T) {
|
|||
data, err := os.ReadFile(outFile)
|
||||
require.NoError(t, err)
|
||||
data = bytes.ReplaceAll(data, []byte("\r"), []byte{}) // Windows.
|
||||
expectedFile := filepath.Join(source, "rpcbindings.out")
|
||||
if rewriteExpectedOutputs {
|
||||
require.NoError(t, os.WriteFile(expectedFile, data, os.ModePerm))
|
||||
} else {
|
||||
|
@ -417,6 +426,7 @@ func TestAssistedRPCBindings(t *testing.T) {
|
|||
checkBinding(filepath.Join("testdata", "types"))
|
||||
checkBinding(filepath.Join("testdata", "structs"))
|
||||
checkBinding(filepath.Join("testdata", "notifications"))
|
||||
checkBinding(filepath.Join("testdata", "notifications"), "_extended")
|
||||
|
||||
require.False(t, rewriteExpectedOutputs)
|
||||
}
|
||||
|
|
|
@ -12,4 +12,8 @@ events:
|
|||
- name: "SomeStruct"
|
||||
parameters:
|
||||
- name: s
|
||||
type: Struct
|
||||
type: Struct
|
||||
- name: "SomeArray"
|
||||
parameters:
|
||||
- name: a
|
||||
type: Array
|
47
cli/smartcontract/testdata/notifications/config_extended.yml
vendored
Normal file
47
cli/smartcontract/testdata/notifications/config_extended.yml
vendored
Normal file
|
@ -0,0 +1,47 @@
|
|||
name: "Notifications"
|
||||
sourceurl: https://github.com/nspcc-dev/neo-go/
|
||||
events:
|
||||
- name: "! complicated name %$#"
|
||||
parameters:
|
||||
- name: ! complicated param @#$%
|
||||
type: String
|
||||
- name: "SomeMap"
|
||||
parameters:
|
||||
- name: m
|
||||
type: Map
|
||||
extendedtype:
|
||||
base: Map
|
||||
key: Integer
|
||||
value:
|
||||
base: Map
|
||||
key: String
|
||||
value:
|
||||
base: Array
|
||||
value:
|
||||
base: Hash160
|
||||
- name: "SomeStruct"
|
||||
parameters:
|
||||
- name: s
|
||||
type: Struct
|
||||
extendedtype:
|
||||
base: Struct
|
||||
name: crazyStruct
|
||||
- name: "SomeArray"
|
||||
parameters:
|
||||
- name: a
|
||||
type: Array
|
||||
extendedtype:
|
||||
base: Array
|
||||
value:
|
||||
base: Array
|
||||
value:
|
||||
base: Integer
|
||||
namedtypes:
|
||||
crazyStruct:
|
||||
base: Struct
|
||||
name: crazyStruct
|
||||
fields:
|
||||
- field: I
|
||||
base: Integer
|
||||
- field: B
|
||||
base: Boolean
|
|
@ -19,3 +19,7 @@ func Struct() {
|
|||
B bool
|
||||
}{I: 123, B: true})
|
||||
}
|
||||
|
||||
func Array() {
|
||||
runtime.Notify("SomeArray", [][]int{})
|
||||
}
|
||||
|
|
|
@ -92,6 +92,11 @@ type SomeStructEvent struct {
|
|||
S []any
|
||||
}
|
||||
|
||||
// SomeArrayEvent represents "SomeArray" event emitted by the contract.
|
||||
type SomeArrayEvent struct {
|
||||
A []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)
|
||||
|
@ -112,6 +117,28 @@ func New(actor Actor) *Contract {
|
|||
return &Contract{actor}
|
||||
}
|
||||
|
||||
// Array creates a transaction invoking `array` 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) Array() (util.Uint256, uint32, error) {
|
||||
return c.actor.SendCall(Hash, "array")
|
||||
}
|
||||
|
||||
// ArrayTransaction creates a transaction invoking `array` method of the contract.
|
||||
// This transaction is signed, but not sent to the network, instead it's
|
||||
// returned to the caller.
|
||||
func (c *Contract) ArrayTransaction() (*transaction.Transaction, error) {
|
||||
return c.actor.MakeCall(Hash, "array")
|
||||
}
|
||||
|
||||
// ArrayUnsigned creates a transaction invoking `array` 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) ArrayUnsigned() (*transaction.Transaction, error) {
|
||||
return c.actor.MakeUnsignedCall(Hash, "array", nil)
|
||||
}
|
||||
|
||||
// CrazyMap creates a transaction invoking `crazyMap` 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.
|
||||
|
@ -936,3 +963,68 @@ func (e *SomeStructEvent) FromStackItem(item *stackitem.Array) error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SomeArrayEventsFromApplicationLog retrieves a set of all emitted events
|
||||
// with "SomeArray" name from the provided ApplicationLog.
|
||||
func SomeArrayEventsFromApplicationLog(log *result.ApplicationLog) ([]*SomeArrayEvent, error) {
|
||||
if log == nil {
|
||||
return nil, errors.New("nil application log")
|
||||
}
|
||||
|
||||
var res []*SomeArrayEvent
|
||||
for i, ex := range log.Executions {
|
||||
for j, e := range ex.Events {
|
||||
if e.Name != "SomeArray" {
|
||||
continue
|
||||
}
|
||||
event := new(SomeArrayEvent)
|
||||
err := event.FromStackItem(e.Item)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to deserialize SomeArrayEvent from stackitem (execution %d, event %d): %w", i, j, err)
|
||||
}
|
||||
res = append(res, event)
|
||||
}
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// FromStackItem converts provided stackitem.Array to SomeArrayEvent and
|
||||
// returns an error if so.
|
||||
func (e *SomeArrayEvent) 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.A, 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 A: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
1126
cli/smartcontract/testdata/notifications/rpcbindings_extended.out
vendored
Executable file
1126
cli/smartcontract/testdata/notifications/rpcbindings_extended.out
vendored
Executable file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue