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

     1  package p2p
     2  
     3  import (
     4  	"reflect"
     5  
     6  	"github.com/pkg/errors"
     7  	types "github.com/prysmaticlabs/eth2-types"
     8  	p2ptypes "github.com/prysmaticlabs/prysm/beacon-chain/p2p/types"
     9  	pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
    10  )
    11  
    12  // SchemaVersionV1 specifies the schema version for our rpc protocol ID.
    13  const SchemaVersionV1 = "/1"
    14  
    15  // Specifies the protocol prefix for all our Req/Resp topics.
    16  const protocolPrefix = "/eth2/beacon_chain/req"
    17  
    18  // Specifies the name for the status message topic.
    19  const statusMessageName = "/status"
    20  
    21  // Specifies the name for the goodbye message topic.
    22  const goodbyeMessageName = "/goodbye"
    23  
    24  // Specifies the name for the beacon blocks by range message topic.
    25  const beaconBlocksByRangeMessageName = "/beacon_blocks_by_range"
    26  
    27  // Specifies the name for the beacon blocks by root message topic.
    28  const beaconBlocksByRootsMessageName = "/beacon_blocks_by_root"
    29  
    30  // Specifies the name for the ping message topic.
    31  const pingMessageName = "/ping"
    32  
    33  // Specifies the name for the metadata message topic.
    34  const metadataMessageName = "/metadata"
    35  
    36  const (
    37  	// V1 RPC Topics
    38  	// RPCStatusTopicV1 defines the v1 topic for the status rpc method.
    39  	RPCStatusTopicV1 = protocolPrefix + statusMessageName + SchemaVersionV1
    40  	// RPCGoodByeTopicV1 defines the v1 topic for the goodbye rpc method.
    41  	RPCGoodByeTopicV1 = protocolPrefix + goodbyeMessageName + SchemaVersionV1
    42  	// RPCBlocksByRangeTopicV1 defines v1 the topic for the blocks by range rpc method.
    43  	RPCBlocksByRangeTopicV1 = protocolPrefix + beaconBlocksByRangeMessageName + SchemaVersionV1
    44  	// RPCBlocksByRootTopicV1 defines the v1 topic for the blocks by root rpc method.
    45  	RPCBlocksByRootTopicV1 = protocolPrefix + beaconBlocksByRootsMessageName + SchemaVersionV1
    46  	// RPCPingTopicV1 defines the v1 topic for the ping rpc method.
    47  	RPCPingTopicV1 = protocolPrefix + pingMessageName + SchemaVersionV1
    48  	// RPCMetaDataTopicV1 defines the v1 topic for the metadata rpc method.
    49  	RPCMetaDataTopicV1 = protocolPrefix + metadataMessageName + SchemaVersionV1
    50  )
    51  
    52  // RPCTopicMappings map the base message type to the rpc request.
    53  var RPCTopicMappings = map[string]interface{}{
    54  	RPCStatusTopicV1:        new(pb.Status),
    55  	RPCGoodByeTopicV1:       new(types.SSZUint64),
    56  	RPCBlocksByRangeTopicV1: new(pb.BeaconBlocksByRangeRequest),
    57  	RPCBlocksByRootTopicV1:  new(p2ptypes.BeaconBlockByRootsReq),
    58  	RPCPingTopicV1:          new(types.SSZUint64),
    59  	RPCMetaDataTopicV1:      new(interface{}),
    60  }
    61  
    62  // Maps all registered protocol prefixes.
    63  var protocolMapping = map[string]bool{
    64  	protocolPrefix: true,
    65  }
    66  
    67  // Maps all the protocol message names for the different rpc
    68  // topics.
    69  var messageMapping = map[string]bool{
    70  	statusMessageName:              true,
    71  	goodbyeMessageName:             true,
    72  	beaconBlocksByRangeMessageName: true,
    73  	beaconBlocksByRootsMessageName: true,
    74  	pingMessageName:                true,
    75  	metadataMessageName:            true,
    76  }
    77  
    78  var versionMapping = map[string]bool{
    79  	SchemaVersionV1: true,
    80  }
    81  
    82  // VerifyTopicMapping verifies that the topic and its accompanying
    83  // message type is correct.
    84  func VerifyTopicMapping(topic string, msg interface{}) error {
    85  	msgType, ok := RPCTopicMappings[topic]
    86  	if !ok {
    87  		return errors.New("rpc topic is not registered currently")
    88  	}
    89  	receivedType := reflect.TypeOf(msg)
    90  	registeredType := reflect.TypeOf(msgType)
    91  	typeMatches := registeredType.AssignableTo(receivedType)
    92  
    93  	if !typeMatches {
    94  		return errors.Errorf("accompanying message type is incorrect for topic: wanted %v  but got %v",
    95  			registeredType.String(), receivedType.String())
    96  	}
    97  	return nil
    98  }
    99  
   100  // TopicDeconstructor splits the provided topic to its logical sub-sections.
   101  // It is assumed all input topics will follow the specific schema:
   102  // /protocol-prefix/message-name/schema-version/...
   103  // For the purposes of deconstruction, only the first 3 components are
   104  // relevant.
   105  func TopicDeconstructor(topic string) (string, string, string, error) {
   106  	origTopic := topic
   107  	protPrefix := ""
   108  	message := ""
   109  	version := ""
   110  
   111  	// Iterate through all the relevant mappings to find the relevant prefixes,messages
   112  	// and version for this topic.
   113  	for k := range protocolMapping {
   114  		keyLen := len(k)
   115  		if keyLen > len(topic) {
   116  			continue
   117  		}
   118  		if topic[:keyLen] == k {
   119  			protPrefix = k
   120  			topic = topic[keyLen:]
   121  		}
   122  	}
   123  
   124  	if protPrefix == "" {
   125  		return "", "", "", errors.Errorf("unable to find a valid protocol prefix for %s", origTopic)
   126  	}
   127  
   128  	for k := range messageMapping {
   129  		keyLen := len(k)
   130  		if keyLen > len(topic) {
   131  			continue
   132  		}
   133  		if topic[:keyLen] == k {
   134  			message = k
   135  			topic = topic[keyLen:]
   136  		}
   137  	}
   138  
   139  	if message == "" {
   140  		return "", "", "", errors.Errorf("unable to find a valid message for %s", origTopic)
   141  	}
   142  
   143  	for k := range versionMapping {
   144  		keyLen := len(k)
   145  		if keyLen > len(topic) {
   146  			continue
   147  		}
   148  		if topic[:keyLen] == k {
   149  			version = k
   150  			topic = topic[keyLen:]
   151  		}
   152  	}
   153  
   154  	if version == "" {
   155  		return "", "", "", errors.Errorf("unable to find a valid schema version for %s", origTopic)
   156  	}
   157  
   158  	return protPrefix, message, version, nil
   159  }
   160  
   161  // RPCTopic is a type used to denote and represent a req/resp topic.
   162  type RPCTopic string
   163  
   164  // ProtocolPrefix returns the protocol prefix of the rpc topic.
   165  func (r RPCTopic) ProtocolPrefix() string {
   166  	prefix, _, _, err := TopicDeconstructor(string(r))
   167  	if err != nil {
   168  		return ""
   169  	}
   170  	return prefix
   171  }
   172  
   173  // MessageType returns the message type of the rpc topic.
   174  func (r RPCTopic) MessageType() string {
   175  	_, message, _, err := TopicDeconstructor(string(r))
   176  	if err != nil {
   177  		return ""
   178  	}
   179  	return message
   180  }
   181  
   182  // Version returns the schema version of the rpc topic.
   183  func (r RPCTopic) Version() string {
   184  	_, _, version, err := TopicDeconstructor(string(r))
   185  	if err != nil {
   186  		return ""
   187  	}
   188  	return version
   189  }