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  }