What changed, and why it matters
This commit is a routine code cleanup: it removes three separate copies of a small helper function called now() and puts a single shared copy in a common utilities file. It does not change what the function does or fix any security issue.
No security action needed; this is a normal refactoring change.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch deduplicates now() implementations in lnchannel.py, onion_message.py, and submarine_swaps.py into electrum.util.now(), which returns int(time.time()). submarine_swaps.py is updated to use the shared helper. onion_message.py keeps its own float-returning now() with an explicit type assertion because that module needs float timestamps. lnchannel.py also has some unrelated import cleanup. There is no functional change to security-sensitive behavior.
Changed components
electrum/util.pyelectrum/submarine_swaps.pyelectrum/lnchannel.pyelectrum/onion_message.pyInspect captured patch +17 / −23
diff --git a/electrum/lnchannel.py b/electrum/lnchannel.py
index 49878de..93dae41 100644
--- a/electrum/lnchannel.py
+++ b/electrum/lnchannel.py
@@ -24,24 +24,21 @@ from enum import IntEnum, Enum
from typing import (
Optional, Dict, List, Tuple, NamedTuple,
Iterable, Sequence, TYPE_CHECKING, Iterator, Union, Mapping)
-import time
-import threading
from abc import ABC, abstractmethod
import itertools
from aiorpcx import NetAddress
-import attr
import electrum_ecc as ecc
from electrum_ecc import ECPubkey
from . import constants, util
-from .util import bfh, chunks, TxMinedInfo, error_text_bytes_to_safe_str
+from .util import bfh, chunks, TxMinedInfo, error_text_bytes_to_safe_str, now
from .bitcoin import redeem_script_to_address
from .crypto import sha256, sha256d
from .transaction import Transaction, PartialTransaction, TxInput, Sighash
from .logging import Logger
-from .lntransport import LNPeerAddr, extract_nodeid, ConnStringFormatError
+from .lntransport import LNPeerAddr
from .lnonion import OnionRoutingFailure
from . import lnutil
from .lnutil import (Outpoint, LocalConfig, RemoteConfig, Keypair, OnlyPubkeyKeypair, ChannelConstraints,
@@ -170,8 +167,6 @@ class RemoteCtnTooFarInFuture(Exception): pass
def htlcsum(htlcs: Iterable[UpdateAddHtlc]):
return sum([x.amount_msat for x in htlcs])
-def now():
- return int(time.time())
class HTLCWithStatus(NamedTuple):
channel_id: bytes
diff --git a/electrum/onion_message.py b/electrum/onion_message.py
index c291f99..167b897 100644
--- a/electrum/onion_message.py
+++ b/electrum/onion_message.py
@@ -45,9 +45,9 @@ from electrum.lnutil import LnFeatures, MIN_FINAL_CLTV_DELTA_ACCEPTED, MAXIMUM_R
from electrum.util import OldTaskGroup, log_exceptions, random_shuffled_copy
-def now():
+def now() -> float:
return time.time()
-
+assert type(now()) == float, "OnionMessageManager requires float timestamps"
if TYPE_CHECKING:
from electrum.lnworker import LNWallet
diff --git a/electrum/submarine_swaps.py b/electrum/submarine_swaps.py
index 9b84932..745ad72 100644
--- a/electrum/submarine_swaps.py
+++ b/electrum/submarine_swaps.py
@@ -34,7 +34,7 @@ from .transaction import (
from .util import (
log_exceptions, ignore_exceptions, BelowDustLimit, OldTaskGroup, ca_path, gen_nostr_ann_pow,
get_nostr_ann_pow_amount, make_aiohttp_proxy_connector, get_running_loop, get_asyncio_loop, wait_for2,
- run_sync_function_on_asyncio_thread, trigger_callback, NoDynamicFeeEstimates, UserFacingException,
+ run_sync_function_on_asyncio_thread, trigger_callback, NoDynamicFeeEstimates, UserFacingException, now
)
from . import lnutil
from .lnutil import hex_to_bytes, REDEEM_AFTER_DOUBLE_SPENT_DELAY, Keypair
@@ -162,10 +162,6 @@ class SwapServerError(Exception):
return _("The swap server errored or is unreachable.")
-def now():
- return int(time.time())
-
-
@attr.s(frozen=True)
class SwapFees:
percentage = attr.ib(type=Decimal)
@@ -295,7 +291,7 @@ class SwapManager(Logger):
await transport.is_connected.wait()
self.logger.info(f'nostr is connected')
# will publish a new announcement if liquidity changed or every OFFER_UPDATE_INTERVAL_SEC
- last_update = time.time()
+ last_update = now()
while True:
await asyncio.sleep(transport.LIQUIDITY_UPDATE_INTERVAL_SEC)
@@ -313,11 +309,11 @@ class SwapManager(Logger):
mining_fees_changed = self.mining_fee != previous_mining_fee
if liquidity_changed or mining_fees_changed:
self.logger.debug(f"updating announcement: {liquidity_changed=}, {mining_fees_changed=}")
- elif time.time() - last_update < transport.OFFER_UPDATE_INTERVAL_SEC:
+ elif now() - last_update < transport.OFFER_UPDATE_INTERVAL_SEC:
continue
await transport.publish_offer(self)
- last_update = time.time()
+ last_update = now()
@log_exceptions
async def main_loop(self):
@@ -1762,8 +1758,7 @@ class NostrTransport(SwapServerTransport):
def get_recent_offers(self) -> Sequence[SwapOffer]:
# filter to fresh timestamps
- now = int(time.time())
- recent_offers = [x for x in self._offers.values() if now - x.timestamp < 3600]
+ recent_offers = [x for x in self._offers.values() if now() - x.timestamp < 3600]
# sort by proof-of-work
recent_offers = sorted(recent_offers, key=lambda x: x.pow_bits, reverse=True)
# cap list size
@@ -1789,7 +1784,7 @@ class NostrTransport(SwapServerTransport):
# the first value of a single letter tag is indexed and can be filtered for
tags = [['d', f'electrum-swapserver-{self.NOSTR_EVENT_VERSION}'],
['r', 'net:' + constants.net.NET_NAME],
- ['expiration', str(int(time.time() + self.OFFER_UPDATE_INTERVAL_SEC + 10))]]
+ ['expiration', str(now() + self.OFFER_UPDATE_INTERVAL_SEC + 10)]]
try:
event_id = await aionostr._add_event(
self.relay_manager,
@@ -1847,7 +1842,7 @@ class NostrTransport(SwapServerTransport):
"limit": 10,
"#d": [f"electrum-swapserver-{self.NOSTR_EVENT_VERSION}"],
"#r": [f"net:{constants.net.NET_NAME}"],
- "since": int(time.time()) - 60 * 60,
+ "since": now() - 60 * 60,
}
async for event in self.relay_manager.get_events(query, single_event=False, only_stored=False):
try:
@@ -1862,8 +1857,8 @@ class NostrTransport(SwapServerTransport):
continue
if tags.get('r') != f"net:{constants.net.NET_NAME}":
continue
- if (event.created_at > int(time.time()) + 60 * 60
- or event.created_at < int(time.time()) - 60 * 60):
+ if (event.created_at > now() + 60 * 60
+ or event.created_at < now() - 60 * 60):
continue
# check if this is the most recent event for this pubkey
pubkey = event.pubkey
diff --git a/electrum/util.py b/electrum/util.py
index 055c5bd..e1012d4 100644
--- a/electrum/util.py
+++ b/electrum/util.py
@@ -901,6 +901,10 @@ def format_time(timestamp: Union[int, float, None]) -> str:
return date.isoformat(' ', timespec="minutes") if date else _("Unknown")
+def now() -> int:
+ return int(time.time())
+
+
def age(
from_date: Union[int, float, None], # POSIX timestamp
*,
Why this scored 15/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.