2022-07-21 13:21:44 +00:00
|
|
|
package rpcsrv
|
2020-05-10 22:00:19 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"github.com/gorilla/websocket"
|
2020-05-13 14:13:33 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/block"
|
2020-09-03 16:58:50 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
2020-05-13 14:13:33 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/rpc/request"
|
2020-05-10 22:00:19 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/rpc/response"
|
2021-09-24 09:15:25 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/rpc/response/result/subscriptions"
|
2020-05-12 19:38:29 +00:00
|
|
|
"go.uber.org/atomic"
|
2020-05-10 22:00:19 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type (
|
|
|
|
// subscriber is an event subscriber.
|
|
|
|
subscriber struct {
|
2020-05-12 19:38:29 +00:00
|
|
|
writer chan<- *websocket.PreparedMessage
|
|
|
|
ws *websocket.Conn
|
|
|
|
overflown atomic.Bool
|
2020-05-10 22:00:19 +00:00
|
|
|
// These work like slots as there is not a lot of them (it's
|
|
|
|
// cheaper doing it this way rather than creating a map),
|
2022-04-20 18:30:09 +00:00
|
|
|
// pointing to an EventID is an obvious overkill at the moment, but
|
2020-05-10 22:00:19 +00:00
|
|
|
// that's not for long.
|
2020-05-13 14:13:33 +00:00
|
|
|
feeds [maxFeeds]feed
|
|
|
|
}
|
|
|
|
feed struct {
|
|
|
|
event response.EventID
|
|
|
|
filter interface{}
|
2020-05-10 22:00:19 +00:00
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
// Maximum number of subscriptions per one client.
|
|
|
|
maxFeeds = 16
|
|
|
|
|
2022-04-20 18:30:09 +00:00
|
|
|
// This sets notification messages buffer depth. It may seem to be quite
|
2020-05-10 22:00:19 +00:00
|
|
|
// big, but there is a big gap in speed between internal event processing
|
|
|
|
// and networking communication that is combined with spiky nature of our
|
|
|
|
// event generation process, which leads to lots of events generated in
|
2022-04-20 18:30:09 +00:00
|
|
|
// a short time and they will put some pressure to this buffer (consider
|
2020-05-10 22:00:19 +00:00
|
|
|
// ~500 invocation txs in one block with some notifications). At the same
|
2022-04-20 18:30:09 +00:00
|
|
|
// time, this channel is about sending pointers, so it's doesn't cost
|
2020-05-10 22:00:19 +00:00
|
|
|
// a lot in terms of memory used.
|
|
|
|
notificationBufSize = 1024
|
|
|
|
)
|
2020-05-13 14:13:33 +00:00
|
|
|
|
|
|
|
func (f *feed) Matches(r *response.Notification) bool {
|
|
|
|
if r.Event != f.event {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
if f.filter == nil {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
switch f.event {
|
|
|
|
case response.BlockEventID:
|
|
|
|
filt := f.filter.(request.BlockFilter)
|
|
|
|
b := r.Payload[0].(*block.Block)
|
2021-03-01 12:20:27 +00:00
|
|
|
return int(b.PrimaryIndex) == filt.Primary
|
2020-05-13 14:13:33 +00:00
|
|
|
case response.TransactionEventID:
|
|
|
|
filt := f.filter.(request.TxFilter)
|
|
|
|
tx := r.Payload[0].(*transaction.Transaction)
|
2020-07-29 16:57:38 +00:00
|
|
|
senderOK := filt.Sender == nil || tx.Sender().Equals(*filt.Sender)
|
|
|
|
signerOK := true
|
|
|
|
if filt.Signer != nil {
|
|
|
|
signerOK = false
|
|
|
|
for i := range tx.Signers {
|
|
|
|
if tx.Signers[i].Account.Equals(*filt.Signer) {
|
|
|
|
signerOK = true
|
2020-05-13 14:13:33 +00:00
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-07-29 16:57:38 +00:00
|
|
|
return senderOK && signerOK
|
2020-05-13 14:13:33 +00:00
|
|
|
case response.NotificationEventID:
|
|
|
|
filt := f.filter.(request.NotificationFilter)
|
2021-09-24 09:15:25 +00:00
|
|
|
notification := r.Payload[0].(*subscriptions.NotificationEvent)
|
2020-09-03 16:58:50 +00:00
|
|
|
hashOk := filt.Contract == nil || notification.ScriptHash.Equals(*filt.Contract)
|
2020-08-04 13:24:32 +00:00
|
|
|
nameOk := filt.Name == nil || notification.Name == *filt.Name
|
|
|
|
return hashOk && nameOk
|
2020-05-13 14:13:33 +00:00
|
|
|
case response.ExecutionEventID:
|
|
|
|
filt := f.filter.(request.ExecutionFilter)
|
2020-09-03 16:58:50 +00:00
|
|
|
applog := r.Payload[0].(*state.AppExecResult)
|
|
|
|
return applog.VMState.String() == filt.State
|
2021-05-28 11:55:06 +00:00
|
|
|
case response.NotaryRequestEventID:
|
|
|
|
filt := f.filter.(request.TxFilter)
|
2021-09-24 09:23:30 +00:00
|
|
|
req := r.Payload[0].(*subscriptions.NotaryRequestEvent)
|
2021-05-28 11:55:06 +00:00
|
|
|
senderOk := filt.Sender == nil || req.NotaryRequest.FallbackTransaction.Signers[1].Account == *filt.Sender
|
|
|
|
signerOK := true
|
|
|
|
if filt.Signer != nil {
|
|
|
|
signerOK = false
|
|
|
|
for _, signer := range req.NotaryRequest.MainTransaction.Signers {
|
|
|
|
if signer.Account.Equals(*filt.Signer) {
|
|
|
|
signerOK = true
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return senderOk && signerOK
|
2020-05-13 14:13:33 +00:00
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|