github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/sync/rpc_ping.go (about) 1 package sync 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "strings" 8 9 libp2pcore "github.com/libp2p/go-libp2p-core" 10 "github.com/libp2p/go-libp2p-core/peer" 11 types "github.com/prysmaticlabs/eth2-types" 12 "github.com/prysmaticlabs/prysm/beacon-chain/p2p" 13 p2ptypes "github.com/prysmaticlabs/prysm/beacon-chain/p2p/types" 14 "github.com/prysmaticlabs/prysm/shared/timeutils" 15 ) 16 17 // pingHandler reads the incoming ping rpc message from the peer. 18 func (s *Service) pingHandler(_ context.Context, msg interface{}, stream libp2pcore.Stream) error { 19 SetRPCStreamDeadlines(stream) 20 21 m, ok := msg.(*types.SSZUint64) 22 if !ok { 23 return fmt.Errorf("wrong message type for ping, got %T, wanted *uint64", msg) 24 } 25 if err := s.rateLimiter.validateRequest(stream, 1); err != nil { 26 return err 27 } 28 s.rateLimiter.add(stream, 1) 29 valid, err := s.validateSequenceNum(*m, stream.Conn().RemotePeer()) 30 if err != nil { 31 // Descore peer for giving us a bad sequence number. 32 if errors.Is(err, p2ptypes.ErrInvalidSequenceNum) { 33 s.cfg.P2P.Peers().Scorers().BadResponsesScorer().Increment(stream.Conn().RemotePeer()) 34 s.writeErrorResponseToStream(responseCodeInvalidRequest, p2ptypes.ErrInvalidSequenceNum.Error(), stream) 35 } 36 return err 37 } 38 if _, err := stream.Write([]byte{responseCodeSuccess}); err != nil { 39 return err 40 } 41 sq := types.SSZUint64(s.cfg.P2P.MetadataSeq()) 42 if _, err := s.cfg.P2P.Encoding().EncodeWithMaxLength(stream, &sq); err != nil { 43 return err 44 } 45 46 closeStream(stream, log) 47 48 if valid { 49 // If the sequence number was valid we're done. 50 return nil 51 } 52 53 // The sequence number was not valid. Start our own ping back to the peer. 54 go func() { 55 // New context so the calling function doesn't cancel on us. 56 ctx, cancel := context.WithTimeout(context.Background(), ttfbTimeout) 57 defer cancel() 58 md, err := s.sendMetaDataRequest(ctx, stream.Conn().RemotePeer()) 59 if err != nil { 60 // We cannot compare errors directly as the stream muxer error 61 // type isn't compatible with the error we have, so a direct 62 // equality checks fails. 63 if !strings.Contains(err.Error(), p2ptypes.ErrIODeadline.Error()) { 64 log.WithField("peer", stream.Conn().RemotePeer()).WithError(err).Debug("Could not send metadata request") 65 } 66 return 67 } 68 // update metadata if there is no error 69 s.cfg.P2P.Peers().SetMetadata(stream.Conn().RemotePeer(), md) 70 }() 71 72 return nil 73 } 74 75 func (s *Service) sendPingRequest(ctx context.Context, id peer.ID) error { 76 ctx, cancel := context.WithTimeout(ctx, respTimeout) 77 defer cancel() 78 79 metadataSeq := types.SSZUint64(s.cfg.P2P.MetadataSeq()) 80 stream, err := s.cfg.P2P.Send(ctx, &metadataSeq, p2p.RPCPingTopicV1, id) 81 if err != nil { 82 return err 83 } 84 currentTime := timeutils.Now() 85 defer closeStream(stream, log) 86 87 code, errMsg, err := ReadStatusCode(stream, s.cfg.P2P.Encoding()) 88 if err != nil { 89 return err 90 } 91 // Records the latency of the ping request for that peer. 92 s.cfg.P2P.Host().Peerstore().RecordLatency(id, timeutils.Now().Sub(currentTime)) 93 94 if code != 0 { 95 s.cfg.P2P.Peers().Scorers().BadResponsesScorer().Increment(stream.Conn().RemotePeer()) 96 return errors.New(errMsg) 97 } 98 // No-op for now with the rpc context. 99 _, err = readContextFromStream(stream, s.cfg.Chain) 100 if err != nil { 101 return err 102 } 103 msg := new(types.SSZUint64) 104 if err := s.cfg.P2P.Encoding().DecodeWithMaxLength(stream, msg); err != nil { 105 return err 106 } 107 valid, err := s.validateSequenceNum(*msg, stream.Conn().RemotePeer()) 108 if err != nil { 109 // Descore peer for giving us a bad sequence number. 110 if errors.Is(err, p2ptypes.ErrInvalidSequenceNum) { 111 s.cfg.P2P.Peers().Scorers().BadResponsesScorer().Increment(stream.Conn().RemotePeer()) 112 } 113 return err 114 } 115 if valid { 116 return nil 117 } 118 md, err := s.sendMetaDataRequest(ctx, stream.Conn().RemotePeer()) 119 if err != nil { 120 // do not increment bad responses, as its 121 // already done in the request method. 122 return err 123 } 124 s.cfg.P2P.Peers().SetMetadata(stream.Conn().RemotePeer(), md) 125 return nil 126 } 127 128 // validates the peer's sequence number. 129 func (s *Service) validateSequenceNum(seq types.SSZUint64, id peer.ID) (bool, error) { 130 md, err := s.cfg.P2P.Peers().Metadata(id) 131 if err != nil { 132 return false, err 133 } 134 if md == nil || md.IsNil() { 135 return false, nil 136 } 137 // Return error on invalid sequence number. 138 if md.SequenceNumber() > uint64(seq) { 139 return false, p2ptypes.ErrInvalidSequenceNum 140 } 141 return md.SequenceNumber() == uint64(seq), nil 142 }