github.com/amazechain/amc@v0.1.3/internal/p2p/rpc_topic_mappings.go (about) 1 package p2p 2 3 import ( 4 "github.com/amazechain/amc/api/protocol/sync_pb" 5 ssztype "github.com/amazechain/amc/common/types/ssz" 6 "reflect" 7 8 "github.com/pkg/errors" 9 ) 10 11 // SchemaVersionV1 specifies the schema version for our rpc protocol ID. 12 const SchemaVersionV1 = "/1" 13 14 // Specifies the protocol prefix for all our Req/Resp topics. 15 const protocolPrefix = "/rpc" 16 17 // StatusMessageName specifies the name for the status message topic. 18 const StatusMessageName = "/status" 19 20 // GoodbyeMessageName specifies the name for the goodbye message topic. 21 const GoodbyeMessageName = "/goodbye" 22 23 // PingMessageName Specifies the name for the ping message topic. 24 const PingMessageName = "/ping" 25 26 // BodiesByRangeMessageName specifies the name for the Bodies by range message topic. 27 const BodiesByRangeMessageName = "/bodies_by_range" 28 29 // HeadersByRangeMessageName specifies the name for the Headers by range message topic. 30 const HeadersByRangeMessageName = "/headers_by_range" 31 32 const ( 33 // V1 RPC Topics 34 // RPCStatusTopicV1 defines the v1 topic for the status rpc method. 35 RPCStatusTopicV1 = protocolPrefix + StatusMessageName + SchemaVersionV1 36 // RPCGoodByeTopicV1 defines the v1 topic for the goodbye rpc method. 37 RPCGoodByeTopicV1 = protocolPrefix + GoodbyeMessageName + SchemaVersionV1 38 // RPCPingTopicV1 defines the v1 topic for the ping rpc method. 39 RPCPingTopicV1 = protocolPrefix + PingMessageName + SchemaVersionV1 40 41 // RPCBodiesDataTopicV1 defines the v1 topic for the Bodies rpc method. 42 RPCBodiesDataTopicV1 = protocolPrefix + BodiesByRangeMessageName + SchemaVersionV1 43 44 // RPCHeadersDataTopicV1 defines the v1 topic for the Headers rpc method. 45 RPCHeadersDataTopicV1 = protocolPrefix + HeadersByRangeMessageName + SchemaVersionV1 46 ) 47 48 // RPC errors for topic parsing. 49 const ( 50 invalidRPCMessageType = "provided message type doesn't have a registered mapping" 51 ) 52 53 // RPCTopicMappings map the base message type to the rpc request. 54 var RPCTopicMappings = map[string]interface{}{ 55 // RPC Status Message 56 RPCStatusTopicV1: new(sync_pb.Status), 57 RPCBodiesDataTopicV1: new(sync_pb.BodiesByRangeRequest), 58 59 RPCPingTopicV1: new(ssztype.SSZUint64), 60 RPCGoodByeTopicV1: new(ssztype.SSZUint64), 61 } 62 63 // Maps all registered protocol prefixes. 64 var protocolMapping = map[string]bool{ 65 protocolPrefix: true, 66 } 67 68 // Maps all the protocol message names for the different rpc 69 // topics. 70 var messageMapping = map[string]bool{ 71 StatusMessageName: true, 72 GoodbyeMessageName: true, 73 PingMessageName: true, 74 BodiesByRangeMessageName: true, 75 HeadersByRangeMessageName: 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 } 190 191 // TopicFromMessage constructs the rpc topic from the provided message 192 // type and epoch. 193 func TopicFromMessage(msg string) (string, error) { 194 if !messageMapping[msg] { 195 return "", errors.Errorf("%s: %s", invalidRPCMessageType, msg) 196 } 197 version := SchemaVersionV1 198 199 return protocolPrefix + msg + version, nil 200 }