mirror of
https://github.com/LBRYFoundation/LBRY-Vault.git
synced 2025-09-20 01:19:49 +00:00
rework on_channel_closed in LNWorker:
- use detect_who_closed; this allows us to redeem to_remote of breach ctx - do not redeem to_local of breach ctx, because it is redundant with lnwatcher - rename a few methods
This commit is contained in:
parent
930d21c31c
commit
6bbdbf7596
3 changed files with 33 additions and 51 deletions
|
@ -46,8 +46,7 @@ from .lnutil import (Outpoint, LocalConfig, RemoteConfig, Keypair, OnlyPubkeyKey
|
||||||
HTLC_TIMEOUT_WEIGHT, HTLC_SUCCESS_WEIGHT, extract_ctn_from_tx_and_chan, UpdateAddHtlc,
|
HTLC_TIMEOUT_WEIGHT, HTLC_SUCCESS_WEIGHT, extract_ctn_from_tx_and_chan, UpdateAddHtlc,
|
||||||
funding_output_script, SENT, RECEIVED, LOCAL, REMOTE, HTLCOwner, make_commitment_outputs,
|
funding_output_script, SENT, RECEIVED, LOCAL, REMOTE, HTLCOwner, make_commitment_outputs,
|
||||||
ScriptHtlc, PaymentFailure, calc_onchain_fees, RemoteMisbehaving, make_htlc_output_witness_script)
|
ScriptHtlc, PaymentFailure, calc_onchain_fees, RemoteMisbehaving, make_htlc_output_witness_script)
|
||||||
from .lnsweep import create_sweeptxs_for_their_just_revoked_ctx
|
from .lnsweep import create_sweeptxs_for_their_revoked_ctx
|
||||||
from .lnsweep import create_sweeptxs_for_our_latest_ctx, create_sweeptxs_for_their_latest_ctx
|
|
||||||
from .lnhtlc import HTLCManager
|
from .lnhtlc import HTLCManager
|
||||||
|
|
||||||
|
|
||||||
|
@ -168,6 +167,7 @@ class Channel(Logger):
|
||||||
|
|
||||||
self.local_commitment = None
|
self.local_commitment = None
|
||||||
self.remote_commitment = None
|
self.remote_commitment = None
|
||||||
|
self.sweep_info = None
|
||||||
|
|
||||||
def get_payments(self):
|
def get_payments(self):
|
||||||
out = {}
|
out = {}
|
||||||
|
@ -186,13 +186,9 @@ class Channel(Logger):
|
||||||
ctn = extract_ctn_from_tx_and_chan(ctx, self)
|
ctn = extract_ctn_from_tx_and_chan(ctx, self)
|
||||||
assert self.signature_fits(ctx), (self.hm.log[LOCAL])
|
assert self.signature_fits(ctx), (self.hm.log[LOCAL])
|
||||||
self.local_commitment = ctx
|
self.local_commitment = ctx
|
||||||
if self.sweep_address is not None:
|
|
||||||
self.local_sweeptxs = create_sweeptxs_for_our_latest_ctx(self, self.local_commitment, self.sweep_address)
|
|
||||||
|
|
||||||
def set_remote_commitment(self):
|
def set_remote_commitment(self):
|
||||||
self.remote_commitment = self.current_commitment(REMOTE)
|
self.remote_commitment = self.current_commitment(REMOTE)
|
||||||
if self.sweep_address is not None:
|
|
||||||
self.remote_sweeptxs = create_sweeptxs_for_their_latest_ctx(self, self.remote_commitment, self.sweep_address)
|
|
||||||
|
|
||||||
def open_with_first_pcp(self, remote_pcp, remote_sig):
|
def open_with_first_pcp(self, remote_pcp, remote_sig):
|
||||||
self.remote_commitment_to_be_revoked = self.pending_commitment(REMOTE)
|
self.remote_commitment_to_be_revoked = self.pending_commitment(REMOTE)
|
||||||
|
@ -460,7 +456,7 @@ class Channel(Logger):
|
||||||
return
|
return
|
||||||
outpoint = self.funding_outpoint.to_str()
|
outpoint = self.funding_outpoint.to_str()
|
||||||
ctx = self.remote_commitment_to_be_revoked # FIXME can't we just reconstruct it?
|
ctx = self.remote_commitment_to_be_revoked # FIXME can't we just reconstruct it?
|
||||||
sweeptxs = create_sweeptxs_for_their_just_revoked_ctx(self, ctx, per_commitment_secret, self.sweep_address)
|
sweeptxs = create_sweeptxs_for_their_revoked_ctx(self, ctx, per_commitment_secret, self.sweep_address)
|
||||||
for prev_txid, tx in sweeptxs.items():
|
for prev_txid, tx in sweeptxs.items():
|
||||||
if tx is not None:
|
if tx is not None:
|
||||||
self.lnwatcher.add_sweep_tx(outpoint, prev_txid, str(tx))
|
self.lnwatcher.add_sweep_tx(outpoint, prev_txid, str(tx))
|
||||||
|
|
|
@ -56,7 +56,7 @@ def maybe_create_sweeptx_for_their_ctx_to_local(ctx: Transaction, revocation_pri
|
||||||
return sweep_tx
|
return sweep_tx
|
||||||
|
|
||||||
|
|
||||||
def create_sweeptxs_for_their_just_revoked_ctx(chan: 'Channel', ctx: Transaction, per_commitment_secret: bytes,
|
def create_sweeptxs_for_their_revoked_ctx(chan: 'Channel', ctx: Transaction, per_commitment_secret: bytes,
|
||||||
sweep_address: str) -> Dict[str,Transaction]:
|
sweep_address: str) -> Dict[str,Transaction]:
|
||||||
"""Presign sweeping transactions using the just received revoked pcs.
|
"""Presign sweeping transactions using the just received revoked pcs.
|
||||||
These will only be utilised if the remote breaches.
|
These will only be utilised if the remote breaches.
|
||||||
|
@ -135,12 +135,8 @@ class ChannelClosedBy(Enum):
|
||||||
UNKNOWN = auto()
|
UNKNOWN = auto()
|
||||||
|
|
||||||
|
|
||||||
class ChannelCloseSituationReport(NamedTuple):
|
|
||||||
closed_by: ChannelClosedBy
|
|
||||||
is_breach: Optional[bool]
|
|
||||||
|
|
||||||
|
def detect_who_closed(chan: 'Channel', ctx: Transaction) -> ChannelClosedBy:
|
||||||
def detect_how_channel_was_closed(chan: 'Channel', ctx: Transaction) -> ChannelCloseSituationReport:
|
|
||||||
ctn = extract_ctn_from_tx_and_chan(ctx, chan)
|
ctn = extract_ctn_from_tx_and_chan(ctx, chan)
|
||||||
our_conf, their_conf = get_ordered_channel_configs(chan=chan, for_us=True)
|
our_conf, their_conf = get_ordered_channel_configs(chan=chan, for_us=True)
|
||||||
|
|
||||||
|
@ -193,18 +189,18 @@ def detect_how_channel_was_closed(chan: 'Channel', ctx: Transaction) -> ChannelC
|
||||||
to_local_address, to_remote_address, is_breach = get_to_local_and_to_remote_addresses_for_our_ctx()
|
to_local_address, to_remote_address, is_breach = get_to_local_and_to_remote_addresses_for_our_ctx()
|
||||||
if (to_local_address and ctx.get_output_idx_from_address(to_local_address) is not None
|
if (to_local_address and ctx.get_output_idx_from_address(to_local_address) is not None
|
||||||
or to_remote_address and ctx.get_output_idx_from_address(to_remote_address) is not None):
|
or to_remote_address and ctx.get_output_idx_from_address(to_remote_address) is not None):
|
||||||
return ChannelCloseSituationReport(closed_by=ChannelClosedBy.US, is_breach=is_breach)
|
return ChannelClosedBy.US
|
||||||
|
|
||||||
# their ctx?
|
# their ctx?
|
||||||
to_local_address, to_remote_address, is_breach = get_to_local_and_to_remote_addresses_for_their_ctx()
|
to_local_address, to_remote_address, is_breach = get_to_local_and_to_remote_addresses_for_their_ctx()
|
||||||
if (to_local_address and ctx.get_output_idx_from_address(to_local_address) is not None
|
if (to_local_address and ctx.get_output_idx_from_address(to_local_address) is not None
|
||||||
or to_remote_address and ctx.get_output_idx_from_address(to_remote_address) is not None):
|
or to_remote_address and ctx.get_output_idx_from_address(to_remote_address) is not None):
|
||||||
return ChannelCloseSituationReport(closed_by=ChannelClosedBy.THEM, is_breach=is_breach)
|
return ChannelClosedBy.THEM
|
||||||
|
|
||||||
return ChannelCloseSituationReport(closed_by=ChannelClosedBy.UNKNOWN, is_breach=None)
|
return ChannelClosedBy.UNKNOWN
|
||||||
|
|
||||||
|
|
||||||
def create_sweeptxs_for_our_latest_ctx(chan: 'Channel', ctx: Transaction,
|
def create_sweeptxs_for_our_ctx(chan: 'Channel', ctx: Transaction,
|
||||||
sweep_address: str) -> Dict[str,Transaction]:
|
sweep_address: str) -> Dict[str,Transaction]:
|
||||||
"""Handle the case where we force close unilaterally with our latest ctx.
|
"""Handle the case where we force close unilaterally with our latest ctx.
|
||||||
Construct sweep txns for 'to_local', and for all HTLCs (2 txns each).
|
Construct sweep txns for 'to_local', and for all HTLCs (2 txns each).
|
||||||
|
@ -277,7 +273,7 @@ def create_sweeptxs_for_our_latest_ctx(chan: 'Channel', ctx: Transaction,
|
||||||
return txs
|
return txs
|
||||||
|
|
||||||
|
|
||||||
def create_sweeptxs_for_their_latest_ctx(chan: 'Channel', ctx: Transaction,
|
def create_sweeptxs_for_their_ctx(chan: 'Channel', ctx: Transaction,
|
||||||
sweep_address: str) -> Dict[str,Transaction]:
|
sweep_address: str) -> Dict[str,Transaction]:
|
||||||
"""Handle the case when the remote force-closes with their ctx.
|
"""Handle the case when the remote force-closes with their ctx.
|
||||||
Regardless of it is a breach or not, construct sweep tx for 'to_remote'.
|
Regardless of it is a breach or not, construct sweep tx for 'to_remote'.
|
||||||
|
@ -313,18 +309,7 @@ def create_sweeptxs_for_their_latest_ctx(chan: 'Channel', ctx: Transaction,
|
||||||
other_payment_privkey = ecc.ECPrivkey.from_secret_scalar(other_payment_privkey)
|
other_payment_privkey = ecc.ECPrivkey.from_secret_scalar(other_payment_privkey)
|
||||||
|
|
||||||
txs = {}
|
txs = {}
|
||||||
if per_commitment_secret: # breach
|
# to_local is handled by lnwatcher
|
||||||
# to_local
|
|
||||||
other_revocation_privkey = derive_blinded_privkey(other_conf.revocation_basepoint.privkey,
|
|
||||||
per_commitment_secret)
|
|
||||||
this_delayed_pubkey = derive_pubkey(this_conf.delayed_basepoint.pubkey, their_pcp)
|
|
||||||
sweep_tx = maybe_create_sweeptx_for_their_ctx_to_local(ctx=ctx,
|
|
||||||
revocation_privkey=other_revocation_privkey,
|
|
||||||
to_self_delay=other_conf.to_self_delay,
|
|
||||||
delayed_pubkey=this_delayed_pubkey,
|
|
||||||
sweep_address=sweep_address)
|
|
||||||
if sweep_tx:
|
|
||||||
txs[sweep_tx.prevout(0)] = sweep_tx
|
|
||||||
# to_remote
|
# to_remote
|
||||||
sweep_tx = maybe_create_sweeptx_for_their_ctx_to_remote(ctx=ctx,
|
sweep_tx = maybe_create_sweeptx_for_their_ctx_to_remote(ctx=ctx,
|
||||||
sweep_address=sweep_address,
|
sweep_address=sweep_address,
|
||||||
|
|
|
@ -46,6 +46,7 @@ from .lnrouter import RouteEdge, is_route_sane_to_use
|
||||||
from .address_synchronizer import TX_HEIGHT_LOCAL
|
from .address_synchronizer import TX_HEIGHT_LOCAL
|
||||||
from . import lnsweep
|
from . import lnsweep
|
||||||
from .lnsweep import ChannelClosedBy
|
from .lnsweep import ChannelClosedBy
|
||||||
|
from .lnsweep import create_sweeptxs_for_their_ctx, create_sweeptxs_for_our_ctx
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from .network import Network
|
from .network import Network
|
||||||
|
@ -511,24 +512,24 @@ class LNWallet(LNWorker):
|
||||||
# remove from channel_db
|
# remove from channel_db
|
||||||
if chan.short_channel_id is not None:
|
if chan.short_channel_id is not None:
|
||||||
self.channel_db.remove_channel(chan.short_channel_id)
|
self.channel_db.remove_channel(chan.short_channel_id)
|
||||||
# detect who closed
|
|
||||||
assert closing_tx, f"no closing tx... {repr(closing_tx)}"
|
# detect who closed and set sweep_info
|
||||||
sitrep = lnsweep.detect_how_channel_was_closed(chan, closing_tx)
|
if chan.sweep_info is None:
|
||||||
if sitrep.closed_by == ChannelClosedBy.US:
|
closed_by = lnsweep.detect_who_closed(chan, closing_tx)
|
||||||
self.logger.info(f'we force closed {funding_outpoint}. sitrep: {repr(sitrep)}')
|
if closed_by == ChannelClosedBy.US:
|
||||||
encumbered_sweeptxs = chan.local_sweeptxs
|
self.logger.info(f'we force closed {funding_outpoint}.')
|
||||||
elif sitrep.closed_by == ChannelClosedBy.THEM and sitrep.is_breach is False:
|
chan.sweep_info = create_sweeptxs_for_our_ctx(chan, closing_tx, chan.sweep_address)
|
||||||
self.logger.info(f'they force closed {funding_outpoint}. sitrep: {repr(sitrep)}')
|
elif closed_by == ChannelClosedBy.THEM:
|
||||||
encumbered_sweeptxs = chan.remote_sweeptxs
|
self.logger.info(f'they force closed {funding_outpoint}.')
|
||||||
|
chan.sweep_info = create_sweeptxs_for_their_ctx(chan, closing_tx, chan.sweep_address)
|
||||||
else:
|
else:
|
||||||
self.logger.info(f'not sure who closed {funding_outpoint} {closing_txid}. sitrep: {repr(sitrep)}')
|
self.logger.info(f'not sure who closed {funding_outpoint} {closing_txid}.')
|
||||||
return
|
chan.sweep_info = {}
|
||||||
# sweep
|
self.logger.info(f'{repr(chan.sweep_info)}')
|
||||||
for prevout, spender in spenders.items():
|
|
||||||
e_tx = encumbered_sweeptxs.get(prevout)
|
# create and broadcast transaction
|
||||||
if e_tx is None:
|
for prevout, e_tx in chan.sweep_info.items():
|
||||||
continue
|
if spenders.get(prevout) is not None:
|
||||||
if spender is not None:
|
|
||||||
self.logger.info(f'outpoint already spent {prevout}')
|
self.logger.info(f'outpoint already spent {prevout}')
|
||||||
continue
|
continue
|
||||||
prev_txid, prev_index = prevout.split(':')
|
prev_txid, prev_index = prevout.split(':')
|
||||||
|
|
Loading…
Add table
Reference in a new issue