Skip to content

Commit

Permalink
plugins/libplugin-pay: hack in blinded path support.
Browse files Browse the repository at this point in the history
We simply take the first one, and route to the start of that.  Then we
append the blinded path to the onion construction.

Signed-off-by: Rusty Russell <[email protected]>
  • Loading branch information
rustyrussell authored and cdecker committed Nov 9, 2022
1 parent 8720bbe commit 01a4772
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 15 deletions.
4 changes: 2 additions & 2 deletions plugins/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ ALL_PROGRAMS += $(C_PLUGINS)
# Make all plugins depend on all plugin headers, for simplicity.
$(PLUGIN_ALL_OBJS): $(PLUGIN_ALL_HEADER)

plugins/pay: $(PLUGIN_PAY_OBJS) $(PLUGIN_LIB_OBJS) $(PLUGIN_PAY_LIB_OBJS) $(PLUGIN_COMMON_OBJS) $(JSMN_OBJS) common/gossmap.o common/fp16.o common/route.o common/dijkstra.o common/bolt12.o common/bolt12_merkle.o wire/bolt12$(EXP)_wiregen.o bitcoin/block.o
plugins/pay: $(PLUGIN_PAY_OBJS) $(PLUGIN_LIB_OBJS) $(PLUGIN_PAY_LIB_OBJS) $(PLUGIN_COMMON_OBJS) $(JSMN_OBJS) common/gossmap.o common/fp16.o common/route.o common/dijkstra.o common/bolt12.o common/bolt12_merkle.o wire/bolt12$(EXP)_wiregen.o bitcoin/block.o common/blindedpay.o common/blindedpath.o common/hmac.o common/blinding.o common/onion_encode.o

plugins/autoclean: $(PLUGIN_AUTOCLEAN_OBJS) $(PLUGIN_LIB_OBJS) $(PLUGIN_COMMON_OBJS) $(JSMN_OBJS)

Expand All @@ -188,7 +188,7 @@ plugins/txprepare: $(PLUGIN_TXPREPARE_OBJS) $(PLUGIN_LIB_OBJS) $(PLUGIN_COMMON_O

plugins/bcli: $(PLUGIN_BCLI_OBJS) $(PLUGIN_LIB_OBJS) $(PLUGIN_COMMON_OBJS) $(JSMN_OBJS)

plugins/keysend: wire/tlvstream.o wire/onion$(EXP)_wiregen.o $(PLUGIN_KEYSEND_OBJS) $(PLUGIN_LIB_OBJS) $(PLUGIN_PAY_LIB_OBJS) $(PLUGIN_COMMON_OBJS) $(JSMN_OBJS) common/gossmap.o common/fp16.o common/route.o common/dijkstra.o
plugins/keysend: wire/tlvstream.o wire/onion$(EXP)_wiregen.o $(PLUGIN_KEYSEND_OBJS) $(PLUGIN_LIB_OBJS) $(PLUGIN_PAY_LIB_OBJS) $(PLUGIN_COMMON_OBJS) $(JSMN_OBJS) common/gossmap.o common/fp16.o common/route.o common/dijkstra.o common/blindedpay.o common/blindedpath.o common/hmac.o common/blinding.o common/onion_encode.o
$(PLUGIN_KEYSEND_OBJS): $(PLUGIN_PAY_LIB_HEADER)

plugins/spenderp: bitcoin/block.o bitcoin/preimage.o bitcoin/psbt.o common/psbt_open.o wire/peer${EXP}_wiregen.o $(PLUGIN_SPENDER_OBJS) $(PLUGIN_LIB_OBJS) $(PLUGIN_COMMON_OBJS) $(JSMN_OBJS)
Expand Down
2 changes: 2 additions & 0 deletions plugins/keysend.c
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,8 @@ static struct command_result *json_keysend(struct command *cmd, const char *buf,
p->destination = tal_steal(p, destination);
p->payment_secret = NULL;
p->payment_metadata = NULL;
p->blindedpath = NULL;
p->blindedpay = NULL;
p->amount = *msat;
p->routes = tal_steal(p, hints);
// 22 is the Rust-Lightning default and the highest minimum we know of.
Expand Down
61 changes: 52 additions & 9 deletions plugins/libplugin-pay.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "config.h"
#include <ccan/array_size/array_size.h>
#include <ccan/tal/str/str.h>
#include <common/blindedpay.h>
#include <common/dijkstra.h>
#include <common/gossmap.h>
#include <common/json_stream.h>
Expand Down Expand Up @@ -1662,6 +1663,33 @@ static void payment_add_hop_onion_payload(struct payment *p,
}
}

static void payment_add_blindedpath(const tal_t *ctx,
struct createonion_hop *hops,
const struct blinded_path *bpath,
struct amount_msat final_amt,
u32 final_cltv)
{
/* It's a bit of a weird API for us, so we convert it back to
* the struct tlv_tlv_payload */
u8 **tlvs = blinded_onion_hops(tmpctx, final_amt, final_cltv, bpath);

for (size_t i = 0; i < tal_count(tlvs); i++) {
const u8 *cursor = tlvs[i];
size_t max = tal_bytelen(tlvs[i]);
/* First one has to use real node_id */
if (i == 0)
node_id_from_pubkey(&hops[i].pubkey,
&bpath->first_node_id);
else
node_id_from_pubkey(&hops[i].pubkey,
&bpath->path[i]->blinded_node_id);

/* Length is prepended, discard that first! */
fromwire_bigsize(&cursor, &max);
hops[i].tlv_payload = fromwire_tlv_tlv_payload(ctx, &cursor, &max);
}
}

static void payment_compute_onion_payloads(struct payment *p)
{
struct createonion_request *cr;
Expand Down Expand Up @@ -1690,7 +1718,9 @@ static void payment_compute_onion_payloads(struct payment *p)
cr->assocdata = tal_arr(cr, u8, 0);
towire_sha256(&cr->assocdata, p->payment_hash);
cr->session_key = NULL;
cr->hops = tal_arr(cr, struct createonion_hop, tal_count(p->route));
cr->hops = tal_arr(cr, struct createonion_hop,
tal_count(p->route)
+ (root->blindedpath ? tal_count(root->blindedpath->path) - 1: 0));

/* Non-final hops */
for (size_t i = 0; i < hopcount - 1; i++) {
Expand All @@ -1704,14 +1734,27 @@ static void payment_compute_onion_payloads(struct payment *p)
&p->route[i].scid));
}

/* Final hop */
payment_add_hop_onion_payload(
p, &cr->hops[hopcount - 1], &p->route[hopcount - 1],
&p->route[hopcount - 1], true,
root->payment_secret, root->payment_metadata);
tal_append_fmt(&routetxt, "%s",
type_to_string(tmpctx, struct short_channel_id,
&p->route[hopcount - 1].scid));
/* If we're headed to a blinded path, connect that now. */
if (root->blindedpath) {
payment_add_blindedpath(cr->hops, cr->hops + hopcount - 1,
root->blindedpath,
root->blindedfinalamount,
root->blindedfinalcltv);
tal_append_fmt(&routetxt, "%s -> blinded path (%zu hops)",
type_to_string(tmpctx, struct short_channel_id,
&p->route[hopcount-1].scid),
tal_count(root->blindedpath->path));
} else {
/* Final hop */
payment_add_hop_onion_payload(
p, &cr->hops[hopcount - 1], &p->route[hopcount - 1],
&p->route[hopcount - 1], true,
root->payment_secret,
root->payment_metadata);
tal_append_fmt(&routetxt, "%s",
type_to_string(tmpctx, struct short_channel_id,
&p->route[hopcount - 1].scid));
}

paymod_log(p, LOG_DBG,
"Created outgoing onion for route: %s", routetxt);
Expand Down
6 changes: 6 additions & 0 deletions plugins/libplugin-pay.h
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,12 @@ struct payment {
/* Payment metadata, from the invoice if any. */
u8 *payment_metadata;

/* Blinded path (for bolt12) */
struct blinded_path *blindedpath;
struct blinded_payinfo *blindedpay;
struct amount_msat blindedfinalamount;
u32 blindedfinalcltv;

u64 groupid;
u32 partid;
u32 next_partid;
Expand Down
50 changes: 46 additions & 4 deletions plugins/pay.c
Original file line number Diff line number Diff line change
Expand Up @@ -1024,6 +1024,9 @@ static struct command_result *json_pay(struct command *cmd,
p = payment_new(cmd, cmd, NULL /* No parent */, paymod_mods);
p->invstring = tal_steal(p, b11str);
p->description = tal_steal(p, description);
/* Overridded by bolt12 if present */
p->blindedpath = NULL;
p->blindedpay = NULL;

if (!bolt12_has_prefix(b11str)) {
b11 =
Expand Down Expand Up @@ -1085,7 +1088,9 @@ static struct command_result *json_pay(struct command *cmd,
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"experimental-offers disabled");

p->features = tal_steal(p, b12->features);
/* FIXME: We disable MPP for now */
/* p->features = tal_steal(p, b12->features); */
p->features = NULL;

if (!b12->node_id)
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
Expand All @@ -1109,8 +1114,33 @@ static struct command_result *json_pay(struct command *cmd,
return command_fail(
cmd, JSONRPC2_INVALID_PARAMS,
"recurring invoice requires a label");
/* FIXME payment_secret should be signature! */
{

/* BOLT-offers #12:
* - MUST reject the invoice if `blindedpay` is not present.
*/
/* FIXME: We allow this for now. */

if (tal_count(b12->paths) != 0) {
/* BOLT-offers #12: - MUST reject the invoice if
* `blindedpay` does not contain exactly one
* `blinded_payinfo` per `blinded_path`.
*/
if (tal_count(b12->paths) != tal_count(b12->blindedpay)) {
return command_fail(
cmd, JSONRPC2_INVALID_PARAMS,
"Wrong blinding info: %zu paths, %zu payinfo",
tal_count(b12->paths),
tal_count(b12->blindedpay));
}

/* FIXME: do MPP across these! We choose first one. */
p->blindedpath = tal_steal(p, b12->paths[0]);
p->blindedpay = tal_steal(p, b12->blindedpay[0]);

/* Set destination to introduction point */
node_id_from_pubkey(p->destination, &p->blindedpath->first_node_id);
} else {
/* FIXME payment_secret should be signature! */
struct sha256 merkle;

p->payment_secret = tal(p, struct secret);
Expand All @@ -1121,7 +1151,6 @@ static struct command_result *json_pay(struct command *cmd,
}
p->payment_metadata = NULL;
p->routes = NULL;
/* FIXME: paths! */
if (b12->cltv)
p->min_final_cltv_expiry = *b12->cltv;
else
Expand Down Expand Up @@ -1161,6 +1190,19 @@ static struct command_result *json_pay(struct command *cmd,
p->amount = *msat;
}

/* We replace real final values if we're using a blinded path */
if (p->blindedpath) {
p->blindedfinalcltv = p->min_final_cltv_expiry;
p->blindedfinalamount = p->amount;

p->min_final_cltv_expiry += p->blindedpay->cltv_expiry_delta;
if (!amount_msat_add_fee(&p->amount,
p->blindedpay->fee_base_msat,
p->blindedpay->fee_proportional_millionths))
return command_fail(cmd, PAY_ROUTE_TOO_EXPENSIVE,
"This payment blinded path fee overflows!");
}

if (node_id_eq(&my_id, p->destination))
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"This payment is destined for ourselves. "
Expand Down
6 changes: 6 additions & 0 deletions plugins/test/run-route-overlong.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@
#include <unistd.h>

/* AUTOGENERATED MOCKS START */
/* Generated stub for blinded_onion_hops */
u8 **blinded_onion_hops(const tal_t *ctx UNNEEDED,
struct amount_msat final_amount UNNEEDED,
u32 final_cltv UNNEEDED,
const struct blinded_path *path UNNEEDED)
{ fprintf(stderr, "blinded_onion_hops called!\n"); abort(); }
/* Generated stub for command_finished */
struct command_result *command_finished(struct command *cmd UNNEEDED, struct json_stream *response UNNEEDED)
{ fprintf(stderr, "command_finished called!\n"); abort(); }
Expand Down

0 comments on commit 01a4772

Please sign in to comment.