test: suppress ECONNABORTED in wait_for_rpc_connection on Windows

Since bitcoin/bitcoin#33362, feature_bind_port_externalip.py runs in CI and
auto-detects whether 1.1.1.5 is assigned by starting nodes with -bind=1.1.1.5,
then converting a FailedToStartError containing "Unable to bind to" into a
SkipTest. On Windows CI the address is not configured, so bitcoind fails as
expected — but intermittently, while the process is shutting down, an RPC probe
raises ConnectionAbortedError (WSAECONNABORTED/WinError 10053) before
wait_for_rpc_connection() notices that the process has exited. That error was
not in the suppressed set, so it escaped and the test failed instead of being
skipped.

The intermittency is a race on TCP connection timing. If the probe connects
before the RPC port is listening, connect can fail with ECONNREFUSED. If the
TCP connection is established but is then closed abortively during shutdown,
the probe can see a connection-reset/aborted error instead. On POSIX systems
this commonly shows up as ECONNRESET ("connection reset by peer"). Winsock
also has WSAECONNABORTED for cases where an established connection is aborted
locally or otherwise terminated due to a timeout/protocol failure, in addition
to WSAECONNRESET for a reset by the remote side. This is why the
Windows-specific error may need to be suppressed separately.

Fix by treating ECONNABORTED identically to ECONNRESET, ETIMEDOUT, and
ECONNREFUSED: retry the probe rather than raising.

Fix was suggested by willcl-ark in
https://github.com/bitcoin/bitcoin/issues/35343#issuecomment-4507329622

Fixes #35343
This commit is contained in:
Ryan Ofsky
2026-05-21 14:57:14 -04:00
parent 0553ce5ddb
commit 7209eb7790

View File

@@ -378,9 +378,13 @@ class TestNode():
# doesn't specify errno.
elif isinstance(e, ConnectionResetError):
error_num = errno.ECONNRESET
# Windows can raise this while bitcoind shuts down during startup.
elif isinstance(e, ConnectionAbortedError):
error_num = errno.ECONNABORTED
# Suppress similarly to the above JSONRPCException errors.
if error_num not in [
errno.ECONNABORTED, # Treat identical to ECONNRESET
errno.ECONNRESET, # This might happen when the RPC server is in warmup,
# but shut down before the call to getblockcount succeeds.
errno.ETIMEDOUT, # Treat identical to ECONNRESET