Skip to content

Commit 5a87e88

Browse files
cdeckerrustyrussell
authored andcommitted
pytest: Add test for failcode conversion
We added a conversion of failcodes that do not have sufficient information in faac4b2. That means that a failcode that'd require additional information in order to be a correct error to return in an onion is mapped to a generic one since we can't backfill the information. This tests that the mapping is performed correctly and replicates the situation in #4070
1 parent 980a951 commit 5a87e88

File tree

2 files changed

+77
-0
lines changed

2 files changed

+77
-0
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#!/usr/bin/env python3
2+
"""A simply plugin that fails HTLCs with a configurable failcode.
3+
4+
"""
5+
from pyln.client import Plugin
6+
7+
8+
plugin = Plugin()
9+
10+
11+
@plugin.hook('htlc_accepted')
12+
def on_htlc_accepted(htlc, onion, plugin, **kwargs):
13+
res = {"result": "fail"}
14+
15+
if plugin.failmsg is not None:
16+
res['failure_message'] = plugin.failmsg
17+
18+
if plugin.failcode is not None:
19+
res['failure_code'] = plugin.failcode
20+
21+
return res
22+
23+
24+
@plugin.method('setfailcode')
25+
def setfailcode(plugin, code=None, msg=None):
26+
"""Sets the failcode to return when receiving an incoming HTLC.
27+
"""
28+
plugin.failcode = code
29+
plugin.failmsg = msg
30+
31+
32+
@plugin.init()
33+
def on_init(**kwargs):
34+
plugin.failcode = None
35+
plugin.failmsg = None
36+
37+
38+
plugin.run()

tests/test_plugin.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1889,3 +1889,42 @@ def test_htlc_accepted_hook_crash(node_factory, executor):
18891889

18901890
with pytest.raises(RpcError, match=r'failed: WIRE_TEMPORARY_NODE_FAILURE'):
18911891
f.result(10)
1892+
1893+
1894+
def test_htlc_accepted_hook_failcodes(node_factory):
1895+
plugin = os.path.join(os.path.dirname(__file__), 'plugins/htlc_accepted-failcode.py')
1896+
l1, l2 = node_factory.line_graph(2, opts=[{}, {'plugin': plugin}])
1897+
1898+
# First let's test the newer failure_message, which should get passed
1899+
# through without being mapped.
1900+
tests = {
1901+
'2002': 'WIRE_TEMPORARY_NODE_FAILURE',
1902+
'400F' + 12 * '00': 'WIRE_INCORRECT_OR_UNKNOWN_PAYMENT_DETAILS',
1903+
'4009': 'WIRE_REQUIRED_CHANNEL_FEATURE_MISSING',
1904+
'4016' + 3 * '00': 'WIRE_INVALID_ONION_PAYLOAD',
1905+
}
1906+
1907+
for failmsg, expected in tests.items():
1908+
l2.rpc.setfailcode(msg=failmsg)
1909+
inv = l2.rpc.invoice(42, 'failmsg{}'.format(failmsg), '')['bolt11']
1910+
with pytest.raises(RpcError, match=r'failcodename.: .{}.'.format(expected)):
1911+
l1.rpc.pay(inv)
1912+
1913+
# And now test the older failcode return value. This is deprecated and can
1914+
# be removed once we have removed the failcode correction code in
1915+
# peer_htlcs.c. The following ones get remapped
1916+
tests.update({
1917+
'400F': 'WIRE_TEMPORARY_NODE_FAILURE',
1918+
'4009': 'WIRE_TEMPORARY_NODE_FAILURE',
1919+
'4016': 'WIRE_TEMPORARY_NODE_FAILURE',
1920+
})
1921+
1922+
for failcode, expected in tests.items():
1923+
# Do not attempt with full messages
1924+
if len(failcode) > 4:
1925+
continue
1926+
1927+
l2.rpc.setfailcode(code=failcode)
1928+
inv = l2.rpc.invoice(42, 'failcode{}'.format(failcode), '')['bolt11']
1929+
with pytest.raises(RpcError, match=r'failcodename.: .{}.'.format(expected)):
1930+
l1.rpc.pay(inv)

0 commit comments

Comments
 (0)