rpc: add an ability to filter out NotaryRequestEvents
Add new filter NotaryRequestFilter, support for filtering NotaryRequestEvents by mempoolevent.Type (added or removed). Closes #2425. Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
This commit is contained in:
parent
afca64f164
commit
3fd48a743e
8 changed files with 139 additions and 14 deletions
|
@ -84,7 +84,8 @@ Recognized stream names:
|
|||
* `notary_request_event`
|
||||
Filter: `sender` field containing a string with hex-encoded Uint160 (LE
|
||||
representation) for notary request's `Sender` and/or `signer` in the same
|
||||
format for one of main transaction's `Signers`.
|
||||
format for one of main transaction's `Signers`. `type` field containing a
|
||||
string with event type, which could be one of "added" or "removed".
|
||||
|
||||
Response: returns subscription ID (string) as a result. This ID can be used to
|
||||
cancel this subscription and has no meaning other than that.
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package neorpc
|
||||
|
||||
import (
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/mempoolevent"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
)
|
||||
|
||||
|
@ -38,6 +39,14 @@ type (
|
|||
State *string `json:"state,omitempty"`
|
||||
Container *util.Uint256 `json:"container,omitempty"`
|
||||
}
|
||||
// NotaryRequestFilter is a wrapper structure used for notary request events.
|
||||
// It allows to choose notary request events with the specified request sender,
|
||||
// main transaction signer and/or type. nil value treated as missing filter.
|
||||
NotaryRequestFilter struct {
|
||||
Sender *util.Uint160 `json:"sender,omitempty"`
|
||||
Signer *util.Uint160 `json:"signer,omitempty"`
|
||||
Type *mempoolevent.Type `json:"type,omitempty"`
|
||||
}
|
||||
)
|
||||
|
||||
// Copy creates a deep copy of the BlockFilter. It handles nil BlockFilter correctly.
|
||||
|
@ -111,3 +120,24 @@ func (f *ExecutionFilter) Copy() *ExecutionFilter {
|
|||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// Copy creates a deep copy of the NotaryRequestFilter. It handles nil NotaryRequestFilter correctly.
|
||||
func (f *NotaryRequestFilter) Copy() *NotaryRequestFilter {
|
||||
if f == nil {
|
||||
return nil
|
||||
}
|
||||
var res = new(NotaryRequestFilter)
|
||||
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
|
||||
}
|
||||
if f.Type != nil {
|
||||
res.Type = new(mempoolevent.Type)
|
||||
*res.Type = *f.Type
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
|
|
@ -69,8 +69,9 @@ func Matches(f Comparator, r Container) bool {
|
|||
containerOK := filt.Container == nil || applog.Container.Equals(*filt.Container)
|
||||
return stateOK && containerOK
|
||||
case neorpc.NotaryRequestEventID:
|
||||
filt := filter.(neorpc.TxFilter)
|
||||
filt := filter.(neorpc.NotaryRequestFilter)
|
||||
req := r.EventPayload().(*result.NotaryRequestEvent)
|
||||
typeOk := filt.Type == nil || req.Type == *filt.Type
|
||||
senderOk := filt.Sender == nil || req.NotaryRequest.FallbackTransaction.Signers[1].Account == *filt.Sender
|
||||
signerOK := true
|
||||
if filt.Signer != nil {
|
||||
|
@ -82,7 +83,7 @@ func Matches(f Comparator, r Container) bool {
|
|||
}
|
||||
}
|
||||
}
|
||||
return senderOk && signerOK
|
||||
return senderOk && signerOK && typeOk
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/block"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/mempoolevent"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||
"github.com/nspcc-dev/neo-go/pkg/neorpc"
|
||||
|
@ -47,11 +48,13 @@ func TestMatches(t *testing.T) {
|
|||
sender := util.Uint160{1, 2, 3}
|
||||
signer := util.Uint160{4, 5, 6}
|
||||
contract := util.Uint160{7, 8, 9}
|
||||
notaryType := mempoolevent.TransactionAdded
|
||||
badUint160 := util.Uint160{9, 9, 9}
|
||||
cnt := util.Uint256{1, 2, 3}
|
||||
badUint256 := util.Uint256{9, 9, 9}
|
||||
name := "ntf name"
|
||||
badName := "bad name"
|
||||
badType := mempoolevent.TransactionRemoved
|
||||
bContainer := testContainer{
|
||||
id: neorpc.BlockEventID,
|
||||
pld: &block.Block{
|
||||
|
@ -76,6 +79,7 @@ func TestMatches(t *testing.T) {
|
|||
ntrContainer := testContainer{
|
||||
id: neorpc.NotaryRequestEventID,
|
||||
pld: &result.NotaryRequestEvent{
|
||||
Type: notaryType,
|
||||
NotaryRequest: &payload.P2PNotaryRequest{
|
||||
MainTransaction: &transaction.Transaction{Signers: []transaction.Signer{{Account: signer}}},
|
||||
FallbackTransaction: &transaction.Transaction{Signers: []transaction.Signer{{Account: util.Uint160{}}, {Account: sender}}},
|
||||
|
@ -254,7 +258,7 @@ func TestMatches(t *testing.T) {
|
|||
name: "notary request, sender mismatch",
|
||||
comparator: testComparator{
|
||||
id: neorpc.NotaryRequestEventID,
|
||||
filter: neorpc.TxFilter{Sender: &badUint160},
|
||||
filter: neorpc.NotaryRequestFilter{Sender: &badUint160},
|
||||
},
|
||||
container: ntrContainer,
|
||||
expected: false,
|
||||
|
@ -263,7 +267,16 @@ func TestMatches(t *testing.T) {
|
|||
name: "notary request, signer mismatch",
|
||||
comparator: testComparator{
|
||||
id: neorpc.NotaryRequestEventID,
|
||||
filter: neorpc.TxFilter{Signer: &badUint160},
|
||||
filter: neorpc.NotaryRequestFilter{Signer: &badUint160},
|
||||
},
|
||||
container: ntrContainer,
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "notary request, type mismatch",
|
||||
comparator: testComparator{
|
||||
id: neorpc.NotaryRequestEventID,
|
||||
filter: neorpc.NotaryRequestFilter{Type: &badType},
|
||||
},
|
||||
container: ntrContainer,
|
||||
expected: false,
|
||||
|
@ -272,7 +285,7 @@ func TestMatches(t *testing.T) {
|
|||
name: "notary request, filter match",
|
||||
comparator: testComparator{
|
||||
id: neorpc.NotaryRequestEventID,
|
||||
filter: neorpc.TxFilter{Sender: &sender, Signer: &signer},
|
||||
filter: neorpc.NotaryRequestFilter{Sender: &sender, Signer: &signer, Type: ¬aryType},
|
||||
},
|
||||
container: ntrContainer,
|
||||
expected: true,
|
||||
|
|
|
@ -305,7 +305,7 @@ func (r *executionReceiver) Close() {
|
|||
|
||||
// notaryRequestReceiver stores information about notary requests subscriber.
|
||||
type notaryRequestReceiver struct {
|
||||
filter *neorpc.TxFilter
|
||||
filter *neorpc.NotaryRequestFilter
|
||||
ch chan<- *result.NotaryRequestEvent
|
||||
}
|
||||
|
||||
|
@ -811,11 +811,13 @@ func (c *WSClient) ReceiveExecutions(flt *neorpc.ExecutionFilter, rcvr chan<- *s
|
|||
}
|
||||
|
||||
// ReceiveNotaryRequests registers provided channel as a receiver for notary request
|
||||
// payload addition or removal events. Events can be filtered by the given TxFilter
|
||||
// payload addition or removal events. Events can be filtered by the given NotaryRequestFilter
|
||||
// where sender corresponds to notary request sender (the second fallback transaction
|
||||
// signer) and signer corresponds to main transaction signers. nil value doesn't add
|
||||
// any filter. See WSClient comments for generic Receive* behaviour details.
|
||||
func (c *WSClient) ReceiveNotaryRequests(flt *neorpc.TxFilter, rcvr chan<- *result.NotaryRequestEvent) (string, error) {
|
||||
// signer), signer corresponds to main transaction signers and type corresponds to the
|
||||
// [mempoolevent.Type] and denotes whether notary request was added to or removed from
|
||||
// the notary request pool. nil value doesn't add any filter. See WSClient comments
|
||||
// for generic Receive* behaviour details.
|
||||
func (c *WSClient) ReceiveNotaryRequests(flt *neorpc.NotaryRequestFilter, rcvr chan<- *result.NotaryRequestEvent) (string, error) {
|
||||
if rcvr == nil {
|
||||
return "", ErrNilNotificationReceiver
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ import (
|
|||
"github.com/gorilla/websocket"
|
||||
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/block"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/mempoolevent"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||
"github.com/nspcc-dev/neo-go/pkg/neorpc"
|
||||
|
@ -574,6 +575,71 @@ func TestWSFilteredSubscriptions(t *testing.T) {
|
|||
require.Equal(t, util.Uint256{1, 2, 3}, *filt.Container)
|
||||
},
|
||||
},
|
||||
{
|
||||
"notary request sender",
|
||||
func(t *testing.T, wsc *WSClient) {
|
||||
sender := util.Uint160{1, 2, 3, 4, 5}
|
||||
_, err := wsc.ReceiveNotaryRequests(&neorpc.NotaryRequestFilter{Sender: &sender}, make(chan *result.NotaryRequestEvent))
|
||||
require.NoError(t, err)
|
||||
},
|
||||
func(t *testing.T, p *params.Params) {
|
||||
param := p.Value(1)
|
||||
filt := new(neorpc.NotaryRequestFilter)
|
||||
require.NoError(t, json.Unmarshal(param.RawMessage, filt))
|
||||
require.Equal(t, util.Uint160{1, 2, 3, 4, 5}, *filt.Sender)
|
||||
require.Nil(t, filt.Signer)
|
||||
require.Nil(t, filt.Type)
|
||||
},
|
||||
},
|
||||
{
|
||||
"notary request signer",
|
||||
func(t *testing.T, wsc *WSClient) {
|
||||
signer := util.Uint160{0, 42}
|
||||
_, err := wsc.ReceiveNotaryRequests(&neorpc.NotaryRequestFilter{Signer: &signer}, make(chan *result.NotaryRequestEvent))
|
||||
require.NoError(t, err)
|
||||
},
|
||||
func(t *testing.T, p *params.Params) {
|
||||
param := p.Value(1)
|
||||
filt := new(neorpc.NotaryRequestFilter)
|
||||
require.NoError(t, json.Unmarshal(param.RawMessage, filt))
|
||||
require.Nil(t, filt.Sender)
|
||||
require.Equal(t, util.Uint160{0, 42}, *filt.Signer)
|
||||
require.Nil(t, filt.Type)
|
||||
},
|
||||
},
|
||||
{
|
||||
"notary request type",
|
||||
func(t *testing.T, wsc *WSClient) {
|
||||
mempoolType := mempoolevent.TransactionAdded
|
||||
_, err := wsc.ReceiveNotaryRequests(&neorpc.NotaryRequestFilter{Type: &mempoolType}, make(chan *result.NotaryRequestEvent))
|
||||
require.NoError(t, err)
|
||||
},
|
||||
func(t *testing.T, p *params.Params) {
|
||||
param := p.Value(1)
|
||||
filt := new(neorpc.NotaryRequestFilter)
|
||||
require.NoError(t, json.Unmarshal(param.RawMessage, filt))
|
||||
require.Equal(t, mempoolevent.TransactionAdded, *filt.Type)
|
||||
require.Nil(t, filt.Sender)
|
||||
require.Nil(t, filt.Signer)
|
||||
},
|
||||
},
|
||||
{"notary request sender, signer and type",
|
||||
func(t *testing.T, wsc *WSClient) {
|
||||
sender := util.Uint160{1, 2, 3, 4, 5}
|
||||
signer := util.Uint160{0, 42}
|
||||
mempoolType := mempoolevent.TransactionAdded
|
||||
_, err := wsc.ReceiveNotaryRequests(&neorpc.NotaryRequestFilter{Type: &mempoolType, Signer: &signer, Sender: &sender}, make(chan *result.NotaryRequestEvent))
|
||||
require.NoError(t, err)
|
||||
},
|
||||
func(t *testing.T, p *params.Params) {
|
||||
param := p.Value(1)
|
||||
filt := new(neorpc.NotaryRequestFilter)
|
||||
require.NoError(t, json.Unmarshal(param.RawMessage, filt))
|
||||
require.Equal(t, util.Uint160{1, 2, 3, 4, 5}, *filt.Sender)
|
||||
require.Equal(t, util.Uint160{0, 42}, *filt.Signer)
|
||||
require.Equal(t, mempoolevent.TransactionAdded, *filt.Type)
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
|
|
|
@ -2734,10 +2734,14 @@ func (s *Server) subscribe(reqParams params.Params, sub *subscriber) (any, *neor
|
|||
flt := new(neorpc.BlockFilter)
|
||||
err = jd.Decode(flt)
|
||||
filter = *flt
|
||||
case neorpc.TransactionEventID, neorpc.NotaryRequestEventID:
|
||||
case neorpc.TransactionEventID:
|
||||
flt := new(neorpc.TxFilter)
|
||||
err = jd.Decode(flt)
|
||||
filter = *flt
|
||||
case neorpc.NotaryRequestEventID:
|
||||
flt := new(neorpc.NotaryRequestFilter)
|
||||
err = jd.Decode(flt)
|
||||
filter = *flt
|
||||
case neorpc.NotificationEventID:
|
||||
flt := new(neorpc.NotificationFilter)
|
||||
err = jd.Decode(flt)
|
||||
|
|
|
@ -354,8 +354,16 @@ func TestFilteredNotaryRequestSubscriptions(t *testing.T) {
|
|||
require.Equal(t, "0x"+goodSender.StringLE(), signer0acc)
|
||||
},
|
||||
},
|
||||
"matching sender and signer": {
|
||||
params: `["notary_request_event", {"sender":"` + goodSender.StringLE() + `", "signer":"` + goodSender.StringLE() + `"}]`,
|
||||
"matching type": {
|
||||
params: `["notary_request_event", {"type":"added"}]`,
|
||||
check: func(t *testing.T, resp *neorpc.Notification) {
|
||||
require.Equal(t, neorpc.NotaryRequestEventID, resp.Event)
|
||||
rmap := resp.Payload[0].(map[string]any)
|
||||
require.Equal(t, "added", rmap["type"].(string))
|
||||
},
|
||||
},
|
||||
"matching sender, signer and type": {
|
||||
params: `["notary_request_event", {"sender":"` + goodSender.StringLE() + `", "signer":"` + goodSender.StringLE() + `","type":"added"}]`,
|
||||
check: func(t *testing.T, resp *neorpc.Notification) {
|
||||
rmap := resp.Payload[0].(map[string]any)
|
||||
require.Equal(t, neorpc.NotaryRequestEventID, resp.Event)
|
||||
|
|
Loading…
Reference in a new issue