From 1a4da8c46217378ea246076952cb1cf9ba8f91a6 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Thu, 16 Mar 2023 23:43:00 +0300 Subject: [PATCH] neorpc: add Copy to filters for easy deep copying --- pkg/neorpc/filters.go | 113 ++++++++++++++++++++++++++++++++++++ pkg/neorpc/filters_test.go | 116 +++++++++++++++++++++++++++++++++++++ pkg/neorpc/types.go | 33 ----------- 3 files changed, 229 insertions(+), 33 deletions(-) create mode 100644 pkg/neorpc/filters.go create mode 100644 pkg/neorpc/filters_test.go diff --git a/pkg/neorpc/filters.go b/pkg/neorpc/filters.go new file mode 100644 index 000000000..2980640ed --- /dev/null +++ b/pkg/neorpc/filters.go @@ -0,0 +1,113 @@ +package neorpc + +import ( + "github.com/nspcc-dev/neo-go/pkg/util" +) + +type ( + // BlockFilter is a wrapper structure for the block event filter. It allows + // to filter blocks by primary index and/or by block index (allowing blocks + // since/till the specified index inclusively). nil value treated as missing + // filter. + BlockFilter struct { + Primary *int `json:"primary,omitempty"` + Since *uint32 `json:"since,omitempty"` + Till *uint32 `json:"till,omitempty"` + } + // TxFilter is a wrapper structure for the transaction event filter. It + // allows to filter transactions by senders and/or signers. nil value treated + // as missing filter. + TxFilter struct { + Sender *util.Uint160 `json:"sender,omitempty"` + Signer *util.Uint160 `json:"signer,omitempty"` + } + // NotificationFilter is a wrapper structure representing a filter used for + // notifications generated during transaction execution. Notifications can + // be filtered by contract hash and/or by name. nil value treated as missing + // filter. + NotificationFilter struct { + Contract *util.Uint160 `json:"contract,omitempty"` + Name *string `json:"name,omitempty"` + } + // ExecutionFilter is a wrapper structure used for transaction and persisting + // scripts execution events. It allows to choose failing or successful + // transactions and persisting scripts based on their VM state and/or to + // choose execution event with the specified container. nil value treated as + // missing filter. + ExecutionFilter struct { + State *string `json:"state,omitempty"` + Container *util.Uint256 `json:"container,omitempty"` + } +) + +// Copy creates a deep copy of the BlockFilter. It handles nil BlockFilter correctly. +func (f *BlockFilter) Copy() *BlockFilter { + if f == nil { + return nil + } + var res = new(BlockFilter) + if f.Primary != nil { + res.Primary = new(int) + *res.Primary = *f.Primary + } + if f.Since != nil { + res.Since = new(uint32) + *res.Since = *f.Since + } + if f.Till != nil { + res.Till = new(uint32) + *res.Till = *f.Till + } + return res +} + +// Copy creates a deep copy of the TxFilter. It handles nil TxFilter correctly. +func (f *TxFilter) Copy() *TxFilter { + if f == nil { + return nil + } + var res = new(TxFilter) + if f.Sender != nil { + res.Sender = new(util.Uint160) + *res.Sender = *f.Sender + } + if f.Signer != nil { + res.Signer = new(util.Uint160) + *res.Signer = *f.Signer + } + return res +} + +// Copy creates a deep copy of the NotificationFilter. It handles nil NotificationFilter correctly. +func (f *NotificationFilter) Copy() *NotificationFilter { + if f == nil { + return nil + } + var res = new(NotificationFilter) + if f.Contract != nil { + res.Contract = new(util.Uint160) + *res.Contract = *f.Contract + } + if f.Name != nil { + res.Name = new(string) + *res.Name = *f.Name + } + return res +} + +// Copy creates a deep copy of the ExecutionFilter. It handles nil ExecutionFilter correctly. +func (f *ExecutionFilter) Copy() *ExecutionFilter { + if f == nil { + return nil + } + var res = new(ExecutionFilter) + if f.State != nil { + res.State = new(string) + *res.State = *f.State + } + if f.Container != nil { + res.Container = new(util.Uint256) + *res.Container = *f.Container + } + return res +} diff --git a/pkg/neorpc/filters_test.go b/pkg/neorpc/filters_test.go new file mode 100644 index 000000000..8f725a588 --- /dev/null +++ b/pkg/neorpc/filters_test.go @@ -0,0 +1,116 @@ +package neorpc + +import ( + "testing" + + "github.com/nspcc-dev/neo-go/pkg/util" + "github.com/stretchr/testify/require" +) + +func TestBlockFilterCopy(t *testing.T) { + var bf, tf *BlockFilter + + require.Nil(t, bf.Copy()) + + bf = new(BlockFilter) + tf = bf.Copy() + require.Equal(t, bf, tf) + + bf.Primary = new(int) + *bf.Primary = 42 + + tf = bf.Copy() + require.Equal(t, bf, tf) + *bf.Primary = 100500 + require.NotEqual(t, bf, tf) + + bf.Since = new(uint32) + *bf.Since = 42 + + tf = bf.Copy() + require.Equal(t, bf, tf) + *bf.Since = 100500 + require.NotEqual(t, bf, tf) + + bf.Till = new(uint32) + *bf.Till = 42 + + tf = bf.Copy() + require.Equal(t, bf, tf) + *bf.Till = 100500 + require.NotEqual(t, bf, tf) +} + +func TestTxFilterCopy(t *testing.T) { + var bf, tf *TxFilter + + require.Nil(t, bf.Copy()) + + bf = new(TxFilter) + tf = bf.Copy() + require.Equal(t, bf, tf) + + bf.Sender = &util.Uint160{1, 2, 3} + + tf = bf.Copy() + require.Equal(t, bf, tf) + *bf.Sender = util.Uint160{3, 2, 1} + require.NotEqual(t, bf, tf) + + bf.Signer = &util.Uint160{1, 2, 3} + + tf = bf.Copy() + require.Equal(t, bf, tf) + *bf.Signer = util.Uint160{3, 2, 1} + require.NotEqual(t, bf, tf) +} + +func TestNotificationFilterCopy(t *testing.T) { + var bf, tf *NotificationFilter + + require.Nil(t, bf.Copy()) + + bf = new(NotificationFilter) + tf = bf.Copy() + require.Equal(t, bf, tf) + + bf.Contract = &util.Uint160{1, 2, 3} + + tf = bf.Copy() + require.Equal(t, bf, tf) + *bf.Contract = util.Uint160{3, 2, 1} + require.NotEqual(t, bf, tf) + + bf.Name = new(string) + *bf.Name = "ololo" + + tf = bf.Copy() + require.Equal(t, bf, tf) + *bf.Name = "azaza" + require.NotEqual(t, bf, tf) +} + +func TestExecutionFilterCopy(t *testing.T) { + var bf, tf *ExecutionFilter + + require.Nil(t, bf.Copy()) + + bf = new(ExecutionFilter) + tf = bf.Copy() + require.Equal(t, bf, tf) + + bf.State = new(string) + *bf.State = "ololo" + + tf = bf.Copy() + require.Equal(t, bf, tf) + *bf.State = "azaza" + require.NotEqual(t, bf, tf) + + bf.Container = &util.Uint256{1, 2, 3} + + tf = bf.Copy() + require.Equal(t, bf, tf) + *bf.Container = util.Uint256{3, 2, 1} + require.NotEqual(t, bf, tf) +} diff --git a/pkg/neorpc/types.go b/pkg/neorpc/types.go index 20e1d2359..223cd591c 100644 --- a/pkg/neorpc/types.go +++ b/pkg/neorpc/types.go @@ -71,39 +71,6 @@ type ( Payload []interface{} `json:"params"` } - // BlockFilter is a wrapper structure for the block event filter. It allows - // to filter blocks by primary index and/or by block index (allowing blocks - // since/till the specified index inclusively). nil value treated as missing - // filter. - BlockFilter struct { - Primary *int `json:"primary,omitempty"` - Since *uint32 `json:"since,omitempty"` - Till *uint32 `json:"till,omitempty"` - } - // TxFilter is a wrapper structure for the transaction event filter. It - // allows to filter transactions by senders and/or signers. nil value treated - // as missing filter. - TxFilter struct { - Sender *util.Uint160 `json:"sender,omitempty"` - Signer *util.Uint160 `json:"signer,omitempty"` - } - // NotificationFilter is a wrapper structure representing a filter used for - // notifications generated during transaction execution. Notifications can - // be filtered by contract hash and/or by name. nil value treated as missing - // filter. - NotificationFilter struct { - Contract *util.Uint160 `json:"contract,omitempty"` - Name *string `json:"name,omitempty"` - } - // ExecutionFilter is a wrapper structure used for transaction and persisting - // scripts execution events. It allows to choose failing or successful - // transactions and persisting scripts based on their VM state and/or to - // choose execution event with the specified container. nil value treated as - // missing filter. - ExecutionFilter struct { - State *string `json:"state,omitempty"` - Container *util.Uint256 `json:"container,omitempty"` - } // SignerWithWitness represents transaction's signer with the corresponding witness. SignerWithWitness struct { transaction.Signer