Skip to content

Commit 3d37fe4

Browse files
committed
dynamically update relays and remove redundant nostr query
1 parent 1e4728b commit 3d37fe4

File tree

2 files changed

+50
-47
lines changed

2 files changed

+50
-47
lines changed

electrum/simple_config.py

+1
Original file line numberDiff line numberDiff line change
@@ -816,6 +816,7 @@ def __setattr__(self, name, value):
816816
SWAPSERVER_URL = ConfigVar('swapserver_url', default='', type_=str)
817817
TEST_SWAPSERVER_REFUND = ConfigVar('test_swapserver_refund', default=False, type_=bool)
818818
SWAPSERVER_NPUB = ConfigVar('swapserver_npub', default=None, type_=str)
819+
LAST_SWAPSERVER_RELAYS = ConfigVar('last_swapserver_relays', default=None, type_=str)
819820
SWAPSERVER_POW_TARGET = ConfigVar('swapserver_pow_target', default=30, type_=int)
820821

821822
# nostr

electrum/submarine_swaps.py

+49-47
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ def __init__(self, *, wallet: 'Abstract_Wallet', lnworker: 'LNWallet'):
202202
self.prepayments[swap.prepay_hash] = bytes.fromhex(k)
203203
self.is_server = False # overriden by swapserver plugin if enabled
204204
self.is_initialized = asyncio.Event()
205+
self.pairs_updated = asyncio.Event()
205206

206207
def start_network(self, network: 'Network'):
207208
assert network
@@ -922,7 +923,15 @@ def update_pairs(self, pairs):
922923
self.percentage = pairs.percentage
923924
self._min_amount = pairs.min_amount
924925
self._max_amount = pairs.max_amount
925-
self.is_initialized.set()
926+
self.trigger_pairs_updated()
927+
928+
def trigger_pairs_updated(self):
929+
def trigger():
930+
self.is_initialized.set()
931+
self.pairs_updated.set()
932+
self.pairs_updated.clear()
933+
loop = get_asyncio_loop()
934+
loop.call_soon_threadsafe(trigger)
926935

927936
def get_max_amount(self) -> int:
928937
"""in satoshis"""
@@ -1065,7 +1074,7 @@ def create_claim_txin(
10651074
*,
10661075
txin: PartialTxInput,
10671076
swap: SwapData,
1068-
) -> PartialTransaction:
1077+
) -> Tuple[PartialTxInput, Optional[int]]:
10691078
if swap.is_reverse: # successful reverse swap
10701079
locktime = None
10711080
# preimage will be set in sign_tx
@@ -1280,11 +1289,10 @@ def __init__(self, config, sm, keypair):
12801289
self.private_key = keypair.privkey
12811290
self.nostr_private_key = to_nip19('nsec', keypair.privkey.hex())
12821291
self.nostr_pubkey = keypair.pubkey.hex()[2:]
1283-
self.dm_replies = defaultdict(asyncio.Future) # type: Dict[bytes, asyncio.Future]
1292+
self.dm_replies = defaultdict(asyncio.Future) # type: Dict[str, asyncio.Future]
12841293
self.ssl_context = ssl.create_default_context(purpose=ssl.Purpose.SERVER_AUTH, cafile=ca_path)
12851294
self.relay_manager = None
12861295
self.taskgroup = OldTaskGroup()
1287-
self.server_relays = None
12881296

12891297
def __enter__(self):
12901298
asyncio.run_coroutine_threadsafe(self.main_loop(), self.network.asyncio_loop)
@@ -1311,8 +1319,8 @@ async def main_loop(self):
13111319
else:
13121320
tasks = [
13131321
self.check_direct_messages(),
1314-
self.receive_offers(),
13151322
self.get_pairs(),
1323+
self.update_relays()
13161324
]
13171325
try:
13181326
async with self.taskgroup as group:
@@ -1333,12 +1341,16 @@ async def stop(self):
13331341

13341342
@property
13351343
def relays(self):
1336-
return self.network.config.NOSTR_RELAYS.split(',')
1344+
our_relays = self.config.NOSTR_RELAYS.split(',') if self.config.NOSTR_RELAYS else []
1345+
if self.sm.is_server:
1346+
return our_relays
1347+
last_swapserver_relays = self.config.LAST_SWAPSERVER_RELAYS.split(',') if self.config.LAST_SWAPSERVER_RELAYS else []
1348+
return list(set(our_relays + last_swapserver_relays))
13371349

13381350
def get_relay_manager(self):
13391351
assert get_running_loop() == get_asyncio_loop(), f"this must be run on the asyncio thread!"
13401352
if not self.relay_manager:
1341-
if self.network.proxy:
1353+
if self.network.proxy and self.network.proxy.enabled:
13421354
proxy = make_aiohttp_proxy_connector(self.network.proxy, self.ssl_context)
13431355
else:
13441356
proxy: Optional['ProxyConnector'] = None
@@ -1396,7 +1408,7 @@ async def publish_offer(self, sm):
13961408
private_key=self.nostr_private_key)
13971409
self.logger.info(f"published offer {event_id}")
13981410

1399-
async def send_direct_message(self, pubkey: str, relays, content: str) -> str:
1411+
async def send_direct_message(self, pubkey: str, content: str) -> str:
14001412
event_id = await aionostr._add_event(
14011413
self.relay_manager,
14021414
kind=self.NOSTR_DM,
@@ -1407,27 +1419,29 @@ async def send_direct_message(self, pubkey: str, relays, content: str) -> str:
14071419

14081420
@log_exceptions
14091421
async def send_request_to_server(self, method: str, request_data: dict) -> dict:
1422+
self.logger.debug(f"swapserver req: method: {method} relays: {self.relays}")
14101423
request_data['method'] = method
1411-
request_data['relays'] = self.config.NOSTR_RELAYS
14121424
server_pubkey = self.config.SWAPSERVER_NPUB
1413-
event_id = await self.send_direct_message(server_pubkey, self.server_relays, json.dumps(request_data))
1425+
event_id = await self.send_direct_message(server_pubkey, json.dumps(request_data))
14141426
response = await self.dm_replies[event_id]
14151427
return response
14161428

1417-
async def receive_offers(self):
1429+
async def get_pairs(self):
14181430
await self.is_connected.wait()
14191431
query = {
14201432
"kinds": [self.USER_STATUS_NIP38],
14211433
"limit":10,
14221434
"#d": [f"electrum-swapserver-{self.NOSTR_EVENT_VERSION}"],
14231435
"#r": [f"net:{constants.net.NET_NAME}"],
1424-
"since": int(time.time()) - self.OFFER_UPDATE_INTERVAL_SEC
1436+
"since": int(time.time()) - 60 * 60,
1437+
"until": int(time.time()) + 60 * 60,
14251438
}
14261439
async for event in self.relay_manager.get_events(query, single_event=False, only_stored=False):
14271440
try:
14281441
content = json.loads(event.content)
14291442
tags = {k: v for k, v in event.tags}
14301443
except Exception as e:
1444+
self.logger.debug(f"failed to parse event: {e}")
14311445
continue
14321446
if tags.get('d') != f"electrum-swapserver-{self.NOSTR_EVENT_VERSION}":
14331447
continue
@@ -1436,8 +1450,9 @@ async def receive_offers(self):
14361450
# check if this is the most recent event for this pubkey
14371451
pubkey = event.pubkey
14381452
ts = self._offers.get(pubkey, {}).get('timestamp', 0)
1439-
if event.created_at <= ts:
1440-
#print('skipping old event', pubkey[0:10], event.id)
1453+
if (event.created_at <= ts
1454+
or event.created_at > time.time() + 60 * 60
1455+
or event.created_at < time.time() - 60 * 60):
14411456
continue
14421457
try:
14431458
pow_bits = get_nostr_ann_pow_amount(
@@ -1452,40 +1467,28 @@ async def receive_offers(self):
14521467
content['pow_bits'] = pow_bits
14531468
content['pubkey'] = pubkey
14541469
content['timestamp'] = event.created_at
1470+
server_relays = content['relays'].split(',') if 'relays' in content else []
1471+
content['relays'] = ','.join(server_relays[:10]) # limit to 10 relays
14551472
self._offers[pubkey] = content
1473+
if self.config.SWAPSERVER_NPUB == pubkey:
1474+
pairs = self._parse_offer(content)
1475+
self.sm.update_pairs(pairs)
14561476
# mirror event to other relays
1457-
server_relays = content['relays'].split(',') if 'relays' in content else []
14581477
await self.taskgroup.spawn(self.rebroadcast_event(event, server_relays))
14591478

1460-
async def get_pairs(self):
1461-
if not self.config.SWAPSERVER_NPUB:
1462-
return
1463-
query = {
1464-
"kinds": [self.USER_STATUS_NIP38],
1465-
"authors": [self.config.SWAPSERVER_NPUB],
1466-
"#d": [f"electrum-swapserver-{self.NOSTR_EVENT_VERSION}"],
1467-
"#r": [f"net:{constants.net.NET_NAME}"],
1468-
"since": int(time.time()) - self.OFFER_UPDATE_INTERVAL_SEC,
1469-
"limit": 1
1470-
}
1471-
async for event in self.relay_manager.get_events(query, single_event=True, only_stored=False):
1472-
try:
1473-
content = json.loads(event.content)
1474-
tags = {k: v for k, v in event.tags}
1475-
except Exception:
1476-
continue
1477-
if tags.get('d') != f"electrum-swapserver-{self.NOSTR_EVENT_VERSION}":
1478-
continue
1479-
if tags.get('r') != f"net:{constants.net.NET_NAME}":
1480-
continue
1481-
# check if this is the most recent event for this pubkey
1482-
pubkey = event.pubkey
1483-
content['pubkey'] = pubkey
1484-
content['timestamp'] = event.created_at
1485-
self.logger.info(f'received offer from {age(event.created_at)}')
1486-
pairs = self._parse_offer(content)
1487-
self.sm.update_pairs(pairs)
1488-
self.server_relays = content['relays'].split(',')
1479+
async def update_relays(self):
1480+
"""
1481+
Update the relays when update_pairs is called.
1482+
This ensures we try to connect to the same relays as the ones announced by the swap server.
1483+
"""
1484+
while True:
1485+
previous_relays = self.config.LAST_SWAPSERVER_RELAYS
1486+
await self.sm.pairs_updated.wait()
1487+
# assign the latest known swapserver relays to the config
1488+
self.config.LAST_SWAPSERVER_RELAYS = self._offers[self.config.SWAPSERVER_NPUB]['relays']
1489+
if self.config.LAST_SWAPSERVER_RELAYS != previous_relays:
1490+
self.logger.debug(f"updating relays")
1491+
await self.relay_manager.update_relays(self.relays)
14891492

14901493
async def rebroadcast_event(self, event: Event, server_relays: Sequence[str]):
14911494
"""If the relays of the origin server are different from our relays we rebroadcast the
@@ -1528,8 +1531,7 @@ async def handle_request(self, request):
15281531
method = request.pop('method')
15291532
event_id = request.pop('event_id')
15301533
event_pubkey = request.pop('event_pubkey')
1531-
self.logger.info(f'handle_request: id={event_id} {method} {request}')
1532-
relays = request.pop('relays').split(',')
1534+
print(f'handle_request: id={event_id} {method} {request}')
15331535
if method == 'addswapinvoice':
15341536
r = self.sm.server_add_swap_invoice(request)
15351537
elif method == 'createswap':
@@ -1540,4 +1542,4 @@ async def handle_request(self, request):
15401542
raise Exception(method)
15411543
r['reply_to'] = event_id
15421544
self.logger.info(f'sending response id={event_id}')
1543-
await self.send_direct_message(event_pubkey, relays, json.dumps(r))
1545+
await self.send_direct_message(event_pubkey, json.dumps(r))

0 commit comments

Comments
 (0)