ln gossip: make sure all signatures are verified
we have not been verifying signatures of ChannelUpdate messages...
(regression from 2d0ef78a11)
This commit is contained in:
@@ -41,9 +41,11 @@ from . import constants, util
|
|||||||
from .util import bh2u, profiler, get_headers_dir, is_ip_address, json_normalize
|
from .util import bh2u, profiler, get_headers_dir, is_ip_address, json_normalize
|
||||||
from .logging import Logger
|
from .logging import Logger
|
||||||
from .lnutil import (LNPeerAddr, format_short_channel_id, ShortChannelID,
|
from .lnutil import (LNPeerAddr, format_short_channel_id, ShortChannelID,
|
||||||
validate_features, IncompatibleOrInsaneFeatures)
|
validate_features, IncompatibleOrInsaneFeatures, InvalidGossipMsg)
|
||||||
from .lnverifier import LNChannelVerifier, verify_sig_for_channel_update
|
from .lnverifier import LNChannelVerifier, verify_sig_for_channel_update
|
||||||
from .lnmsg import decode_msg
|
from .lnmsg import decode_msg
|
||||||
|
from . import ecc
|
||||||
|
from .crypto import sha256d
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from .network import Network
|
from .network import Network
|
||||||
@@ -378,7 +380,7 @@ class ChannelDB(SqlDB):
|
|||||||
# even slower; especially as servers will start throttling us.
|
# even slower; especially as servers will start throttling us.
|
||||||
# It would probably put significant strain on servers if all clients
|
# It would probably put significant strain on servers if all clients
|
||||||
# verified the complete gossip.
|
# verified the complete gossip.
|
||||||
def add_channel_announcement(self, msg_payloads, *, trusted=True):
|
def add_channel_announcements(self, msg_payloads, *, trusted=True):
|
||||||
# note: signatures have already been verified.
|
# note: signatures have already been verified.
|
||||||
if type(msg_payloads) is dict:
|
if type(msg_payloads) is dict:
|
||||||
msg_payloads = [msg_payloads]
|
msg_payloads = [msg_payloads]
|
||||||
@@ -452,7 +454,8 @@ class ChannelDB(SqlDB):
|
|||||||
self.logger.info(f'policy unchanged: {old_policy.timestamp} -> {new_policy.timestamp}')
|
self.logger.info(f'policy unchanged: {old_policy.timestamp} -> {new_policy.timestamp}')
|
||||||
return changed
|
return changed
|
||||||
|
|
||||||
def add_channel_update(self, payload, max_age=None, verify=False, verbose=True):
|
def add_channel_update(
|
||||||
|
self, payload, *, max_age=None, verify=True, verbose=True) -> UpdateStatus:
|
||||||
now = int(time.time())
|
now = int(time.time())
|
||||||
short_channel_id = ShortChannelID(payload['short_channel_id'])
|
short_channel_id = ShortChannelID(payload['short_channel_id'])
|
||||||
timestamp = payload['timestamp']
|
timestamp = payload['timestamp']
|
||||||
@@ -468,8 +471,6 @@ class ChannelDB(SqlDB):
|
|||||||
start_node = channel_info.node1_id if direction == 0 else channel_info.node2_id
|
start_node = channel_info.node1_id if direction == 0 else channel_info.node2_id
|
||||||
payload['start_node'] = start_node
|
payload['start_node'] = start_node
|
||||||
# compare updates to existing database entries
|
# compare updates to existing database entries
|
||||||
timestamp = payload['timestamp']
|
|
||||||
start_node = payload['start_node']
|
|
||||||
short_channel_id = ShortChannelID(payload['short_channel_id'])
|
short_channel_id = ShortChannelID(payload['short_channel_id'])
|
||||||
key = (start_node, short_channel_id)
|
key = (start_node, short_channel_id)
|
||||||
old_policy = self._policies.get(key)
|
old_policy = self._policies.get(key)
|
||||||
@@ -495,7 +496,7 @@ class ChannelDB(SqlDB):
|
|||||||
unchanged = []
|
unchanged = []
|
||||||
good = []
|
good = []
|
||||||
for payload in payloads:
|
for payload in payloads:
|
||||||
r = self.add_channel_update(payload, max_age=max_age, verbose=False)
|
r = self.add_channel_update(payload, max_age=max_age, verbose=False, verify=True)
|
||||||
if r == UpdateStatus.ORPHANED:
|
if r == UpdateStatus.ORPHANED:
|
||||||
orphaned.append(payload)
|
orphaned.append(payload)
|
||||||
elif r == UpdateStatus.EXPIRED:
|
elif r == UpdateStatus.EXPIRED:
|
||||||
@@ -567,15 +568,33 @@ class ChannelDB(SqlDB):
|
|||||||
if r == []:
|
if r == []:
|
||||||
c.execute("INSERT INTO address (node_id, host, port, timestamp) VALUES (?,?,?,?)", (addr.pubkey, addr.host, addr.port, 0))
|
c.execute("INSERT INTO address (node_id, host, port, timestamp) VALUES (?,?,?,?)", (addr.pubkey, addr.host, addr.port, 0))
|
||||||
|
|
||||||
def verify_channel_update(self, payload):
|
@classmethod
|
||||||
|
def verify_channel_update(cls, payload) -> None:
|
||||||
short_channel_id = payload['short_channel_id']
|
short_channel_id = payload['short_channel_id']
|
||||||
short_channel_id = ShortChannelID(short_channel_id)
|
short_channel_id = ShortChannelID(short_channel_id)
|
||||||
if constants.net.rev_genesis_bytes() != payload['chain_hash']:
|
if constants.net.rev_genesis_bytes() != payload['chain_hash']:
|
||||||
raise Exception('wrong chain hash')
|
raise InvalidGossipMsg('wrong chain hash')
|
||||||
if not verify_sig_for_channel_update(payload, payload['start_node']):
|
if not verify_sig_for_channel_update(payload, payload['start_node']):
|
||||||
raise Exception(f'failed verifying channel update for {short_channel_id}')
|
raise InvalidGossipMsg(f'failed verifying channel update for {short_channel_id}')
|
||||||
|
|
||||||
def add_node_announcement(self, msg_payloads):
|
@classmethod
|
||||||
|
def verify_channel_announcement(cls, payload) -> None:
|
||||||
|
h = sha256d(payload['raw'][2+256:])
|
||||||
|
pubkeys = [payload['node_id_1'], payload['node_id_2'], payload['bitcoin_key_1'], payload['bitcoin_key_2']]
|
||||||
|
sigs = [payload['node_signature_1'], payload['node_signature_2'], payload['bitcoin_signature_1'], payload['bitcoin_signature_2']]
|
||||||
|
for pubkey, sig in zip(pubkeys, sigs):
|
||||||
|
if not ecc.verify_signature(pubkey, sig, h):
|
||||||
|
raise InvalidGossipMsg('signature failed')
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def verify_node_announcement(cls, payload) -> None:
|
||||||
|
pubkey = payload['node_id']
|
||||||
|
signature = payload['signature']
|
||||||
|
h = sha256d(payload['raw'][66:])
|
||||||
|
if not ecc.verify_signature(pubkey, signature, h):
|
||||||
|
raise InvalidGossipMsg('signature failed')
|
||||||
|
|
||||||
|
def add_node_announcements(self, msg_payloads):
|
||||||
# note: signatures have already been verified.
|
# note: signatures have already been verified.
|
||||||
if type(msg_payloads) is dict:
|
if type(msg_payloads) is dict:
|
||||||
msg_payloads = [msg_payloads]
|
msg_payloads = [msg_payloads]
|
||||||
|
|||||||
@@ -342,29 +342,9 @@ class Peer(Logger):
|
|||||||
raise Exception('unknown message')
|
raise Exception('unknown message')
|
||||||
if self.gossip_queue.empty():
|
if self.gossip_queue.empty():
|
||||||
break
|
break
|
||||||
# verify in peer's TaskGroup so that we fail the connection
|
|
||||||
self.verify_channel_announcements(chan_anns)
|
|
||||||
self.verify_node_announcements(node_anns)
|
|
||||||
if self.network.lngossip:
|
if self.network.lngossip:
|
||||||
await self.network.lngossip.process_gossip(chan_anns, node_anns, chan_upds)
|
await self.network.lngossip.process_gossip(chan_anns, node_anns, chan_upds)
|
||||||
|
|
||||||
def verify_channel_announcements(self, chan_anns):
|
|
||||||
for payload in chan_anns:
|
|
||||||
h = sha256d(payload['raw'][2+256:])
|
|
||||||
pubkeys = [payload['node_id_1'], payload['node_id_2'], payload['bitcoin_key_1'], payload['bitcoin_key_2']]
|
|
||||||
sigs = [payload['node_signature_1'], payload['node_signature_2'], payload['bitcoin_signature_1'], payload['bitcoin_signature_2']]
|
|
||||||
for pubkey, sig in zip(pubkeys, sigs):
|
|
||||||
if not ecc.verify_signature(pubkey, sig, h):
|
|
||||||
raise Exception('signature failed')
|
|
||||||
|
|
||||||
def verify_node_announcements(self, node_anns):
|
|
||||||
for payload in node_anns:
|
|
||||||
pubkey = payload['node_id']
|
|
||||||
signature = payload['signature']
|
|
||||||
h = sha256d(payload['raw'][66:])
|
|
||||||
if not ecc.verify_signature(pubkey, signature, h):
|
|
||||||
raise Exception('signature failed')
|
|
||||||
|
|
||||||
async def query_gossip(self):
|
async def query_gossip(self):
|
||||||
try:
|
try:
|
||||||
await asyncio.wait_for(self.initialized, LN_P2P_NETWORK_TIMEOUT)
|
await asyncio.wait_for(self.initialized, LN_P2P_NETWORK_TIMEOUT)
|
||||||
|
|||||||
@@ -288,6 +288,8 @@ class RemoteMisbehaving(LightningError): pass
|
|||||||
class UpfrontShutdownScriptViolation(RemoteMisbehaving): pass
|
class UpfrontShutdownScriptViolation(RemoteMisbehaving): pass
|
||||||
|
|
||||||
class NotFoundChanAnnouncementForUpdate(Exception): pass
|
class NotFoundChanAnnouncementForUpdate(Exception): pass
|
||||||
|
class InvalidGossipMsg(Exception):
|
||||||
|
"""e.g. signature check failed"""
|
||||||
|
|
||||||
class PaymentFailure(UserFacingException): pass
|
class PaymentFailure(UserFacingException): pass
|
||||||
class NoPathFound(PaymentFailure):
|
class NoPathFound(PaymentFailure):
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ from .lnutil import (Outpoint, LNPeerAddr,
|
|||||||
NUM_MAX_EDGES_IN_PAYMENT_PATH, SENT, RECEIVED, HTLCOwner,
|
NUM_MAX_EDGES_IN_PAYMENT_PATH, SENT, RECEIVED, HTLCOwner,
|
||||||
UpdateAddHtlc, Direction, LnFeatures, ShortChannelID,
|
UpdateAddHtlc, Direction, LnFeatures, ShortChannelID,
|
||||||
HtlcLog, derive_payment_secret_from_payment_preimage,
|
HtlcLog, derive_payment_secret_from_payment_preimage,
|
||||||
NoPathFound)
|
NoPathFound, InvalidGossipMsg)
|
||||||
from .lnutil import ln_dummy_address, ln_compare_features, IncompatibleLightningFeatures
|
from .lnutil import ln_dummy_address, ln_compare_features, IncompatibleLightningFeatures
|
||||||
from .lnrouter import TrampolineEdge
|
from .lnrouter import TrampolineEdge
|
||||||
from .transaction import PartialTxOutput, PartialTransaction, PartialTxInput
|
from .transaction import PartialTxOutput, PartialTransaction, PartialTxInput
|
||||||
@@ -552,15 +552,21 @@ class LNGossip(LNWorker):
|
|||||||
return current_est, total_est, progress_percent
|
return current_est, total_est, progress_percent
|
||||||
|
|
||||||
async def process_gossip(self, chan_anns, node_anns, chan_upds):
|
async def process_gossip(self, chan_anns, node_anns, chan_upds):
|
||||||
|
# note: we run in the originating peer's TaskGroup, so we can safely raise here
|
||||||
|
# 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)}')
|
||||||
# note: data processed in chunks to avoid taking sql lock for too long
|
# note: data processed in chunks to avoid taking sql lock for too long
|
||||||
# channel announcements
|
# channel announcements
|
||||||
|
for payload in chan_anns:
|
||||||
|
self.channel_db.verify_channel_announcement(payload)
|
||||||
for chan_anns_chunk in chunks(chan_anns, 300):
|
for chan_anns_chunk in chunks(chan_anns, 300):
|
||||||
self.channel_db.add_channel_announcement(chan_anns_chunk)
|
self.channel_db.add_channel_announcements(chan_anns_chunk)
|
||||||
# node announcements
|
# node announcements
|
||||||
|
for payload in node_anns:
|
||||||
|
self.channel_db.verify_node_announcement(payload)
|
||||||
for node_anns_chunk in chunks(node_anns, 100):
|
for node_anns_chunk in chunks(node_anns, 100):
|
||||||
self.channel_db.add_node_announcement(node_anns_chunk)
|
self.channel_db.add_node_announcements(node_anns_chunk)
|
||||||
# channel updates
|
# channel updates
|
||||||
for chan_upds_chunk in chunks(chan_upds, 1000):
|
for chan_upds_chunk in chunks(chan_upds, 1000):
|
||||||
categorized_chan_upds = self.channel_db.add_channel_updates(
|
categorized_chan_upds = self.channel_db.add_channel_updates(
|
||||||
@@ -1269,7 +1275,10 @@ class LNWallet(LNWorker):
|
|||||||
def _handle_chanupd_from_failed_htlc(self, payload, *, route, sender_idx) -> Tuple[bool, bool]:
|
def _handle_chanupd_from_failed_htlc(self, payload, *, route, sender_idx) -> Tuple[bool, bool]:
|
||||||
blacklist = False
|
blacklist = False
|
||||||
update = False
|
update = False
|
||||||
r = self.channel_db.add_channel_update(payload)
|
try:
|
||||||
|
r = self.channel_db.add_channel_update(payload, verify=True)
|
||||||
|
except InvalidGossipMsg:
|
||||||
|
return True, False # blacklist
|
||||||
short_channel_id = ShortChannelID(payload['short_channel_id'])
|
short_channel_id = ShortChannelID(payload['short_channel_id'])
|
||||||
if r == UpdateStatus.GOOD:
|
if r == UpdateStatus.GOOD:
|
||||||
self.logger.info(f"applied channel update to {short_channel_id}")
|
self.logger.info(f"applied channel update to {short_channel_id}")
|
||||||
|
|||||||
@@ -40,49 +40,51 @@ class Test_LNRouter(TestCaseForTestnet):
|
|||||||
cdb = fake_network.channel_db
|
cdb = fake_network.channel_db
|
||||||
path_finder = lnrouter.LNPathFinder(cdb)
|
path_finder = lnrouter.LNPathFinder(cdb)
|
||||||
self.assertEqual(cdb.num_channels, 0)
|
self.assertEqual(cdb.num_channels, 0)
|
||||||
cdb.add_channel_announcement({'node_id_1': b'\x02bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb', 'node_id_2': b'\x02cccccccccccccccccccccccccccccccc',
|
cdb.add_channel_announcements({'node_id_1': b'\x02bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb', 'node_id_2': b'\x02cccccccccccccccccccccccccccccccc',
|
||||||
'bitcoin_key_1': b'\x02bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb', 'bitcoin_key_2': b'\x02cccccccccccccccccccccccccccccccc',
|
'bitcoin_key_1': b'\x02bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb', 'bitcoin_key_2': b'\x02cccccccccccccccccccccccccccccccc',
|
||||||
'short_channel_id': bfh('0000000000000001'),
|
'short_channel_id': bfh('0000000000000001'),
|
||||||
'chain_hash': BitcoinTestnet.rev_genesis_bytes(),
|
'chain_hash': BitcoinTestnet.rev_genesis_bytes(),
|
||||||
'len': 0, 'features': b''}, trusted=True)
|
'len': 0, 'features': b''}, trusted=True)
|
||||||
self.assertEqual(cdb.num_channels, 1)
|
self.assertEqual(cdb.num_channels, 1)
|
||||||
cdb.add_channel_announcement({'node_id_1': b'\x02bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb', 'node_id_2': b'\x02eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
|
cdb.add_channel_announcements({'node_id_1': b'\x02bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb', 'node_id_2': b'\x02eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
|
||||||
'bitcoin_key_1': b'\x02bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb', 'bitcoin_key_2': b'\x02eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
|
'bitcoin_key_1': b'\x02bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb', 'bitcoin_key_2': b'\x02eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
|
||||||
'short_channel_id': bfh('0000000000000002'),
|
'short_channel_id': bfh('0000000000000002'),
|
||||||
'chain_hash': BitcoinTestnet.rev_genesis_bytes(),
|
'chain_hash': BitcoinTestnet.rev_genesis_bytes(),
|
||||||
'len': 0, 'features': b''}, trusted=True)
|
'len': 0, 'features': b''}, trusted=True)
|
||||||
cdb.add_channel_announcement({'node_id_1': b'\x02aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'node_id_2': b'\x02bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb',
|
cdb.add_channel_announcements({'node_id_1': b'\x02aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'node_id_2': b'\x02bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb',
|
||||||
'bitcoin_key_1': b'\x02aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'bitcoin_key_2': b'\x02bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb',
|
'bitcoin_key_1': b'\x02aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'bitcoin_key_2': b'\x02bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb',
|
||||||
'short_channel_id': bfh('0000000000000003'),
|
'short_channel_id': bfh('0000000000000003'),
|
||||||
'chain_hash': BitcoinTestnet.rev_genesis_bytes(),
|
'chain_hash': BitcoinTestnet.rev_genesis_bytes(),
|
||||||
'len': 0, 'features': b''}, trusted=True)
|
'len': 0, 'features': b''}, trusted=True)
|
||||||
cdb.add_channel_announcement({'node_id_1': b'\x02cccccccccccccccccccccccccccccccc', 'node_id_2': b'\x02dddddddddddddddddddddddddddddddd',
|
cdb.add_channel_announcements({'node_id_1': b'\x02cccccccccccccccccccccccccccccccc', 'node_id_2': b'\x02dddddddddddddddddddddddddddddddd',
|
||||||
'bitcoin_key_1': b'\x02cccccccccccccccccccccccccccccccc', 'bitcoin_key_2': b'\x02dddddddddddddddddddddddddddddddd',
|
'bitcoin_key_1': b'\x02cccccccccccccccccccccccccccccccc', 'bitcoin_key_2': b'\x02dddddddddddddddddddddddddddddddd',
|
||||||
'short_channel_id': bfh('0000000000000004'),
|
'short_channel_id': bfh('0000000000000004'),
|
||||||
'chain_hash': BitcoinTestnet.rev_genesis_bytes(),
|
'chain_hash': BitcoinTestnet.rev_genesis_bytes(),
|
||||||
'len': 0, 'features': b''}, trusted=True)
|
'len': 0, 'features': b''}, trusted=True)
|
||||||
cdb.add_channel_announcement({'node_id_1': b'\x02dddddddddddddddddddddddddddddddd', 'node_id_2': b'\x02eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
|
cdb.add_channel_announcements({'node_id_1': b'\x02dddddddddddddddddddddddddddddddd', 'node_id_2': b'\x02eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
|
||||||
'bitcoin_key_1': b'\x02dddddddddddddddddddddddddddddddd', 'bitcoin_key_2': b'\x02eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
|
'bitcoin_key_1': b'\x02dddddddddddddddddddddddddddddddd', 'bitcoin_key_2': b'\x02eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
|
||||||
'short_channel_id': bfh('0000000000000005'),
|
'short_channel_id': bfh('0000000000000005'),
|
||||||
'chain_hash': BitcoinTestnet.rev_genesis_bytes(),
|
'chain_hash': BitcoinTestnet.rev_genesis_bytes(),
|
||||||
'len': 0, 'features': b''}, trusted=True)
|
'len': 0, 'features': b''}, trusted=True)
|
||||||
cdb.add_channel_announcement({'node_id_1': b'\x02aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'node_id_2': b'\x02dddddddddddddddddddddddddddddddd',
|
cdb.add_channel_announcements({'node_id_1': b'\x02aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'node_id_2': b'\x02dddddddddddddddddddddddddddddddd',
|
||||||
'bitcoin_key_1': b'\x02aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'bitcoin_key_2': b'\x02dddddddddddddddddddddddddddddddd',
|
'bitcoin_key_1': b'\x02aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'bitcoin_key_2': b'\x02dddddddddddddddddddddddddddddddd',
|
||||||
'short_channel_id': bfh('0000000000000006'),
|
'short_channel_id': bfh('0000000000000006'),
|
||||||
'chain_hash': BitcoinTestnet.rev_genesis_bytes(),
|
'chain_hash': BitcoinTestnet.rev_genesis_bytes(),
|
||||||
'len': 0, 'features': b''}, trusted=True)
|
'len': 0, 'features': b''}, trusted=True)
|
||||||
cdb.add_channel_update({'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})
|
def add_chan_upd(payload):
|
||||||
cdb.add_channel_update({'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})
|
cdb.add_channel_update(payload, verify=False)
|
||||||
cdb.add_channel_update({'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': 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})
|
||||||
cdb.add_channel_update({'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': 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})
|
||||||
cdb.add_channel_update({'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': 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})
|
||||||
cdb.add_channel_update({'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': 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})
|
||||||
cdb.add_channel_update({'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': 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})
|
||||||
cdb.add_channel_update({'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': 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})
|
||||||
cdb.add_channel_update({'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': 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})
|
||||||
cdb.add_channel_update({'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': 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})
|
||||||
cdb.add_channel_update({'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': 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})
|
||||||
cdb.add_channel_update({'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': 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': 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': 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})
|
||||||
path = path_finder.find_path_for_payment(
|
path = path_finder.find_path_for_payment(
|
||||||
nodeA=b'\x02aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
|
nodeA=b'\x02aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
|
||||||
nodeB=b'\x02eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
|
nodeB=b'\x02eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
|
||||||
|
|||||||
Reference in New Issue
Block a user