@@ -154,6 +154,83 @@ fn hello_world_happy_path() {
154154 assert_eq ! ( message, decrypted_message[ 1 ..] . to_vec( ) ) ; // Skip header byte
155155}
156156
157+ #[ tokio:: test]
158+ #[ cfg( feature = "tokio" ) ]
159+ async fn pingpong_with_closed_connection_async ( ) {
160+ use bip324:: { futures:: Protocol , io:: Payload } ;
161+ use bitcoin:: consensus;
162+ use p2p:: message:: { NetworkMessage , V2NetworkMessage } ;
163+ use tokio:: net:: TcpListener ;
164+ use tokio:: net:: TcpStream ;
165+
166+ // Start a server that responds to exactly one Ping(x) message with a
167+ // Pong(x) message and then stops. This allows testing to read from a closed stream.
168+ let listener = TcpListener :: bind ( "127.0.0.1:0" ) . await . unwrap ( ) ;
169+ let addr = listener. local_addr ( ) . unwrap ( ) ;
170+ let server = tokio:: spawn ( async move {
171+ let ( stream, _) = listener. accept ( ) . await . unwrap ( ) ;
172+ let ( reader, writer) = stream. into_split ( ) ;
173+ let mut protocol = Protocol :: new (
174+ p2p:: Magic :: REGTEST ,
175+ bip324:: Role :: Responder ,
176+ None , // no garbage
177+ None , // no decoys
178+ reader,
179+ writer,
180+ )
181+ . await
182+ . unwrap ( ) ;
183+
184+ let payload = protocol. read ( ) . await . unwrap ( ) ;
185+ let received_message =
186+ consensus:: deserialize :: < V2NetworkMessage > ( payload. contents ( ) ) . unwrap ( ) ;
187+ if let NetworkMessage :: Ping ( x) = received_message. payload ( ) {
188+ let pong = V2NetworkMessage :: new ( NetworkMessage :: Pong ( * x) ) ;
189+ let message = consensus:: serialize ( & pong) ;
190+ protocol. write ( & Payload :: genuine ( message) ) . await . unwrap ( ) ;
191+ println ! ( "Pong sent, stopping server." )
192+ } else {
193+ panic ! ( "Expected Ping, but received: {received_message:?}" ) ;
194+ }
195+ } ) ;
196+
197+ let stream = TcpStream :: connect ( addr) . await . unwrap ( ) ;
198+
199+ let ( reader, writer) = stream. into_split ( ) ;
200+
201+ // Initialize high-level async protocol with handshake
202+ println ! ( "Starting async BIP-324 handshake" ) ;
203+ let mut protocol = Protocol :: new (
204+ p2p:: Magic :: REGTEST ,
205+ bip324:: Role :: Initiator ,
206+ None , // no garbage
207+ None , // no decoys
208+ reader,
209+ writer,
210+ )
211+ . await
212+ . unwrap ( ) ;
213+
214+ println ! ( "Sending Ping using async Protocol::write()" ) ;
215+ let ping = V2NetworkMessage :: new ( NetworkMessage :: Ping ( 45324 ) ) ;
216+ let message = consensus:: serialize ( & ping) ;
217+ protocol. write ( & Payload :: genuine ( message) ) . await . unwrap ( ) ;
218+
219+ println ! ( "Reading response using async Protocol::read()" ) ;
220+ let payload = protocol. read ( ) . await . unwrap ( ) ;
221+ let response_message = consensus:: deserialize :: < V2NetworkMessage > ( payload. contents ( ) ) . unwrap ( ) ;
222+
223+ assert_eq ! ( NetworkMessage :: Pong ( 45324 ) , * response_message. payload( ) ) ;
224+
225+ println ! ( "Successfully ping-pong message using async Protocol API!" ) ;
226+ server. await . unwrap ( ) ;
227+
228+ println ! (
229+ "Trying to read another message from the server, while the connection is already closed."
230+ ) ;
231+ assert ! ( protocol. read( ) . await . is_err( ) ) ;
232+ }
233+
157234#[ test]
158235#[ cfg( feature = "std" ) ]
159236fn regtest_handshake ( ) {
0 commit comments