11use crate :: rpc:: methods:: * ;
2- use crate :: rpc:: {
3- codec:: base:: OutboundCodec ,
4- protocol:: { Encoding , ProtocolId , RPCError , SupportedProtocol , ERROR_TYPE_MAX , ERROR_TYPE_MIN } ,
2+ use crate :: rpc:: protocol:: {
3+ Encoding , ProtocolId , RPCError , SupportedProtocol , ERROR_TYPE_MAX , ERROR_TYPE_MIN ,
54} ;
65use crate :: rpc:: { InboundRequest , OutboundRequest } ;
6+ use libp2p:: bytes:: BufMut ;
77use libp2p:: bytes:: BytesMut ;
88use snap:: read:: FrameDecoder ;
99use snap:: write:: FrameEncoder ;
@@ -57,13 +57,13 @@ impl<E: EthSpec> SSZSnappyInboundCodec<E> {
5757 max_packet_size,
5858 }
5959 }
60- }
6160
62- // Encoder for inbound streams: Encodes RPC Responses sent to peers.
63- impl < E : EthSpec > Encoder < RPCCodedResponse < E > > for SSZSnappyInboundCodec < E > {
64- type Error = RPCError ;
65-
66- fn encode ( & mut self , item : RPCCodedResponse < E > , dst : & mut BytesMut ) -> Result < ( ) , Self :: Error > {
61+ /// Encodes RPC Responses sent to peers.
62+ fn encode_response (
63+ & mut self ,
64+ item : RPCCodedResponse < E > ,
65+ dst : & mut BytesMut ,
66+ ) -> Result < ( ) , RPCError > {
6767 let bytes = match & item {
6868 RPCCodedResponse :: Success ( resp) => match & resp {
6969 RPCResponse :: Status ( res) => res. as_ssz_bytes ( ) ,
@@ -125,6 +125,21 @@ impl<E: EthSpec> Encoder<RPCCodedResponse<E>> for SSZSnappyInboundCodec<E> {
125125 }
126126}
127127
128+ // Encoder for inbound streams: Encodes RPC Responses sent to peers.
129+ impl < E : EthSpec > Encoder < RPCCodedResponse < E > > for SSZSnappyInboundCodec < E > {
130+ type Error = RPCError ;
131+
132+ fn encode ( & mut self , item : RPCCodedResponse < E > , dst : & mut BytesMut ) -> Result < ( ) , Self :: Error > {
133+ dst. clear ( ) ;
134+ dst. reserve ( 1 ) ;
135+ dst. put_u8 (
136+ item. as_u8 ( )
137+ . expect ( "Should never encode a stream termination" ) ,
138+ ) ;
139+ self . encode_response ( item, dst)
140+ }
141+ }
142+
128143// Decoder for inbound streams: Decodes RPC requests from peers
129144impl < E : EthSpec > Decoder for SSZSnappyInboundCodec < E > {
130145 type Item = InboundRequest < E > ;
@@ -188,6 +203,8 @@ pub struct SSZSnappyOutboundCodec<E: EthSpec> {
188203 /// The fork name corresponding to the received context bytes.
189204 fork_name : Option < ForkName > ,
190205 fork_context : Arc < ForkContext > ,
206+ /// Keeps track of the current response code for a chunk.
207+ current_response_code : Option < u8 > ,
191208 phantom : PhantomData < E > ,
192209}
193210
@@ -209,66 +226,12 @@ impl<E: EthSpec> SSZSnappyOutboundCodec<E> {
209226 fork_name : None ,
210227 fork_context,
211228 phantom : PhantomData ,
229+ current_response_code : None ,
212230 }
213231 }
214- }
215-
216- // Encoder for outbound streams: Encodes RPC Requests to peers
217- impl < E : EthSpec > Encoder < OutboundRequest < E > > for SSZSnappyOutboundCodec < E > {
218- type Error = RPCError ;
219-
220- fn encode ( & mut self , item : OutboundRequest < E > , dst : & mut BytesMut ) -> Result < ( ) , Self :: Error > {
221- let bytes = match item {
222- OutboundRequest :: Status ( req) => req. as_ssz_bytes ( ) ,
223- OutboundRequest :: Goodbye ( req) => req. as_ssz_bytes ( ) ,
224- OutboundRequest :: BlocksByRange ( r) => match r {
225- OldBlocksByRangeRequest :: V1 ( req) => req. as_ssz_bytes ( ) ,
226- OldBlocksByRangeRequest :: V2 ( req) => req. as_ssz_bytes ( ) ,
227- } ,
228- OutboundRequest :: BlocksByRoot ( r) => match r {
229- BlocksByRootRequest :: V1 ( req) => req. block_roots . as_ssz_bytes ( ) ,
230- BlocksByRootRequest :: V2 ( req) => req. block_roots . as_ssz_bytes ( ) ,
231- } ,
232- OutboundRequest :: BlobsByRange ( req) => req. as_ssz_bytes ( ) ,
233- OutboundRequest :: BlobsByRoot ( req) => req. blob_ids . as_ssz_bytes ( ) ,
234- OutboundRequest :: DataColumnsByRange ( req) => req. as_ssz_bytes ( ) ,
235- OutboundRequest :: DataColumnsByRoot ( req) => req. data_column_ids . as_ssz_bytes ( ) ,
236- OutboundRequest :: Ping ( req) => req. as_ssz_bytes ( ) ,
237- OutboundRequest :: MetaData ( _) => return Ok ( ( ) ) , // no metadata to encode
238- } ;
239- // SSZ encoded bytes should be within `max_packet_size`
240- if bytes. len ( ) > self . max_packet_size {
241- return Err ( RPCError :: InternalError (
242- "attempting to encode data > max_packet_size" ,
243- ) ) ;
244- }
245232
246- // Inserts the length prefix of the uncompressed bytes into dst
247- // encoded as a unsigned varint
248- self . inner
249- . encode ( bytes. len ( ) , dst)
250- . map_err ( RPCError :: from) ?;
251-
252- let mut writer = FrameEncoder :: new ( Vec :: new ( ) ) ;
253- writer. write_all ( & bytes) . map_err ( RPCError :: from) ?;
254- writer. flush ( ) . map_err ( RPCError :: from) ?;
255-
256- // Write compressed bytes to `dst`
257- dst. extend_from_slice ( writer. get_ref ( ) ) ;
258- Ok ( ( ) )
259- }
260- }
261-
262- // Decoder for outbound streams: Decodes RPC responses from peers.
263- //
264- // The majority of the decoding has now been pushed upstream due to the changing specification.
265- // We prefer to decode blocks and attestations with extra knowledge about the chain to perform
266- // faster verification checks before decoding entire blocks/attestations.
267- impl < E : EthSpec > Decoder for SSZSnappyOutboundCodec < E > {
268- type Item = RPCResponse < E > ;
269- type Error = RPCError ;
270-
271- fn decode ( & mut self , src : & mut BytesMut ) -> Result < Option < Self :: Item > , Self :: Error > {
233+ // Decode an Rpc response.
234+ fn decode_response ( & mut self , src : & mut BytesMut ) -> Result < Option < RPCResponse < E > > , RPCError > {
272235 // Read the context bytes if required
273236 if self . protocol . has_context_bytes ( ) && self . fork_name . is_none ( ) {
274237 if src. len ( ) >= CONTEXT_BYTES_LEN {
@@ -318,15 +281,8 @@ impl<E: EthSpec> Decoder for SSZSnappyOutboundCodec<E> {
318281 Err ( e) => handle_error ( e, reader. get_ref ( ) . get_ref ( ) . position ( ) , max_compressed_len) ,
319282 }
320283 }
321- }
322-
323- impl < E : EthSpec > OutboundCodec < OutboundRequest < E > > for SSZSnappyOutboundCodec < E > {
324- type CodecErrorType = ErrorType ;
325284
326- fn decode_error (
327- & mut self ,
328- src : & mut BytesMut ,
329- ) -> Result < Option < Self :: CodecErrorType > , RPCError > {
285+ fn decode_error ( & mut self , src : & mut BytesMut ) -> Result < Option < ErrorType > , RPCError > {
330286 let Some ( length) = handle_length ( & mut self . inner , & mut self . len , src) ? else {
331287 return Ok ( None ) ;
332288 } ;
@@ -361,6 +317,95 @@ impl<E: EthSpec> OutboundCodec<OutboundRequest<E>> for SSZSnappyOutboundCodec<E>
361317 }
362318}
363319
320+ // Encoder for outbound streams: Encodes RPC Requests to peers
321+ impl < E : EthSpec > Encoder < OutboundRequest < E > > for SSZSnappyOutboundCodec < E > {
322+ type Error = RPCError ;
323+
324+ fn encode ( & mut self , item : OutboundRequest < E > , dst : & mut BytesMut ) -> Result < ( ) , Self :: Error > {
325+ let bytes = match item {
326+ OutboundRequest :: Status ( req) => req. as_ssz_bytes ( ) ,
327+ OutboundRequest :: Goodbye ( req) => req. as_ssz_bytes ( ) ,
328+ OutboundRequest :: BlocksByRange ( r) => match r {
329+ OldBlocksByRangeRequest :: V1 ( req) => req. as_ssz_bytes ( ) ,
330+ OldBlocksByRangeRequest :: V2 ( req) => req. as_ssz_bytes ( ) ,
331+ } ,
332+ OutboundRequest :: BlocksByRoot ( r) => match r {
333+ BlocksByRootRequest :: V1 ( req) => req. block_roots . as_ssz_bytes ( ) ,
334+ BlocksByRootRequest :: V2 ( req) => req. block_roots . as_ssz_bytes ( ) ,
335+ } ,
336+ OutboundRequest :: BlobsByRange ( req) => req. as_ssz_bytes ( ) ,
337+ OutboundRequest :: BlobsByRoot ( req) => req. blob_ids . as_ssz_bytes ( ) ,
338+ OutboundRequest :: DataColumnsByRange ( req) => req. as_ssz_bytes ( ) ,
339+ OutboundRequest :: DataColumnsByRoot ( req) => req. data_column_ids . as_ssz_bytes ( ) ,
340+ OutboundRequest :: Ping ( req) => req. as_ssz_bytes ( ) ,
341+ OutboundRequest :: MetaData ( _) => return Ok ( ( ) ) , // no metadata to encode
342+ } ;
343+ // SSZ encoded bytes should be within `max_packet_size`
344+ if bytes. len ( ) > self . max_packet_size {
345+ return Err ( RPCError :: InternalError (
346+ "attempting to encode data > max_packet_size" ,
347+ ) ) ;
348+ }
349+
350+ // Inserts the length prefix of the uncompressed bytes into dst
351+ // encoded as a unsigned varint
352+ self . inner
353+ . encode ( bytes. len ( ) , dst)
354+ . map_err ( RPCError :: from) ?;
355+
356+ let mut writer = FrameEncoder :: new ( Vec :: new ( ) ) ;
357+ writer. write_all ( & bytes) . map_err ( RPCError :: from) ?;
358+ writer. flush ( ) . map_err ( RPCError :: from) ?;
359+
360+ // Write compressed bytes to `dst`
361+ dst. extend_from_slice ( writer. get_ref ( ) ) ;
362+ Ok ( ( ) )
363+ }
364+ }
365+
366+ // Decoder for outbound streams: Decodes RPC responses from peers.
367+ //
368+ // The majority of the decoding has now been pushed upstream due to the changing specification.
369+ // We prefer to decode blocks and attestations with extra knowledge about the chain to perform
370+ // faster verification checks before decoding entire blocks/attestations.
371+ impl < E : EthSpec > Decoder for SSZSnappyOutboundCodec < E > {
372+ type Item = RPCCodedResponse < E > ;
373+ type Error = RPCError ;
374+
375+ fn decode ( & mut self , src : & mut BytesMut ) -> Result < Option < Self :: Item > , Self :: Error > {
376+ // if we have only received the response code, wait for more bytes
377+ if src. len ( ) <= 1 {
378+ return Ok ( None ) ;
379+ }
380+ // using the response code determine which kind of payload needs to be decoded.
381+ let response_code = self . current_response_code . unwrap_or_else ( || {
382+ let resp_code = src. split_to ( 1 ) [ 0 ] ;
383+ self . current_response_code = Some ( resp_code) ;
384+ resp_code
385+ } ) ;
386+
387+ let inner_result = {
388+ if RPCCodedResponse :: < E > :: is_response ( response_code) {
389+ // decode an actual response and mutates the buffer if enough bytes have been read
390+ // returning the result.
391+ self . decode_response ( src)
392+ . map ( |r| r. map ( RPCCodedResponse :: Success ) )
393+ } else {
394+ // decode an error
395+ self . decode_error ( src)
396+ . map ( |r| r. map ( |resp| RPCCodedResponse :: from_error ( response_code, resp) ) )
397+ }
398+ } ;
399+ // if the inner decoder was capable of decoding a chunk, we need to reset the current
400+ // response code for the next chunk
401+ if let Ok ( Some ( _) ) = inner_result {
402+ self . current_response_code = None ;
403+ }
404+ // return the result
405+ inner_result
406+ }
407+ }
408+
364409/// Handle errors that we get from decoding an RPC message from the stream.
365410/// `num_bytes_read` is the number of bytes the snappy decoder has read from the underlying stream.
366411/// `max_compressed_len` is the maximum compressed size for a given uncompressed size.
@@ -1030,7 +1075,7 @@ mod tests {
10301075 let mut snappy_inbound_codec =
10311076 SSZSnappyInboundCodec :: < Spec > :: new ( snappy_protocol_id, max_packet_size, fork_context) ;
10321077
1033- snappy_inbound_codec. encode ( message, & mut buf) ?;
1078+ snappy_inbound_codec. encode_response ( message, & mut buf) ?;
10341079 Ok ( buf)
10351080 }
10361081
@@ -1075,7 +1120,7 @@ mod tests {
10751120 let mut snappy_outbound_codec =
10761121 SSZSnappyOutboundCodec :: < Spec > :: new ( snappy_protocol_id, max_packet_size, fork_context) ;
10771122 // decode message just as snappy message
1078- snappy_outbound_codec. decode ( message)
1123+ snappy_outbound_codec. decode_response ( message)
10791124 }
10801125
10811126 /// Encodes the provided protocol message as bytes and tries to decode the encoding bytes.
@@ -1847,4 +1892,129 @@ mod tests {
18471892 RPCError :: InvalidData ( _)
18481893 ) ) ;
18491894 }
1895+
1896+ #[ test]
1897+ fn test_decode_status_message ( ) {
1898+ let message = hex:: decode ( "0054ff060000734e615070590032000006e71e7b54989925efd6c9cbcb8ceb9b5f71216f5137282bf6a1e3b50f64e42d6c7fb347abe07eb0db8200000005029e2800" ) . unwrap ( ) ;
1899+ let mut buf = BytesMut :: new ( ) ;
1900+ buf. extend_from_slice ( & message) ;
1901+
1902+ let snappy_protocol_id = ProtocolId :: new ( SupportedProtocol :: StatusV1 , Encoding :: SSZSnappy ) ;
1903+
1904+ let fork_context = Arc :: new ( fork_context ( ForkName :: Base ) ) ;
1905+
1906+ let chain_spec = Spec :: default_spec ( ) ;
1907+
1908+ let mut snappy_outbound_codec = SSZSnappyOutboundCodec :: < Spec > :: new (
1909+ snappy_protocol_id,
1910+ max_rpc_size ( & fork_context, chain_spec. max_chunk_size as usize ) ,
1911+ fork_context,
1912+ ) ;
1913+
1914+ // remove response code
1915+ let mut snappy_buf = buf. clone ( ) ;
1916+ let _ = snappy_buf. split_to ( 1 ) ;
1917+
1918+ // decode message just as snappy message
1919+ let _snappy_decoded_message = snappy_outbound_codec
1920+ . decode_response ( & mut snappy_buf)
1921+ . unwrap ( ) ;
1922+
1923+ // decode message as ssz snappy chunk
1924+ let _snappy_decoded_chunk = snappy_outbound_codec. decode ( & mut buf) . unwrap ( ) ;
1925+ }
1926+
1927+ #[ test]
1928+ fn test_invalid_length_prefix ( ) {
1929+ let mut uvi_codec: Uvi < u128 > = Uvi :: default ( ) ;
1930+ let mut dst = BytesMut :: with_capacity ( 1024 ) ;
1931+
1932+ // Smallest > 10 byte varint
1933+ let len: u128 = 2u128 . pow ( 70 ) ;
1934+
1935+ // Insert length-prefix
1936+ uvi_codec. encode ( len, & mut dst) . unwrap ( ) ;
1937+
1938+ let snappy_protocol_id = ProtocolId :: new ( SupportedProtocol :: StatusV1 , Encoding :: SSZSnappy ) ;
1939+
1940+ let fork_context = Arc :: new ( fork_context ( ForkName :: Base ) ) ;
1941+
1942+ let chain_spec = Spec :: default_spec ( ) ;
1943+
1944+ let mut snappy_outbound_codec = SSZSnappyOutboundCodec :: < Spec > :: new (
1945+ snappy_protocol_id,
1946+ max_rpc_size ( & fork_context, chain_spec. max_chunk_size as usize ) ,
1947+ fork_context,
1948+ ) ;
1949+
1950+ let snappy_decoded_message = snappy_outbound_codec. decode_response ( & mut dst) . unwrap_err ( ) ;
1951+
1952+ assert_eq ! (
1953+ snappy_decoded_message,
1954+ RPCError :: IoError ( "input bytes exceed maximum" . to_string( ) ) ,
1955+ "length-prefix of > 10 bytes is invalid"
1956+ ) ;
1957+ }
1958+
1959+ #[ test]
1960+ fn test_length_limits ( ) {
1961+ fn encode_len ( len : usize ) -> BytesMut {
1962+ let mut uvi_codec: Uvi < usize > = Uvi :: default ( ) ;
1963+ let mut dst = BytesMut :: with_capacity ( 1024 ) ;
1964+ uvi_codec. encode ( len, & mut dst) . unwrap ( ) ;
1965+ dst
1966+ }
1967+
1968+ let protocol_id = ProtocolId :: new ( SupportedProtocol :: BlocksByRangeV1 , Encoding :: SSZSnappy ) ;
1969+
1970+ // Response limits
1971+ let fork_context = Arc :: new ( fork_context ( ForkName :: Base ) ) ;
1972+
1973+ let chain_spec = Spec :: default_spec ( ) ;
1974+
1975+ let max_rpc_size = max_rpc_size ( & fork_context, chain_spec. max_chunk_size as usize ) ;
1976+ let limit = protocol_id. rpc_response_limits :: < Spec > ( & fork_context) ;
1977+ let mut max = encode_len ( limit. max + 1 ) ;
1978+ let mut codec = SSZSnappyOutboundCodec :: < Spec > :: new (
1979+ protocol_id. clone ( ) ,
1980+ max_rpc_size,
1981+ fork_context. clone ( ) ,
1982+ ) ;
1983+ assert ! ( matches!(
1984+ codec. decode_response( & mut max) . unwrap_err( ) ,
1985+ RPCError :: InvalidData ( _)
1986+ ) ) ;
1987+
1988+ let mut min = encode_len ( limit. min - 1 ) ;
1989+ let mut codec = SSZSnappyOutboundCodec :: < Spec > :: new (
1990+ protocol_id. clone ( ) ,
1991+ max_rpc_size,
1992+ fork_context. clone ( ) ,
1993+ ) ;
1994+ assert ! ( matches!(
1995+ codec. decode_response( & mut min) . unwrap_err( ) ,
1996+ RPCError :: InvalidData ( _)
1997+ ) ) ;
1998+
1999+ // Request limits
2000+ let limit = protocol_id. rpc_request_limits ( & fork_context. spec ) ;
2001+ let mut max = encode_len ( limit. max + 1 ) ;
2002+ let mut codec = SSZSnappyOutboundCodec :: < Spec > :: new (
2003+ protocol_id. clone ( ) ,
2004+ max_rpc_size,
2005+ fork_context. clone ( ) ,
2006+ ) ;
2007+ assert ! ( matches!(
2008+ codec. decode_response( & mut max) . unwrap_err( ) ,
2009+ RPCError :: InvalidData ( _)
2010+ ) ) ;
2011+
2012+ let mut min = encode_len ( limit. min - 1 ) ;
2013+ let mut codec =
2014+ SSZSnappyOutboundCodec :: < Spec > :: new ( protocol_id, max_rpc_size, fork_context) ;
2015+ assert ! ( matches!(
2016+ codec. decode_response( & mut min) . unwrap_err( ) ,
2017+ RPCError :: InvalidData ( _)
2018+ ) ) ;
2019+ }
18502020}
0 commit comments