mirror of
https://github.com/LBRYFoundation/LBRY-Vault.git
synced 2025-09-02 18:25:21 +00:00
ln: channel announcements
This commit is contained in:
parent
98818c3c3a
commit
cc815c318d
2 changed files with 100 additions and 17 deletions
|
@ -4,15 +4,13 @@
|
|||
Derived from https://gist.github.com/AdamISZ/046d05c156aaeb56cc897f85eecb3eb8
|
||||
"""
|
||||
|
||||
from ecdsa.util import sigdecode_der, sigencode_string_canonize
|
||||
from ecdsa import VerifyingKey
|
||||
from ecdsa.util import sigdecode_der, sigencode_string_canonize, sigdecode_string
|
||||
from ecdsa.curves import SECP256k1
|
||||
import queue
|
||||
import traceback
|
||||
import json
|
||||
from collections import OrderedDict, defaultdict
|
||||
import asyncio
|
||||
import sys
|
||||
import os
|
||||
import time
|
||||
import binascii
|
||||
|
@ -599,6 +597,8 @@ class Peer(PrintError):
|
|||
self.revoke_and_ack = defaultdict(asyncio.Queue)
|
||||
self.update_fulfill_htlc = defaultdict(asyncio.Queue)
|
||||
self.commitment_signed = defaultdict(asyncio.Queue)
|
||||
self.announcement_signatures = defaultdict(asyncio.Queue)
|
||||
self.is_funding_six_deep = defaultdict(lambda: False)
|
||||
self.localfeatures = (0x08 if request_initial_sync else 0)
|
||||
self.nodes = {}
|
||||
self.channels = lnworker.channels
|
||||
|
@ -766,6 +766,10 @@ class Peer(PrintError):
|
|||
self.channel_db.on_channel_announcement(payload)
|
||||
self.channel_update_event.set()
|
||||
|
||||
def on_announcement_signatures(self, payload):
|
||||
channel_id = payload['channel_id']
|
||||
self.announcement_signatures[channel_id].put_nowait(payload)
|
||||
|
||||
@aiosafe
|
||||
async def main_loop(self):
|
||||
self.reader, self.writer = await asyncio.open_connection(self.host, self.port)
|
||||
|
@ -835,6 +839,7 @@ class Peer(PrintError):
|
|||
first_per_commitment_point=per_commitment_point_first,
|
||||
to_self_delay=local_config.to_self_delay,
|
||||
max_htlc_value_in_flight_msat=local_config.max_htlc_value_in_flight_msat,
|
||||
channel_flags=0x01, # publicly announcing channel
|
||||
channel_reserve_satoshis=10
|
||||
)
|
||||
self.send_message(msg)
|
||||
|
@ -968,6 +973,49 @@ class Peer(PrintError):
|
|||
if chan.short_channel_id:
|
||||
self.mark_open(chan)
|
||||
|
||||
async def funding_six_deep(self, chan):
|
||||
if self.is_funding_six_deep[chan.channel_id]:
|
||||
return
|
||||
self.is_funding_six_deep[chan.channel_id] = True
|
||||
h, local_node_sig, local_bitcoin_sig = self.send_announcement_signatures(chan)
|
||||
announcement_signatures_msg = await self.announcement_signatures[chan.channel_id].get()
|
||||
remote_node_sig = announcement_signatures_msg["node_signature"]
|
||||
remote_bitcoin_sig = announcement_signatures_msg["bitcoin_signature"]
|
||||
if not ecc.verify_signature(chan.remote_config.multisig_key.pubkey, remote_bitcoin_sig, h):
|
||||
raise Exception("bitcoin_sig invalid in announcement_signatures")
|
||||
if not ecc.verify_signature(self.pubkey, remote_node_sig, h):
|
||||
raise Exception("node_sig invalid in announcement_signatures")
|
||||
|
||||
node_sigs = [local_node_sig, remote_node_sig]
|
||||
bitcoin_sigs = [local_bitcoin_sig, remote_bitcoin_sig]
|
||||
node_ids = [privkey_to_pubkey(self.privkey), self.pubkey]
|
||||
bitcoin_keys = [chan.local_config.multisig_key.pubkey, chan.remote_config.multisig_key.pubkey]
|
||||
|
||||
if node_ids[0] > node_ids[1]:
|
||||
node_sigs.reverse()
|
||||
bitcoin_sigs.reverse()
|
||||
node_ids.reverse()
|
||||
bitcoin_keys.reverse()
|
||||
|
||||
channel_announcement = gen_msg("channel_announcement",
|
||||
node_signatures_1=node_sigs[0],
|
||||
node_signatures_2=node_sigs[1],
|
||||
bitcoin_signature_1=bitcoin_sigs[0],
|
||||
bitcoin_signature_2=bitcoin_sigs[1],
|
||||
len=0,
|
||||
#features
|
||||
chain_hash=bytes.fromhex(rev_hex(constants.net.GENESIS)),
|
||||
short_channel_id=chan.short_channel_id,
|
||||
node_id_1=node_ids[0],
|
||||
node_id_2=node_ids[1],
|
||||
bitcoin_key_1=bitcoin_keys[0],
|
||||
bitcoin_key_2=bitcoin_keys[1]
|
||||
)
|
||||
|
||||
self.send_message(channel_announcement)
|
||||
|
||||
print("SENT CHANNEL ANNOUNCEMENT")
|
||||
|
||||
def mark_open(self, chan):
|
||||
if self.channel_state[chan.channel_id] == "OPEN":
|
||||
return
|
||||
|
@ -979,8 +1027,45 @@ class Peer(PrintError):
|
|||
self.channel_db.on_channel_announcement({"short_channel_id": chan.short_channel_id, "node_id_1": sorted_keys[0], "node_id_2": sorted_keys[1]})
|
||||
self.channel_db.on_channel_update({"short_channel_id": chan.short_channel_id, 'flags': b'\x01', 'cltv_expiry_delta': b'\x90', 'htlc_minimum_msat': b'\x03\xe8', 'fee_base_msat': b'\x03\xe8', 'fee_proportional_millionths': b'\x01'})
|
||||
self.channel_db.on_channel_update({"short_channel_id": chan.short_channel_id, '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'})
|
||||
|
||||
self.print_error("CHANNEL OPENING COMPLETED")
|
||||
|
||||
def send_announcement_signatures(self, chan):
|
||||
|
||||
bitcoin_keys = [chan.local_config.multisig_key.pubkey,
|
||||
chan.remote_config.multisig_key.pubkey]
|
||||
|
||||
node_ids = [privkey_to_pubkey(self.privkey),
|
||||
self.pubkey]
|
||||
|
||||
sorted_node_ids = list(sorted(node_ids))
|
||||
if sorted_node_ids != node_ids:
|
||||
node_ids = sorted_node_ids
|
||||
bitcoin_keys.reverse()
|
||||
|
||||
chan_ann = gen_msg("channel_announcement",
|
||||
len=0,
|
||||
#features
|
||||
chain_hash=bytes.fromhex(rev_hex(constants.net.GENESIS)),
|
||||
short_channel_id=chan.short_channel_id,
|
||||
node_id_1=node_ids[0],
|
||||
node_id_2=node_ids[1],
|
||||
bitcoin_key_1=bitcoin_keys[0],
|
||||
bitcoin_key_2=bitcoin_keys[1]
|
||||
)
|
||||
to_hash = chan_ann[256+2:]
|
||||
h = bitcoin.Hash(to_hash)
|
||||
bitcoin_signature = ecc.ECPrivkey(chan.local_config.multisig_key.privkey).sign(h, sigencode_string_canonize, sigdecode_string)
|
||||
node_signature = ecc.ECPrivkey(self.privkey).sign(h, sigencode_string_canonize, sigdecode_string)
|
||||
self.send_message(gen_msg("announcement_signatures",
|
||||
channel_id=chan.channel_id,
|
||||
short_channel_id=chan.short_channel_id,
|
||||
node_signature=node_signature,
|
||||
bitcoin_signature=bitcoin_signature
|
||||
))
|
||||
|
||||
return h, node_signature, bitcoin_signature
|
||||
|
||||
def on_update_fail_htlc(self, payload):
|
||||
print("UPDATE_FAIL_HTLC", decode_onion_error(payload["reason"], self.node_keys, self.secret_key))
|
||||
|
||||
|
|
|
@ -1,13 +1,8 @@
|
|||
import traceback
|
||||
import sys
|
||||
import json
|
||||
import binascii
|
||||
import asyncio
|
||||
import time
|
||||
import os
|
||||
from decimal import Decimal
|
||||
import binascii
|
||||
import asyncio
|
||||
import threading
|
||||
from collections import defaultdict
|
||||
|
||||
|
@ -15,11 +10,7 @@ from . import constants
|
|||
from .bitcoin import sha256, COIN
|
||||
from .util import bh2u, bfh, PrintError
|
||||
from .constants import set_testnet, set_simnet
|
||||
from .simple_config import SimpleConfig
|
||||
from .network import Network
|
||||
from .storage import WalletStorage
|
||||
from .wallet import Wallet
|
||||
from .lnbase import Peer, Outpoint, ChannelConfig, LocalState, RemoteState, Keypair, OnlyPubkeyKeypair, OpenChannel, ChannelConstraints, RevocationStore, aiosafe, calc_short_channel_id, privkey_to_pubkey
|
||||
from .lnbase import Peer, Outpoint, ChannelConfig, LocalState, RemoteState, Keypair, OnlyPubkeyKeypair, OpenChannel, ChannelConstraints, RevocationStore, calc_short_channel_id, privkey_to_pubkey
|
||||
from .lightning_payencode.lnaddr import lnencode, LnAddr, lndecode
|
||||
from . import lnrouter
|
||||
from .ecc import ECPrivkey
|
||||
|
@ -142,7 +133,7 @@ class LNWorker(PrintError):
|
|||
|
||||
If the Funding TX has not been mined, return None
|
||||
"""
|
||||
assert self.channel_state[chan.channel_id] == "OPENING"
|
||||
assert self.channel_state[chan.channel_id] in ["OPEN", "OPENING"]
|
||||
peer = self.peers[chan.node_id]
|
||||
conf = self.wallet.get_tx_height(chan.funding_outpoint.txid)[1]
|
||||
if conf >= chan.constraints.funding_txn_minimum_depth:
|
||||
|
@ -153,14 +144,21 @@ class LNWorker(PrintError):
|
|||
return None
|
||||
chan = chan._replace(short_channel_id = calc_short_channel_id(block_height, tx_pos, chan.funding_outpoint.output_index))
|
||||
self.save_channel(chan)
|
||||
return chan
|
||||
return None
|
||||
return chan, conf
|
||||
return None, None
|
||||
|
||||
def on_network_update(self, event, *args):
|
||||
for chan in self.channels.values():
|
||||
if self.channel_state[chan.channel_id] == "OPEN":
|
||||
conf = self.wallet.get_tx_height(chan.funding_outpoint.txid)[1]
|
||||
if conf >= 6:
|
||||
peer = self.peers[chan.node_id]
|
||||
coro = peer.funding_six_deep(chan)
|
||||
fut = asyncio.run_coroutine_threadsafe(coro, self.network.asyncio_loop)
|
||||
fut.result()
|
||||
if self.channel_state[chan.channel_id] != "OPENING":
|
||||
continue
|
||||
chan = self.save_short_chan_id(chan)
|
||||
chan, conf = self.save_short_chan_id(chan)
|
||||
if not chan:
|
||||
self.print_error("network update but funding tx is still not at sufficient depth")
|
||||
continue
|
||||
|
|
Loading…
Add table
Reference in a new issue