mirror of
https://github.com/LBRYFoundation/LBRY-Vault.git
synced 2025-08-30 08:51:32 +00:00
move channel_state into HTLCStateMachine
This commit is contained in:
parent
c0c7b92bff
commit
d9208f3245
5 changed files with 26 additions and 20 deletions
|
@ -20,12 +20,11 @@ class ChannelsList(MyTreeWidget):
|
||||||
self.status = QLabel('')
|
self.status = QLabel('')
|
||||||
|
|
||||||
def format_fields(self, chan):
|
def format_fields(self, chan):
|
||||||
status = self.parent.wallet.lnworker.channel_state[chan.channel_id]
|
|
||||||
return [
|
return [
|
||||||
bh2u(chan.node_id),
|
bh2u(chan.node_id),
|
||||||
self.parent.format_amount(chan.local_state.amount_msat//1000),
|
self.parent.format_amount(chan.local_state.amount_msat//1000),
|
||||||
self.parent.format_amount(chan.remote_state.amount_msat//1000),
|
self.parent.format_amount(chan.remote_state.amount_msat//1000),
|
||||||
status
|
chan.state
|
||||||
]
|
]
|
||||||
|
|
||||||
def create_menu(self, position):
|
def create_menu(self, position):
|
||||||
|
|
|
@ -292,7 +292,6 @@ class Peer(PrintError):
|
||||||
self.privkey = lnworker.privkey
|
self.privkey = lnworker.privkey
|
||||||
self.network = lnworker.network
|
self.network = lnworker.network
|
||||||
self.channel_db = lnworker.network.channel_db
|
self.channel_db = lnworker.network.channel_db
|
||||||
self.channel_state = lnworker.channel_state
|
|
||||||
self.read_buffer = b''
|
self.read_buffer = b''
|
||||||
self.ping_time = 0
|
self.ping_time = 0
|
||||||
self.initialized = asyncio.Future()
|
self.initialized = asyncio.Future()
|
||||||
|
@ -305,10 +304,13 @@ class Peer(PrintError):
|
||||||
self.announcement_signatures = defaultdict(asyncio.Queue)
|
self.announcement_signatures = defaultdict(asyncio.Queue)
|
||||||
self.update_fail_htlc = defaultdict(asyncio.Queue)
|
self.update_fail_htlc = defaultdict(asyncio.Queue)
|
||||||
self.localfeatures = (0x08 if request_initial_sync else 0)
|
self.localfeatures = (0x08 if request_initial_sync else 0)
|
||||||
self.channels = lnworker.channels_for_peer(pubkey)
|
|
||||||
self.invoices = lnworker.invoices
|
self.invoices = lnworker.invoices
|
||||||
self.attempted_route = {}
|
self.attempted_route = {}
|
||||||
|
|
||||||
|
@property
|
||||||
|
def channels(self):
|
||||||
|
return self.lnworker.channels_for_peer(self.pubkey)
|
||||||
|
|
||||||
def diagnostic_name(self):
|
def diagnostic_name(self):
|
||||||
return 'lnbase:' + str(self.host)
|
return 'lnbase:' + str(self.host)
|
||||||
|
|
||||||
|
@ -630,13 +632,14 @@ class Peer(PrintError):
|
||||||
assert success, success
|
assert success, success
|
||||||
m.remote_state = m.remote_state._replace(ctn=0)
|
m.remote_state = m.remote_state._replace(ctn=0)
|
||||||
m.local_state = m.local_state._replace(ctn=0, current_commitment_signature=remote_sig)
|
m.local_state = m.local_state._replace(ctn=0, current_commitment_signature=remote_sig)
|
||||||
|
m.state = 'OPENING'
|
||||||
return m
|
return m
|
||||||
|
|
||||||
@aiosafe
|
@aiosafe
|
||||||
async def reestablish_channel(self, chan):
|
async def reestablish_channel(self, chan):
|
||||||
await self.initialized
|
await self.initialized
|
||||||
chan_id = chan.channel_id
|
chan_id = chan.channel_id
|
||||||
self.channel_state[chan_id] = 'REESTABLISHING'
|
chan.state = 'REESTABLISHING'
|
||||||
self.network.trigger_callback('channel', chan)
|
self.network.trigger_callback('channel', chan)
|
||||||
self.send_message(gen_msg("channel_reestablish",
|
self.send_message(gen_msg("channel_reestablish",
|
||||||
channel_id=chan_id,
|
channel_id=chan_id,
|
||||||
|
@ -644,7 +647,7 @@ class Peer(PrintError):
|
||||||
next_remote_revocation_number=chan.remote_state.ctn
|
next_remote_revocation_number=chan.remote_state.ctn
|
||||||
))
|
))
|
||||||
await self.channel_reestablished[chan_id]
|
await self.channel_reestablished[chan_id]
|
||||||
self.channel_state[chan_id] = 'OPENING'
|
chan.state = 'OPENING'
|
||||||
if chan.local_state.funding_locked_received and chan.short_channel_id:
|
if chan.local_state.funding_locked_received and chan.short_channel_id:
|
||||||
self.mark_open(chan)
|
self.mark_open(chan)
|
||||||
self.network.trigger_callback('channel', chan)
|
self.network.trigger_callback('channel', chan)
|
||||||
|
@ -684,6 +687,7 @@ class Peer(PrintError):
|
||||||
channel_id = payload['channel_id']
|
channel_id = payload['channel_id']
|
||||||
chan = self.channels.get(channel_id)
|
chan = self.channels.get(channel_id)
|
||||||
if not chan:
|
if not chan:
|
||||||
|
print(self.channels)
|
||||||
raise Exception("Got unknown funding_locked", channel_id)
|
raise Exception("Got unknown funding_locked", channel_id)
|
||||||
if not chan.local_state.funding_locked_received:
|
if not chan.local_state.funding_locked_received:
|
||||||
our_next_point = chan.remote_state.next_per_commitment_point
|
our_next_point = chan.remote_state.next_per_commitment_point
|
||||||
|
@ -750,10 +754,10 @@ class Peer(PrintError):
|
||||||
print("SENT CHANNEL ANNOUNCEMENT")
|
print("SENT CHANNEL ANNOUNCEMENT")
|
||||||
|
|
||||||
def mark_open(self, chan):
|
def mark_open(self, chan):
|
||||||
if self.channel_state[chan.channel_id] == "OPEN":
|
if chan.state == "OPEN":
|
||||||
return
|
return
|
||||||
assert chan.local_state.funding_locked_received
|
assert chan.local_state.funding_locked_received
|
||||||
self.channel_state[chan.channel_id] = "OPEN"
|
chan.state = "OPEN"
|
||||||
self.network.trigger_callback('channel', chan)
|
self.network.trigger_callback('channel', chan)
|
||||||
# add channel to database
|
# add channel to database
|
||||||
sorted_keys = list(sorted([self.pubkey, self.lnworker.pubkey]))
|
sorted_keys = list(sorted([self.pubkey, self.lnworker.pubkey]))
|
||||||
|
@ -827,7 +831,7 @@ class Peer(PrintError):
|
||||||
|
|
||||||
@aiosafe
|
@aiosafe
|
||||||
async def pay(self, path, chan, amount_msat, payment_hash, pubkey_in_invoice, min_final_cltv_expiry):
|
async def pay(self, path, chan, amount_msat, payment_hash, pubkey_in_invoice, min_final_cltv_expiry):
|
||||||
assert self.channel_state[chan.channel_id] == "OPEN"
|
assert chan.state == "OPEN"
|
||||||
assert amount_msat > 0, "amount_msat is not greater zero"
|
assert amount_msat > 0, "amount_msat is not greater zero"
|
||||||
height = self.network.get_local_height()
|
height = self.network.get_local_height()
|
||||||
route = self.network.path_finder.create_route_from_path(path, self.lnworker.pubkey)
|
route = self.network.path_finder.create_route_from_path(path, self.lnworker.pubkey)
|
||||||
|
@ -929,7 +933,7 @@ class Peer(PrintError):
|
||||||
htlc_id = int.from_bytes(htlc["id"], 'big')
|
htlc_id = int.from_bytes(htlc["id"], 'big')
|
||||||
assert htlc_id == chan.remote_state.next_htlc_id, (htlc_id, chan.remote_state.next_htlc_id)
|
assert htlc_id == chan.remote_state.next_htlc_id, (htlc_id, chan.remote_state.next_htlc_id)
|
||||||
|
|
||||||
assert self.channel_state[channel_id] == "OPEN"
|
assert chan.state == "OPEN"
|
||||||
|
|
||||||
cltv_expiry = int.from_bytes(htlc["cltv_expiry"], 'big')
|
cltv_expiry = int.from_bytes(htlc["cltv_expiry"], 'big')
|
||||||
# TODO verify sanity of their cltv expiry
|
# TODO verify sanity of their cltv expiry
|
||||||
|
|
|
@ -139,6 +139,8 @@ class HTLCStateMachine(PrintError):
|
||||||
self.local_commitment = self.pending_local_commitment
|
self.local_commitment = self.pending_local_commitment
|
||||||
self.remote_commitment = self.pending_remote_commitment
|
self.remote_commitment = self.pending_remote_commitment
|
||||||
|
|
||||||
|
self.state = 'DISCONNECTED'
|
||||||
|
|
||||||
def add_htlc(self, htlc):
|
def add_htlc(self, htlc):
|
||||||
"""
|
"""
|
||||||
AddHTLC adds an HTLC to the state machine's local update log. This method
|
AddHTLC adds an HTLC to the state machine's local update log. This method
|
||||||
|
|
|
@ -40,7 +40,6 @@ class LNWorker(PrintError):
|
||||||
self.peers = {}
|
self.peers = {}
|
||||||
self.channels = {x.channel_id: x for x in map(HTLCStateMachine, wallet.storage.get("channels", []))}
|
self.channels = {x.channel_id: x for x in map(HTLCStateMachine, wallet.storage.get("channels", []))}
|
||||||
self.invoices = wallet.storage.get('lightning_invoices', {})
|
self.invoices = wallet.storage.get('lightning_invoices', {})
|
||||||
self.channel_state = {chan.channel_id: "DISCONNECTED" for chan in self.channels.values()}
|
|
||||||
for chan_id, chan in self.channels.items():
|
for chan_id, chan in self.channels.items():
|
||||||
self.network.lnwatcher.watch_channel(chan, self.on_channel_utxos)
|
self.network.lnwatcher.watch_channel(chan, self.on_channel_utxos)
|
||||||
peer_list = self.config.get('lightning_peers', node_list)
|
peer_list = self.config.get('lightning_peers', node_list)
|
||||||
|
@ -71,8 +70,6 @@ class LNWorker(PrintError):
|
||||||
|
|
||||||
def save_channel(self, openchannel):
|
def save_channel(self, openchannel):
|
||||||
assert type(openchannel) is HTLCStateMachine
|
assert type(openchannel) is HTLCStateMachine
|
||||||
if openchannel.channel_id not in self.channel_state:
|
|
||||||
self.channel_state[openchannel.channel_id] = "OPENING"
|
|
||||||
self.channels[openchannel.channel_id] = openchannel
|
self.channels[openchannel.channel_id] = openchannel
|
||||||
if openchannel.remote_state.next_per_commitment_point == openchannel.remote_state.current_per_commitment_point:
|
if openchannel.remote_state.next_per_commitment_point == openchannel.remote_state.current_per_commitment_point:
|
||||||
raise Exception("Tried to save channel with next_point == current_point, this should not happen")
|
raise Exception("Tried to save channel with next_point == current_point, this should not happen")
|
||||||
|
@ -87,7 +84,7 @@ class LNWorker(PrintError):
|
||||||
|
|
||||||
If the Funding TX has not been mined, return None
|
If the Funding TX has not been mined, return None
|
||||||
"""
|
"""
|
||||||
assert self.channel_state[chan.channel_id] in ["OPEN", "OPENING"]
|
assert chan.state in ["OPEN", "OPENING"]
|
||||||
peer = self.peers[chan.node_id]
|
peer = self.peers[chan.node_id]
|
||||||
conf = self.wallet.get_tx_height(chan.funding_outpoint.txid)[1]
|
conf = self.wallet.get_tx_height(chan.funding_outpoint.txid)[1]
|
||||||
if conf >= chan.constraints.funding_txn_minimum_depth:
|
if conf >= chan.constraints.funding_txn_minimum_depth:
|
||||||
|
@ -104,26 +101,30 @@ class LNWorker(PrintError):
|
||||||
def on_channel_utxos(self, chan, utxos):
|
def on_channel_utxos(self, chan, utxos):
|
||||||
outpoints = [Outpoint(x["tx_hash"], x["tx_pos"]) for x in utxos]
|
outpoints = [Outpoint(x["tx_hash"], x["tx_pos"]) for x in utxos]
|
||||||
if chan.funding_outpoint not in outpoints:
|
if chan.funding_outpoint not in outpoints:
|
||||||
self.channel_state[chan.channel_id] = "CLOSED"
|
chan.state = "CLOSED"
|
||||||
# FIXME is this properly GC-ed? (or too soon?)
|
# FIXME is this properly GC-ed? (or too soon?)
|
||||||
LNChanCloseHandler(self.network, self.wallet, chan)
|
LNChanCloseHandler(self.network, self.wallet, chan)
|
||||||
elif self.channel_state[chan.channel_id] == 'DISCONNECTED':
|
elif chan.state == 'DISCONNECTED':
|
||||||
|
if chan.node_id not in self.peers:
|
||||||
|
self.print_error("received channel_utxos for channel which does not have peer (errored?)")
|
||||||
|
return
|
||||||
peer = self.peers[chan.node_id]
|
peer = self.peers[chan.node_id]
|
||||||
coro = peer.reestablish_channel(chan)
|
coro = peer.reestablish_channel(chan)
|
||||||
asyncio.run_coroutine_threadsafe(coro, self.network.asyncio_loop)
|
asyncio.run_coroutine_threadsafe(coro, self.network.asyncio_loop)
|
||||||
|
|
||||||
def on_network_update(self, event, *args):
|
def on_network_update(self, event, *args):
|
||||||
for chan in self.channels.values():
|
for chan in self.channels.values():
|
||||||
peer = self.peers[chan.node_id]
|
if chan.state == "OPENING":
|
||||||
if self.channel_state[chan.channel_id] == "OPENING":
|
|
||||||
res = self.save_short_chan_id(chan)
|
res = self.save_short_chan_id(chan)
|
||||||
if not res:
|
if not res:
|
||||||
self.print_error("network update but funding tx is still not at sufficient depth")
|
self.print_error("network update but funding tx is still not at sufficient depth")
|
||||||
continue
|
continue
|
||||||
# this results in the channel being marked OPEN
|
# this results in the channel being marked OPEN
|
||||||
|
peer = self.peers[chan.node_id]
|
||||||
peer.funding_locked(chan)
|
peer.funding_locked(chan)
|
||||||
elif self.channel_state[chan.channel_id] == "OPEN":
|
elif chan.state == "OPEN":
|
||||||
conf = self.wallet.get_tx_height(chan.funding_outpoint.txid)[1]
|
conf = self.wallet.get_tx_height(chan.funding_outpoint.txid)[1]
|
||||||
|
peer = self.peers[chan.node_id]
|
||||||
peer.on_network_update(chan, conf)
|
peer.on_network_update(chan, conf)
|
||||||
|
|
||||||
async def _open_channel_coroutine(self, node_id, local_amount_sat, push_sat, password):
|
async def _open_channel_coroutine(self, node_id, local_amount_sat, push_sat, password):
|
||||||
|
|
|
@ -31,9 +31,9 @@ class Test_LNRouter(unittest.TestCase):
|
||||||
path_finder = lnrouter.LNPathFinder(fake_network.channel_db)
|
path_finder = lnrouter.LNPathFinder(fake_network.channel_db)
|
||||||
privkey = bitcoin.sha256('privkeyseed')
|
privkey = bitcoin.sha256('privkeyseed')
|
||||||
network = fake_network
|
network = fake_network
|
||||||
channel_state = {}
|
|
||||||
channels = []
|
channels = []
|
||||||
invoices = {}
|
invoices = {}
|
||||||
|
channels_for_peer = lambda x: []
|
||||||
p = Peer(fake_ln_worker, '', 0, 'a')
|
p = Peer(fake_ln_worker, '', 0, 'a')
|
||||||
p.on_channel_announcement({'node_id_1': b'b', 'node_id_2': b'c', 'short_channel_id': bfh('0000000000000001')})
|
p.on_channel_announcement({'node_id_1': b'b', 'node_id_2': b'c', 'short_channel_id': bfh('0000000000000001')})
|
||||||
p.on_channel_announcement({'node_id_1': b'b', 'node_id_2': b'e', 'short_channel_id': bfh('0000000000000002')})
|
p.on_channel_announcement({'node_id_1': b'b', 'node_id_2': b'e', 'short_channel_id': bfh('0000000000000002')})
|
||||||
|
|
Loading…
Add table
Reference in a new issue