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)
|
payment_attempt = self._receive_fail_reasons.get(htlc.htlc_id)
|
||||||
self.lnworker.payment_failed(self, htlc.payment_hash, payment_attempt)
|
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:
|
def balance(self, whose: HTLCOwner, *, ctx_owner=HTLCOwner.LOCAL, ctn: int = None) -> int:
|
||||||
assert type(whose) is HTLCOwner
|
assert type(whose) is HTLCOwner
|
||||||
initial = self.config[whose].initial_msat
|
initial = self.config[whose].initial_msat
|
||||||
|
|||||||
@@ -364,7 +364,7 @@ class LNWalletWatcher(LNWatcher):
|
|||||||
# detect who closed and set sweep_info
|
# detect who closed and set sweep_info
|
||||||
sweep_info_dict = chan.sweep_ctx(closing_tx)
|
sweep_info_dict = chan.sweep_ctx(closing_tx)
|
||||||
keep_watching = False if sweep_info_dict else not self.is_deeply_mined(closing_tx.txid())
|
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
|
# create and broadcast transaction
|
||||||
for prevout, sweep_info in sweep_info_dict.items():
|
for prevout, sweep_info in sweep_info_dict.items():
|
||||||
name = sweep_info.name + ' ' + chan.get_id_for_log()
|
name = sweep_info.name + ' ' + chan.get_id_for_log()
|
||||||
@@ -387,6 +387,7 @@ class LNWalletWatcher(LNWatcher):
|
|||||||
else:
|
else:
|
||||||
self.logger.info(f'(chan {chan.get_id_for_log()}) outpoint already spent {name}: {prevout}')
|
self.logger.info(f'(chan {chan.get_id_for_log()}) outpoint already spent {name}: {prevout}')
|
||||||
keep_watching |= not self.is_deeply_mined(spender_txid)
|
keep_watching |= not self.is_deeply_mined(spender_txid)
|
||||||
|
chan.extract_preimage_from_htlc_tx(spender_tx)
|
||||||
else:
|
else:
|
||||||
self.logger.info(f'(chan {chan.get_id_for_log()}) trying to redeem {name}: {prevout}')
|
self.logger.info(f'(chan {chan.get_id_for_log()}) trying to redeem {name}: {prevout}')
|
||||||
await self.try_redeem(prevout, sweep_info, name)
|
await self.try_redeem(prevout, sweep_info, name)
|
||||||
|
|||||||
@@ -39,6 +39,9 @@ class TestLightningAB(TestLightning):
|
|||||||
def test_breach(self):
|
def test_breach(self):
|
||||||
self.run_shell(['breach'])
|
self.run_shell(['breach'])
|
||||||
|
|
||||||
|
def test_extract_preimage(self):
|
||||||
|
self.run_shell(['extract_preimage'])
|
||||||
|
|
||||||
def test_redeem_htlcs(self):
|
def test_redeem_htlcs(self):
|
||||||
self.run_shell(['redeem_htlcs'])
|
self.run_shell(['redeem_htlcs'])
|
||||||
|
|
||||||
|
|||||||
@@ -162,6 +162,39 @@ if [[ $1 == "breach" ]]; then
|
|||||||
$bob getbalance
|
$bob getbalance
|
||||||
fi
|
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
|
if [[ $1 == "redeem_htlcs" ]]; then
|
||||||
$bob enable_htlc_settle false
|
$bob enable_htlc_settle false
|
||||||
wait_for_balance alice 1
|
wait_for_balance alice 1
|
||||||
|
|||||||
@@ -235,6 +235,12 @@ class TxInput:
|
|||||||
d['witness'] = self.witness.hex()
|
d['witness'] = self.witness.hex()
|
||||||
return d
|
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):
|
class BCDataStream(object):
|
||||||
"""Workalike python implementation of Bitcoin's CDataStream class."""
|
"""Workalike python implementation of Bitcoin's CDataStream class."""
|
||||||
|
|||||||
Reference in New Issue
Block a user