2018-10-16 17:45:28 +02:00
|
|
|
import asyncio
|
2019-09-22 20:46:01 +02:00
|
|
|
|
asyncio: stop using get_event_loop(). introduce ~singleton loop.
asyncio.get_event_loop() became deprecated in python3.10. (see https://github.com/python/cpython/issues/83710)
```
.../electrum/electrum/daemon.py:470: DeprecationWarning: There is no current event loop
self.asyncio_loop = asyncio.get_event_loop()
.../electrum/electrum/network.py:276: DeprecationWarning: There is no current event loop
self.asyncio_loop = asyncio.get_event_loop()
```
Also, according to that thread, "set_event_loop() [... is] not deprecated by oversight".
So, we stop using get_event_loop() and set_event_loop() in our own code.
Note that libraries we use (such as the stdlib for python <3.10), might call get_event_loop,
which then relies on us having called set_event_loop e.g. for the GUI thread. To work around
this, a custom event loop policy providing a get_event_loop implementation is used.
Previously, we have been using a single asyncio event loop, created with
util.create_and_start_event_loop, and code in many places got a reference to this loop
using asyncio.get_event_loop().
Now, we still use a single asyncio event loop, but it is now stored as a global in
util._asyncio_event_loop (access with util.get_asyncio_loop()).
I believe these changes also fix https://github.com/spesmilo/electrum/issues/5376
2022-04-29 18:24:49 +02:00
|
|
|
from electrum import util
|
2019-09-22 20:46:01 +02:00
|
|
|
from electrum.ecc import ECPrivkey
|
2019-02-02 09:58:31 +01:00
|
|
|
from electrum.lnutil import LNPeerAddr
|
2018-10-16 17:45:28 +02:00
|
|
|
from electrum.lntransport import LNResponderTransport, LNTransport
|
2022-02-08 12:34:49 +01:00
|
|
|
from electrum.util import OldTaskGroup
|
2021-03-21 22:11:16 +01:00
|
|
|
|
2019-09-22 20:46:01 +02:00
|
|
|
from . import ElectrumTestCase
|
2020-03-04 18:54:20 +01:00
|
|
|
from .test_bitcoin import needs_test_with_all_chacha20_implementations
|
2019-09-22 20:46:01 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
class TestLNTransport(ElectrumTestCase):
|
|
|
|
|
|
2020-03-04 18:54:20 +01:00
|
|
|
@needs_test_with_all_chacha20_implementations
|
2018-10-16 17:45:28 +02:00
|
|
|
def test_responder(self):
|
|
|
|
|
# local static
|
|
|
|
|
ls_priv=bytes.fromhex('2121212121212121212121212121212121212121212121212121212121212121')
|
|
|
|
|
# ephemeral
|
|
|
|
|
e_priv=bytes.fromhex('2222222222222222222222222222222222222222222222222222222222222222')
|
|
|
|
|
|
|
|
|
|
class Writer:
|
|
|
|
|
def __init__(self):
|
|
|
|
|
self.state = 0
|
|
|
|
|
def write(self, data):
|
|
|
|
|
assert self.state == 0
|
|
|
|
|
self.state += 1
|
|
|
|
|
assert len(data) == 50
|
|
|
|
|
class Reader:
|
|
|
|
|
def __init__(self):
|
|
|
|
|
self.state = 0
|
|
|
|
|
async def read(self, num_bytes):
|
|
|
|
|
assert self.state in (0, 1)
|
|
|
|
|
self.state += 1
|
|
|
|
|
if self.state-1 == 0:
|
|
|
|
|
assert num_bytes == 50
|
|
|
|
|
return bytes.fromhex('00036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c6a')
|
|
|
|
|
elif self.state-1 == 1:
|
|
|
|
|
assert num_bytes == 66
|
|
|
|
|
return bytes.fromhex('00b9e3a702e93e3a9948c2ed6e5fd7590a6e1c3a0344cfc9d5b57357049aa22355361aa02e55a8fc28fef5bd6d71ad0c38228dc68b1c466263b47fdf31e560e139ba')
|
|
|
|
|
transport = LNResponderTransport(ls_priv, Reader(), Writer())
|
asyncio: stop using get_event_loop(). introduce ~singleton loop.
asyncio.get_event_loop() became deprecated in python3.10. (see https://github.com/python/cpython/issues/83710)
```
.../electrum/electrum/daemon.py:470: DeprecationWarning: There is no current event loop
self.asyncio_loop = asyncio.get_event_loop()
.../electrum/electrum/network.py:276: DeprecationWarning: There is no current event loop
self.asyncio_loop = asyncio.get_event_loop()
```
Also, according to that thread, "set_event_loop() [... is] not deprecated by oversight".
So, we stop using get_event_loop() and set_event_loop() in our own code.
Note that libraries we use (such as the stdlib for python <3.10), might call get_event_loop,
which then relies on us having called set_event_loop e.g. for the GUI thread. To work around
this, a custom event loop policy providing a get_event_loop implementation is used.
Previously, we have been using a single asyncio event loop, created with
util.create_and_start_event_loop, and code in many places got a reference to this loop
using asyncio.get_event_loop().
Now, we still use a single asyncio event loop, but it is now stored as a global in
util._asyncio_event_loop (access with util.get_asyncio_loop()).
I believe these changes also fix https://github.com/spesmilo/electrum/issues/5376
2022-04-29 18:24:49 +02:00
|
|
|
asyncio.run_coroutine_threadsafe(
|
|
|
|
|
transport.handshake(epriv=e_priv), self.asyncio_loop).result()
|
2019-09-22 20:46:01 +02:00
|
|
|
|
2020-03-04 18:54:20 +01:00
|
|
|
@needs_test_with_all_chacha20_implementations
|
2018-10-16 17:45:28 +02:00
|
|
|
def test_loop(self):
|
|
|
|
|
responder_shaked = asyncio.Event()
|
|
|
|
|
server_shaked = asyncio.Event()
|
|
|
|
|
responder_key = ECPrivkey.generate_random_key()
|
|
|
|
|
initiator_key = ECPrivkey.generate_random_key()
|
2021-03-21 22:11:16 +01:00
|
|
|
messages_sent_by_client = [
|
|
|
|
|
b'hello from client',
|
|
|
|
|
b'long data from client ' + bytes(range(256)) * 100 + b'... client done',
|
|
|
|
|
b'client is running out of things to say',
|
|
|
|
|
]
|
|
|
|
|
messages_sent_by_server = [
|
|
|
|
|
b'hello from server',
|
|
|
|
|
b'hello2 from server',
|
|
|
|
|
b'long data from server ' + bytes(range(256)) * 100 + b'... server done',
|
|
|
|
|
]
|
|
|
|
|
async def read_messages(transport, expected_messages):
|
|
|
|
|
ctr = 0
|
|
|
|
|
async for msg in transport.read_messages():
|
|
|
|
|
self.assertEqual(expected_messages[ctr], msg)
|
|
|
|
|
ctr += 1
|
|
|
|
|
if ctr == len(expected_messages):
|
|
|
|
|
return
|
|
|
|
|
async def write_messages(transport, expected_messages):
|
|
|
|
|
for msg in expected_messages:
|
|
|
|
|
transport.send_bytes(msg)
|
|
|
|
|
await asyncio.sleep(0.01)
|
|
|
|
|
|
2018-10-16 17:45:28 +02:00
|
|
|
async def cb(reader, writer):
|
|
|
|
|
t = LNResponderTransport(responder_key.get_secret_bytes(), reader, writer)
|
|
|
|
|
self.assertEqual(await t.handshake(), initiator_key.get_public_key_bytes())
|
2022-02-08 12:34:49 +01:00
|
|
|
async with OldTaskGroup() as group:
|
2021-03-21 22:11:16 +01:00
|
|
|
await group.spawn(read_messages(t, messages_sent_by_client))
|
|
|
|
|
await group.spawn(write_messages(t, messages_sent_by_server))
|
2018-10-16 17:45:28 +02:00
|
|
|
responder_shaked.set()
|
2022-11-03 15:45:15 +00:00
|
|
|
async def connect(port: int):
|
|
|
|
|
peer_addr = LNPeerAddr('127.0.0.1', port, responder_key.get_public_key_bytes())
|
2020-04-15 21:41:33 +02:00
|
|
|
t = LNTransport(initiator_key.get_secret_bytes(), peer_addr, proxy=None)
|
2018-10-16 17:45:28 +02:00
|
|
|
await t.handshake()
|
2022-02-08 12:34:49 +01:00
|
|
|
async with OldTaskGroup() as group:
|
2021-03-21 22:11:16 +01:00
|
|
|
await group.spawn(read_messages(t, messages_sent_by_server))
|
|
|
|
|
await group.spawn(write_messages(t, messages_sent_by_client))
|
2018-10-16 17:45:28 +02:00
|
|
|
server_shaked.set()
|
|
|
|
|
|
2021-03-21 22:11:16 +01:00
|
|
|
async def f():
|
2022-11-03 15:45:15 +00:00
|
|
|
server = await asyncio.start_server(cb, '127.0.0.1', port=None)
|
|
|
|
|
server_port = server.sockets[0].getsockname()[1]
|
2021-03-21 22:11:16 +01:00
|
|
|
try:
|
2022-02-08 12:34:49 +01:00
|
|
|
async with OldTaskGroup() as group:
|
2022-11-03 15:45:15 +00:00
|
|
|
await group.spawn(connect(port=server_port))
|
2021-03-21 22:11:16 +01:00
|
|
|
await group.spawn(responder_shaked.wait())
|
|
|
|
|
await group.spawn(server_shaked.wait())
|
|
|
|
|
finally:
|
|
|
|
|
server.close()
|
|
|
|
|
await server.wait_closed()
|
|
|
|
|
|
asyncio: stop using get_event_loop(). introduce ~singleton loop.
asyncio.get_event_loop() became deprecated in python3.10. (see https://github.com/python/cpython/issues/83710)
```
.../electrum/electrum/daemon.py:470: DeprecationWarning: There is no current event loop
self.asyncio_loop = asyncio.get_event_loop()
.../electrum/electrum/network.py:276: DeprecationWarning: There is no current event loop
self.asyncio_loop = asyncio.get_event_loop()
```
Also, according to that thread, "set_event_loop() [... is] not deprecated by oversight".
So, we stop using get_event_loop() and set_event_loop() in our own code.
Note that libraries we use (such as the stdlib for python <3.10), might call get_event_loop,
which then relies on us having called set_event_loop e.g. for the GUI thread. To work around
this, a custom event loop policy providing a get_event_loop implementation is used.
Previously, we have been using a single asyncio event loop, created with
util.create_and_start_event_loop, and code in many places got a reference to this loop
using asyncio.get_event_loop().
Now, we still use a single asyncio event loop, but it is now stored as a global in
util._asyncio_event_loop (access with util.get_asyncio_loop()).
I believe these changes also fix https://github.com/spesmilo/electrum/issues/5376
2022-04-29 18:24:49 +02:00
|
|
|
asyncio.run_coroutine_threadsafe(f(), self.asyncio_loop).result()
|