diff --git a/contrib/pyln-client/pyln/client/lightning.py b/contrib/pyln-client/pyln/client/lightning.py index f80006e91..9d37fb86e 100644 --- a/contrib/pyln-client/pyln/client/lightning.py +++ b/contrib/pyln-client/pyln/client/lightning.py @@ -616,7 +616,7 @@ class LightningRpc(UnixDomainSocketRpc): def dev_pay(self, bolt11, msatoshi=None, label=None, riskfactor=None, maxfeepercent=None, retry_for=None, - maxdelay=None, exemptfee=None, use_shadow=True): + maxdelay=None, exemptfee=None, use_shadow=True, exclude=[]): """ A developer version of `pay`, with the possibility to deactivate shadow routing (used for testing). @@ -631,6 +631,7 @@ class LightningRpc(UnixDomainSocketRpc): "maxdelay": maxdelay, "exemptfee": exemptfee, "use_shadow": use_shadow, + "exclude": exclude, } return self.call("pay", payload) @@ -989,7 +990,7 @@ class LightningRpc(UnixDomainSocketRpc): def pay(self, bolt11, msatoshi=None, label=None, riskfactor=None, maxfeepercent=None, retry_for=None, - maxdelay=None, exemptfee=None): + maxdelay=None, exemptfee=None, exclude=[]): """ Send payment specified by {bolt11} with {msatoshi} (ignored if {bolt11} has an amount), optional {label} @@ -1004,6 +1005,7 @@ class LightningRpc(UnixDomainSocketRpc): "retry_for": retry_for, "maxdelay": maxdelay, "exemptfee": exemptfee, + "exclude": exclude, } return self.call("pay", payload) diff --git a/tests/test_pay.py b/tests/test_pay.py index 2213066b3..1232c3a44 100644 --- a/tests/test_pay.py +++ b/tests/test_pay.py @@ -5001,3 +5001,30 @@ def test_sendpay_grouping(node_factory, bitcoind): pays = l1.rpc.listpays()['pays'] assert(len(pays) == 3) assert([p['status'] for p in pays] == ['failed', 'failed', 'complete']) + + +def test_pay_manual_exclude(node_factory, bitcoind): + l1, l2, l3 = node_factory.line_graph(3, wait_for_announce=True) + l1_id = l1.rpc.getinfo()['id'] + l2_id = l2.rpc.getinfo()['id'] + l3_id = l3.rpc.getinfo()['id'] + chan12 = l1.rpc.listpeers(l2_id)['peers'][0]['channels'][0] + chan23 = l2.rpc.listpeers(l3_id)['peers'][0]['channels'][0] + scid12 = chan12['short_channel_id'] + '/' + str(chan12['direction']) + scid23 = chan23['short_channel_id'] + '/' + str(chan23['direction']) + inv = l3.rpc.invoice(msatoshi='123000', label='label1', description='desc')['bolt11'] + # Exclude the payer node id + with pytest.raises(RpcError, match=r'Payer is manually excluded'): + l1.rpc.pay(inv, exclude=[l1_id]) + # Exclude the direct payee node id + with pytest.raises(RpcError, match=r'Payee is manually excluded'): + l2.rpc.pay(inv, exclude=[l3_id]) + # Exclude intermediate node id + with pytest.raises(RpcError, match=r'is not reachable directly and all routehints were unusable.'): + l1.rpc.pay(inv, exclude=[l2_id]) + # Exclude intermediate channel id + with pytest.raises(RpcError, match=r'is not reachable directly and all routehints were unusable.'): + l1.rpc.pay(inv, exclude=[scid12]) + # Exclude direct channel id + with pytest.raises(RpcError, match=r'is not reachable directly and all routehints were unusable.'): + l2.rpc.pay(inv, exclude=[scid23]) diff --git a/tests/test_plugin.py b/tests/test_plugin.py index 3141aaa4d..777647d74 100644 --- a/tests/test_plugin.py +++ b/tests/test_plugin.py @@ -397,7 +397,7 @@ def test_pay_plugin(node_factory): # Make sure usage messages are present. msg = 'pay bolt11 [msatoshi] [label] [riskfactor] [maxfeepercent] '\ - '[retry_for] [maxdelay] [exemptfee] [localofferid]' + '[retry_for] [maxdelay] [exemptfee] [localofferid] [exclude]' if DEVELOPER: msg += ' [use_shadow]' assert only_one(l1.rpc.help('pay')['help'])['command'] == msg