fix #6122: extract preimage from on-chain htlc_tx
This commit is contained in:
@@ -956,6 +956,21 @@ class Channel(AbstractChannel):
|
||||
payment_attempt = self._receive_fail_reasons.get(htlc.htlc_id)
|
||||
self.lnworker.payment_failed(self, htlc.payment_hash, payment_attempt)
|
||||
|
||||
def extract_preimage_from_htlc_tx(self, tx):
|
||||
witness = tx.inputs()[0].witness_elements()
|
||||
if len(witness) != 5:
|
||||
return
|
||||
preimage = witness[3]
|
||||
payment_hash = sha256(preimage)
|
||||
for direction, htlc in self.hm.get_htlcs_in_oldest_unrevoked_ctx(REMOTE):
|
||||
if htlc.payment_hash == payment_hash:
|
||||
self.logger.info(f'found preimage for {payment_hash.hex()} in tx witness')
|
||||
self.lnworker.save_preimage(payment_hash, preimage)
|
||||
if direction == RECEIVED:
|
||||
self.lnworker.payment_sent(self, payment_hash)
|
||||
else:
|
||||
self.lnworker.payment_received(self, payment_hash)
|
||||
|
||||
def balance(self, whose: HTLCOwner, *, ctx_owner=HTLCOwner.LOCAL, ctn: int = None) -> int:
|
||||
assert type(whose) is HTLCOwner
|
||||
initial = self.config[whose].initial_msat
|
||||
|
||||
@@ -364,7 +364,7 @@ class LNWalletWatcher(LNWatcher):
|
||||
# detect who closed and set sweep_info
|
||||
sweep_info_dict = chan.sweep_ctx(closing_tx)
|
||||
keep_watching = False if sweep_info_dict else not self.is_deeply_mined(closing_tx.txid())
|
||||
self.logger.info(f'(chan {chan.get_id_for_log()}) sweep_info_dict length: {len(sweep_info_dict)}')
|
||||
self.logger.info(f'(chan {chan.get_id_for_log()}) sweep_info_dict {[x.name for x in sweep_info_dict.values()]}')
|
||||
# create and broadcast transaction
|
||||
for prevout, sweep_info in sweep_info_dict.items():
|
||||
name = sweep_info.name + ' ' + chan.get_id_for_log()
|
||||
@@ -387,6 +387,7 @@ class LNWalletWatcher(LNWatcher):
|
||||
else:
|
||||
self.logger.info(f'(chan {chan.get_id_for_log()}) outpoint already spent {name}: {prevout}')
|
||||
keep_watching |= not self.is_deeply_mined(spender_txid)
|
||||
chan.extract_preimage_from_htlc_tx(spender_tx)
|
||||
else:
|
||||
self.logger.info(f'(chan {chan.get_id_for_log()}) trying to redeem {name}: {prevout}')
|
||||
await self.try_redeem(prevout, sweep_info, name)
|
||||
|
||||
@@ -39,6 +39,9 @@ class TestLightningAB(TestLightning):
|
||||
def test_breach(self):
|
||||
self.run_shell(['breach'])
|
||||
|
||||
def test_extract_preimage(self):
|
||||
self.run_shell(['extract_preimage'])
|
||||
|
||||
def test_redeem_htlcs(self):
|
||||
self.run_shell(['redeem_htlcs'])
|
||||
|
||||
|
||||
@@ -162,6 +162,39 @@ if [[ $1 == "breach" ]]; then
|
||||
$bob getbalance
|
||||
fi
|
||||
|
||||
|
||||
if [[ $1 == "extract_preimage" ]]; then
|
||||
# instead of settling bob will broadcast
|
||||
$bob enable_htlc_settle false
|
||||
wait_for_balance alice 1
|
||||
echo "alice opens channel"
|
||||
bob_node=$($bob nodeid)
|
||||
$alice open_channel $bob_node 0.15
|
||||
new_blocks 3
|
||||
wait_until_channel_open alice
|
||||
chan_id=$($alice list_channels | jq -r ".[0].channel_point")
|
||||
# alice pays bob
|
||||
invoice=$($bob add_lightning_request 0.04 -m "test")
|
||||
screen -S alice_payment -dm -L -Logfile /tmp/alice/screen.log $alice lnpay $invoice --timeout=600
|
||||
sleep 1
|
||||
unsettled=$($alice list_channels | jq '.[] | .local_unsettled_sent')
|
||||
if [[ "$unsettled" == "0" ]]; then
|
||||
echo 'enable_htlc_settle did not work'
|
||||
exit 1
|
||||
fi
|
||||
# bob force closes
|
||||
$bob close_channel $chan_id --force
|
||||
new_blocks 1
|
||||
wait_until_channel_closed bob
|
||||
sleep 5
|
||||
success=$(cat /tmp/alice/screen.log | jq -r ".success")
|
||||
if [[ "$success" != "true" ]]; then
|
||||
exit 1
|
||||
fi
|
||||
cat /tmp/alice/screen.log
|
||||
fi
|
||||
|
||||
|
||||
if [[ $1 == "redeem_htlcs" ]]; then
|
||||
$bob enable_htlc_settle false
|
||||
wait_for_balance alice 1
|
||||
|
||||
@@ -235,6 +235,12 @@ class TxInput:
|
||||
d['witness'] = self.witness.hex()
|
||||
return d
|
||||
|
||||
def witness_elements(self)-> Sequence[bytes]:
|
||||
vds = BCDataStream()
|
||||
vds.write(self.witness)
|
||||
n = vds.read_compact_size()
|
||||
return list(vds.read_bytes(vds.read_compact_size()) for i in range(n))
|
||||
|
||||
|
||||
class BCDataStream(object):
|
||||
"""Workalike python implementation of Bitcoin's CDataStream class."""
|
||||
|
||||
Reference in New Issue
Block a user