Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Require modern onion #5058

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
357 changes: 131 additions & 226 deletions common/onion.c

Large diffs are not rendered by default.

13 changes: 1 addition & 12 deletions common/onion.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,7 @@

struct route_step;

enum onion_payload_type {
ONION_V0_PAYLOAD = 0,
ONION_TLV_PAYLOAD = 1,
};

struct onion_payload {
enum onion_payload_type type;

struct amount_msat amt_to_forward;
u32 outgoing_cltv;
struct amount_msat *total_msat;
Expand All @@ -29,7 +22,6 @@ struct onion_payload {
};

u8 *onion_nonfinal_hop(const tal_t *ctx,
bool use_tlv,
const struct short_channel_id *scid,
struct amount_msat forward,
u32 outgoing_cltv,
Expand All @@ -38,7 +30,6 @@ u8 *onion_nonfinal_hop(const tal_t *ctx,

/* Note that this can fail if we supply payment_secret and !use_tlv! */
u8 *onion_final_hop(const tal_t *ctx,
bool use_tlv,
struct amount_msat forward,
u32 outgoing_cltv,
struct amount_msat total_msat,
Expand All @@ -52,16 +43,14 @@ u8 *onion_final_hop(const tal_t *ctx,
* @len: length of @raw_payload in bytes.
* @has_realm: used for HTLCs, where first byte 0 is magical.
* @valid: set to true if it is valid, false otherwise.
* @type: if non-NULL, set to type of payload if *@valid is true.
*
* If @valid is set, there is room for the HMAC immediately following,
* as the return value is <= ROUTING_INFO_SIZE - HMAC_SIZE. Otherwise,
* the return value is @len (i.e. the entire payload).
*/
size_t onion_payload_length(const u8 *raw_payload, size_t len,
bool has_realm,
bool *valid,
enum onion_payload_type *type);
bool *valid);

/**
* onion_decode: decode payload from a decrypted onion.
Expand Down
6 changes: 0 additions & 6 deletions common/route.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,6 @@ static bool dijkstra_to_hops(struct route_hop **hops,
/* Find other end of channel. */
next = gossmap_nth_node(gossmap, c, !(*hops)[num_hops].direction);
gossmap_node_get_id(gossmap, next, &(*hops)[num_hops].node_id);
/* If we don't have a node_announcement, we *assume* modern */
if (next->nann_off == 0
|| gossmap_node_get_feature(gossmap, next, OPT_VAR_ONION) != -1)
(*hops)[num_hops].style = ROUTE_HOP_TLV;
else
(*hops)[num_hops].style = ROUTE_HOP_LEGACY;

/* These are (ab)used by others. */
(*hops)[num_hops].blinding = NULL;
Expand Down
7 changes: 0 additions & 7 deletions common/route.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,6 @@ struct gossmap;
struct gossmap_chan;
struct gossmap_node;

enum route_hop_style {
ROUTE_HOP_LEGACY = 1,
ROUTE_HOP_TLV = 2,
};

/**
* struct route_hop: a hop in a route.
*
Expand All @@ -26,7 +21,6 @@ enum route_hop_style {
* @delay: total cltv delay at this hop.
* @blinding: blinding key for this hop (if any)
* @enctlv: encrypted TLV for this hop (if any)
* @style: onion encoding style for this hop.
*/
struct route_hop {
struct short_channel_id scid;
Expand All @@ -36,7 +30,6 @@ struct route_hop {
u32 delay;
struct pubkey *blinding;
u8 *enctlv;
enum route_hop_style style;
};

/* Can c carry amount in dir? */
Expand Down
2 changes: 1 addition & 1 deletion common/sphinx.c
Original file line number Diff line number Diff line change
Expand Up @@ -627,7 +627,7 @@ struct route_step *process_onionpacket(
payload_size = onion_payload_length(paddedheader,
tal_bytelen(msg->routinginfo),
has_realm,
&valid, NULL);
&valid);

/* Can't decode? Treat it as terminal. */
if (!valid) {
Expand Down
3 changes: 1 addition & 2 deletions common/test/run-sphinx-xor_cipher_stream.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,7 @@ struct onionreply *new_onionreply(const tal_t *ctx UNNEEDED, const u8 *contents
/* Generated stub for onion_payload_length */
size_t onion_payload_length(const u8 *raw_payload UNNEEDED, size_t len UNNEEDED,
bool has_realm UNNEEDED,
bool *valid UNNEEDED,
enum onion_payload_type *type UNNEEDED)
bool *valid UNNEEDED)
{ fprintf(stderr, "onion_payload_length called!\n"); abort(); }
/* Generated stub for pubkey_from_node_id */
bool pubkey_from_node_id(struct pubkey *key UNNEEDED, const struct node_id *id UNNEEDED)
Expand Down
4 changes: 2 additions & 2 deletions contrib/pyln-proto/tests/test_onion.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ def test_tu_fields():


dirname = os.path.dirname(__file__)
vector_base = os.path.join(dirname, '..', '..', '..', 'tests', 'vectors')
vector_base = os.path.join(dirname, '..', 'vectors')
have_vectors = os.path.exists(os.path.join(vector_base, 'onion-test-v0.json'))


Expand Down Expand Up @@ -181,7 +181,7 @@ def sphinx_path_from_test_vector(filename: str) -> Tuple[onion.SphinxPath, dict]
"""Loads a sphinx test vector from the repo root.
"""
path = os.path.dirname(__file__)
root = os.path.join(path, '..', '..', '..')
root = os.path.join(path, '..')
filename = os.path.join(root, filename)
v = json.load(open(filename, 'r'))
session_key = onion.Secret(bytes.fromhex(v['generate']['session_key']))
Expand Down
7 changes: 1 addition & 6 deletions devtools/onion.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,22 +71,19 @@ static void do_generate(int argc, char **argv,
} else {
struct short_channel_id scid;
struct amount_msat amt;
bool use_tlv = streq(argv[1 + i] + klen, "/tlv");

/* FIXME: support secret and and total_msat */
memset(&scid, i, sizeof(scid));
amt = amount_msat(i);
if (i == num_hops - 1)
sphinx_add_hop(sp, &path[i],
take(onion_final_hop(NULL,
use_tlv,
amt, i, amt,
NULL, NULL,
NULL)));
else
sphinx_add_hop(sp, &path[i],
take(onion_nonfinal_hop(NULL,
use_tlv,
&scid,
amt, i,
NULL,
Expand Down Expand Up @@ -273,7 +270,6 @@ static void runtest(const char *filename)
decodetok = json_get_member(buffer, toks, "decode");

json_for_each_arr(i, hop, decodetok) {
enum onion_payload_type type;
bool valid;

hexprivkey = json_strdup(ctx, buffer, hop);
Expand All @@ -284,9 +280,8 @@ static void runtest(const char *filename)
errx(1, "Error serializing message.");
onion_payload_length(step->raw_payload,
tal_bytelen(step->raw_payload),
true, &valid, &type);
true, &valid);
assert(valid);
printf(" Type: %d\n", type);
printf(" Payload: %s\n", tal_hex(ctx, step->raw_payload));
printf(" Next onion: %s\n", tal_hex(ctx, serialized));
printf(" Next HMAC: %s\n",
Expand Down
4 changes: 1 addition & 3 deletions lightningd/invoice.c
Original file line number Diff line number Diff line change
Expand Up @@ -175,14 +175,12 @@ static void invoice_payment_add_tlvs(struct json_stream *stream,
struct htlc_set *hset)
{
struct htlc_in *hin;
struct tlv_tlv_payload *tlvs;
const struct tlv_tlv_payload *tlvs;
assert(tal_count(hset->htlcs) > 0);

/* Pick the first HTLC as representative for the entire set. */
hin = hset->htlcs[0];

if (hin->payload->type != ONION_TLV_PAYLOAD)
return;
tlvs = hin->payload->tlv;

json_array_start(stream, "extratlvs");
Expand Down
2 changes: 1 addition & 1 deletion lightningd/lightningd.c
Original file line number Diff line number Diff line change
Expand Up @@ -812,7 +812,7 @@ static struct feature_set *default_features(const tal_t *ctx)
OPTIONAL_FEATURE(OPT_DATA_LOSS_PROTECT),
OPTIONAL_FEATURE(OPT_UPFRONT_SHUTDOWN_SCRIPT),
OPTIONAL_FEATURE(OPT_GOSSIP_QUERIES),
OPTIONAL_FEATURE(OPT_VAR_ONION),
COMPULSORY_FEATURE(OPT_VAR_ONION),
COMPULSORY_FEATURE(OPT_PAYMENT_SECRET),
OPTIONAL_FEATURE(OPT_BASIC_MPP),
OPTIONAL_FEATURE(OPT_GOSSIP_QUERIES_EX),
Expand Down
52 changes: 8 additions & 44 deletions lightningd/pay.c
Original file line number Diff line number Diff line change
Expand Up @@ -751,18 +751,6 @@ static struct command_result *wait_payment(struct lightningd *ld,
abort();
}

static bool should_use_tlv(enum route_hop_style style)
{
switch (style) {
case ROUTE_HOP_TLV:
return true;
/* Otherwise fall thru */
case ROUTE_HOP_LEGACY:
return false;
}
abort();
}

/* Returns failmsg on failure, tallocated off ctx */
static const u8 *send_onion(const tal_t *ctx, struct lightningd *ld,
const struct onionpacket *packet,
Expand Down Expand Up @@ -1126,7 +1114,7 @@ send_payment(struct lightningd *ld,
struct short_channel_id *channels;
struct sphinx_path *path;
struct pubkey pubkey;
bool final_tlv, ret;
bool ret;
u8 *onion;

/* Expiry for HTLCs is absolute. And add one to give some margin. */
Expand All @@ -1144,7 +1132,6 @@ send_payment(struct lightningd *ld,

sphinx_add_hop(path, &pubkey,
take(onion_nonfinal_hop(NULL,
should_use_tlv(route[i].style),
&route[i + 1].scid,
route[i + 1].amount,
base_expiry + route[i + 1].delay,
Expand All @@ -1157,25 +1144,15 @@ send_payment(struct lightningd *ld,
ret = pubkey_from_node_id(&pubkey, &ids[i]);
assert(ret);

final_tlv = should_use_tlv(route[i].style);
/* BOLT #4:
* - Unless `node_announcement`, `init` message or the
* [BOLT #11](11-payment-encoding.md#tagged-fields) offers feature
* `var_onion_optin`:
* - MUST use the legacy payload format instead.
*/
/* In our case, we don't use it unless we also have a payment_secret;
* everyone should support this eventually */
if (!final_tlv && payment_secret)
final_tlv = true;

/* Parallel payments are invalid for legacy. */
if (partid && !final_tlv)
return command_fail(cmd, PAY_DESTINATION_PERM_FAIL,
"Cannot do parallel payments to legacy node");
/* FIXME: This requirement is now obsolete, and we should remove it! */

onion = onion_final_hop(cmd,
final_tlv,
route[i].amount,
base_expiry + route[i].delay,
total_msat, route[i].blinding, route[i].enctlv,
Expand Down Expand Up @@ -1326,23 +1303,19 @@ AUTODATA(json_command, &sendonion_command);
JSON-RPC sendpay interface
-----------------------------------------------------------------------------*/

/* FIXME: We accept his parameter for now, will deprecate eventually */
static struct command_result *param_route_hop_style(struct command *cmd,
const char *name,
const char *buffer,
const jsmntok_t *tok,
enum route_hop_style **style)
int **unused)
{
*style = tal(cmd, enum route_hop_style);
if (json_tok_streq(buffer, tok, "legacy")) {
**style = ROUTE_HOP_LEGACY;
return NULL;
} else if (json_tok_streq(buffer, tok, "tlv")) {
**style = ROUTE_HOP_TLV;
if (json_tok_streq(buffer, tok, "tlv")) {
return NULL;
}

return command_fail_badparam(cmd, name, buffer, tok,
"should be 'legacy' or 'tlv'");
"should be 'tlv' ('legacy' not supported)");
}

static struct command_result *param_route_hops(struct command *cmd,
Expand All @@ -1366,7 +1339,7 @@ static struct command_result *param_route_hops(struct command *cmd,
unsigned *delay, *direction;
struct pubkey *blinding;
u8 *enctlv;
enum route_hop_style *style, default_style;
int *ignored;

if (!param(cmd, buffer, t,
/* Only *one* of these is required */
Expand All @@ -1378,7 +1351,7 @@ static struct command_result *param_route_hops(struct command *cmd,
p_opt("channel", param_short_channel_id, &channel),
/* Allowed (getroute supplies it) but ignored */
p_opt("direction", param_number, &direction),
p_opt("style", param_route_hop_style, &style),
p_opt("style", param_route_hop_style, &ignored),
p_opt("blinding", param_pubkey, &blinding),
p_opt("encrypted_recipient_data", param_bin_from_hex, &enctlv),
NULL))
Expand All @@ -1405,21 +1378,12 @@ static struct command_result *param_route_hops(struct command *cmd,
if (!msat)
msat = amount_msat;

if (blinding || enctlv) {
if (style && *style == ROUTE_HOP_LEGACY)
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"%s[%zi]: Can't have blinding or enctlv with legacy", name, i);
default_style = ROUTE_HOP_TLV;
} else
default_style = ROUTE_HOP_LEGACY;

(*hops)[i].amount = *msat;
(*hops)[i].node_id = *id;
(*hops)[i].delay = *delay;
(*hops)[i].scid = *channel;
(*hops)[i].blinding = blinding;
(*hops)[i].enctlv = enctlv;
(*hops)[i].style = style ? *style : default_style;
}

return NULL;
Expand Down
10 changes: 1 addition & 9 deletions lightningd/peer_htlcs.c
Original file line number Diff line number Diff line change
Expand Up @@ -945,15 +945,7 @@ static void htlc_accepted_hook_serialize(struct htlc_accepted_hook_payload *p,

json_add_hex_talarr(s, "payload", rs->raw_payload);
if (p->payload) {
switch (p->payload->type) {
case ONION_V0_PAYLOAD:
json_add_string(s, "type", "legacy");
break;

case ONION_TLV_PAYLOAD:
json_add_string(s, "type", "tlv");
break;
}
json_add_string(s, "type", "tlv");

if (p->payload->forward_channel)
json_add_short_channel_id(s, "short_channel_id",
Expand Down
10 changes: 1 addition & 9 deletions plugins/keysend.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,7 @@ static void keysend_cb(struct keysend_data *d, struct payment *p) {
size_t hopcount;

/* On the root payment we perform the featurebit check. */
if (p->parent == NULL && p->step == PAYMENT_STEP_INITIALIZED) {
if (!payment_root(p)->destination_has_tlv)
return payment_fail(
p,
"Recipient %s does not support keysend payments "
"(no TLV support)",
node_id_to_hexstr(tmpctx, p->destination));
} else if (p->step == PAYMENT_STEP_FAILED) {
if (p->step == PAYMENT_STEP_FAILED) {
/* Now we can look at the error, and the failing node,
and determine whether they didn't like our
attempt. This is required since most nodes don't
Expand Down Expand Up @@ -184,7 +177,6 @@ static struct command_result *json_keysend(struct command *cmd, const char *buf,
p->json_buffer = tal_dup_talarr(p, const char, buf);
p->json_toks = params;
p->destination = tal_steal(p, destination);
p->destination_has_tlv = true;
p->payment_secret = NULL;
p->amount = *msat;
p->routes = tal_steal(p, hints);
Expand Down
Loading