@@ -21,7 +21,7 @@ use std::borrow::Cow;
2121
2222#[ derive( Clone , Debug , PartialEq , Eq ) ]
2323pub struct PeerResponse {
24- pub peers : Vec < SocketAddr > ,
24+ pub peers : Vec < ( SocketAddr , Option < u32 > ) > ,
2525}
2626
2727impl MessageTrait for PeerResponse {
@@ -39,20 +39,59 @@ impl ToBytes for PeerResponse {
3939 return Err ( io:: Error :: new ( io:: ErrorKind :: InvalidInput , format ! ( "Too many peers: {}" , self . peers. len( ) ) ) ) ;
4040 }
4141
42+ // A version indicator; we don't expect empty peer responses, so a zero value can serve
43+ // as an indicator that this message is to be processed differently. The version value
44+ // can be changed to a 2 in the future, once everyone expects it there.
45+ 0u8 . write_le ( & mut writer) ?;
46+
4247 ( self . peers . len ( ) as u8 ) . write_le ( & mut writer) ?;
43- for peer in self . peers . iter ( ) {
44- peer. write_le ( & mut writer) ?;
48+ for ( addr, height) in self . peers . iter ( ) {
49+ addr. write_le ( & mut writer) ?;
50+ if let Some ( h) = height {
51+ 1u8 . write_le ( & mut writer) ?;
52+ h. write_le ( & mut writer) ?;
53+ } else {
54+ 0u8 . write_le ( & mut writer) ?;
55+ }
4556 }
4657 Ok ( ( ) )
4758 }
4859}
4960
5061impl FromBytes for PeerResponse {
5162 fn read_le < R : io:: Read > ( mut reader : R ) -> io:: Result < Self > {
52- let count = u8:: read_le ( & mut reader) ?;
63+ // Read the peer count if their heights aren't present; otherwise, interpret this value
64+ // as the message version. It is a workaround for a currently missing version value.
65+ // The worst-case scenario is if a node hasn't updated, and it gets a `PeerRequest` from
66+ // its only peer who has; this would cause it to return a message that appears as if it
67+ // contains heights (due to a leading `0`), but it would end up failing to deserialize.
68+ // TODO: after a release or two, we should always be expecting the version to be present,
69+ // simplifying the deserialization; also, remove the `empty_old_peerlist_handling` test.
70+ let mut contains_heights = false ;
71+ let count_or_version = u8:: read_le ( & mut reader) ?;
72+ let count = if count_or_version == 0 {
73+ // Version indicator found; this message will contain optional heights.
74+ contains_heights = true ;
75+ // If the first value is a zero, the next u8 is the peer count.
76+ u8:: read_le ( & mut reader) ?
77+ } else {
78+ // A non-zero value indicates that this is the "old" PeerResponse without heights.
79+ count_or_version
80+ } ;
81+
5382 let mut peers = Vec :: with_capacity ( count as usize ) ;
5483 for _ in 0 ..count {
55- peers. push ( SocketAddr :: read_le ( & mut reader) ?) ;
84+ let addr = SocketAddr :: read_le ( & mut reader) ?;
85+ let height = if contains_heights {
86+ match u8:: read_le ( & mut reader) ? {
87+ 1 => Some ( u32:: read_le ( & mut reader) ?) ,
88+ 0 => None ,
89+ _ => return Err ( io:: Error :: new ( io:: ErrorKind :: InvalidInput , "Invalid peer height" . to_string ( ) ) ) ,
90+ }
91+ } else {
92+ None
93+ } ;
94+ peers. push ( ( addr, height) ) ;
5695 }
5796
5897 Ok ( Self { peers } )
@@ -69,14 +108,19 @@ pub mod prop_tests {
69108 collection:: vec,
70109 prelude:: { BoxedStrategy , Strategy , any} ,
71110 } ;
72- use std:: net:: { IpAddr , SocketAddr } ;
111+ use std:: {
112+ io,
113+ net:: { IpAddr , SocketAddr } ,
114+ } ;
73115 use test_strategy:: proptest;
74116
75- pub fn any_valid_socket_addr ( ) -> BoxedStrategy < SocketAddr > {
76- any :: < ( IpAddr , u16 ) > ( ) . prop_map ( |( ip_addr, port) | SocketAddr :: new ( ip_addr, port) ) . boxed ( )
117+ pub fn any_valid_socket_addr ( ) -> BoxedStrategy < ( SocketAddr , Option < u32 > ) > {
118+ any :: < ( IpAddr , u16 , Option < u32 > ) > ( )
119+ . prop_map ( |( ip_addr, port, height) | ( SocketAddr :: new ( ip_addr, port) , height) )
120+ . boxed ( )
77121 }
78122
79- pub fn any_vec ( ) -> BoxedStrategy < Vec < SocketAddr > > {
123+ pub fn any_vec ( ) -> BoxedStrategy < Vec < ( SocketAddr , Option < u32 > ) > > {
80124 vec ( any_valid_socket_addr ( ) , 0 ..50 ) . prop_map ( |v| v) . boxed ( )
81125 }
82126
@@ -91,4 +135,14 @@ pub mod prop_tests {
91135 let decoded = PeerResponse :: read_le ( & mut bytes. into_inner ( ) . reader ( ) ) . unwrap ( ) ;
92136 assert_eq ! ( decoded, peer_response) ;
93137 }
138+
139+ // The following test will be obsolete once all the nodes handle heights in the `PeerResponse`.
140+ #[ test]
141+ fn empty_old_peerlist_handling ( ) {
142+ // An empty `PeerResponse` without heights contains a single 0u8.
143+ let serialized = & [ 0u8 ] ;
144+ let deserialized = PeerResponse :: read_le ( & serialized[ ..] ) . unwrap_err ( ) ;
145+ // Check for the expected error.
146+ assert_eq ! ( deserialized. kind( ) , io:: ErrorKind :: UnexpectedEof ) ;
147+ }
94148}
0 commit comments