Browse Source

lnpeer: send own outgoing channel updates to remote peer

dependabot/pip/contrib/deterministic-build/ecdsa-0.13.3
SomberNight 6 years ago
committed by ThomasV
parent
commit
47ee02569a
  1. 3
      electrum/lnchannel.py
  2. 72
      electrum/lnpeer.py

3
electrum/lnchannel.py

@ -129,7 +129,7 @@ class Channel(Logger):
self.channel_id = bfh(state["channel_id"]) if type(state["channel_id"]) not in (bytes, type(None)) else state["channel_id"] self.channel_id = bfh(state["channel_id"]) if type(state["channel_id"]) not in (bytes, type(None)) else state["channel_id"]
self.constraints = ChannelConstraints(**state["constraints"]) if type(state["constraints"]) is not ChannelConstraints else state["constraints"] self.constraints = ChannelConstraints(**state["constraints"]) if type(state["constraints"]) is not ChannelConstraints else state["constraints"]
self.funding_outpoint = Outpoint(**dict(decodeAll(state["funding_outpoint"], False))) if type(state["funding_outpoint"]) is not Outpoint else state["funding_outpoint"] self.funding_outpoint = Outpoint(**dict(decodeAll(state["funding_outpoint"], False))) if type(state["funding_outpoint"]) is not Outpoint else state["funding_outpoint"]
self.node_id = bfh(state["node_id"]) if type(state["node_id"]) not in (bytes, type(None)) else state["node_id"] self.node_id = bfh(state["node_id"]) if type(state["node_id"]) not in (bytes, type(None)) else state["node_id"] # type: bytes
self.short_channel_id = bfh(state["short_channel_id"]) if type(state["short_channel_id"]) not in (bytes, type(None)) else state["short_channel_id"] self.short_channel_id = bfh(state["short_channel_id"]) if type(state["short_channel_id"]) not in (bytes, type(None)) else state["short_channel_id"]
self.short_channel_id_predicted = self.short_channel_id self.short_channel_id_predicted = self.short_channel_id
self.onion_keys = str_bytes_dict_from_save(state.get('onion_keys', {})) self.onion_keys = str_bytes_dict_from_save(state.get('onion_keys', {}))
@ -145,6 +145,7 @@ class Channel(Logger):
self._state = None self._state = None
self.set_state('DISCONNECTED') self.set_state('DISCONNECTED')
self.sweep_info = {} self.sweep_info = {}
self._outgoing_channel_update = None # type: Optional[bytes]
def get_feerate(self, subject, ctn): def get_feerate(self, subject, ctn):
return self.hm.get_feerate(subject, ctn) return self.hm.get_feerate(subject, ctn)

72
electrum/lnpeer.py

@ -63,9 +63,9 @@ class Peer(Logger):
self.initialized = asyncio.Event() self.initialized = asyncio.Event()
self.querying = asyncio.Event() self.querying = asyncio.Event()
self.transport = transport self.transport = transport
self.pubkey = pubkey self.pubkey = pubkey # remote pubkey
self.lnworker = lnworker self.lnworker = lnworker
self.privkey = lnworker.node_keypair.privkey self.privkey = lnworker.node_keypair.privkey # local privkey
self.localfeatures = self.lnworker.localfeatures self.localfeatures = self.lnworker.localfeatures
self.node_ids = [self.pubkey, privkey_to_pubkey(self.privkey)] self.node_ids = [self.pubkey, privkey_to_pubkey(self.privkey)]
self.network = lnworker.network self.network = lnworker.network
@ -938,6 +938,7 @@ class Peer(Logger):
def mark_open(self, chan: Channel): def mark_open(self, chan: Channel):
assert chan.short_channel_id is not None assert chan.short_channel_id is not None
scid = format_short_channel_id(chan.short_channel_id)
# only allow state transition to "OPEN" from "OPENING" # only allow state transition to "OPEN" from "OPENING"
if chan.get_state() != "OPENING": if chan.get_state() != "OPENING":
return return
@ -945,17 +946,21 @@ class Peer(Logger):
chan.set_state("OPEN") chan.set_state("OPEN")
self.network.trigger_callback('channel', chan) self.network.trigger_callback('channel', chan)
asyncio.ensure_future(self.add_own_channel(chan)) asyncio.ensure_future(self.add_own_channel(chan))
self.logger.info("CHANNEL OPENING COMPLETED") self.logger.info(f"CHANNEL OPENING COMPLETED for {scid}")
forwarding_enabled = self.network.config.get('lightning_forward_payments', False)
if forwarding_enabled:
# send channel_update of outgoing edge to peer,
# so that channel can be used to to receive payments
self.logger.info(f"sending channel update for outgoing edge of {scid}")
chan_upd = self.get_outgoing_gossip_channel_update_for_chan(chan)
self.transport.send_bytes(chan_upd)
async def add_own_channel(self, chan): async def add_own_channel(self, chan):
# add channel to database # add channel to database
bitcoin_keys = [chan.config[LOCAL].multisig_key.pubkey, chan.config[REMOTE].multisig_key.pubkey] bitcoin_keys = [chan.config[LOCAL].multisig_key.pubkey, chan.config[REMOTE].multisig_key.pubkey]
sorted_node_ids = list(sorted(self.node_ids)) sorted_node_ids = list(sorted(self.node_ids))
if sorted_node_ids != self.node_ids: if sorted_node_ids != self.node_ids:
node_ids = sorted_node_ids
bitcoin_keys.reverse() bitcoin_keys.reverse()
else:
node_ids = self.node_ids
# note: we inject a channel announcement, and a channel update (for outgoing direction) # note: we inject a channel announcement, and a channel update (for outgoing direction)
# This is atm needed for # This is atm needed for
# - finding routes # - finding routes
@ -966,8 +971,8 @@ class Peer(Logger):
self.channel_db.add_channel_announcement( self.channel_db.add_channel_announcement(
{ {
"short_channel_id": chan.short_channel_id, "short_channel_id": chan.short_channel_id,
"node_id_1": node_ids[0], "node_id_1": sorted_node_ids[0],
"node_id_2": node_ids[1], "node_id_2": sorted_node_ids[1],
'chain_hash': constants.net.rev_genesis_bytes(), 'chain_hash': constants.net.rev_genesis_bytes(),
'len': b'\x00\x00', 'len': b'\x00\x00',
'features': b'', 'features': b'',
@ -976,29 +981,44 @@ class Peer(Logger):
}, },
trusted=True) trusted=True)
# only inject outgoing direction: # only inject outgoing direction:
channel_flags = b'\x00' if node_ids[0] == privkey_to_pubkey(self.privkey) else b'\x01' chan_upd_bytes = self.get_outgoing_gossip_channel_update_for_chan(chan)
now = int(time.time()) chan_upd_payload = decode_msg(chan_upd_bytes)[1]
self.channel_db.add_channel_update( self.channel_db.add_channel_update(chan_upd_payload)
{
"short_channel_id": chan.short_channel_id,
'channel_flags': channel_flags,
'message_flags': b'\x00',
'cltv_expiry_delta': b'\x90',
'htlc_minimum_msat': b'\x03\xe8',
'fee_base_msat': b'\x03\xe8',
'fee_proportional_millionths': b'\x01',
'chain_hash': constants.net.rev_genesis_bytes(),
'timestamp': now.to_bytes(4, byteorder="big")
})
# peer may have sent us a channel update for the incoming direction previously # peer may have sent us a channel update for the incoming direction previously
# note: if we were offline when the 3rd conf happened, lnd will never send us this channel_update
# see https://github.com/lightningnetwork/lnd/issues/1347
#self.send_message("query_short_channel_ids", chain_hash=constants.net.rev_genesis_bytes(),
# len=9, encoded_short_ids=b'\x00'+chan.short_channel_id)
pending_channel_update = self.orphan_channel_updates.get(chan.short_channel_id) pending_channel_update = self.orphan_channel_updates.get(chan.short_channel_id)
if pending_channel_update: if pending_channel_update:
self.channel_db.add_channel_update(pending_channel_update) self.channel_db.add_channel_update(pending_channel_update)
def get_outgoing_gossip_channel_update_for_chan(self, chan: Channel) -> bytes:
if chan._outgoing_channel_update is not None:
return chan._outgoing_channel_update
sorted_node_ids = list(sorted(self.node_ids))
channel_flags = b'\x00' if sorted_node_ids[0] == privkey_to_pubkey(self.privkey) else b'\x01'
now = int(time.time())
htlc_maximum_msat = min(chan.config[REMOTE].max_htlc_value_in_flight_msat, 1000 * chan.constraints.capacity)
chan_upd = encode_msg(
"channel_update",
short_channel_id=chan.short_channel_id,
channel_flags=channel_flags,
message_flags=b'\x01',
cltv_expiry_delta=lnutil.NBLOCK_OUR_CLTV_EXPIRY_DELTA.to_bytes(2, byteorder="big"),
htlc_minimum_msat=chan.config[REMOTE].htlc_minimum_msat.to_bytes(8, byteorder="big"),
htlc_maximum_msat=htlc_maximum_msat.to_bytes(8, byteorder="big"),
fee_base_msat=lnutil.OUR_FEE_BASE_MSAT.to_bytes(4, byteorder="big"),
fee_proportional_millionths=lnutil.OUR_FEE_PROPORTIONAL_MILLIONTHS.to_bytes(4, byteorder="big"),
chain_hash=constants.net.rev_genesis_bytes(),
timestamp=now.to_bytes(4, byteorder="big"),
)
sighash = sha256d(chan_upd[2 + 64:])
sig = ecc.ECPrivkey(self.privkey).sign(sighash, sig_string_from_r_and_s, get_r_and_s_from_sig_string)
message_type, payload = decode_msg(chan_upd)
payload['signature'] = sig
chan_upd = encode_msg(message_type, **payload)
chan._outgoing_channel_update = chan_upd
return chan_upd
def send_announcement_signatures(self, chan: Channel): def send_announcement_signatures(self, chan: Channel):
bitcoin_keys = [chan.config[REMOTE].multisig_key.pubkey, bitcoin_keys = [chan.config[REMOTE].multisig_key.pubkey,

Loading…
Cancel
Save