1
0

lnworker: imports, whitespace

This commit is contained in:
Sander van Grieken
2025-02-17 14:37:46 +01:00
parent 18baf003d4
commit c740057bc7

View File

@@ -7,16 +7,14 @@ import os
from decimal import Decimal from decimal import Decimal
import random import random
import time import time
import operator from enum import IntEnum
import enum from typing import (
from enum import IntEnum, Enum Optional, Sequence, Tuple, List, Set, Dict, TYPE_CHECKING, NamedTuple, Mapping, Any, Iterable, AsyncGenerator,
from typing import (Optional, Sequence, Tuple, List, Set, Dict, TYPE_CHECKING, Callable, Awaitable
NamedTuple, Union, Mapping, Any, Iterable, AsyncGenerator, DefaultDict, Callable, Awaitable) )
import threading import threading
import socket import socket
import json from functools import partial
from datetime import datetime, timezone
from functools import partial, cached_property
from collections import defaultdict from collections import defaultdict
import concurrent import concurrent
from concurrent import futures from concurrent import futures
@@ -27,67 +25,54 @@ import aiohttp
import dns.resolver import dns.resolver
import dns.exception import dns.exception
from aiorpcx import run_in_thread, NetAddress, ignore_after from aiorpcx import run_in_thread, NetAddress, ignore_after
from electrum_ecc import ecdsa_der_sig_from_ecdsa_sig64
from .logging import Logger
from .i18n import _
from .json_db import stored_in
from .channel_db import UpdateStatus, ChannelDBNotLoaded, get_mychannel_info, get_mychannel_policy
from . import constants, util from . import constants, util
from . import keystore from .util import (
from .util import profiler, chunks, OldTaskGroup, ESocksProxy profiler, OldTaskGroup, ESocksProxy, NetworkRetryManager, JsonRPCClient, NotEnoughFunds, EventListener,
from .invoices import Invoice, PR_UNPAID, PR_EXPIRED, PR_PAID, PR_INFLIGHT, PR_FAILED, PR_ROUTING, LN_EXPIRY_NEVER event_listener, bfh, InvoiceError, resolve_dns_srv, is_ip_address, log_exceptions, ignore_exceptions,
from .invoices import BaseInvoice make_aiohttp_session, timestamp_to_datetime, random_shuffled_copy, is_private_netaddress,
from .util import NetworkRetryManager, JsonRPCClient, NotEnoughFunds UnrelatedTransactionException
from .util import EventListener, event_listener )
from .keystore import BIP32_KeyStore from .invoices import Invoice, PR_UNPAID, PR_PAID, PR_INFLIGHT, PR_FAILED, LN_EXPIRY_NEVER, BaseInvoice
from .bitcoin import COIN from .bitcoin import COIN, opcodes, make_op_return, address_to_scripthash, DummyAddress
from .bitcoin import opcodes, make_op_return, address_to_scripthash
from .transaction import Transaction
from .transaction import get_script_type_from_output_script
from .crypto import sha256
from .bip32 import BIP32Node from .bip32 import BIP32Node
from .util import bfh, InvoiceError, resolve_dns_srv, is_ip_address, log_exceptions from .address_synchronizer import TX_HEIGHT_LOCAL, TX_TIMESTAMP_INF
from .crypto import chacha20_encrypt, chacha20_decrypt from .transaction import (
from .util import ignore_exceptions, make_aiohttp_session Transaction, get_script_type_from_output_script, PartialTxOutput, PartialTransaction, PartialTxInput
from .util import timestamp_to_datetime, random_shuffled_copy )
from .util import MyEncoder, is_private_netaddress, UnrelatedTransactionException from .crypto import (
from .logging import Logger sha256, chacha20_encrypt, chacha20_decrypt, pw_encode_with_version_and_mac, pw_decode_with_version_and_mac
)
from .lntransport import LNTransport, LNResponderTransport, LNTransportBase, LNPeerAddr, split_host_port, extract_nodeid, ConnStringFormatError from .lntransport import LNTransport, LNResponderTransport, LNTransportBase, LNPeerAddr, split_host_port, extract_nodeid, ConnStringFormatError
from .lnpeer import Peer, LN_P2P_NETWORK_TIMEOUT from .lnpeer import Peer, LN_P2P_NETWORK_TIMEOUT
from .lnaddr import lnencode, LnAddr, lndecode from .lnaddr import lnencode, LnAddr, lndecode
from .lnchannel import Channel, AbstractChannel from .lnchannel import Channel, AbstractChannel, ChannelState, PeerState, HTLCWithStatus, ChannelBackup
from .lnchannel import ChannelState, PeerState, HTLCWithStatus
from .lnrater import LNRater from .lnrater import LNRater
from . import lnutil from .lnutil import (
from .lnutil import funding_output_script get_compressed_pubkey_from_bech32, serialize_htlc_key, deserialize_htlc_key, PaymentFailure, generate_keypair,
from .lnutil import serialize_htlc_key, deserialize_htlc_key LnKeyFamily, LOCAL, REMOTE, MIN_FINAL_CLTV_DELTA_FOR_INVOICE, SENT, RECEIVED, HTLCOwner, UpdateAddHtlc, LnFeatures,
from .bitcoin import DummyAddress ShortChannelID, HtlcLog, NoPathFound, InvalidGossipMsg, FeeBudgetExceeded, ImportedChannelBackupStorage,
from .lnutil import (Outpoint, OnchainChannelBackupStorage, ln_compare_features, IncompatibleLightningFeatures, PaymentFeeBudget,
get_compressed_pubkey_from_bech32, NBLOCK_CLTV_DELTA_TOO_FAR_INTO_FUTURE
PaymentFailure, )
generate_keypair, LnKeyFamily, LOCAL, REMOTE,
MIN_FINAL_CLTV_DELTA_FOR_INVOICE,
NUM_MAX_EDGES_IN_PAYMENT_PATH, SENT, RECEIVED, HTLCOwner,
UpdateAddHtlc, Direction, LnFeatures, ShortChannelID,
HtlcLog, derive_payment_secret_from_payment_preimage,
NoPathFound, InvalidGossipMsg, FeeBudgetExceeded)
from .lnutil import ln_compare_features, IncompatibleLightningFeatures, PaymentFeeBudget
from .transaction import PartialTxOutput, PartialTransaction, PartialTxInput
from .lnonion import decode_onion_error, OnionFailureCode, OnionRoutingFailure, OnionPacket from .lnonion import decode_onion_error, OnionFailureCode, OnionRoutingFailure, OnionPacket
from .lnmsg import decode_msg from .lnmsg import decode_msg
from .i18n import _ from .lnrouter import (
from .lnrouter import (RouteEdge, LNPaymentRoute, LNPaymentPath, is_route_within_budget, RouteEdge, LNPaymentRoute, LNPaymentPath, is_route_within_budget, NoChannelPolicy, LNPathInconsistent
NoChannelPolicy, LNPathInconsistent) )
from .address_synchronizer import TX_HEIGHT_LOCAL, TX_TIMESTAMP_INF
from . import lnsweep
from .lnwatcher import LNWalletWatcher from .lnwatcher import LNWalletWatcher
from .crypto import pw_encode_with_version_and_mac, pw_decode_with_version_and_mac
from .lnutil import ImportedChannelBackupStorage, OnchainChannelBackupStorage
from .lnchannel import ChannelBackup
from .channel_db import UpdateStatus, ChannelDBNotLoaded
from .channel_db import get_mychannel_info, get_mychannel_policy
from .submarine_swaps import SwapManager from .submarine_swaps import SwapManager
from .channel_db import ChannelInfo, Policy
from .mpp_split import suggest_splits, SplitConfigRating from .mpp_split import suggest_splits, SplitConfigRating
from .trampoline import create_trampoline_route_and_onion, is_legacy_relay from .trampoline import (
from .json_db import stored_in create_trampoline_route_and_onion, is_legacy_relay, trampolines_by_id, hardcoded_trampoline_nodes,
is_hardcoded_trampoline
)
if TYPE_CHECKING: if TYPE_CHECKING:
from .network import Network from .network import Network
@@ -96,7 +81,7 @@ if TYPE_CHECKING:
from .simple_config import SimpleConfig from .simple_config import SimpleConfig
SAVED_PR_STATUS = [PR_PAID, PR_UNPAID] # status that are persisted SAVED_PR_STATUS = [PR_PAID, PR_UNPAID] # status that are persisted
NUM_PEERS_TARGET = 4 NUM_PEERS_TARGET = 4
@@ -106,9 +91,6 @@ CB_MAGIC_BYTES = bytes([0, 0, 0, CB_VERSION])
NODE_ID_PREFIX_LEN = 16 NODE_ID_PREFIX_LEN = 16
from .trampoline import trampolines_by_id, hardcoded_trampoline_nodes, is_hardcoded_trampoline
class PaymentDirection(IntEnum): class PaymentDirection(IntEnum):
SENT = 0 SENT = 0
RECEIVED = 1 RECEIVED = 1
@@ -139,12 +121,13 @@ class ReceivedMPPStatus(NamedTuple):
@stored_in('received_mpp_htlcs', tuple) @stored_in('received_mpp_htlcs', tuple)
def from_tuple(resolution, expected_msat, htlc_list) -> 'ReceivedMPPStatus': def from_tuple(resolution, expected_msat, htlc_list) -> 'ReceivedMPPStatus':
htlc_set = set([(ShortChannelID(bytes.fromhex(scid)), UpdateAddHtlc.from_tuple(*x)) for (scid,x) in htlc_list]) htlc_set = set([(ShortChannelID(bytes.fromhex(scid)), UpdateAddHtlc.from_tuple(*x)) for (scid, x) in htlc_list])
return ReceivedMPPStatus( return ReceivedMPPStatus(
resolution=RecvMPPResolution(resolution), resolution=RecvMPPResolution(resolution),
expected_msat=expected_msat, expected_msat=expected_msat,
htlc_set=htlc_set) htlc_set=htlc_set)
SentHtlcKey = Tuple[bytes, ShortChannelID, int] # RHASH, scid, htlc_id SentHtlcKey = Tuple[bytes, ShortChannelID, int] # RHASH, scid, htlc_id
@@ -219,10 +202,10 @@ class LNWorker(Logger, EventListener, NetworkRetryManager[LNPeerAddr]):
self.register_callbacks() self.register_callbacks()
@property @property
def channel_db(self): def channel_db(self) -> 'ChannelDB':
return self.network.channel_db if self.network else None return self.network.channel_db if self.network else None
def uses_trampoline(self): def uses_trampoline(self) -> bool:
return not bool(self.channel_db) return not bool(self.channel_db)
@property @property
@@ -259,6 +242,7 @@ class LNWorker(Logger, EventListener, NetworkRetryManager[LNPeerAddr]):
self.logger.error(f"failed to parse config key '{self.config.cv.LIGHTNING_LISTEN.key()}'. got: {e!r}") self.logger.error(f"failed to parse config key '{self.config.cv.LIGHTNING_LISTEN.key()}'. got: {e!r}")
return return
addr = str(netaddr.host) addr = str(netaddr.host)
async def cb(reader, writer): async def cb(reader, writer):
transport = LNResponderTransport(self.node_keypair.privkey, reader, writer) transport = LNResponderTransport(self.node_keypair.privkey, reader, writer)
try: try:
@@ -598,12 +582,14 @@ class LNGossip(LNWorker):
# and disconnect only from that peer # and disconnect only from that peer
await self.channel_db.data_loaded.wait() await self.channel_db.data_loaded.wait()
self.logger.debug(f'process_gossip {len(chan_anns)} {len(node_anns)} {len(chan_upds)}') self.logger.debug(f'process_gossip {len(chan_anns)} {len(node_anns)} {len(chan_upds)}')
# channel announcements # channel announcements
def process_chan_anns(): def process_chan_anns():
for payload in chan_anns: for payload in chan_anns:
self.channel_db.verify_channel_announcement(payload) self.channel_db.verify_channel_announcement(payload)
self.channel_db.add_channel_announcements(chan_anns) self.channel_db.add_channel_announcements(chan_anns)
await run_in_thread(process_chan_anns) await run_in_thread(process_chan_anns)
# node announcements # node announcements
def process_node_anns(): def process_node_anns():
for payload in node_anns: for payload in node_anns:
@@ -1494,7 +1480,7 @@ class LNWallet(LNWorker):
fwd_trampoline_onion: OnionPacket = None, fwd_trampoline_onion: OnionPacket = None,
budget: PaymentFeeBudget, budget: PaymentFeeBudget,
channels: Optional[Sequence[Channel]] = None, channels: Optional[Sequence[Channel]] = None,
fw_payment_key = None,# for forwarding fw_payment_key: str = None, # for forwarding
) -> None: ) -> None:
assert budget assert budget
@@ -1791,7 +1777,7 @@ class LNWallet(LNWorker):
if addr.amount is None: if addr.amount is None:
raise InvoiceError(_("Missing amount")) raise InvoiceError(_("Missing amount"))
# check cltv # check cltv
if addr.get_min_final_cltv_delta() > lnutil.NBLOCK_CLTV_DELTA_TOO_FAR_INTO_FUTURE: if addr.get_min_final_cltv_delta() > NBLOCK_CLTV_DELTA_TOO_FAR_INTO_FUTURE:
raise InvoiceError("{}\n{}".format( raise InvoiceError("{}\n{}".format(
_("Invoice wants us to risk locking funds for unreasonably long."), _("Invoice wants us to risk locking funds for unreasonably long."),
f"min_final_cltv_delta: {addr.get_min_final_cltv_delta()}")) f"min_final_cltv_delta: {addr.get_min_final_cltv_delta()}"))
@@ -2435,7 +2421,6 @@ class LNWallet(LNWorker):
if len(fw_htlcs) == 0 and not paysession_active: if len(fw_htlcs) == 0 and not paysession_active:
self.notify_upstream_peer(htlc_key) self.notify_upstream_peer(htlc_key)
def htlc_failed( def htlc_failed(
self, self,
chan: Channel, chan: Channel,
@@ -2597,6 +2582,7 @@ class LNWallet(LNWorker):
""" """
if deltas is None: if deltas is None:
deltas = {} deltas = {}
def send_capacity(chan): def send_capacity(chan):
if chan in deltas: if chan in deltas:
delta_msat = deltas[chan] * 1000 delta_msat = deltas[chan] * 1000
@@ -2653,6 +2639,7 @@ class LNWallet(LNWorker):
""" """
if deltas is None: if deltas is None:
deltas = {} deltas = {}
def recv_capacity(chan): def recv_capacity(chan):
if chan in deltas: if chan in deltas:
delta_msat = deltas[chan] * 1000 delta_msat = deltas[chan] * 1000
@@ -2669,7 +2656,6 @@ class LNWallet(LNWorker):
can_receive_msat = max(recv_chan_msats) can_receive_msat = max(recv_chan_msats)
return Decimal(can_receive_msat) / 1000 return Decimal(can_receive_msat) / 1000
def _suggest_channels_for_rebalance(self, direction, amount_sat) -> Sequence[Tuple[Channel, int]]: def _suggest_channels_for_rebalance(self, direction, amount_sat) -> Sequence[Tuple[Channel, int]]:
""" """
Suggest a channel and amount to send/receive with that channel, so that we will be able to receive/send amount_sat Suggest a channel and amount to send/receive with that channel, so that we will be able to receive/send amount_sat
@@ -2753,7 +2739,7 @@ class LNWallet(LNWorker):
swap_output = PartialTxOutput.from_address_and_value(DummyAddress.SWAP, int(swap_funding_sat)) swap_output = PartialTxOutput.from_address_and_value(DummyAddress.SWAP, int(swap_funding_sat))
if not self.wallet.can_pay_onchain([swap_output], coins=coins): if not self.wallet.can_pay_onchain([swap_output], coins=coins):
continue continue
return (chan, swap_recv_amount) return chan, swap_recv_amount
def suggest_swap_to_receive(self, amount_sat): def suggest_swap_to_receive(self, amount_sat):
assert amount_sat > self.num_sats_can_receive() assert amount_sat > self.num_sats_can_receive()
@@ -2762,7 +2748,7 @@ class LNWallet(LNWorker):
except NotEnoughFunds: except NotEnoughFunds:
return return
for chan, swap_recv_amount in suggestions: for chan, swap_recv_amount in suggestions:
return (chan, swap_recv_amount) return chan, swap_recv_amount
async def rebalance_channels(self, chan1: Channel, chan2: Channel, *, amount_msat: int): async def rebalance_channels(self, chan1: Channel, chan2: Channel, *, amount_msat: int):
if chan1 == chan2: if chan1 == chan2:
@@ -3100,4 +3086,3 @@ class LNWallet(LNWorker):
error_bytes = bytes.fromhex(error_hex) if error_hex else None error_bytes = bytes.fromhex(error_hex) if error_hex else None
failure_message = OnionRoutingFailure.from_bytes(bytes.fromhex(failure_hex)) if failure_hex else None failure_message = OnionRoutingFailure.from_bytes(bytes.fromhex(failure_hex)) if failure_hex else None
return error_bytes, failure_message return error_bytes, failure_message