1
0

cli: add command to export preimage

..also export preimage in check_hold_invoice return value if available.

I intentionally did not return the preimage in the returned dict of
wallet.export_requests as this seems risky to do considering some users
of the cli might forward the response to a payer and the payserver
exposes it too.

Closes https://github.com/spesmilo/electrum/issues/10176
This commit is contained in:
f321x
2025-09-29 18:06:12 +02:00
parent 3d27992fb7
commit b57f867c2f
3 changed files with 34 additions and 2 deletions

View File

@@ -1514,10 +1514,22 @@ class Commands(Logger):
plist = wallet.lnworker.get_payments(status='settled')[bfh(payment_hash)]
_dir, amount_msat, _fee, _ts = wallet.lnworker.get_payment_value(info, plist)
result["received_amount_sat"] = amount_msat // 1000
result['preimage'] = wallet.lnworker.get_preimage_hex(payment_hash)
if info is not None:
result["invoice_amount_sat"] = (info.amount_msat or 0) // 1000
return result
@command('wl')
async def export_lightning_preimage(self, payment_hash: str, wallet: 'Abstract_Wallet' = None) -> Optional[str]:
"""
Returns the stored preimage of the given payment_hash if it is known.
arg:str:payment_hash: Hash of the preimage
"""
preimage = wallet.lnworker.get_preimage_hex(payment_hash)
assert preimage is None or crypto.sha256(bytes.fromhex(preimage)).hex() == payment_hash
return preimage
@command('w')
async def addtransaction(self, tx, wallet: Abstract_Wallet = None):
"""

View File

@@ -2930,8 +2930,11 @@ class Abstract_Wallet(ABC, Logger, EventListener):
if x.is_lightning():
d['rhash'] = x.rhash
d['lightning_invoice'] = self.get_bolt11_invoice(x)
if self.lnworker and status == PR_UNPAID:
d['can_receive'] = self.lnworker.can_receive_invoice(x)
if self.lnworker:
if status == PR_UNPAID:
d['can_receive'] = self.lnworker.can_receive_invoice(x)
elif status == PR_PAID and (preimage := self.lnworker.get_preimage(x.payment_hash)):
d['preimage'] = preimage.hex()
if address := x.get_address():
d['address'] = address
d['URI'] = self.get_request_URI(x)

View File

@@ -572,6 +572,7 @@ class TestCommandsTestnet(ElectrumTestCase):
assert settled_status['status'] == 'settled'
assert settled_status['received_amount_sat'] == 10000
assert settled_status['invoice_amount_sat'] == 10000
assert settled_status['preimage'] == preimage.hex()
with self.assertRaises(AssertionError):
# cancelling a settled invoice should raise
@@ -723,3 +724,19 @@ class TestCommandsTestnet(ElectrumTestCase):
}
}
self.assertEqual(result, expected_result)
@mock.patch.object(wallet.Abstract_Wallet, 'save_db')
async def test_export_lightning_preimage(self, *mock_args):
w = restore_wallet_from_text__for_unittest(
'disagree rug lemon bean unaware square alone beach tennis exhibit fix mimic',
path='if_this_exists_mocking_failed_648151893',
config=self.config)['wallet']
cmds = Commands(config=self.config)
preimage = os.urandom(32)
payment_hash = sha256(preimage)
w.lnworker.save_preimage(payment_hash, preimage)
assert await cmds.export_lightning_preimage(payment_hash=payment_hash.hex(), wallet=w) == preimage.hex()
assert await cmds.export_lightning_preimage(payment_hash=os.urandom(32).hex(), wallet=w) is None