mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-02-22 14:42:40 +01:00
pytest: test fetchinvoice reply path which is not a direct peer.
Our fetchinvoice always creates a reply path which terminates at their peer, so we need a dev overrride for that. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
8714289c8c
commit
9aed594177
2 changed files with 60 additions and 5 deletions
|
@ -42,6 +42,9 @@ struct sent {
|
|||
/* When creating blinded return path, use scid not pubkey for intro node. */
|
||||
struct short_channel_id_dir *dev_path_use_scidd;
|
||||
|
||||
/* Force reply path, for testing. */
|
||||
struct pubkey *dev_reply_path;
|
||||
|
||||
/* The invreq we sent, OR the invoice we sent */
|
||||
struct tlv_invoice_request *invreq;
|
||||
|
||||
|
@ -603,11 +606,15 @@ static struct command_result *make_reply_path(struct command *cmd,
|
|||
sending->sent->reply_secret = tal(sending->sent, struct secret);
|
||||
randombytes_buf(sending->sent->reply_secret, sizeof(struct secret));
|
||||
|
||||
/* FIXME: Could create an independent reply path, not just
|
||||
* reverse existing. */
|
||||
ids = tal_arr(tmpctx, struct pubkey, nhops - 1);
|
||||
for (int i = nhops - 2; i >= 0; i--)
|
||||
ids[nhops - 2 - i] = sending->sent->path[i];
|
||||
if (sending->sent->dev_reply_path) {
|
||||
ids = sending->sent->dev_reply_path;
|
||||
} else {
|
||||
/* FIXME: Could create an independent reply path, not just
|
||||
* reverse existing. */
|
||||
ids = tal_arr(tmpctx, struct pubkey, nhops - 1);
|
||||
for (int i = nhops - 2; i >= 0; i--)
|
||||
ids[nhops - 2 - i] = sending->sent->path[i];
|
||||
}
|
||||
|
||||
rpath = blinded_path(cmd, cmd, ids, sending->sent->dev_path_use_scidd,
|
||||
sending->sent->reply_secret);
|
||||
|
@ -802,6 +809,29 @@ static struct command_result *param_dev_scidd(struct command *cmd, const char *n
|
|||
"should be a short_channel_id of form NxNxN/dir");
|
||||
}
|
||||
|
||||
static struct command_result *param_dev_reply_path(struct command *cmd, const char *name,
|
||||
const char *buffer, const jsmntok_t *tok,
|
||||
struct pubkey **path)
|
||||
{
|
||||
size_t i;
|
||||
const jsmntok_t *t;
|
||||
|
||||
if (!plugin_developer_mode(cmd->plugin))
|
||||
return command_fail_badparam(cmd, name, buffer, tok,
|
||||
"not available outside --developer mode");
|
||||
|
||||
if (tok->type != JSMN_ARRAY)
|
||||
return command_fail_badparam(cmd, name, buffer, tok, "Must be array");
|
||||
|
||||
*path = tal_arr(cmd, struct pubkey, tok->size);
|
||||
|
||||
json_for_each_arr(i, t, tok) {
|
||||
if (!json_to_pubkey(buffer, t, &(*path)[i]))
|
||||
return command_fail_badparam(cmd, name, buffer, t, "invalid pubkey");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Fetches an invoice for this offer, and makes sure it corresponds. */
|
||||
static struct command_result *json_fetchinvoice(struct command *cmd,
|
||||
const char *buffer,
|
||||
|
@ -826,6 +856,7 @@ static struct command_result *json_fetchinvoice(struct command *cmd,
|
|||
p_opt_def("timeout", param_number, &timeout, 60),
|
||||
p_opt("payer_note", param_string, &payer_note),
|
||||
p_opt("dev_path_use_scidd", param_dev_scidd, &sent->dev_path_use_scidd),
|
||||
p_opt("dev_reply_path", param_dev_reply_path, &sent->dev_reply_path),
|
||||
NULL))
|
||||
return command_param_failed();
|
||||
|
||||
|
@ -1274,6 +1305,7 @@ static struct command_result *json_sendinvoice(struct command *cmd,
|
|||
return command_param_failed();
|
||||
|
||||
sent->dev_path_use_scidd = NULL;
|
||||
sent->dev_reply_path = NULL;
|
||||
|
||||
/* BOLT-offers #12:
|
||||
* - if the invoice is in response to an `invoice_request`:
|
||||
|
@ -1392,6 +1424,7 @@ static struct command_result *json_dev_rawrequest(struct command *cmd,
|
|||
sent->cmd = cmd;
|
||||
sent->offer = NULL;
|
||||
sent->dev_path_use_scidd = NULL;
|
||||
sent->dev_reply_path = NULL;
|
||||
|
||||
return establish_onion_path(cmd, get_gossmap(cmd->plugin), &local_id,
|
||||
node_id,
|
||||
|
|
|
@ -4731,6 +4731,28 @@ def test_fetchinvoice_autoconnect(node_factory, bitcoind):
|
|||
assert l3.rpc.listpeers(l2.info['id'])['peers'] != []
|
||||
|
||||
|
||||
def test_fetchinvoice_disconnected_reply(node_factory, bitcoind):
|
||||
"""We ask for invoice, but reply path doesn't lead directly from recipient"""
|
||||
l1, l2, l3 = node_factory.get_nodes(3,
|
||||
opts={'experimental-offers': None,
|
||||
'may_reconnect': True,
|
||||
'dev-no-reconnect': None,
|
||||
'dev-allow-localhost': None})
|
||||
l3.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
||||
|
||||
# Make l1, l2 public (so l3 can auto connect).
|
||||
node_factory.join_nodes([l1, l2], wait_for_announce=True)
|
||||
wait_for(lambda: l3.rpc.listnodes(l1.info['id'])['nodes'] != [])
|
||||
|
||||
offer = l3.rpc.offer(amount='5msat', description='test_fetchinvoice_disconnected_reply')
|
||||
|
||||
# l2 sets reply_path to be l1->l2, l3 will connect to l1 to send reply.
|
||||
# FIXME: if code were smarter, it would simply send via l2, and this test
|
||||
# would have to get more sophisticated!
|
||||
l2.rpc.fetchinvoice(offer=offer['bolt12'], dev_reply_path=[l1.info['id'], l2.info['id']])
|
||||
assert only_one(l1.rpc.listpeers(l3.info['id'])['peers'])
|
||||
|
||||
|
||||
def test_pay_blockheight_mismatch(node_factory, bitcoind):
|
||||
"""Test that we can send a payment even if not caught up with the chain.
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue