The p2p_v2_encrypted.py test can fail in the -- improbable -- case when network reads happen to arrive in smaller chunks (when reading HTTP response from the socket).
Related to #36726 .
All networking code using sockets must not make assumption about the chunking of the incoming/outgoing data, and should be resilient against any chunking. Normally, the chunking of the sends of the writer dictate the chunking of the receives at the reader, but this is not guaranteed by IP/TCP, intermediate networking elements may change the packet structure. In test using sockets on the same host, this is not very likely, but still possible.
The v1 message parser in P2PConnection rejected the stream as soon as the first 4 bytes did not match the network magic. bitcoind's V1Transport::readHeader waits for the full 24-byte header before checking the magic.
The v2 to v1 downgrade relies on bitcoind's behaviour: an outbound v2 connection is only retried with v1 (V2Transport::ShouldReconnectV1) if at least a v1 header's worth of bytes had been sent before the peer disconnected. If the node's first send reaches the test peer in small pieces, the Python peer could disconnect after just 4 bytes, the node would not retry with v1, and p2p_v2_encrypted.py would time out waiting for the reconnection.
This was found -- and can be reproduced -- by using a reproducer patch, that forces all socket sends to use smaller chunking. For the run with the reproducer see #36724 .
The issue is test-code only, the non-test code is correct.
The fix is to match bitcoind by checking the magic only once the full header has been received.
This fix makes the test more robust, even though a failure due to this issue in CI is very unlikely, but not impossible.