@@ -18,54 +18,83 @@ pub const SUPPORTED_ETH_CAPABILITIES: [Capability; 1] = [Capability::eth(68)];
18
18
pub const SUPPORTED_SNAP_CAPABILITIES : [ Capability ; 1 ] = [ Capability :: snap ( 1 ) ] ;
19
19
pub const SUPPORTED_P2P_CAPABILITIES : [ Capability ; 1 ] = [ Capability :: p2p ( 5 ) ] ;
20
20
21
+ const CAPABILITY_NAME_MAX_LENGTH : usize = 8 ;
22
+
23
+ // Pads the input array to the right with zeros to ensure it is 8 bytes long.
24
+ // Panics if the input is longer than 8 bytes.
25
+ const fn pad_right < const N : usize > ( input : & [ u8 ; N ] ) -> [ u8 ; 8 ] {
26
+ assert ! (
27
+ N <= CAPABILITY_NAME_MAX_LENGTH ,
28
+ "Input array must be 8 bytes or less"
29
+ ) ;
30
+
31
+ let mut padded = [ 0_u8 ; CAPABILITY_NAME_MAX_LENGTH ] ;
32
+ let mut i = 0 ;
33
+ while i < input. len ( ) {
34
+ padded[ i] = input[ i] ;
35
+ i += 1 ;
36
+ }
37
+ padded
38
+ }
39
+
21
40
#[ derive( Debug , Clone , PartialEq ) ]
41
+ /// A capability is identified by a short ASCII name (max eight characters) and version number
22
42
pub struct Capability {
23
- pub protocol : & ' static str ,
43
+ protocol : [ u8 ; CAPABILITY_NAME_MAX_LENGTH ] ,
24
44
pub version : u8 ,
25
45
}
26
46
27
47
impl Capability {
28
48
pub const fn eth ( version : u8 ) -> Self {
29
49
Capability {
30
- protocol : "eth" ,
50
+ protocol : pad_right ( b "eth") ,
31
51
version,
32
52
}
33
53
}
34
54
35
55
pub const fn p2p ( version : u8 ) -> Self {
36
56
Capability {
37
- protocol : "p2p" ,
57
+ protocol : pad_right ( b "p2p") ,
38
58
version,
39
59
}
40
60
}
41
61
42
62
pub const fn snap ( version : u8 ) -> Self {
43
63
Capability {
44
- protocol : "snap" ,
64
+ protocol : pad_right ( b "snap") ,
45
65
version,
46
66
}
47
67
}
68
+
69
+ pub fn protocol ( & self ) -> & str {
70
+ let len = self
71
+ . protocol
72
+ . iter ( )
73
+ . position ( |c| c == & b'\0' )
74
+ . unwrap_or ( CAPABILITY_NAME_MAX_LENGTH ) ;
75
+ str:: from_utf8 ( & self . protocol [ ..len] ) . expect ( "value parsed as utf8 in RLPDecode" )
76
+ }
48
77
}
49
78
50
79
impl RLPEncode for Capability {
51
80
fn encode ( & self , buf : & mut dyn BufMut ) {
52
81
Encoder :: new ( buf)
53
- . encode_field ( & self . protocol )
82
+ . encode_field ( & self . protocol ( ) )
54
83
. encode_field ( & self . version )
55
84
. finish ( ) ;
56
85
}
57
86
}
58
87
59
88
impl RLPDecode for Capability {
60
89
fn decode_unfinished ( rlp : & [ u8 ] ) -> Result < ( Self , & [ u8 ] ) , RLPDecodeError > {
61
- let ( protocol, rest) = String :: decode_unfinished ( & rlp[ 1 ..] ) ?;
62
- let ( version, rest) = u8:: decode_unfinished ( rest) ?;
63
- match protocol. as_str ( ) {
64
- "eth" => Ok ( ( Capability :: eth ( version) , rest) ) ,
65
- "p2p" => Ok ( ( Capability :: p2p ( version) , rest) ) ,
66
- "snap" => Ok ( ( Capability :: snap ( version) , rest) ) ,
67
- _ => Err ( RLPDecodeError :: MalformedData ) ,
90
+ let ( protocol_name, rest) = String :: decode_unfinished ( & rlp[ 1 ..] ) ?;
91
+ if protocol_name. len ( ) > CAPABILITY_NAME_MAX_LENGTH {
92
+ return Err ( RLPDecodeError :: InvalidLength ) ;
68
93
}
94
+ let ( version, rest) = u8:: decode_unfinished ( rest) ?;
95
+ let mut protocol = [ 0 ; CAPABILITY_NAME_MAX_LENGTH ] ;
96
+ protocol[ ..protocol_name. len ( ) ] . copy_from_slice ( protocol_name. as_bytes ( ) ) ;
97
+ Ok ( ( Capability { protocol, version } , rest) )
69
98
}
70
99
}
71
100
@@ -74,7 +103,7 @@ impl Serialize for Capability {
74
103
where
75
104
S : serde:: Serializer ,
76
105
{
77
- serializer. serialize_str ( & format ! ( "{}/{}" , self . protocol, self . version) )
106
+ serializer. serialize_str ( & format ! ( "{}/{}" , self . protocol( ) , self . version) )
78
107
}
79
108
}
80
109
@@ -320,3 +349,33 @@ impl RLPxMessage for PongMessage {
320
349
Ok ( Self { } )
321
350
}
322
351
}
352
+
353
+ #[ cfg( test) ]
354
+ mod tests {
355
+ use ethrex_rlp:: { decode:: RLPDecode , encode:: RLPEncode } ;
356
+
357
+ use crate :: rlpx:: p2p:: Capability ;
358
+
359
+ #[ test]
360
+ fn test_encode_capability ( ) {
361
+ let capability = Capability :: eth ( 8 ) ;
362
+ let encoded = capability. encode_to_vec ( ) ;
363
+
364
+ assert_eq ! ( & encoded, & [ 197_u8 , 131 , b'e' , b't' , b'h' , 8 ] ) ;
365
+ }
366
+
367
+ #[ test]
368
+ fn test_decode_capability ( ) {
369
+ let encoded_bytes = & [ 197_u8 , 131 , b'e' , b't' , b'h' , 8 ] ;
370
+ let decoded = Capability :: decode ( encoded_bytes) . unwrap ( ) ;
371
+
372
+ assert_eq ! ( decoded, Capability :: eth( 8 ) ) ;
373
+ }
374
+
375
+ #[ test]
376
+ fn test_protocol ( ) {
377
+ let capability = Capability :: eth ( 68 ) ;
378
+
379
+ assert_eq ! ( capability. protocol( ) , "eth" ) ;
380
+ }
381
+ }
0 commit comments