Skip to content

async protocol.read().await does not return when underlying connection is closed #159

@0xB10C

Description

@0xB10C

As demonstrated by 0xB10C@d89df30, protocol.read().await does not err nor return when the underlying connection is closed.

diff --git a/protocol/tests/round_trips.rs b/protocol/tests/round_trips.rs
index 8b07daa..06c144e 100644
--- a/protocol/tests/round_trips.rs
+++ b/protocol/tests/round_trips.rs
@@ -384,7 +384,7 @@ async fn regtest_handshake_async() {
     };
     use tokio::net::TcpStream;

-    let bitcoind = regtest_process(TransportVersion::V2);
+    let mut bitcoind = regtest_process(TransportVersion::V2);

     let stream = TcpStream::connect(bitcoind.params.p2p_socket.unwrap())
         .await
@@ -437,6 +437,25 @@ async fn regtest_handshake_async() {
     assert_eq!(response_message.cmd(), "version");

     println!("Successfully exchanged version messages using async Protocol API!");
+
+    let message = consensus::serialize(&V2NetworkMessage::new(NetworkMessage::Verack));
+    println!("Sending verack message using Protocol::write()");
+    protocol.write(&Payload::genuine(message)).await.unwrap();
+
+    let mut node_up = true;
+    loop {
+        let payload = protocol.read().await.unwrap();
+        let response_message = consensus::deserialize::<V2NetworkMessage>(payload.contents()).unwrap();
+        println!("read {:?}", response_message);
+
+        // Stopping the node here. The next few read()'s should fail?
+        if node_up {
+            node_up = false;
+            bitcoind.stop().unwrap();
+            println!("node is now shutdown!");
+        }
+    }
+
 }

 #[test]

Running this, I always get 100% CPU usage on one core.

Tested against a v30.0 bitcoind.

$ cargo test --features tokio regtest_handshake_async -- --nocapture

running 1 test
Using bitcoind at /nix/store/wbdd2i4vmw1mn25vkzbx0gssa04si9r9-bitcoind-30.0/bin/bitcoind
Starting async BIP-324 handshake
Async handshake completed successfully!
Sending version message using async Protocol::write()
Reading version response using async Protocol::read()
Successfully exchanged version messages using async Protocol API!
Sending verack message using Protocol::write()
read V2NetworkMessage { payload: Verack }
node is now shutdown!
read V2NetworkMessage { payload: SendCmpct(SendCmpct { send_compact: false, version: 2 }) }
read V2NetworkMessage { payload: Ping(17509515947851498945) }
read V2NetworkMessage { payload: FeeFilter(FeeRate(9936506000)) }
test regtest_handshake_async has been running for over 60 seconds
^C

I haven't actually spent time investigating deeper.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions