Merge pull request #10463 from f321x/jit_2
lnwallet: zeroconf/just-in-time improvements and tests
This commit is contained in:
+4
-4
@@ -151,12 +151,12 @@ class TestLightningABC(TestLightning):
|
||||
class TestLightningJIT(TestLightning):
|
||||
agents = {
|
||||
'alice': {
|
||||
'accept_zeroconf_channels': 'true',
|
||||
'open_zeroconf_channels': 'true',
|
||||
},
|
||||
'bob': {
|
||||
'lightning_listen': 'localhost:9735',
|
||||
'lightning_forward_payments': 'true',
|
||||
'accept_zeroconf_channels': 'true',
|
||||
'open_zeroconf_channels': 'true',
|
||||
},
|
||||
'carol': {
|
||||
}
|
||||
@@ -170,13 +170,13 @@ class TestLightningJITTrampoline(TestLightningJIT):
|
||||
agents = {
|
||||
'alice': {
|
||||
'use_gossip': 'false',
|
||||
'accept_zeroconf_channels': 'true',
|
||||
'open_zeroconf_channels': 'true',
|
||||
},
|
||||
'bob': {
|
||||
'lightning_listen': 'localhost:9735',
|
||||
'lightning_forward_payments': 'true',
|
||||
'lightning_forward_trampoline_payments': 'true',
|
||||
'accept_zeroconf_channels': 'true',
|
||||
'open_zeroconf_channels': 'true',
|
||||
},
|
||||
'carol': {
|
||||
'use_gossip': 'false',
|
||||
|
||||
@@ -774,10 +774,24 @@ if [[ $1 == "just_in_time" ]]; then
|
||||
echo "carol pays alice"
|
||||
# note: set amount to 0.001 to test failure: 'payment too low'
|
||||
invoice=$($alice add_request 0.01 --lightning --memo "invoice" | jq -r ".lightning_invoice")
|
||||
success=$($carol lnpay $invoice| jq '.success')
|
||||
if [[ $success != "true" ]]; then
|
||||
echo "JIT payment failed"
|
||||
exit 1
|
||||
success=$($carol lnpay $invoice | jq -r ".success")
|
||||
if [[ "$success" != "true" ]]; then
|
||||
echo "jit payment failed"
|
||||
exit 1
|
||||
fi
|
||||
# try again, multiple jit openings should work without issues
|
||||
new_blocks 3
|
||||
echo "carol pays alice again"
|
||||
invoice=$($alice add_request 0.04 --lightning --memo "invoice2" | jq -r ".lightning_invoice")
|
||||
success=$($carol lnpay $invoice | jq -r ".success")
|
||||
if [[ "$success" != "true" ]]; then
|
||||
echo "jit payment failed"
|
||||
exit 1
|
||||
fi
|
||||
alice_chan_count=$($alice list_channels | jq '. | length')
|
||||
if [[ "$alice_chan_count" != "2" ]]; then
|
||||
echo "alice should have two jit channels"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
+63
-1
@@ -40,7 +40,8 @@ from electrum import lnutil
|
||||
from electrum.crypto import privkey_to_pubkey
|
||||
from electrum.lnutil import (
|
||||
SENT, LOCAL, REMOTE, RECEIVED, UpdateAddHtlc, LnFeatures, secret_to_pubkey, ChannelType,
|
||||
effective_htlc_tx_weight, LocalConfig, RemoteConfig, OnlyPubkeyKeypair,
|
||||
effective_htlc_tx_weight, LocalConfig, RemoteConfig, OnlyPubkeyKeypair, ZEROCONF_TIMEOUT,
|
||||
CHANNEL_OPENING_TIMEOUT_SEC,
|
||||
)
|
||||
from electrum.logging import console_stderr_handler
|
||||
from electrum.lnchannel import ChannelState, Channel
|
||||
@@ -787,6 +788,67 @@ class TestChannel(ElectrumTestCase):
|
||||
self.alice_channel._state = ChannelState.OPENING
|
||||
self.assertFalse(self.alice_channel.can_be_deleted())
|
||||
|
||||
async def test_update_unfunded_zeroconf_channel(self):
|
||||
"""Cover the zeroconf branch of update_unfunded_state"""
|
||||
chan = self.bob_channel
|
||||
chan.set_state(ChannelState.OPEN, force=True)
|
||||
bob = self.bob_lnwallet
|
||||
self.assertFalse(chan.is_initiator())
|
||||
trusted_node = f"{chan.node_id.hex()}@127.0.0.1:9735"
|
||||
chan.storage['channel_type'] |= ChannelType.OPTION_ZEROCONF
|
||||
self.assertTrue(chan.is_zeroconf())
|
||||
# add channel to lnwallet/db
|
||||
bob._channels[chan.channel_id] = chan
|
||||
bob.db.get('channels')[chan.channel_id.hex()] = "something"
|
||||
self.assertIsNotNone(bob.get_channel_by_id(chan.channel_id))
|
||||
chan.storage['init_height'] = 0 # checked by has_funding_timed_out
|
||||
chan.storage['init_timestamp'] = int(time.time())
|
||||
self.assertEqual(chan.get_state(), ChannelState.OPEN)
|
||||
self.assertEqual(chan.balance(LOCAL), 500000000000)
|
||||
bob.config.ZEROCONF_TRUSTED_NODE = trusted_node
|
||||
|
||||
chan.update_unfunded_state()
|
||||
|
||||
# assert nothing happened
|
||||
self.assertIsNotNone(bob.get_channel_by_id(chan.channel_id))
|
||||
self.assertIsNotNone(bob.db.get('channels').get(chan.channel_id.hex()))
|
||||
self.assertEqual(chan.get_state(), ChannelState.OPEN)
|
||||
self.assertEqual(bob.config.ZEROCONF_TRUSTED_NODE, trusted_node)
|
||||
|
||||
# now time out zeroconf funding and try again, however her wallet is not up to date
|
||||
chan.storage['init_timestamp'] -= ZEROCONF_TIMEOUT + 1
|
||||
bob.wallet.is_up_to_date = lambda: False
|
||||
|
||||
chan.update_unfunded_state()
|
||||
|
||||
# assert nothing happened again
|
||||
self.assertIsNotNone(bob.get_channel_by_id(chan.channel_id))
|
||||
self.assertIsNotNone(bob.db.get('channels').get(chan.channel_id.hex()))
|
||||
self.assertEqual(chan.get_state(), ChannelState.OPEN)
|
||||
self.assertEqual(bob.config.ZEROCONF_TRUSTED_NODE, trusted_node)
|
||||
self.assertFalse(chan.is_frozen_for_receiving())
|
||||
|
||||
# now her wallet is synced, and the channel is still unfunded
|
||||
bob.wallet.is_up_to_date = lambda: True
|
||||
|
||||
chan.update_unfunded_state()
|
||||
|
||||
# check zeroconf provider gets unset
|
||||
self.assertEqual(bob.config.ZEROCONF_TRUSTED_NODE, "")
|
||||
self.assertFalse(chan.has_funding_timed_out())
|
||||
self.assertTrue(chan.is_frozen_for_receiving())
|
||||
|
||||
# time out funding (~2 weeks)
|
||||
chan.storage['init_timestamp'] -= CHANNEL_OPENING_TIMEOUT_SEC + 1
|
||||
self.assertTrue(chan.has_funding_timed_out())
|
||||
|
||||
chan.update_unfunded_state()
|
||||
|
||||
# check that channel got removed, now that funding has timed out
|
||||
self.assertIsNone(self.alice_lnwallet.get_channel_by_id(chan.channel_id))
|
||||
self.assertIsNone(self.alice_lnwallet.db.get('channels').get(chan.channel_id.hex()))
|
||||
|
||||
|
||||
class TestChannelAnchors(TestChannel):
|
||||
TEST_ANCHOR_CHANNELS = True
|
||||
|
||||
|
||||
@@ -636,6 +636,55 @@ class TestPeerUtils(TestPeer):
|
||||
with self.assertRaises(InvalidGossipMsg):
|
||||
ChannelDB.verify_channel_update(payload, start_node=alice_bob_peer.pubkey)
|
||||
|
||||
async def test_zeroconf_feature_bit(self):
|
||||
workers = self.prepare_lnwallets(self.GRAPH_DEFINITIONS['single_chan'])
|
||||
|
||||
with self.subTest(msg="zeroconf is disabled in Alice LNWallet, so peers shouldn't signal it either"):
|
||||
graph = self.prepare_chans_and_peers_in_graph(
|
||||
self.GRAPH_DEFINITIONS['single_chan'],
|
||||
workers=workers,
|
||||
)
|
||||
alice, _ = graph.peers.values()
|
||||
self.assertFalse(alice.features.supports(LnFeatures.OPTION_ZEROCONF_OPT))
|
||||
|
||||
# enable zeroconf in alice LNWallet
|
||||
workers['alice'].features |= LnFeatures.OPTION_ZEROCONF_OPT
|
||||
|
||||
with self.subTest(msg="no trusted zeroconf node, zeroconf should be signaled in new peers"):
|
||||
graph = self.prepare_chans_and_peers_in_graph(
|
||||
self.GRAPH_DEFINITIONS['single_chan'],
|
||||
workers=workers,
|
||||
)
|
||||
alice, _ = graph.peers.values() # alice is LSP
|
||||
self.assertTrue(alice.features.supports(LnFeatures.OPTION_ZEROCONF_OPT))
|
||||
|
||||
with self.subTest(msg="trusted node is configured, but it is not bob"):
|
||||
workers['alice'].config.ZEROCONF_TRUSTED_NODE = f"{os.urandom(33).hex()}@1.1.1.1:9735"
|
||||
graph = self.prepare_chans_and_peers_in_graph(
|
||||
self.GRAPH_DEFINITIONS['single_chan'],
|
||||
workers=workers,
|
||||
)
|
||||
alice, _ = graph.peers.values() # alice is client
|
||||
self.assertFalse(alice.features.supports(LnFeatures.OPTION_ZEROCONF_OPT))
|
||||
|
||||
with self.subTest(msg="trusted node is configured, but it is invalid"):
|
||||
workers['alice'].config.ZEROCONF_TRUSTED_NODE = f"{os.urandom(8).hex()}@1.1.1.1:9735"
|
||||
graph = self.prepare_chans_and_peers_in_graph(
|
||||
self.GRAPH_DEFINITIONS['single_chan'],
|
||||
workers=workers,
|
||||
)
|
||||
alice, _ = graph.peers.values() # alice is client
|
||||
self.assertFalse(alice.features.supports(LnFeatures.OPTION_ZEROCONF_OPT))
|
||||
|
||||
with self.subTest(msg="Alice uses Bob as her trusted LSP"):
|
||||
workers['alice'].config.ZEROCONF_TRUSTED_NODE = workers['bob'].node_keypair.pubkey.hex()
|
||||
graph = self.prepare_chans_and_peers_in_graph(
|
||||
self.GRAPH_DEFINITIONS['single_chan'],
|
||||
workers=workers,
|
||||
)
|
||||
alice, _ = graph.peers.values()
|
||||
self.assertTrue(alice.features.supports(LnFeatures.OPTION_ZEROCONF_OPT))
|
||||
|
||||
|
||||
class TestPeerDirect(TestPeer):
|
||||
|
||||
|
||||
+273
-2
@@ -1,14 +1,22 @@
|
||||
import logging
|
||||
import os
|
||||
import asyncio
|
||||
from unittest import mock
|
||||
from decimal import Decimal
|
||||
|
||||
from electrum.address_synchronizer import TX_HEIGHT_LOCAL
|
||||
import electrum.trampoline
|
||||
from . import ElectrumTestCase
|
||||
from .test_lnchannel import create_test_channels
|
||||
|
||||
from electrum.lnutil import RECEIVED, MIN_FINAL_CLTV_DELTA_ACCEPTED, LnFeatures
|
||||
from electrum.lntransport import LNPeerAddr
|
||||
from electrum.lnutil import RECEIVED, MIN_FINAL_CLTV_DELTA_ACCEPTED, serialize_htlc_key, LnFeatures
|
||||
from electrum.logging import console_stderr_handler
|
||||
from electrum.lntransport import LNPeerAddr
|
||||
from electrum.invoices import LN_EXPIRY_NEVER, PR_UNPAID
|
||||
from electrum.lnpeer import Peer
|
||||
from electrum.lnchannel import Channel, ChannelState
|
||||
from electrum.lnonion import OnionPacket, OnionRoutingFailure
|
||||
from electrum.crypto import sha256
|
||||
|
||||
|
||||
class TestLNWallet(ElectrumTestCase):
|
||||
@@ -144,3 +152,266 @@ class TestLNWallet(ElectrumTestCase):
|
||||
lnaddr3, _ = wallet.get_bolt11_invoice(payment_info=pi2, message='test', fallback_address=None)
|
||||
hint_node_ids3 = {route[0][0] for route in lnaddr3.get_routing_info('r')}
|
||||
self.assertEqual(hint_node_ids3, {trampoline_pubkey})
|
||||
|
||||
async def test_open_channel_just_in_time_success(self):
|
||||
wallet = self.lnwallet_anchors
|
||||
wallet.config.ZEROCONF_MIN_OPENING_FEE = 0
|
||||
wallet.config.OPEN_ZEROCONF_CHANNELS = True
|
||||
|
||||
next_peer = mock.Mock(spec=Peer)
|
||||
next_chan = mock.Mock(spec=Channel)
|
||||
next_chan.get_scid_or_local_alias.return_value = bytes(8)
|
||||
|
||||
funding_tx = mock.Mock()
|
||||
funding_tx.txid.return_value = os.urandom(32).hex()
|
||||
funding_tx.get_fee = lambda: 250
|
||||
|
||||
wallet.open_channel_with_peer = mock.AsyncMock(return_value=(next_chan, funding_tx))
|
||||
wallet.network.try_broadcasting = mock.AsyncMock(return_value=True)
|
||||
|
||||
preimage = os.urandom(32)
|
||||
payment_hash = sha256(preimage)
|
||||
|
||||
htlc = mock.Mock()
|
||||
htlc.htlc_id = 0
|
||||
next_peer.send_htlc.return_value = htlc
|
||||
|
||||
task = asyncio.create_task(wallet.open_channel_just_in_time(
|
||||
next_peer=next_peer,
|
||||
next_amount_msat_htlc=1000000,
|
||||
next_cltv_abs=500,
|
||||
payment_hash=payment_hash,
|
||||
next_onion=mock.Mock(spec=OnionPacket)
|
||||
))
|
||||
|
||||
await asyncio.sleep(0.1)
|
||||
wallet.save_preimage(payment_hash, preimage)
|
||||
htlc_key = await task
|
||||
htlc_key_correct = serialize_htlc_key(next_chan.get_scid_or_local_alias(), htlc.htlc_id)
|
||||
self.assertEqual(htlc_key, htlc_key_correct)
|
||||
|
||||
wallet.open_channel_with_peer.assert_called_once()
|
||||
next_peer.send_htlc.assert_called_once()
|
||||
wallet.network.try_broadcasting.assert_called()
|
||||
|
||||
async def test_open_channel_just_in_time_failure_channel_open(self):
|
||||
"""The channel opening failed on the LSP side because the client rejected the incoming channel"""
|
||||
wallet = self.lnwallet_anchors
|
||||
wallet.config.ZEROCONF_MIN_OPENING_FEE = 0
|
||||
wallet.config.OPEN_ZEROCONF_CHANNELS = True
|
||||
next_peer = mock.Mock(spec=Peer)
|
||||
wallet.open_channel_with_peer = mock.AsyncMock(side_effect=Exception("peer rejected incoming channel"))
|
||||
preimage = os.urandom(32)
|
||||
wallet.save_preimage(sha256(preimage), preimage)
|
||||
wallet._cleanup_failed_jit_channel = mock.AsyncMock()
|
||||
|
||||
with self.assertRaises(OnionRoutingFailure):
|
||||
await wallet.open_channel_just_in_time(
|
||||
next_peer=next_peer,
|
||||
next_amount_msat_htlc=1000000,
|
||||
next_cltv_abs=500,
|
||||
payment_hash=sha256(preimage),
|
||||
next_onion=mock.Mock(spec=OnionPacket)
|
||||
)
|
||||
|
||||
self.assertIsNone(wallet.get_preimage(sha256(preimage)))
|
||||
wallet._cleanup_failed_jit_channel.assert_not_called()
|
||||
|
||||
async def test_open_channel_just_in_time_failure_send_htlc(self):
|
||||
"""The LSP fails to forward the htlc to the client"""
|
||||
wallet = self.lnwallet_anchors
|
||||
wallet.config.ZEROCONF_MIN_OPENING_FEE = 0
|
||||
wallet.config.OPEN_ZEROCONF_CHANNELS = True
|
||||
|
||||
next_peer = mock.Mock(spec=Peer)
|
||||
chan = mock.Mock(spec=Channel)
|
||||
funding_tx = mock.Mock()
|
||||
|
||||
wallet.open_channel_with_peer = mock.AsyncMock(return_value=(chan, funding_tx))
|
||||
next_peer.send_htlc.side_effect = Exception("couldn't send htlc, peer disconnected")
|
||||
preimage = os.urandom(32)
|
||||
wallet.save_preimage(sha256(preimage), preimage)
|
||||
wallet._cleanup_failed_jit_channel = mock.AsyncMock()
|
||||
|
||||
with self.assertRaises(OnionRoutingFailure):
|
||||
await wallet.open_channel_just_in_time(
|
||||
next_peer=next_peer,
|
||||
next_amount_msat_htlc=1000000,
|
||||
next_cltv_abs=500,
|
||||
payment_hash=sha256(preimage),
|
||||
next_onion=mock.Mock(spec=OnionPacket)
|
||||
)
|
||||
|
||||
self.assertIsNone(wallet.get_preimage(sha256(preimage)))
|
||||
wallet._cleanup_failed_jit_channel.assert_called_once_with(chan)
|
||||
|
||||
async def test_open_channel_just_in_time_failure_preimage_timeout(self):
|
||||
"""The client never releases the preimage"""
|
||||
wallet = self.lnwallet_anchors
|
||||
wallet.config.ZEROCONF_MIN_OPENING_FEE = 0
|
||||
wallet.config.OPEN_ZEROCONF_CHANNELS = True
|
||||
|
||||
next_peer = mock.Mock(spec=Peer)
|
||||
chan = mock.Mock(spec=Channel)
|
||||
funding_tx = mock.Mock()
|
||||
|
||||
wallet.open_channel_with_peer = mock.AsyncMock(return_value=(chan, funding_tx))
|
||||
|
||||
htlc = mock.Mock()
|
||||
next_peer.send_htlc.return_value = htlc
|
||||
|
||||
wallet._cleanup_failed_jit_channel = mock.AsyncMock()
|
||||
|
||||
with mock.patch('electrum.lnworker.LN_P2P_NETWORK_TIMEOUT', 0.01):
|
||||
with self.assertRaises(OnionRoutingFailure):
|
||||
await wallet.open_channel_just_in_time(
|
||||
next_peer=next_peer,
|
||||
next_amount_msat_htlc=1000000,
|
||||
next_cltv_abs=500,
|
||||
payment_hash=os.urandom(32),
|
||||
next_onion=mock.Mock(spec=OnionPacket)
|
||||
)
|
||||
|
||||
wallet._cleanup_failed_jit_channel.assert_called_once_with(chan)
|
||||
|
||||
async def test_open_channel_just_in_time_failure_broadcast(self):
|
||||
wallet = self.lnwallet_anchors
|
||||
wallet.config.ZEROCONF_MIN_OPENING_FEE = 0
|
||||
wallet.config.OPEN_ZEROCONF_CHANNELS = True
|
||||
|
||||
next_peer = mock.Mock(spec=Peer)
|
||||
chan = mock.Mock(spec=Channel)
|
||||
|
||||
funding_tx = mock.Mock()
|
||||
|
||||
wallet.open_channel_with_peer = mock.AsyncMock(return_value=(chan, funding_tx))
|
||||
|
||||
preimage = os.urandom(32)
|
||||
wallet.save_preimage(sha256(preimage), preimage)
|
||||
|
||||
wallet.network.try_broadcasting = mock.AsyncMock(return_value=False)
|
||||
wallet.wallet.adb.get_tx_height = mock.Mock(return_value=mock.Mock(height=lambda: TX_HEIGHT_LOCAL))
|
||||
|
||||
wallet._cleanup_failed_jit_channel = mock.AsyncMock()
|
||||
|
||||
with mock.patch('electrum.lnworker.ZEROCONF_TIMEOUT', 0.01), \
|
||||
mock.patch('electrum.lnworker.asyncio.sleep', new_callable=mock.AsyncMock):
|
||||
with self.assertRaises(OnionRoutingFailure):
|
||||
await wallet.open_channel_just_in_time(
|
||||
next_peer=next_peer,
|
||||
next_amount_msat_htlc=1000000,
|
||||
next_cltv_abs=500,
|
||||
payment_hash=sha256(preimage),
|
||||
next_onion=mock.Mock(spec=OnionPacket)
|
||||
)
|
||||
|
||||
self.assertIsNone(wallet.get_preimage(sha256(preimage)))
|
||||
wallet._cleanup_failed_jit_channel.assert_called_once_with(chan)
|
||||
|
||||
async def test_open_channel_just_in_time_config_disabled(self):
|
||||
"""open_channel_just_in_time rejects to open a channel if the config is disabled"""
|
||||
wallet = self.lnwallet_anchors
|
||||
wallet.config.ZEROCONF_MIN_OPENING_FEE = 0
|
||||
wallet.config.OPEN_ZEROCONF_CHANNELS = False
|
||||
|
||||
with self.assertRaises(AssertionError):
|
||||
await wallet.open_channel_just_in_time(
|
||||
next_peer=mock.Mock(spec=Peer),
|
||||
next_amount_msat_htlc=1000000,
|
||||
next_cltv_abs=500,
|
||||
payment_hash=os.urandom(32),
|
||||
next_onion=mock.Mock(spec=OnionPacket)
|
||||
)
|
||||
|
||||
async def test_cleanup_failed_jit_channel(self):
|
||||
wallet = self.lnwallet_anchors
|
||||
|
||||
chan = mock.Mock(spec=Channel)
|
||||
chan_id = os.urandom(32).hex()
|
||||
chan.channel_id = chan_id
|
||||
funding_txid = os.urandom(32).hex()
|
||||
chan.funding_outpoint = mock.Mock()
|
||||
chan.funding_outpoint.txid = funding_txid
|
||||
chan.get_funding_height.return_value = None
|
||||
|
||||
# close_channel fails with exception
|
||||
wallet.close_channel = mock.AsyncMock(side_effect=Exception("peer disconnected"))
|
||||
wallet.remove_channel = mock.Mock()
|
||||
wallet.lnwatcher = mock.Mock()
|
||||
wallet.lnwatcher.adb = mock.Mock()
|
||||
wallet.lnwatcher.adb.remove_transaction = mock.Mock()
|
||||
|
||||
await wallet._cleanup_failed_jit_channel(chan)
|
||||
|
||||
wallet.close_channel.assert_called_once_with(chan_id)
|
||||
chan.set_state.assert_called_once_with(ChannelState.REDEEMED, force=True)
|
||||
wallet.lnwatcher.adb.remove_transaction.assert_called_once_with(funding_txid)
|
||||
wallet.remove_channel.assert_called_once_with(chan_id)
|
||||
|
||||
async def test_receive_requires_jit_channel(self):
|
||||
wallet = self.lnwallet_anchors
|
||||
|
||||
with self.subTest(msg="cannot get jit channel"):
|
||||
wallet.can_get_zeroconf_channel = mock.Mock(return_value=False)
|
||||
wallet.num_sats_can_receive = mock.Mock(return_value=Decimal(0))
|
||||
self.assertFalse(wallet.receive_requires_jit_channel(1_000_000))
|
||||
|
||||
with self.subTest(msg="could get zeroconf channel but doesn't need one"):
|
||||
wallet.can_get_zeroconf_channel = mock.Mock(return_value=True)
|
||||
wallet.num_sats_can_receive = mock.Mock(return_value=Decimal(2000))
|
||||
self.assertFalse(wallet.receive_requires_jit_channel(1_000_000))
|
||||
|
||||
with self.subTest(msg="could get zeroconf channel and needs one"):
|
||||
wallet.can_get_zeroconf_channel = mock.Mock(return_value=True)
|
||||
wallet.num_sats_can_receive = mock.Mock(return_value=Decimal(500))
|
||||
self.assertTrue(wallet.receive_requires_jit_channel(1_000_000))
|
||||
|
||||
with self.subTest(msg="could get one but can receive exactly the requested amount"):
|
||||
wallet.can_get_zeroconf_channel = mock.Mock(return_value=True)
|
||||
wallet.num_sats_can_receive = mock.Mock(return_value=Decimal(1000))
|
||||
self.assertFalse(wallet.receive_requires_jit_channel(1_000_000))
|
||||
|
||||
with self.subTest(msg="0 amount invoice, could get channel but can receive something"):
|
||||
wallet.can_get_zeroconf_channel = mock.Mock(return_value=True)
|
||||
wallet.num_sats_can_receive = mock.Mock(return_value=Decimal(1))
|
||||
self.assertFalse(wallet.receive_requires_jit_channel(None))
|
||||
|
||||
with self.subTest(msg="0 amount invoice (None amount), cannot receive anything and can get channel"):
|
||||
wallet.can_get_zeroconf_channel = mock.Mock(return_value=True)
|
||||
wallet.num_sats_can_receive = mock.Mock(return_value=Decimal(0))
|
||||
self.assertTrue(wallet.receive_requires_jit_channel(None))
|
||||
|
||||
with self.subTest(msg="0 amount invoice (0 msat), cannot receive anything, could get channel"):
|
||||
wallet.can_get_zeroconf_channel = mock.Mock(return_value=True)
|
||||
wallet.num_sats_can_receive = mock.Mock(return_value=Decimal(0))
|
||||
self.assertTrue(wallet.receive_requires_jit_channel(0))
|
||||
|
||||
async def test_can_get_zeroconf_channel(self):
|
||||
wallet = self.lnwallet_anchors
|
||||
valid_peer = "02" * 33 + "@localhost:9735"
|
||||
|
||||
with self.subTest(msg="disabled in config"):
|
||||
wallet.config.OPEN_ZEROCONF_CHANNELS = False
|
||||
wallet.config.ZEROCONF_TRUSTED_NODE = valid_peer
|
||||
self.assertFalse(wallet.can_get_zeroconf_channel())
|
||||
|
||||
with self.subTest(msg="enabled, but no trusted node configured"):
|
||||
wallet.config.OPEN_ZEROCONF_CHANNELS = True
|
||||
wallet.config.ZEROCONF_TRUSTED_NODE = ''
|
||||
self.assertFalse(wallet.can_get_zeroconf_channel())
|
||||
|
||||
with self.subTest(msg="enabled, invalid trusted node string"):
|
||||
wallet.config.OPEN_ZEROCONF_CHANNELS = True
|
||||
wallet.config.ZEROCONF_TRUSTED_NODE = "invalid_node_string"
|
||||
self.assertFalse(wallet.can_get_zeroconf_channel())
|
||||
|
||||
with self.subTest(msg="enabled, valid trusted node, but not connected"):
|
||||
wallet.config.OPEN_ZEROCONF_CHANNELS = True
|
||||
wallet.config.ZEROCONF_TRUSTED_NODE = valid_peer
|
||||
self.assertFalse(wallet.can_get_zeroconf_channel())
|
||||
|
||||
with self.subTest(msg="enabled, valid trusted node, and connected"):
|
||||
wallet.lnpeermgr.get_peer_by_pubkey = mock.Mock(return_value=mock.Mock(spec=Peer))
|
||||
wallet.config.OPEN_ZEROCONF_CHANNELS = True
|
||||
wallet.config.ZEROCONF_TRUSTED_NODE = valid_peer
|
||||
self.assertTrue(wallet.can_get_zeroconf_channel())
|
||||
|
||||
Reference in New Issue
Block a user