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 }