|
@ -1,21 +1,31 @@ |
|
|
|
|
|
from math import inf |
|
|
import unittest |
|
|
import unittest |
|
|
import tempfile |
|
|
import tempfile |
|
|
import shutil |
|
|
import shutil |
|
|
import asyncio |
|
|
import asyncio |
|
|
|
|
|
|
|
|
from electrum.util import bh2u, bfh, create_and_start_event_loop |
|
|
from electrum.util import bh2u, bfh, create_and_start_event_loop |
|
|
|
|
|
from electrum.lnutil import ShortChannelID |
|
|
from electrum.lnonion import (OnionHopsDataSingle, new_onion_packet, |
|
|
from electrum.lnonion import (OnionHopsDataSingle, new_onion_packet, |
|
|
process_onion_packet, _decode_onion_error, decode_onion_error, |
|
|
process_onion_packet, _decode_onion_error, decode_onion_error, |
|
|
OnionFailureCode, OnionPacket) |
|
|
OnionFailureCode, OnionPacket) |
|
|
from electrum import bitcoin, lnrouter |
|
|
from electrum import bitcoin, lnrouter |
|
|
from electrum.constants import BitcoinTestnet |
|
|
from electrum.constants import BitcoinTestnet |
|
|
from electrum.simple_config import SimpleConfig |
|
|
from electrum.simple_config import SimpleConfig |
|
|
from electrum.lnrouter import PathEdge |
|
|
from electrum.lnrouter import PathEdge, LiquidityHintMgr, DEFAULT_PENALTY_PROPORTIONAL_MILLIONTH, DEFAULT_PENALTY_BASE_MSAT, fee_for_edge_msat |
|
|
|
|
|
|
|
|
from . import TestCaseForTestnet |
|
|
from . import TestCaseForTestnet |
|
|
from .test_bitcoin import needs_test_with_all_chacha20_implementations |
|
|
from .test_bitcoin import needs_test_with_all_chacha20_implementations |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def channel(number: int) -> ShortChannelID: |
|
|
|
|
|
return ShortChannelID(bfh(format(number, '016x'))) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def node(character: str) -> bytes: |
|
|
|
|
|
return b'\x02' + f'{character}'.encode() * 32 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Test_LNRouter(TestCaseForTestnet): |
|
|
class Test_LNRouter(TestCaseForTestnet): |
|
|
|
|
|
|
|
|
def setUp(self): |
|
|
def setUp(self): |
|
@ -28,7 +38,24 @@ class Test_LNRouter(TestCaseForTestnet): |
|
|
self._loop_thread.join(timeout=1) |
|
|
self._loop_thread.join(timeout=1) |
|
|
super().tearDown() |
|
|
super().tearDown() |
|
|
|
|
|
|
|
|
def test_find_path_for_payment(self): |
|
|
def prepare_graph(self): |
|
|
|
|
|
""" |
|
|
|
|
|
Network topology with channel ids: |
|
|
|
|
|
3 |
|
|
|
|
|
A --- B |
|
|
|
|
|
| 2/ | |
|
|
|
|
|
6 | E | 1 |
|
|
|
|
|
| /5 \7 | |
|
|
|
|
|
D --- C |
|
|
|
|
|
4 |
|
|
|
|
|
valid routes from A -> E: |
|
|
|
|
|
A -3-> B -2-> E |
|
|
|
|
|
A -6-> D -5-> E |
|
|
|
|
|
A -6-> D -4-> C -7-> E |
|
|
|
|
|
A -3-> B -1-> C -7-> E |
|
|
|
|
|
A -6-> D -4-> C -1-> B -2-> E |
|
|
|
|
|
A -3-> B -1-> C -4-> D -5-> E |
|
|
|
|
|
""" |
|
|
class fake_network: |
|
|
class fake_network: |
|
|
config = self.config |
|
|
config = self.config |
|
|
asyncio_loop = asyncio.get_event_loop() |
|
|
asyncio_loop = asyncio.get_event_loop() |
|
@ -37,67 +64,193 @@ class Test_LNRouter(TestCaseForTestnet): |
|
|
interface = None |
|
|
interface = None |
|
|
fake_network.channel_db = lnrouter.ChannelDB(fake_network()) |
|
|
fake_network.channel_db = lnrouter.ChannelDB(fake_network()) |
|
|
fake_network.channel_db.data_loaded.set() |
|
|
fake_network.channel_db.data_loaded.set() |
|
|
cdb = fake_network.channel_db |
|
|
self.cdb = fake_network.channel_db |
|
|
path_finder = lnrouter.LNPathFinder(cdb) |
|
|
self.path_finder = lnrouter.LNPathFinder(self.cdb) |
|
|
self.assertEqual(cdb.num_channels, 0) |
|
|
self.assertEqual(self.cdb.num_channels, 0) |
|
|
cdb.add_channel_announcements({'node_id_1': b'\x02bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb', 'node_id_2': b'\x02cccccccccccccccccccccccccccccccc', |
|
|
self.cdb.add_channel_announcements({ |
|
|
'bitcoin_key_1': b'\x02bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb', 'bitcoin_key_2': b'\x02cccccccccccccccccccccccccccccccc', |
|
|
'node_id_1': node('b'), 'node_id_2': node('c'), |
|
|
'short_channel_id': bfh('0000000000000001'), |
|
|
'bitcoin_key_1': node('b'), 'bitcoin_key_2': node('c'), |
|
|
'chain_hash': BitcoinTestnet.rev_genesis_bytes(), |
|
|
'short_channel_id': channel(1), |
|
|
'len': 0, 'features': b''}, trusted=True) |
|
|
'chain_hash': BitcoinTestnet.rev_genesis_bytes(), |
|
|
self.assertEqual(cdb.num_channels, 1) |
|
|
'len': 0, 'features': b'' |
|
|
cdb.add_channel_announcements({'node_id_1': b'\x02bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb', 'node_id_2': b'\x02eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', |
|
|
}, trusted=True) |
|
|
'bitcoin_key_1': b'\x02bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb', 'bitcoin_key_2': b'\x02eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', |
|
|
self.assertEqual(self.cdb.num_channels, 1) |
|
|
'short_channel_id': bfh('0000000000000002'), |
|
|
self.cdb.add_channel_announcements({ |
|
|
'chain_hash': BitcoinTestnet.rev_genesis_bytes(), |
|
|
'node_id_1': node('b'), 'node_id_2': node('e'), |
|
|
'len': 0, 'features': b''}, trusted=True) |
|
|
'bitcoin_key_1': node('b'), 'bitcoin_key_2': node('e'), |
|
|
cdb.add_channel_announcements({'node_id_1': b'\x02aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'node_id_2': b'\x02bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb', |
|
|
'short_channel_id': channel(2), |
|
|
'bitcoin_key_1': b'\x02aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'bitcoin_key_2': b'\x02bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb', |
|
|
'chain_hash': BitcoinTestnet.rev_genesis_bytes(), |
|
|
'short_channel_id': bfh('0000000000000003'), |
|
|
'len': 0, 'features': b'' |
|
|
'chain_hash': BitcoinTestnet.rev_genesis_bytes(), |
|
|
}, trusted=True) |
|
|
'len': 0, 'features': b''}, trusted=True) |
|
|
self.cdb.add_channel_announcements({ |
|
|
cdb.add_channel_announcements({'node_id_1': b'\x02cccccccccccccccccccccccccccccccc', 'node_id_2': b'\x02dddddddddddddddddddddddddddddddd', |
|
|
'node_id_1': node('a'), 'node_id_2': node('b'), |
|
|
'bitcoin_key_1': b'\x02cccccccccccccccccccccccccccccccc', 'bitcoin_key_2': b'\x02dddddddddddddddddddddddddddddddd', |
|
|
'bitcoin_key_1': node('a'), 'bitcoin_key_2': node('b'), |
|
|
'short_channel_id': bfh('0000000000000004'), |
|
|
'short_channel_id': channel(3), |
|
|
'chain_hash': BitcoinTestnet.rev_genesis_bytes(), |
|
|
'chain_hash': BitcoinTestnet.rev_genesis_bytes(), |
|
|
'len': 0, 'features': b''}, trusted=True) |
|
|
'len': 0, 'features': b'' |
|
|
cdb.add_channel_announcements({'node_id_1': b'\x02dddddddddddddddddddddddddddddddd', 'node_id_2': b'\x02eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', |
|
|
}, trusted=True) |
|
|
'bitcoin_key_1': b'\x02dddddddddddddddddddddddddddddddd', 'bitcoin_key_2': b'\x02eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', |
|
|
self.cdb.add_channel_announcements({ |
|
|
'short_channel_id': bfh('0000000000000005'), |
|
|
'node_id_1': node('c'), 'node_id_2': node('d'), |
|
|
'chain_hash': BitcoinTestnet.rev_genesis_bytes(), |
|
|
'bitcoin_key_1': node('c'), 'bitcoin_key_2': node('d'), |
|
|
'len': 0, 'features': b''}, trusted=True) |
|
|
'short_channel_id': channel(4), |
|
|
cdb.add_channel_announcements({'node_id_1': b'\x02aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'node_id_2': b'\x02dddddddddddddddddddddddddddddddd', |
|
|
'chain_hash': BitcoinTestnet.rev_genesis_bytes(), |
|
|
'bitcoin_key_1': b'\x02aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'bitcoin_key_2': b'\x02dddddddddddddddddddddddddddddddd', |
|
|
'len': 0, 'features': b'' |
|
|
'short_channel_id': bfh('0000000000000006'), |
|
|
}, trusted=True) |
|
|
'chain_hash': BitcoinTestnet.rev_genesis_bytes(), |
|
|
self.cdb.add_channel_announcements({ |
|
|
'len': 0, 'features': b''}, trusted=True) |
|
|
'node_id_1': node('d'), 'node_id_2': node('e'), |
|
|
|
|
|
'bitcoin_key_1': node('d'), 'bitcoin_key_2': node('e'), |
|
|
|
|
|
'short_channel_id': channel(5), |
|
|
|
|
|
'chain_hash': BitcoinTestnet.rev_genesis_bytes(), |
|
|
|
|
|
'len': 0, 'features': b'' |
|
|
|
|
|
}, trusted=True) |
|
|
|
|
|
self.cdb.add_channel_announcements({ |
|
|
|
|
|
'node_id_1': node('a'), 'node_id_2': node('d'), |
|
|
|
|
|
'bitcoin_key_1': node('a'), 'bitcoin_key_2': node('d'), |
|
|
|
|
|
'short_channel_id': channel(6), |
|
|
|
|
|
'chain_hash': BitcoinTestnet.rev_genesis_bytes(), |
|
|
|
|
|
'len': 0, 'features': b'' |
|
|
|
|
|
}, trusted=True) |
|
|
|
|
|
self.cdb.add_channel_announcements({ |
|
|
|
|
|
'node_id_1': node('c'), 'node_id_2': node('e'), |
|
|
|
|
|
'bitcoin_key_1': node('c'), 'bitcoin_key_2': node('e'), |
|
|
|
|
|
'short_channel_id': channel(7), |
|
|
|
|
|
'chain_hash': BitcoinTestnet.rev_genesis_bytes(), |
|
|
|
|
|
'len': 0, 'features': b'' |
|
|
|
|
|
}, trusted=True) |
|
|
def add_chan_upd(payload): |
|
|
def add_chan_upd(payload): |
|
|
cdb.add_channel_update(payload, verify=False) |
|
|
self.cdb.add_channel_update(payload, verify=False) |
|
|
add_chan_upd({'short_channel_id': bfh('0000000000000001'), 'message_flags': b'\x00', 'channel_flags': b'\x00', 'cltv_expiry_delta': 10, 'htlc_minimum_msat': 250, 'fee_base_msat': 100, 'fee_proportional_millionths': 150, 'chain_hash': BitcoinTestnet.rev_genesis_bytes(), 'timestamp': 0}) |
|
|
add_chan_upd({'short_channel_id': channel(1), 'message_flags': b'\x00', 'channel_flags': b'\x00', 'cltv_expiry_delta': 10, 'htlc_minimum_msat': 250, 'fee_base_msat': 100, 'fee_proportional_millionths': 150, 'chain_hash': BitcoinTestnet.rev_genesis_bytes(), 'timestamp': 0}) |
|
|
add_chan_upd({'short_channel_id': bfh('0000000000000001'), 'message_flags': b'\x00', 'channel_flags': b'\x01', 'cltv_expiry_delta': 10, 'htlc_minimum_msat': 250, 'fee_base_msat': 100, 'fee_proportional_millionths': 150, 'chain_hash': BitcoinTestnet.rev_genesis_bytes(), 'timestamp': 0}) |
|
|
add_chan_upd({'short_channel_id': channel(1), 'message_flags': b'\x00', 'channel_flags': b'\x01', 'cltv_expiry_delta': 10, 'htlc_minimum_msat': 250, 'fee_base_msat': 100, 'fee_proportional_millionths': 150, 'chain_hash': BitcoinTestnet.rev_genesis_bytes(), 'timestamp': 0}) |
|
|
add_chan_upd({'short_channel_id': bfh('0000000000000002'), 'message_flags': b'\x00', 'channel_flags': b'\x00', 'cltv_expiry_delta': 99, 'htlc_minimum_msat': 250, 'fee_base_msat': 100, 'fee_proportional_millionths': 150, 'chain_hash': BitcoinTestnet.rev_genesis_bytes(), 'timestamp': 0}) |
|
|
add_chan_upd({'short_channel_id': channel(2), 'message_flags': b'\x00', 'channel_flags': b'\x00', 'cltv_expiry_delta': 99, 'htlc_minimum_msat': 250, 'fee_base_msat': 100, 'fee_proportional_millionths': 150, 'chain_hash': BitcoinTestnet.rev_genesis_bytes(), 'timestamp': 0}) |
|
|
add_chan_upd({'short_channel_id': bfh('0000000000000002'), 'message_flags': b'\x00', 'channel_flags': b'\x01', 'cltv_expiry_delta': 10, 'htlc_minimum_msat': 250, 'fee_base_msat': 100, 'fee_proportional_millionths': 150, 'chain_hash': BitcoinTestnet.rev_genesis_bytes(), 'timestamp': 0}) |
|
|
add_chan_upd({'short_channel_id': channel(2), 'message_flags': b'\x00', 'channel_flags': b'\x01', 'cltv_expiry_delta': 10, 'htlc_minimum_msat': 250, 'fee_base_msat': 100, 'fee_proportional_millionths': 150, 'chain_hash': BitcoinTestnet.rev_genesis_bytes(), 'timestamp': 0}) |
|
|
add_chan_upd({'short_channel_id': bfh('0000000000000003'), 'message_flags': b'\x00', 'channel_flags': b'\x01', 'cltv_expiry_delta': 10, 'htlc_minimum_msat': 250, 'fee_base_msat': 100, 'fee_proportional_millionths': 150, 'chain_hash': BitcoinTestnet.rev_genesis_bytes(), 'timestamp': 0}) |
|
|
add_chan_upd({'short_channel_id': channel(3), 'message_flags': b'\x00', 'channel_flags': b'\x01', 'cltv_expiry_delta': 10, 'htlc_minimum_msat': 250, 'fee_base_msat': 100, 'fee_proportional_millionths': 150, 'chain_hash': BitcoinTestnet.rev_genesis_bytes(), 'timestamp': 0}) |
|
|
add_chan_upd({'short_channel_id': bfh('0000000000000003'), 'message_flags': b'\x00', 'channel_flags': b'\x00', 'cltv_expiry_delta': 10, 'htlc_minimum_msat': 250, 'fee_base_msat': 100, 'fee_proportional_millionths': 150, 'chain_hash': BitcoinTestnet.rev_genesis_bytes(), 'timestamp': 0}) |
|
|
add_chan_upd({'short_channel_id': channel(3), 'message_flags': b'\x00', 'channel_flags': b'\x00', 'cltv_expiry_delta': 10, 'htlc_minimum_msat': 250, 'fee_base_msat': 100, 'fee_proportional_millionths': 150, 'chain_hash': BitcoinTestnet.rev_genesis_bytes(), 'timestamp': 0}) |
|
|
add_chan_upd({'short_channel_id': bfh('0000000000000004'), 'message_flags': b'\x00', 'channel_flags': b'\x01', 'cltv_expiry_delta': 10, 'htlc_minimum_msat': 250, 'fee_base_msat': 100, 'fee_proportional_millionths': 150, 'chain_hash': BitcoinTestnet.rev_genesis_bytes(), 'timestamp': 0}) |
|
|
add_chan_upd({'short_channel_id': channel(4), 'message_flags': b'\x00', 'channel_flags': b'\x01', 'cltv_expiry_delta': 10, 'htlc_minimum_msat': 250, 'fee_base_msat': 100, 'fee_proportional_millionths': 150, 'chain_hash': BitcoinTestnet.rev_genesis_bytes(), 'timestamp': 0}) |
|
|
add_chan_upd({'short_channel_id': bfh('0000000000000004'), 'message_flags': b'\x00', 'channel_flags': b'\x00', 'cltv_expiry_delta': 10, 'htlc_minimum_msat': 250, 'fee_base_msat': 100, 'fee_proportional_millionths': 150, 'chain_hash': BitcoinTestnet.rev_genesis_bytes(), 'timestamp': 0}) |
|
|
add_chan_upd({'short_channel_id': channel(4), 'message_flags': b'\x00', 'channel_flags': b'\x00', 'cltv_expiry_delta': 10, 'htlc_minimum_msat': 250, 'fee_base_msat': 100, 'fee_proportional_millionths': 150, 'chain_hash': BitcoinTestnet.rev_genesis_bytes(), 'timestamp': 0}) |
|
|
add_chan_upd({'short_channel_id': bfh('0000000000000005'), 'message_flags': b'\x00', 'channel_flags': b'\x01', 'cltv_expiry_delta': 10, 'htlc_minimum_msat': 250, 'fee_base_msat': 100, 'fee_proportional_millionths': 150, 'chain_hash': BitcoinTestnet.rev_genesis_bytes(), 'timestamp': 0}) |
|
|
add_chan_upd({'short_channel_id': channel(5), 'message_flags': b'\x00', 'channel_flags': b'\x01', 'cltv_expiry_delta': 10, 'htlc_minimum_msat': 250, 'fee_base_msat': 100, 'fee_proportional_millionths': 150, 'chain_hash': BitcoinTestnet.rev_genesis_bytes(), 'timestamp': 0}) |
|
|
add_chan_upd({'short_channel_id': bfh('0000000000000005'), 'message_flags': b'\x00', 'channel_flags': b'\x00', 'cltv_expiry_delta': 10, 'htlc_minimum_msat': 250, 'fee_base_msat': 100, 'fee_proportional_millionths': 999, 'chain_hash': BitcoinTestnet.rev_genesis_bytes(), 'timestamp': 0}) |
|
|
add_chan_upd({'short_channel_id': channel(5), 'message_flags': b'\x00', 'channel_flags': b'\x00', 'cltv_expiry_delta': 10, 'htlc_minimum_msat': 250, 'fee_base_msat': 100, 'fee_proportional_millionths': 999, 'chain_hash': BitcoinTestnet.rev_genesis_bytes(), 'timestamp': 0}) |
|
|
add_chan_upd({'short_channel_id': bfh('0000000000000006'), 'message_flags': b'\x00', 'channel_flags': b'\x00', 'cltv_expiry_delta': 10, 'htlc_minimum_msat': 250, 'fee_base_msat': 100, 'fee_proportional_millionths': 99999999, 'chain_hash': BitcoinTestnet.rev_genesis_bytes(), 'timestamp': 0}) |
|
|
add_chan_upd({'short_channel_id': channel(6), 'message_flags': b'\x00', 'channel_flags': b'\x00', 'cltv_expiry_delta': 10, 'htlc_minimum_msat': 250, 'fee_base_msat': 100, 'fee_proportional_millionths': 200, 'chain_hash': BitcoinTestnet.rev_genesis_bytes(), 'timestamp': 0}) |
|
|
add_chan_upd({'short_channel_id': bfh('0000000000000006'), 'message_flags': b'\x00', 'channel_flags': b'\x01', 'cltv_expiry_delta': 10, 'htlc_minimum_msat': 250, 'fee_base_msat': 100, 'fee_proportional_millionths': 150, 'chain_hash': BitcoinTestnet.rev_genesis_bytes(), 'timestamp': 0}) |
|
|
add_chan_upd({'short_channel_id': channel(6), 'message_flags': b'\x00', 'channel_flags': b'\x01', 'cltv_expiry_delta': 10, 'htlc_minimum_msat': 250, 'fee_base_msat': 100, 'fee_proportional_millionths': 150, 'chain_hash': BitcoinTestnet.rev_genesis_bytes(), 'timestamp': 0}) |
|
|
path = path_finder.find_path_for_payment( |
|
|
add_chan_upd({'short_channel_id': channel(7), 'message_flags': b'\x00', 'channel_flags': b'\x00', 'cltv_expiry_delta': 10, 'htlc_minimum_msat': 250, 'fee_base_msat': 100, 'fee_proportional_millionths': 150, 'chain_hash': BitcoinTestnet.rev_genesis_bytes(), 'timestamp': 0}) |
|
|
nodeA=b'\x02aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', |
|
|
add_chan_upd({'short_channel_id': channel(7), 'message_flags': b'\x00', 'channel_flags': b'\x01', 'cltv_expiry_delta': 10, 'htlc_minimum_msat': 250, 'fee_base_msat': 100, 'fee_proportional_millionths': 150, 'chain_hash': BitcoinTestnet.rev_genesis_bytes(), 'timestamp': 0}) |
|
|
nodeB=b'\x02eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', |
|
|
|
|
|
invoice_amount_msat=100000) |
|
|
def test_find_path_for_payment(self): |
|
|
self.assertEqual([PathEdge(start_node=b'\x02aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', end_node=b'\x02bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb', short_channel_id=bfh('0000000000000003')), |
|
|
self.prepare_graph() |
|
|
PathEdge(start_node=b'\x02bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb', end_node=b'\x02eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', short_channel_id=bfh('0000000000000002')), |
|
|
amount_to_send = 100000 |
|
|
], path) |
|
|
|
|
|
route = path_finder.create_route_from_path(path) |
|
|
path = self.path_finder.find_path_for_payment( |
|
|
self.assertEqual(b'\x02bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb', route[0].node_id) |
|
|
nodeA=node('a'), |
|
|
self.assertEqual(bfh('0000000000000003'), route[0].short_channel_id) |
|
|
nodeB=node('e'), |
|
|
|
|
|
invoice_amount_msat=amount_to_send) |
|
|
cdb.stop() |
|
|
self.assertEqual([ |
|
|
asyncio.run_coroutine_threadsafe(cdb.stopped_event.wait(), self.asyncio_loop).result() |
|
|
PathEdge(start_node=node('a'), end_node=node('b'), short_channel_id=channel(3)), |
|
|
|
|
|
PathEdge(start_node=node('b'), end_node=node('e'), short_channel_id=channel(2)), |
|
|
|
|
|
], path) |
|
|
|
|
|
|
|
|
|
|
|
route = self.path_finder.create_route_from_path(path) |
|
|
|
|
|
self.assertEqual(node('b'), route[0].node_id) |
|
|
|
|
|
self.assertEqual(channel(3), route[0].short_channel_id) |
|
|
|
|
|
|
|
|
|
|
|
self.cdb.stop() |
|
|
|
|
|
asyncio.run_coroutine_threadsafe(self.cdb.stopped_event.wait(), self.asyncio_loop).result() |
|
|
|
|
|
|
|
|
|
|
|
def test_find_path_liquidity_hints_failure(self): |
|
|
|
|
|
self.prepare_graph() |
|
|
|
|
|
amount_to_send = 100000 |
|
|
|
|
|
|
|
|
|
|
|
""" |
|
|
|
|
|
assume failure over channel 2, B -> E |
|
|
|
|
|
A -3-> B |-2-> E |
|
|
|
|
|
A -6-> D -5-> E <= chosen path |
|
|
|
|
|
A -6-> D -4-> C -7-> E |
|
|
|
|
|
A -3-> B -1-> C -7-> E |
|
|
|
|
|
A -6-> D -4-> C -1-> B -2-> E |
|
|
|
|
|
A -3-> B -1-> C -4-> D -5-> E |
|
|
|
|
|
""" |
|
|
|
|
|
self.path_finder.liquidity_hints.update_cannot_send(node('b'), node('e'), channel(2), amount_to_send - 1) |
|
|
|
|
|
path = self.path_finder.find_path_for_payment( |
|
|
|
|
|
nodeA=node('a'), |
|
|
|
|
|
nodeB=node('e'), |
|
|
|
|
|
invoice_amount_msat=amount_to_send) |
|
|
|
|
|
self.assertEqual(channel(6), path[0].short_channel_id) |
|
|
|
|
|
self.assertEqual(channel(5), path[1].short_channel_id) |
|
|
|
|
|
|
|
|
|
|
|
""" |
|
|
|
|
|
assume failure over channel 5, D -> E |
|
|
|
|
|
A -3-> B |-2-> E |
|
|
|
|
|
A -6-> D |-5-> E |
|
|
|
|
|
A -6-> D -4-> C -7-> E |
|
|
|
|
|
A -3-> B -1-> C -7-> E <= chosen path |
|
|
|
|
|
A -6-> D -4-> C -1-> B |-2-> E |
|
|
|
|
|
A -3-> B -1-> C -4-> D |-5-> E |
|
|
|
|
|
""" |
|
|
|
|
|
self.path_finder.liquidity_hints.update_cannot_send(node('d'), node('e'), channel(5), amount_to_send - 1) |
|
|
|
|
|
path = self.path_finder.find_path_for_payment( |
|
|
|
|
|
nodeA=node('a'), |
|
|
|
|
|
nodeB=node('e'), |
|
|
|
|
|
invoice_amount_msat=amount_to_send) |
|
|
|
|
|
self.assertEqual(channel(3), path[0].short_channel_id) |
|
|
|
|
|
self.assertEqual(channel(1), path[1].short_channel_id) |
|
|
|
|
|
self.assertEqual(channel(7), path[2].short_channel_id) |
|
|
|
|
|
|
|
|
|
|
|
""" |
|
|
|
|
|
assume success over channel 4, D -> C |
|
|
|
|
|
A -3-> B |-2-> E |
|
|
|
|
|
A -6-> D |-5-> E |
|
|
|
|
|
A -6-> D -4-> C -7-> E <= chosen path |
|
|
|
|
|
A -3-> B -1-> C -7-> E |
|
|
|
|
|
A -6-> D -4-> C -1-> B |-2-> E |
|
|
|
|
|
A -3-> B -1-> C -4-> D |-5-> E |
|
|
|
|
|
""" |
|
|
|
|
|
self.path_finder.liquidity_hints.update_can_send(node('d'), node('c'), channel(4), amount_to_send + 1000) |
|
|
|
|
|
path = self.path_finder.find_path_for_payment( |
|
|
|
|
|
nodeA=node('a'), |
|
|
|
|
|
nodeB=node('e'), |
|
|
|
|
|
invoice_amount_msat=amount_to_send) |
|
|
|
|
|
self.assertEqual(channel(6), path[0].short_channel_id) |
|
|
|
|
|
self.assertEqual(channel(4), path[1].short_channel_id) |
|
|
|
|
|
self.assertEqual(channel(7), path[2].short_channel_id) |
|
|
|
|
|
|
|
|
|
|
|
self.cdb.stop() |
|
|
|
|
|
asyncio.run_coroutine_threadsafe(self.cdb.stopped_event.wait(), self.asyncio_loop).result() |
|
|
|
|
|
|
|
|
|
|
|
def test_liquidity_hints(self): |
|
|
|
|
|
liquidity_hints = LiquidityHintMgr() |
|
|
|
|
|
node_from = bytes(0) |
|
|
|
|
|
node_to = bytes(1) |
|
|
|
|
|
channel_id = ShortChannelID.from_components(0, 0, 0) |
|
|
|
|
|
amount_to_send = 1_000_000 |
|
|
|
|
|
|
|
|
|
|
|
# check default penalty |
|
|
|
|
|
self.assertEqual( |
|
|
|
|
|
fee_for_edge_msat(amount_to_send, DEFAULT_PENALTY_BASE_MSAT, DEFAULT_PENALTY_PROPORTIONAL_MILLIONTH), |
|
|
|
|
|
liquidity_hints.penalty(node_from, node_to, channel_id, amount_to_send) |
|
|
|
|
|
) |
|
|
|
|
|
liquidity_hints.update_can_send(node_from, node_to, channel_id, 1_000_000) |
|
|
|
|
|
liquidity_hints.update_cannot_send(node_from, node_to, channel_id, 2_000_000) |
|
|
|
|
|
hint = liquidity_hints.get_hint(channel_id) |
|
|
|
|
|
self.assertEqual(1_000_000, hint.can_send(node_from < node_to)) |
|
|
|
|
|
self.assertEqual(None, hint.cannot_send(node_to < node_from)) |
|
|
|
|
|
self.assertEqual(2_000_000, hint.cannot_send(node_from < node_to)) |
|
|
|
|
|
# the can_send backward hint is set automatically |
|
|
|
|
|
self.assertEqual(2_000_000, hint.can_send(node_to < node_from)) |
|
|
|
|
|
|
|
|
|
|
|
# check penalties |
|
|
|
|
|
self.assertEqual(0., liquidity_hints.penalty(node_from, node_to, channel_id, 1_000_000)) |
|
|
|
|
|
self.assertEqual(650, liquidity_hints.penalty(node_from, node_to, channel_id, 1_500_000)) |
|
|
|
|
|
self.assertEqual(inf, liquidity_hints.penalty(node_from, node_to, channel_id, 2_000_000)) |
|
|
|
|
|
|
|
|
|
|
|
# test that we don't overwrite significant info with less significant info |
|
|
|
|
|
liquidity_hints.update_can_send(node_from, node_to, channel_id, 500_000) |
|
|
|
|
|
hint = liquidity_hints.get_hint(channel_id) |
|
|
|
|
|
self.assertEqual(1_000_000, hint.can_send(node_from < node_to)) |
|
|
|
|
|
|
|
|
|
|
|
# test case when can_send > cannot_send |
|
|
|
|
|
liquidity_hints.update_can_send(node_from, node_to, channel_id, 3_000_000) |
|
|
|
|
|
hint = liquidity_hints.get_hint(channel_id) |
|
|
|
|
|
self.assertEqual(3_000_000, hint.can_send(node_from < node_to)) |
|
|
|
|
|
self.assertEqual(None, hint.cannot_send(node_from < node_to)) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@needs_test_with_all_chacha20_implementations |
|
|
@needs_test_with_all_chacha20_implementations |
|
|
def test_new_onion_packet_legacy(self): |
|
|
def test_new_onion_packet_legacy(self): |
|
|