test: Move event loop creation to network thread
What changed, and why it matters
This is a small test-only change in Bitcoin Core's Python testing framework. It moves where an internal networking event loop is created so it is created on the same thread that later runs it, rather than on the main test thread. The goal is to stop an intermittent crash/abort that happens on Windows when running functional tests. It does not change the Bitcoin node itself, consensus rules, wallet handling, or network protocol, and there is no indication it fixes a security vulnerability.
No security action required. Treat as a normal test-framework reliability improvement. Reviewers may want to confirm the intermittent Windows crash is resolved in CI before closing the linked issue.
Security signals we found
No security-relevant signals in the diff or commit message
Change is confined to the functional test framework (Python test code)
No modifications to consensus, networking protocol, cryptography, or wallet logic
Commit message frames the change as a test stability fix, not a security fix
Evidence from the diff
The patch modifies two files under test/functional/test_framework/. In p2p.py, the asyncio event loop instantiation is moved from the NetworkThread constructor (init) into run(), so the loop is created on the network thread. In test_framework.py, the startup wait condition is updated to first check that the loop is not None before checking is_running(). The change is intended to resolve GitHub issue #34367, an intermittent Windows Python fast abort with no stderr output.
Changed components
test/functional/test_framework/p2p.pytest/functional/test_framework/test_framework.pyInspect captured patch +2 / −2
diff --git a/test/functional/test_framework/p2p.py b/test/functional/test_framework/p2p.py
index bd8a1da7..fae4eb94 100755
--- a/test/functional/test_framework/p2p.py
+++ b/test/functional/test_framework/p2p.py
@@ -740,10 +740,10 @@ class NetworkThread(threading.Thread):
NetworkThread.listeners = {}
NetworkThread.protos = {}
- NetworkThread.network_event_loop = asyncio.SelectorEventLoop() if platform.system() == "Windows" else asyncio.new_event_loop()
def run(self):
"""Start the network thread."""
+ NetworkThread.network_event_loop = asyncio.SelectorEventLoop() if platform.system() == "Windows" else asyncio.new_event_loop()
self.network_event_loop.run_forever()
def close(self, *, timeout):
diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py
index fb0fc0af..95bfc964 100755
--- a/test/functional/test_framework/test_framework.py
+++ b/test/functional/test_framework/test_framework.py
@@ -260,7 +260,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
self.log.debug('Setting up network thread')
self.network_thread = NetworkThread()
self.network_thread.start()
- self.wait_until(lambda: self.network_thread.network_event_loop.is_running())
+ self.wait_until(lambda: self.network_thread.network_event_loop is not None and self.network_thread.network_event_loop.is_running())
if self.options.usecli:
if not self.supports_cli:
Why this scored 17/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.