Skip to content

Commit

Permalink
fetchinvoice: add developer option to send raw invoice_request.
Browse files Browse the repository at this point in the history
This will be used for bootstrap.bolt12.org to provide a raw request API.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
  • Loading branch information
rustyrussell committed Aug 20, 2021
1 parent 12fbb23 commit f1e0fe5
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 0 deletions.
77 changes: 77 additions & 0 deletions plugins/fetchinvoice.c
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,16 @@ static struct command_result *handle_invreq_response(struct command *cmd,
goto badinv;
}

#if DEVELOPER
/* Raw send? Just fwd reply. */
if (!sent->offer) {
out = jsonrpc_stream_success(sent->cmd);
json_add_string(out, "invoice", invoice_encode(tmpctx, inv));
discard_result(command_finished(sent->cmd, out));
return command_hook_success(cmd);
}
#endif /* DEVELOPER */

/* BOLT-offers #12:
* - MUST reject the invoice unless `node_id` is equal to the offer.
*/
Expand Down Expand Up @@ -1490,6 +1500,64 @@ static struct command_result *json_sendinvoice(struct command *cmd,
return sign_invoice(cmd, sent);
}

#if DEVELOPER
static struct command_result *param_invreq(struct command *cmd,
const char *name,
const char *buffer,
const jsmntok_t *tok,
struct tlv_invoice_request **invreq)
{
char *fail;

*invreq = invrequest_decode(cmd, buffer + tok->start, tok->end - tok->start,
plugin_feature_set(cmd->plugin), chainparams,
&fail);
if (!*invreq)
return command_fail_badparam(cmd, name, buffer, tok,
tal_fmt(cmd,
"Unparsable invreq: %s",
fail));
return NULL;
}

static struct command_result *json_rawrequest(struct command *cmd,
const char *buffer,
const jsmntok_t *params)
{
struct sent *sent = tal(cmd, struct sent);
u32 *timeout;
struct node_id *node_id;
struct pubkey32 node_id32;
bool try_connect;

if (!param(cmd, buffer, params,
p_req("invreq", param_invreq, &sent->invreq),
p_req("nodeid", param_node_id, &node_id),
p_opt_def("timeout", param_number, &timeout, 60),
NULL))
return command_param_failed();

/* Skip over 02/03 in node_id */
if (!secp256k1_xonly_pubkey_parse(secp256k1_ctx,
&node_id32.pubkey,
node_id->k + 1))
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"Invalid nodeid");
/* This is how long we'll wait for a reply for. */
sent->wait_timeout = *timeout;
sent->cmd = cmd;
sent->offer = NULL;

sent->path = path_to_node(sent, get_gossmap(cmd->plugin),
&node_id32, &try_connect);
if (try_connect)
return connect_direct(cmd, node_id,
sendinvreq_after_connect, sent);

return sendinvreq_after_connect(cmd, NULL, NULL, sent);
}
#endif /* DEVELOPER */

static const struct plugin_command commands[] = {
{
"fetchinvoice",
Expand All @@ -1505,6 +1573,15 @@ static const struct plugin_command commands[] = {
NULL,
json_sendinvoice,
},
#if DEVELOPER
{
"dev-rawrequest",
"util",
"Send {invreq} to {nodeid}, wait {timeout} (60 seconds by default)",
NULL,
json_rawrequest,
},
#endif /* DEVELOPER */
};

static const char *init(struct plugin *p, const char *buf UNUSED,
Expand Down
17 changes: 17 additions & 0 deletions tests/test_pay.py
Original file line number Diff line number Diff line change
Expand Up @@ -4403,6 +4403,23 @@ def test_pay_waitblockheight_timeout(node_factory, bitcoind):
assert len(status['pay'][0]['attempts']) == 1


@pytest.mark.developer("dev-rawrequest is DEVELOPER-only")
def test_dev_rawrequest(node_factory):
l1, l2 = node_factory.line_graph(2, fundchannel=False,
opts={'experimental-offers': None})

offer = l2.rpc.call('offer', {'amount': '2msat',
'description': 'simple test'})
# Get fetchinvoice to make us an invoice_request
l1.rpc.call('fetchinvoice', {'offer': offer['bolt12']})

m = re.search(r'invoice_request: \\"([a-z0-9]*)\\"', l1.daemon.is_in_log('invoice_request:'))
ret = l1.rpc.call('dev-rawrequest', {'invreq': m.group(1),
'nodeid': l2.info['id'],
'timeout': 10})
assert 'invoice' in ret


def test_sendinvoice(node_factory, bitcoind):
l1, l2 = node_factory.line_graph(2, wait_for_announce=True,
opts={'experimental-offers': None})
Expand Down

0 comments on commit f1e0fe5

Please sign in to comment.