github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/sync/error.go (about)

     1  package sync
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  
     7  	libp2pcore "github.com/libp2p/go-libp2p-core"
     8  	"github.com/libp2p/go-libp2p-core/mux"
     9  	"github.com/libp2p/go-libp2p-core/network"
    10  	"github.com/prysmaticlabs/prysm/beacon-chain/p2p"
    11  	"github.com/prysmaticlabs/prysm/beacon-chain/p2p/encoder"
    12  	"github.com/prysmaticlabs/prysm/beacon-chain/p2p/types"
    13  	"github.com/prysmaticlabs/prysm/shared/params"
    14  	"github.com/sirupsen/logrus"
    15  )
    16  
    17  var responseCodeSuccess = byte(0x00)
    18  var responseCodeInvalidRequest = byte(0x01)
    19  var responseCodeServerError = byte(0x02)
    20  
    21  func (s *Service) generateErrorResponse(code byte, reason string) ([]byte, error) {
    22  	return createErrorResponse(code, reason, s.cfg.P2P)
    23  }
    24  
    25  // ReadStatusCode response from a RPC stream.
    26  func ReadStatusCode(stream network.Stream, encoding encoder.NetworkEncoding) (uint8, string, error) {
    27  	// Set ttfb deadline.
    28  	SetStreamReadDeadline(stream, params.BeaconNetworkConfig().TtfbTimeout)
    29  	b := make([]byte, 1)
    30  	_, err := stream.Read(b)
    31  	if err != nil {
    32  		return 0, "", err
    33  	}
    34  
    35  	if b[0] == responseCodeSuccess {
    36  		// Set response deadline on a successful response code.
    37  		SetStreamReadDeadline(stream, params.BeaconNetworkConfig().RespTimeout)
    38  
    39  		return 0, "", nil
    40  	}
    41  
    42  	// Set response deadline, when reading error message.
    43  	SetStreamReadDeadline(stream, params.BeaconNetworkConfig().RespTimeout)
    44  	msg := &types.ErrorMessage{}
    45  	if err := encoding.DecodeWithMaxLength(stream, msg); err != nil {
    46  		return 0, "", err
    47  	}
    48  
    49  	return b[0], string(*msg), nil
    50  }
    51  
    52  func writeErrorResponseToStream(responseCode byte, reason string, stream libp2pcore.Stream, encoder p2p.EncodingProvider) {
    53  	resp, err := createErrorResponse(responseCode, reason, encoder)
    54  	if err != nil {
    55  		log.WithError(err).Debug("Could not generate a response error")
    56  	} else if _, err := stream.Write(resp); err != nil {
    57  		log.WithError(err).Debugf("Could not write to stream")
    58  	} else {
    59  		// If sending the error message succeeded, close to send an EOF.
    60  		closeStream(stream, log)
    61  	}
    62  }
    63  
    64  func createErrorResponse(code byte, reason string, encoder p2p.EncodingProvider) ([]byte, error) {
    65  	buf := bytes.NewBuffer([]byte{code})
    66  	errMsg := types.ErrorMessage(reason)
    67  	if _, err := encoder.Encoding().EncodeWithMaxLength(buf, &errMsg); err != nil {
    68  		return nil, err
    69  	}
    70  
    71  	return buf.Bytes(), nil
    72  }
    73  
    74  // reads data from the stream without applying any timeouts.
    75  func readStatusCodeNoDeadline(stream network.Stream, encoding encoder.NetworkEncoding) (uint8, string, error) {
    76  	b := make([]byte, 1)
    77  	_, err := stream.Read(b)
    78  	if err != nil {
    79  		return 0, "", err
    80  	}
    81  
    82  	if b[0] == responseCodeSuccess {
    83  		return 0, "", nil
    84  	}
    85  
    86  	msg := &types.ErrorMessage{}
    87  	if err := encoding.DecodeWithMaxLength(stream, msg); err != nil {
    88  		return 0, "", err
    89  	}
    90  
    91  	return b[0], string(*msg), nil
    92  }
    93  
    94  // only returns true for errors that are valid (no resets or expectedEOF errors).
    95  func isValidStreamError(err error) bool {
    96  	// check the error message itself as well as libp2p doesn't currently
    97  	// return the correct error type from Close{Read,Write,}.
    98  	return err != nil && !errors.Is(err, mux.ErrReset) && err.Error() != mux.ErrReset.Error()
    99  }
   100  
   101  func closeStream(stream network.Stream, log *logrus.Entry) {
   102  	if err := stream.Close(); isValidStreamError(err) {
   103  		log.WithError(err).Debugf("Could not reset stream with protocol %s", stream.Protocol())
   104  	}
   105  }
   106  
   107  func closeStreamAndWait(stream network.Stream, log *logrus.Entry) {
   108  	if err := stream.CloseWrite(); err != nil {
   109  		_err := stream.Reset()
   110  		_ = _err
   111  		if isValidStreamError(err) {
   112  			log.WithError(err).Debugf("Could not reset stream with protocol %s", stream.Protocol())
   113  		}
   114  		return
   115  	}
   116  	// Wait for the remote side to respond.
   117  	//
   118  	// 1. On success, we expect to read an EOF (remote side received our
   119  	//    response and closed the stream.
   120  	// 2. On failure (e.g., disconnect), we expect to receive an error.
   121  	// 3. If the remote side misbehaves, we may receive data.
   122  	//
   123  	// However, regardless of what happens, we just close the stream and
   124  	// walk away. We only read to wait for a response, we close regardless.
   125  	_, _err := stream.Read([]byte{0})
   126  	_ = _err
   127  	_err = stream.Close()
   128  	_ = _err
   129  }