Skip to content

Commit

Permalink
lightningd: deprecate decodepay.
Browse files Browse the repository at this point in the history
It only works on BOLT11, and has long been replaced by the more
generic "decode".

Removing it will stop the confusion!

(Note: documentation claims it was introduced in 23.08, but that was
 wrong, as it's been in CLN since the beginning).

Fixes: #6419
Changelog-Deprecated: JSON-RPC: `decodepay`: use `decode`.
Signed-off-by: Rusty Russell <[email protected]>
  • Loading branch information
rustyrussell committed Aug 11, 2024
1 parent 975dd76 commit 182121c
Show file tree
Hide file tree
Showing 11 changed files with 115 additions and 73 deletions.
6 changes: 6 additions & 0 deletions contrib/msggen/msggen/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -9221,9 +9221,15 @@
"type": "object",
"additionalProperties": false,
"added": "v23.05",
"depecated": [
"v24.08",
"v25.08"
],
"rpc": "decodepay",
"title": "Command for decoding a bolt11 string (low-level)",
"description": [
"WARNING: deprecated: use *decode* which also handles bolt12.",
"",
"The **decodepay** RPC command checks and parses a *bolt11* string as specified by the BOLT 11 specification."
],
"request": {
Expand Down
3 changes: 1 addition & 2 deletions contrib/pyln-testing/pyln/testing/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -1207,8 +1207,7 @@ def pay(self, dst, amt, label=None, route=False):

# make an invoice
inv = dst.rpc.invoice(amt, label, label)
# FIXME: pre 0.10.1 invoice calls didn't have payment_secret field
psecret = dst.rpc.decodepay(inv['bolt11'])['payment_secret']
psecret = inv['payment_secret']
rhash = inv['payment_hash']
invoices = dst.rpc.listinvoices(label)['invoices']
assert len(invoices) == 1 and invoices[0]['status'] == 'unpaid'
Expand Down
1 change: 1 addition & 0 deletions doc/developers-guide/deprecations.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ hidden: false
| listpeers.features.option_anchors_zero_fee_htlc_tx | Field | v24.08 | v25.08 | Renamed to `option_anchors` in the spec: check for that in `features` instead |
| experimental-anchors | Config | v24.02 | v25.02 | Now the default |
| experimental-onion-messages | Config | v24.08 | v25.02 | Now the default |
| decodepay | Command | v24.08 | v25.08 | Use `decode` which is more powerful (since v3.08) |


Inevitably there are features which need to change: either to be generalized, or removed when they can no longer be supported.
Expand Down
6 changes: 6 additions & 0 deletions doc/schemas/lightning-decodepay.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,15 @@
"type": "object",
"additionalProperties": false,
"added": "v23.05",
"depecated": [
"v24.08",
"v25.08"
],
"rpc": "decodepay",
"title": "Command for decoding a bolt11 string (low-level)",
"description": [
"WARNING: deprecated: use *decode* which also handles bolt12.",
"",
"The **decodepay** RPC command checks and parses a *bolt11* string as specified by the BOLT 11 specification."
],
"request": {
Expand Down
2 changes: 2 additions & 0 deletions lightningd/invoice.c
Original file line number Diff line number Diff line change
Expand Up @@ -1582,6 +1582,8 @@ static struct command_result *json_decodepay(struct command *cmd,
static const struct json_command decodepay_command = {
"decodepay",
json_decodepay,
.depr_start = "v24.08",
.depr_end = "v25.08"
};
AUTODATA(json_command, &decodepay_command);

Expand Down
1 change: 0 additions & 1 deletion tests/autogenerate-rpc-examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -689,7 +689,6 @@ def generate_utils_examples(l1, l2, l3, l4, l5, l6, c23, c34, inv_l11, inv_l22,
update_example(node=l2, method='signmessage', params={'message': 'message for you'})
update_example(node=l2, method='checkmessage', params={'message': 'testcase to check new rpc error', 'zbase': 'd66bqz3qsku5fxtqsi37j11pci47ydxa95iusphutggz9ezaxt56neh77kxe5hyr41kwgkncgiu94p9ecxiexgpgsz8daoq4tw8kj8yx', 'pubkey': '03be3b0e9992153b1d5a6e1623670b6c3663f72ce6cf2e0dd39c0a373a7de5a3b7'})
update_example(node=l2, method='checkmessage', params={'message': 'this is a test!', 'zbase': 'd6tqaeuonjhi98mmont9m4wag7gg4krg1f4txonug3h31e9h6p6k6nbwjondnj46dkyausobstnk7fhyy998bhgc1yr98dfmhb4k54d7'})
update_example(node=l2, method='decodepay', params={'bolt11': inv_l11['bolt11']})
update_example(node=l2, method='decode', params=[rune_l21['rune']])
update_example(node=l2, method='decode', params=[inv_l22['bolt11']])

Expand Down
40 changes: 21 additions & 19 deletions tests/test_invoices.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ def test_invoice(node_factory, chainparams):
l1.daemon.wait_for_log(r': "{}:invoice#[0-9]*/cln:listincoming#[0-9]*"\[OUT\]'.format(myname))

after = int(time.time())
b11 = l1.rpc.decodepay(inv['bolt11'])
b11 = l1.rpc.decode(inv['bolt11'])
assert b11['type'] == 'bolt11 invoice'
assert b11['currency'] == chainparams['bip173_prefix']
assert b11['created_at'] >= before
assert b11['created_at'] <= after
Expand Down Expand Up @@ -63,7 +64,7 @@ def test_invoice(node_factory, chainparams):

# Test cltv option.
inv = l1.rpc.invoice(123000, 'label3', 'description', 3700, cltv=99)
b11 = l1.rpc.decodepay(inv['bolt11'])
b11 = l1.rpc.decode(inv['bolt11'])
assert b11['min_final_cltv_expiry'] == 99


Expand Down Expand Up @@ -103,7 +104,7 @@ def test_invoice_weirdstring(node_factory):
inv = only_one(l1.rpc.listinvoices()['invoices'])
assert inv['label'] == weird_label

b11 = l1.rpc.decodepay(inv['bolt11'])
b11 = l1.rpc.decode(inv['bolt11'])
assert b11['description'] == weird_desc

# Can delete by weird label.
Expand All @@ -123,7 +124,7 @@ def test_invoice_weirdstring(node_factory):
inv = only_one(l1.rpc.listinvoices()['invoices'])
assert inv['label'] == str(weird_label)

b11 = l1.rpc.decodepay(inv['bolt11'])
b11 = l1.rpc.decode(inv['bolt11'])
assert b11['description'] == weird_desc

# Can delete by weird label.
Expand Down Expand Up @@ -167,7 +168,7 @@ def test_invoice_routeboost(node_factory, bitcoind):
assert 'warning_deadends' not in inv
assert 'warning_mpp' not in inv
# Route array has single route with single element.
r = only_one(only_one(l2.rpc.decodepay(inv['bolt11'])['routes']))
r = only_one(only_one(l2.rpc.decode(inv['bolt11'])['routes']))
assert r['pubkey'] == l2.info['id']
assert r['short_channel_id'] == l3.rpc.listpeerchannels(l2.info['id'])['channels'][0]['short_channel_id']
assert r['fee_base_msat'] == 1
Expand Down Expand Up @@ -241,7 +242,7 @@ def test_invoice_routeboost_private(node_factory, bitcoind):
assert 'warning_deadends' not in inv
assert 'warning_mpp' not in inv
# Route array has single route with single element.
r = only_one(only_one(l1.rpc.decodepay(inv['bolt11'])['routes']))
r = only_one(only_one(l1.rpc.decode(inv['bolt11'])['routes']))
assert r['pubkey'] == l1.info['id']
# It uses our private alias!
assert r['short_channel_id'] != l1.rpc.listchannels()['channels'][0]['short_channel_id']
Expand All @@ -257,7 +258,7 @@ def test_invoice_routeboost_private(node_factory, bitcoind):
assert 'warning_offline' not in inv
assert 'warning_deadends' not in inv
assert 'warning_mpp' not in inv
assert 'routes' not in l1.rpc.decodepay(inv['bolt11'])
assert 'routes' not in l1.rpc.decode(inv['bolt11'])

# If we ask for it, we get it.
inv = l2.rpc.invoice(amount_msat=123456, label="inv1a", description="?", exposeprivatechannels=scid)
Expand All @@ -267,7 +268,7 @@ def test_invoice_routeboost_private(node_factory, bitcoind):
assert 'warning_deadends' not in inv
assert 'warning_mpp' not in inv
# Route array has single route with single element.
r = only_one(only_one(l1.rpc.decodepay(inv['bolt11'])['routes']))
r = only_one(only_one(l1.rpc.decode(inv['bolt11'])['routes']))
assert r['pubkey'] == l1.info['id']
assert r['short_channel_id'] == alias
assert r['fee_base_msat'] == 1
Expand All @@ -282,7 +283,7 @@ def test_invoice_routeboost_private(node_factory, bitcoind):
assert 'warning_deadends' not in inv
assert 'warning_mpp' not in inv
# Route array has single route with single element.
r = only_one(only_one(l1.rpc.decodepay(inv['bolt11'])['routes']))
r = only_one(only_one(l1.rpc.decode(inv['bolt11'])['routes']))
assert r['pubkey'] == l1.info['id']
assert r['short_channel_id'] == alias
assert r['fee_base_msat'] == 1
Expand Down Expand Up @@ -314,7 +315,7 @@ def test_invoice_routeboost_private(node_factory, bitcoind):
assert 'warning_deadends' not in inv
assert 'warning_mpp' not in inv
# Route array has single route with single element.
r = only_one(only_one(l1.rpc.decodepay(inv['bolt11'])['routes']))
r = only_one(only_one(l1.rpc.decode(inv['bolt11'])['routes']))
assert r['pubkey'] == l1.info['id']
assert r['short_channel_id'] == alias
assert r['fee_base_msat'] == 1
Expand All @@ -328,7 +329,7 @@ def test_invoice_routeboost_private(node_factory, bitcoind):
assert 'warning_deadends' not in inv
assert 'warning_mpp' not in inv
# Route array has single route with single element.
r = only_one(only_one(l1.rpc.decodepay(inv['bolt11'])['routes']))
r = only_one(only_one(l1.rpc.decode(inv['bolt11'])['routes']))
assert r['pubkey'] == l1.info['id']
assert r['short_channel_id'] == alias
assert r['fee_base_msat'] == 1
Expand All @@ -351,7 +352,7 @@ def test_invoice_routeboost_private(node_factory, bitcoind):
assert 'warning_deadends' not in inv
assert 'warning_mpp' not in inv
# Route array has single route with single element.
r = only_one(only_one(l1.rpc.decodepay(inv['bolt11'])['routes']))
r = only_one(only_one(l1.rpc.decode(inv['bolt11'])['routes']))
assert r['pubkey'] == l1.info['id']
assert r['short_channel_id'] == alias
assert r['fee_base_msat'] == 1
Expand All @@ -371,7 +372,7 @@ def test_invoice_routeboost_private(node_factory, bitcoind):
assert 'warning_deadends' not in inv
assert 'warning_mpp' not in inv
# Route array has single route with single element.
r = only_one(only_one(l1.rpc.decodepay(inv['bolt11'])['routes']))
r = only_one(only_one(l1.rpc.decode(inv['bolt11'])['routes']))
assert r['pubkey'] == l1.info['id']
assert r['short_channel_id'] == alias
assert r['fee_base_msat'] == 1
Expand Down Expand Up @@ -535,11 +536,11 @@ def test_signinvoice(node_factory, executor):

# Create an invoice for l1
inv1 = l1.rpc.invoice(1000, 'inv1', 'inv1')['bolt11']
assert l1.rpc.decodepay(inv1)['payee'] == l1.info['id']
assert l1.rpc.decode(inv1)['payee'] == l1.info['id']

# Have l2 re-sign the invoice
inv2 = l2.rpc.signinvoice(inv1)['bolt11']
assert l1.rpc.decodepay(inv2)['payee'] == l2.info['id']
assert l1.rpc.decode(inv2)['payee'] == l2.info['id']


def test_waitanyinvoice_reversed(node_factory, executor):
Expand Down Expand Up @@ -570,7 +571,8 @@ def test_waitanyinvoice_reversed(node_factory, executor):
def test_decode_unknown(node_factory):
l1 = node_factory.get_node()

b11 = l1.rpc.decodepay('lntb30m1pw2f2yspp5s59w4a0kjecw3zyexm7zur8l8n4scw674w8sftjhwec33km882gsdpa2pshjmt9de6zqun9w96k2um5ypmkjargypkh2mr5d9cxzun5ypeh2ursdae8gxqruyqvzddp68gup69uhnzwfj9cejuvf3xshrwde68qcrswf0d46kcarfwpshyaplw3skw0tdw4k8g6tsv9e8gu2etcvsym36pdjpz04wm9nn96f9ntc3t3h5r08pe9d62p3js5wt5rkurqnrl7zkj2fjpvl3rmn7wwazt80letwxlm22hngu8n88g7hsp542qpl')
b11 = l1.rpc.decode('lntb30m1pw2f2yspp5s59w4a0kjecw3zyexm7zur8l8n4scw674w8sftjhwec33km882gsdpa2pshjmt9de6zqun9w96k2um5ypmkjargypkh2mr5d9cxzun5ypeh2ursdae8gxqruyqvzddp68gup69uhnzwfj9cejuvf3xshrwde68qcrswf0d46kcarfwpshyaplw3skw0tdw4k8g6tsv9e8gu2etcvsym36pdjpz04wm9nn96f9ntc3t3h5r08pe9d62p3js5wt5rkurqnrl7zkj2fjpvl3rmn7wwazt80letwxlm22hngu8n88g7hsp542qpl')
assert b11['type'] == 'bolt11 invoice'
assert b11['currency'] == 'tb'
assert b11['created_at'] == 1554294928
assert b11['payment_hash'] == '850aeaf5f69670e8889936fc2e0cff3ceb0c3b5eab8f04ae57767118db673a91'
Expand All @@ -596,7 +598,7 @@ def test_amountless_invoice(node_factory):
assert(len(i) == 1)
assert('amount_received_msat' not in i[0])
assert(i[0]['status'] == 'unpaid')
details = l1.rpc.decodepay(inv)
details = l1.rpc.decode(inv)
assert('msatoshi' not in details)

l1.rpc.pay(inv, amount_msat=1337)
Expand Down Expand Up @@ -781,7 +783,7 @@ def test_invoice_deschash(node_factory, chainparams):
inv = l2.rpc.invoice(42, 'label', 'One piece of chocolate cake, one icecream cone, one pickle, one slice of swiss cheese, one slice of salami, one lollypop, one piece of cherry pie, one sausage, one cupcake, and one slice of watermelon', deschashonly=True)
assert '8yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqs' in inv['bolt11']

b11 = l2.rpc.decodepay(inv['bolt11'])
b11 = l2.rpc.decode(inv['bolt11'])
assert 'description' not in b11
assert b11['description_hash'] == '3925b6f67e2c340036ed12093dd44e0368df1b6ea26c53dbe4811f58fd5db8c1'

Expand Down Expand Up @@ -864,7 +866,7 @@ def test_unified_invoices(node_factory, executor, bitcoind):
l1, l2 = node_factory.line_graph(2, opts={'invoices-onchain-fallback': None})
amount_sat = 1000
inv = l1.rpc.invoice(amount_sat * 1000, "inv1", "test_unified_invoices")
b11 = l1.rpc.decodepay(inv['bolt11'])
b11 = l1.rpc.decode(inv['bolt11'])

assert len(b11['fallbacks']) == 1

Expand Down
12 changes: 6 additions & 6 deletions tests/test_misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -3695,21 +3695,21 @@ def test_field_filter(node_factory, chainparams):
inv = l1.rpc.invoice(123000, 'label', 'description', 3700, [addr1, addr2])

# Simple case: single field
dec = l1.rpc.call('decodepay', {'bolt11': inv['bolt11']}, filter={"currency": True})
dec = l1.rpc.call('decode', {'string': inv['bolt11']}, filter={"currency": True})
assert dec == {"currency": chainparams['bip173_prefix']}

# Use context manager:
with l1.rpc.reply_filter({"currency": True}):
dec = l1.rpc.decodepay(bolt11=inv['bolt11'])
dec = l1.rpc.decode(string=inv['bolt11'])
assert dec == {"currency": chainparams['bip173_prefix']}

# Two fields
dec = l1.rpc.call('decodepay', {'bolt11': inv['bolt11']}, filter={"currency": True, "payment_hash": True})
dec = l1.rpc.call('decode', {'string': inv['bolt11']}, filter={"currency": True, "payment_hash": True})
assert dec == {"currency": chainparams['bip173_prefix'],
"payment_hash": inv['payment_hash']}

# Nested fields
dec = l1.rpc.call('decodepay', {'bolt11': inv['bolt11']},
dec = l1.rpc.call('decode', {'string': inv['bolt11']},
filter={"currency": True,
"payment_hash": True,
"fallbacks": [{"type": True}]})
Expand All @@ -3718,12 +3718,12 @@ def test_field_filter(node_factory, chainparams):
"fallbacks": [{"type": 'P2WPKH'}, {"type": 'P2SH'}]}

# Nonexistent fields.
dec = l1.rpc.call('decodepay', {'bolt11': inv['bolt11']},
dec = l1.rpc.call('decode', {'string': inv['bolt11']},
filter={"foobar": True})
assert dec == {}

# Bad filters
dec = l1.rpc.call('decodepay', {'bolt11': inv['bolt11']},
dec = l1.rpc.call('decode', {'string': inv['bolt11']},
filter={"currency": True,
"payment_hash": True,
"fallbacks": {'type': True}})
Expand Down
5 changes: 1 addition & 4 deletions tests/test_opening.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
from pyln.testing.utils import FUNDAMOUNT

from pathlib import Path
from pprint import pprint
import pytest
import re
import unittest
Expand Down Expand Up @@ -1665,8 +1664,7 @@ def test_zeroconf_open(bitcoind, node_factory):
wait_for(lambda: l3.rpc.listchannels() != {'channels': []})

inv = l3.rpc.invoice(10**8, 'lbl', 'desc')['bolt11']
details = l2.rpc.decodepay(inv)
pprint(details)
details = l2.rpc.decode(inv)
assert('routes' in details and len(details['routes']) == 1)
hop = details['routes'][0][0] # First (and only) hop of hint 0
l2alias = only_one(l2.rpc.listpeerchannels(l3.info['id'])['channels'])['alias']['local']
Expand All @@ -1679,7 +1677,6 @@ def test_zeroconf_open(bitcoind, node_factory):
l3.daemon.wait_for_log(r'Balance [0-9]+msat -> [0-9]+msat')

# Inverse payments should work too
pprint(l3.rpc.listpeers())
inv = l2.rpc.invoice(10**5, 'lbl', 'desc')['bolt11']
l3.rpc.pay(inv)

Expand Down
Loading

0 comments on commit 182121c

Please sign in to comment.