diff --git a/plugins/clnrest/utilities/shared.py b/plugins/clnrest/utilities/shared.py index 3b51369e10ef..f58e0026d2f6 100644 --- a/plugins/clnrest/utilities/shared.py +++ b/plugins/clnrest/utilities/shared.py @@ -1,5 +1,6 @@ import json5 import ipaddress +import pyln.client CERTS_PATH, REST_PROTOCOL, REST_HOST, REST_PORT, REST_CSP, REST_CORS_ORIGINS = "", "", "", "", "", [] @@ -64,8 +65,29 @@ def set_config(options): return None +def convert_millisatoshis(item): + """ + The global JSON encoder has been replaced (see + monkey_patch_json!) by one that turns Millisatoshi class object + into strings ending in msat. We do not want the http response + to be encoded like that! pyln-client should probably not do that, + but meanwhile, convert them to integers. + """ + if isinstance(item, dict): + ret = {} + for k in item: + ret[k] = convert_millisatoshis(item[k]) + elif isinstance(item, list): + ret = [convert_millisatoshis(i) for i in item] + elif isinstance(item, pyln.client.Millisatoshi): + ret = int(item) + else: + ret = item + return ret + + def call_rpc_method(plugin, rpc_method, payload): - return plugin.rpc.call(rpc_method, payload) + return convert_millisatoshis(plugin.rpc.call(rpc_method, payload)) def verify_rune(plugin, rune, rpc_method, rpc_params): diff --git a/tests/test_clnrest.py b/tests/test_clnrest.py index 4a9e66979a07..fedf42166862 100644 --- a/tests/test_clnrest.py +++ b/tests/test_clnrest.py @@ -237,6 +237,28 @@ def test_clnrest_rpc_method(node_factory): assert 'bolt11' in response.json() +def test_clnrest_large_response(node_factory): + """Test a large reply still works (and msat fields are integers!)""" + # start a node with clnrest + l1, base_url, ca_cert = start_node_with_clnrest(node_factory) + http_session = http_session_with_retry() + + # Add 500 invoices, test list + NUM_INVOICES = 500 + for i in range(NUM_INVOICES): + l1.rpc.invoice(amount_msat=100, label=str(i), description="inv") + + rune = l1.rpc.createrune()['rune'] + response = http_session.post(base_url + '/v1/listinvoices', headers={'Rune': rune}, + verify=ca_cert) + # No, this doesn't return JSON, it *parses* it into a Python object! + resp = response.json() + + # Make sure it hasn't turned msat fields into strings! + assert not isinstance(resp['invoices'][0]['amount_msat'], Millisatoshi) + assert len(resp['invoices']) == NUM_INVOICES + + # Tests for websocket are written separately to avoid flake8 # to complain with the errors F811 like this "F811 redefinition of # unused 'message'".