github.com/ledgerwatch/erigon-lib@v1.0.0/direct/sentry_client.go (about)

     1  /*
     2     Copyright 2021 Erigon contributors
     3  
     4     Licensed under the Apache License, Version 2.0 (the "License");
     5     you may not use this file except in compliance with the License.
     6     You may obtain a copy of the License at
     7  
     8         http://www.apache.org/licenses/LICENSE-2.0
     9  
    10     Unless required by applicable law or agreed to in writing, software
    11     distributed under the License is distributed on an "AS IS" BASIS,
    12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13     See the License for the specific language governing permissions and
    14     limitations under the License.
    15  */
    16  
    17  package direct
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"io"
    23  	"sync"
    24  
    25  	"google.golang.org/grpc"
    26  	"google.golang.org/protobuf/proto"
    27  	"google.golang.org/protobuf/types/known/emptypb"
    28  
    29  	"github.com/ledgerwatch/erigon-lib/gointerfaces/sentry"
    30  	"github.com/ledgerwatch/erigon-lib/gointerfaces/types"
    31  )
    32  
    33  const (
    34  	ETH65 = 65
    35  	ETH66 = 66
    36  	ETH67 = 67
    37  	ETH68 = 68
    38  )
    39  
    40  var ProtoIds = map[uint]map[sentry.MessageId]struct{}{
    41  	ETH65: {
    42  		sentry.MessageId_GET_BLOCK_HEADERS_65:             struct{}{},
    43  		sentry.MessageId_BLOCK_HEADERS_65:                 struct{}{},
    44  		sentry.MessageId_GET_BLOCK_BODIES_65:              struct{}{},
    45  		sentry.MessageId_BLOCK_BODIES_65:                  struct{}{},
    46  		sentry.MessageId_GET_NODE_DATA_65:                 struct{}{},
    47  		sentry.MessageId_NODE_DATA_65:                     struct{}{},
    48  		sentry.MessageId_GET_RECEIPTS_65:                  struct{}{},
    49  		sentry.MessageId_RECEIPTS_65:                      struct{}{},
    50  		sentry.MessageId_NEW_BLOCK_HASHES_65:              struct{}{},
    51  		sentry.MessageId_NEW_BLOCK_65:                     struct{}{},
    52  		sentry.MessageId_TRANSACTIONS_65:                  struct{}{},
    53  		sentry.MessageId_NEW_POOLED_TRANSACTION_HASHES_65: struct{}{},
    54  		sentry.MessageId_GET_POOLED_TRANSACTIONS_65:       struct{}{},
    55  		sentry.MessageId_POOLED_TRANSACTIONS_65:           struct{}{},
    56  	},
    57  	ETH66: {
    58  		sentry.MessageId_GET_BLOCK_HEADERS_66:             struct{}{},
    59  		sentry.MessageId_BLOCK_HEADERS_66:                 struct{}{},
    60  		sentry.MessageId_GET_BLOCK_BODIES_66:              struct{}{},
    61  		sentry.MessageId_BLOCK_BODIES_66:                  struct{}{},
    62  		sentry.MessageId_GET_NODE_DATA_66:                 struct{}{},
    63  		sentry.MessageId_NODE_DATA_66:                     struct{}{},
    64  		sentry.MessageId_GET_RECEIPTS_66:                  struct{}{},
    65  		sentry.MessageId_RECEIPTS_66:                      struct{}{},
    66  		sentry.MessageId_NEW_BLOCK_HASHES_66:              struct{}{},
    67  		sentry.MessageId_NEW_BLOCK_66:                     struct{}{},
    68  		sentry.MessageId_TRANSACTIONS_66:                  struct{}{},
    69  		sentry.MessageId_NEW_POOLED_TRANSACTION_HASHES_66: struct{}{},
    70  		sentry.MessageId_GET_POOLED_TRANSACTIONS_66:       struct{}{},
    71  		sentry.MessageId_POOLED_TRANSACTIONS_66:           struct{}{},
    72  	},
    73  	ETH67: {
    74  		sentry.MessageId_GET_BLOCK_HEADERS_66:             struct{}{},
    75  		sentry.MessageId_BLOCK_HEADERS_66:                 struct{}{},
    76  		sentry.MessageId_GET_BLOCK_BODIES_66:              struct{}{},
    77  		sentry.MessageId_BLOCK_BODIES_66:                  struct{}{},
    78  		sentry.MessageId_GET_RECEIPTS_66:                  struct{}{},
    79  		sentry.MessageId_RECEIPTS_66:                      struct{}{},
    80  		sentry.MessageId_NEW_BLOCK_HASHES_66:              struct{}{},
    81  		sentry.MessageId_NEW_BLOCK_66:                     struct{}{},
    82  		sentry.MessageId_TRANSACTIONS_66:                  struct{}{},
    83  		sentry.MessageId_NEW_POOLED_TRANSACTION_HASHES_66: struct{}{},
    84  		sentry.MessageId_GET_POOLED_TRANSACTIONS_66:       struct{}{},
    85  		sentry.MessageId_POOLED_TRANSACTIONS_66:           struct{}{},
    86  	},
    87  	ETH68: {
    88  		sentry.MessageId_GET_BLOCK_HEADERS_66:             struct{}{},
    89  		sentry.MessageId_BLOCK_HEADERS_66:                 struct{}{},
    90  		sentry.MessageId_GET_BLOCK_BODIES_66:              struct{}{},
    91  		sentry.MessageId_BLOCK_BODIES_66:                  struct{}{},
    92  		sentry.MessageId_GET_RECEIPTS_66:                  struct{}{},
    93  		sentry.MessageId_RECEIPTS_66:                      struct{}{},
    94  		sentry.MessageId_NEW_BLOCK_HASHES_66:              struct{}{},
    95  		sentry.MessageId_NEW_BLOCK_66:                     struct{}{},
    96  		sentry.MessageId_TRANSACTIONS_66:                  struct{}{},
    97  		sentry.MessageId_NEW_POOLED_TRANSACTION_HASHES_68: struct{}{},
    98  		sentry.MessageId_GET_POOLED_TRANSACTIONS_66:       struct{}{},
    99  		sentry.MessageId_POOLED_TRANSACTIONS_66:           struct{}{},
   100  	},
   101  }
   102  
   103  type SentryClient interface {
   104  	sentry.SentryClient
   105  	Protocol() uint
   106  	Ready() bool
   107  	MarkDisconnected()
   108  }
   109  
   110  type SentryClientRemote struct {
   111  	sentry.SentryClient
   112  	sync.RWMutex
   113  	protocol uint
   114  	ready    bool
   115  }
   116  
   117  var _ SentryClient = (*SentryClientRemote)(nil) // compile-time interface check
   118  var _ SentryClient = (*SentryClientDirect)(nil) // compile-time interface check
   119  
   120  // NewSentryClientRemote - app code must use this class
   121  // to avoid concurrency - it accepts protocol (which received async by SetStatus) in constructor,
   122  // means app can't use client which protocol unknown yet
   123  func NewSentryClientRemote(client sentry.SentryClient) *SentryClientRemote {
   124  	return &SentryClientRemote{SentryClient: client}
   125  }
   126  
   127  func (c *SentryClientRemote) Protocol() uint {
   128  	c.RLock()
   129  	defer c.RUnlock()
   130  	return c.protocol
   131  }
   132  
   133  func (c *SentryClientRemote) Ready() bool {
   134  	c.RLock()
   135  	defer c.RUnlock()
   136  	return c.ready
   137  }
   138  
   139  func (c *SentryClientRemote) MarkDisconnected() {
   140  	c.Lock()
   141  	defer c.Unlock()
   142  	c.ready = false
   143  }
   144  
   145  func (c *SentryClientRemote) HandShake(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*sentry.HandShakeReply, error) {
   146  	reply, err := c.SentryClient.HandShake(ctx, in, opts...)
   147  	if err != nil {
   148  		return nil, err
   149  	}
   150  	c.Lock()
   151  	defer c.Unlock()
   152  	switch reply.Protocol {
   153  	case sentry.Protocol_ETH65:
   154  		c.protocol = ETH65
   155  	case sentry.Protocol_ETH66:
   156  		c.protocol = ETH66
   157  	case sentry.Protocol_ETH67:
   158  		c.protocol = ETH67
   159  	case sentry.Protocol_ETH68:
   160  		c.protocol = ETH68
   161  	default:
   162  		return nil, fmt.Errorf("unexpected protocol: %d", reply.Protocol)
   163  	}
   164  	c.ready = true
   165  	return reply, nil
   166  }
   167  func (c *SentryClientRemote) SetStatus(ctx context.Context, in *sentry.StatusData, opts ...grpc.CallOption) (*sentry.SetStatusReply, error) {
   168  	return c.SentryClient.SetStatus(ctx, in, opts...)
   169  }
   170  
   171  func (c *SentryClientRemote) Messages(ctx context.Context, in *sentry.MessagesRequest, opts ...grpc.CallOption) (sentry.Sentry_MessagesClient, error) {
   172  	in.Ids = filterIds(in.Ids, c.Protocol())
   173  	return c.SentryClient.Messages(ctx, in, opts...)
   174  }
   175  
   176  func (c *SentryClientRemote) PeerCount(ctx context.Context, in *sentry.PeerCountRequest, opts ...grpc.CallOption) (*sentry.PeerCountReply, error) {
   177  	return c.SentryClient.PeerCount(ctx, in)
   178  }
   179  
   180  // Contains implementations of SentryServer, SentryClient, ControlClient, and ControlServer, that may be linked to each other
   181  // SentryClient is linked directly to the SentryServer, for example, so any function call on the instance of the SentryClient
   182  // cause invocations directly on the corresponding instance of the SentryServer. However, the link between SentryClient and
   183  // SentryServer is established outside of the constructor. This means that the reference from the SentyClient to the corresponding
   184  // SentryServer can be injected at any point in time.
   185  
   186  // SentryClientDirect implements SentryClient interface by connecting the instance of the client directly with the corresponding
   187  // instance of SentryServer
   188  type SentryClientDirect struct {
   189  	server   sentry.SentryServer
   190  	protocol uint
   191  }
   192  
   193  func NewSentryClientDirect(protocol uint, sentryServer sentry.SentryServer) *SentryClientDirect {
   194  	return &SentryClientDirect{protocol: protocol, server: sentryServer}
   195  }
   196  
   197  func (c *SentryClientDirect) Protocol() uint    { return c.protocol }
   198  func (c *SentryClientDirect) Ready() bool       { return true }
   199  func (c *SentryClientDirect) MarkDisconnected() {}
   200  
   201  func (c *SentryClientDirect) PenalizePeer(ctx context.Context, in *sentry.PenalizePeerRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
   202  	return c.server.PenalizePeer(ctx, in)
   203  }
   204  
   205  func (c *SentryClientDirect) PeerMinBlock(ctx context.Context, in *sentry.PeerMinBlockRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
   206  	return c.server.PeerMinBlock(ctx, in)
   207  }
   208  
   209  func (c *SentryClientDirect) SendMessageByMinBlock(ctx context.Context, in *sentry.SendMessageByMinBlockRequest, opts ...grpc.CallOption) (*sentry.SentPeers, error) {
   210  	return c.server.SendMessageByMinBlock(ctx, in)
   211  }
   212  
   213  func (c *SentryClientDirect) SendMessageById(ctx context.Context, in *sentry.SendMessageByIdRequest, opts ...grpc.CallOption) (*sentry.SentPeers, error) {
   214  	return c.server.SendMessageById(ctx, in)
   215  }
   216  
   217  func (c *SentryClientDirect) SendMessageToRandomPeers(ctx context.Context, in *sentry.SendMessageToRandomPeersRequest, opts ...grpc.CallOption) (*sentry.SentPeers, error) {
   218  	return c.server.SendMessageToRandomPeers(ctx, in)
   219  }
   220  
   221  func (c *SentryClientDirect) SendMessageToAll(ctx context.Context, in *sentry.OutboundMessageData, opts ...grpc.CallOption) (*sentry.SentPeers, error) {
   222  	return c.server.SendMessageToAll(ctx, in)
   223  }
   224  
   225  func (c *SentryClientDirect) HandShake(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*sentry.HandShakeReply, error) {
   226  	return c.server.HandShake(ctx, in)
   227  }
   228  
   229  func (c *SentryClientDirect) SetStatus(ctx context.Context, in *sentry.StatusData, opts ...grpc.CallOption) (*sentry.SetStatusReply, error) {
   230  	return c.server.SetStatus(ctx, in)
   231  }
   232  
   233  func (c *SentryClientDirect) Peers(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*sentry.PeersReply, error) {
   234  	return c.server.Peers(ctx, in)
   235  }
   236  
   237  func (c *SentryClientDirect) PeerCount(ctx context.Context, in *sentry.PeerCountRequest, opts ...grpc.CallOption) (*sentry.PeerCountReply, error) {
   238  	return c.server.PeerCount(ctx, in)
   239  }
   240  
   241  func (c *SentryClientDirect) PeerById(ctx context.Context, in *sentry.PeerByIdRequest, opts ...grpc.CallOption) (*sentry.PeerByIdReply, error) {
   242  	return c.server.PeerById(ctx, in)
   243  }
   244  
   245  // -- start Messages
   246  
   247  func (c *SentryClientDirect) Messages(ctx context.Context, in *sentry.MessagesRequest, opts ...grpc.CallOption) (sentry.Sentry_MessagesClient, error) {
   248  	in.Ids = filterIds(in.Ids, c.Protocol())
   249  	ch := make(chan *inboundMessageReply, 16384)
   250  	streamServer := &SentryMessagesStreamS{ch: ch, ctx: ctx}
   251  	go func() {
   252  		defer close(ch)
   253  		streamServer.Err(c.server.Messages(in, streamServer))
   254  	}()
   255  	return &SentryMessagesStreamC{ch: ch, ctx: ctx}, nil
   256  }
   257  
   258  type inboundMessageReply struct {
   259  	r   *sentry.InboundMessage
   260  	err error
   261  }
   262  
   263  // SentryMessagesStreamS implements proto_sentry.Sentry_ReceiveMessagesServer
   264  type SentryMessagesStreamS struct {
   265  	ch  chan *inboundMessageReply
   266  	ctx context.Context
   267  	grpc.ServerStream
   268  }
   269  
   270  func (s *SentryMessagesStreamS) Send(m *sentry.InboundMessage) error {
   271  	s.ch <- &inboundMessageReply{r: m}
   272  	return nil
   273  }
   274  
   275  func (s *SentryMessagesStreamS) Context() context.Context { return s.ctx }
   276  
   277  func (s *SentryMessagesStreamS) Err(err error) {
   278  	if err == nil {
   279  		return
   280  	}
   281  	s.ch <- &inboundMessageReply{err: err}
   282  }
   283  
   284  type SentryMessagesStreamC struct {
   285  	ch  chan *inboundMessageReply
   286  	ctx context.Context
   287  	grpc.ClientStream
   288  }
   289  
   290  func (c *SentryMessagesStreamC) Recv() (*sentry.InboundMessage, error) {
   291  	m, ok := <-c.ch
   292  	if !ok || m == nil {
   293  		return nil, io.EOF
   294  	}
   295  	return m.r, m.err
   296  }
   297  
   298  func (c *SentryMessagesStreamC) Context() context.Context { return c.ctx }
   299  
   300  func (c *SentryMessagesStreamC) RecvMsg(anyMessage interface{}) error {
   301  	m, err := c.Recv()
   302  	if err != nil {
   303  		return err
   304  	}
   305  	outMessage := anyMessage.(*sentry.InboundMessage)
   306  	proto.Merge(outMessage, m)
   307  	return nil
   308  }
   309  
   310  // -- end Messages
   311  // -- start Peers
   312  
   313  func (c *SentryClientDirect) PeerEvents(ctx context.Context, in *sentry.PeerEventsRequest, opts ...grpc.CallOption) (sentry.Sentry_PeerEventsClient, error) {
   314  	ch := make(chan *peersReply, 16384)
   315  	streamServer := &SentryPeersStreamS{ch: ch, ctx: ctx}
   316  	go func() {
   317  		defer close(ch)
   318  		streamServer.Err(c.server.PeerEvents(in, streamServer))
   319  	}()
   320  	return &SentryPeersStreamC{ch: ch, ctx: ctx}, nil
   321  }
   322  
   323  func (c *SentryClientDirect) AddPeer(ctx context.Context, in *sentry.AddPeerRequest, opts ...grpc.CallOption) (*sentry.AddPeerReply, error) {
   324  	return c.server.AddPeer(ctx, in)
   325  }
   326  
   327  type peersReply struct {
   328  	r   *sentry.PeerEvent
   329  	err error
   330  }
   331  
   332  // SentryPeersStreamS - implements proto_sentry.Sentry_ReceivePeersServer
   333  type SentryPeersStreamS struct {
   334  	ch  chan *peersReply
   335  	ctx context.Context
   336  	grpc.ServerStream
   337  }
   338  
   339  func (s *SentryPeersStreamS) Send(m *sentry.PeerEvent) error {
   340  	s.ch <- &peersReply{r: m}
   341  	return nil
   342  }
   343  
   344  func (s *SentryPeersStreamS) Context() context.Context { return s.ctx }
   345  
   346  func (s *SentryPeersStreamS) Err(err error) {
   347  	if err == nil {
   348  		return
   349  	}
   350  	s.ch <- &peersReply{err: err}
   351  }
   352  
   353  type SentryPeersStreamC struct {
   354  	ch  chan *peersReply
   355  	ctx context.Context
   356  	grpc.ClientStream
   357  }
   358  
   359  func (c *SentryPeersStreamC) Recv() (*sentry.PeerEvent, error) {
   360  	m, ok := <-c.ch
   361  	if !ok || m == nil {
   362  		return nil, io.EOF
   363  	}
   364  	return m.r, m.err
   365  }
   366  
   367  func (c *SentryPeersStreamC) Context() context.Context { return c.ctx }
   368  
   369  func (c *SentryPeersStreamC) RecvMsg(anyMessage interface{}) error {
   370  	m, err := c.Recv()
   371  	if err != nil {
   372  		return err
   373  	}
   374  	outMessage := anyMessage.(*sentry.PeerEvent)
   375  	proto.Merge(outMessage, m)
   376  	return nil
   377  }
   378  
   379  // -- end Peers
   380  
   381  func (c *SentryClientDirect) NodeInfo(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*types.NodeInfoReply, error) {
   382  	return c.server.NodeInfo(ctx, in)
   383  }
   384  
   385  func filterIds(in []sentry.MessageId, protocol uint) (filtered []sentry.MessageId) {
   386  	for _, id := range in {
   387  		if _, ok := ProtoIds[protocol][id]; ok {
   388  			filtered = append(filtered, id)
   389  		}
   390  	}
   391  	return filtered
   392  }