mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-19 07:04:22 +01:00
lightningd: Restore forwarding of legacy onions.
Partial revert of 43a833e405
"lightningd: remove support for legacy onion format."; we restore the
ability to decode legacy onions for forwarding, but not to generate them.
(We don't accept them properly since making payment_secret compulsory
anyway, so no real change there!)
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Removed: Protocol: ... but we still forward legacy HTLC onions for now.
This commit is contained in:
@@ -109,10 +109,11 @@ u8 *onion_final_hop(const tal_t *ctx,
|
|||||||
return make_tlv_hop(ctx, tlv);
|
return make_tlv_hop(ctx, tlv);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns true if valid, and fills in len. */
|
/* Returns true if valid, and fills in type. */
|
||||||
static bool pull_payload_length(const u8 **cursor,
|
static bool pull_payload_length(const u8 **cursor,
|
||||||
size_t *max,
|
size_t *max,
|
||||||
bool has_realm,
|
bool has_realm,
|
||||||
|
enum onion_payload_type *type,
|
||||||
size_t *len)
|
size_t *len)
|
||||||
{
|
{
|
||||||
/* *len will incorporate bytes we read from cursor */
|
/* *len will incorporate bytes we read from cursor */
|
||||||
@@ -127,6 +128,19 @@ static bool pull_payload_length(const u8 **cursor,
|
|||||||
if (!cursor)
|
if (!cursor)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
/* BOLT #4:
|
||||||
|
* - Legacy `hop_data` format, identified by a single `0x00` byte for
|
||||||
|
* length. In this case the `hop_payload_length` is defined to be 32
|
||||||
|
* bytes.
|
||||||
|
*/
|
||||||
|
if (has_realm && *len == 0) {
|
||||||
|
if (type)
|
||||||
|
*type = ONION_V0_PAYLOAD;
|
||||||
|
assert(*cursor - start == 1);
|
||||||
|
*len = 1 + 32;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/* BOLT #4:
|
/* BOLT #4:
|
||||||
* - `tlv_payload` format, identified by any length over `1`. In this
|
* - `tlv_payload` format, identified by any length over `1`. In this
|
||||||
* case the `hop_payload_length` is equal to the numeric value of
|
* case the `hop_payload_length` is equal to the numeric value of
|
||||||
@@ -142,6 +156,8 @@ static bool pull_payload_length(const u8 **cursor,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type)
|
||||||
|
*type = ONION_TLV_PAYLOAD;
|
||||||
*len += (*cursor - start);
|
*len += (*cursor - start);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -150,10 +166,11 @@ static bool pull_payload_length(const u8 **cursor,
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t onion_payload_length(const u8 *raw_payload, size_t len, bool has_realm,
|
size_t onion_payload_length(const u8 *raw_payload, size_t len, bool has_realm,
|
||||||
bool *valid)
|
bool *valid,
|
||||||
|
enum onion_payload_type *type)
|
||||||
{
|
{
|
||||||
size_t max = len, payload_len;
|
size_t max = len, payload_len;
|
||||||
*valid = pull_payload_length(&raw_payload, &max, has_realm, &payload_len);
|
*valid = pull_payload_length(&raw_payload, &max, has_realm, type, &payload_len);
|
||||||
|
|
||||||
/* If it's not valid, copy the entire thing. */
|
/* If it's not valid, copy the entire thing. */
|
||||||
if (!*valid)
|
if (!*valid)
|
||||||
@@ -210,12 +227,31 @@ struct onion_payload *onion_decode(const tal_t *ctx,
|
|||||||
size_t max = tal_bytelen(cursor), len;
|
size_t max = tal_bytelen(cursor), len;
|
||||||
struct tlv_tlv_payload *tlv;
|
struct tlv_tlv_payload *tlv;
|
||||||
|
|
||||||
if (!pull_payload_length(&cursor, &max, true, &len)) {
|
if (!pull_payload_length(&cursor, &max, true, &p->type, &len)) {
|
||||||
*failtlvtype = 0;
|
*failtlvtype = 0;
|
||||||
*failtlvpos = tal_bytelen(rs->raw_payload);
|
*failtlvpos = tal_bytelen(rs->raw_payload);
|
||||||
goto fail_no_tlv;
|
goto fail_no_tlv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Very limited legacy handling: forward only. */
|
||||||
|
if (p->type == ONION_V0_PAYLOAD && rs->nextcase == ONION_FORWARD) {
|
||||||
|
p->forward_channel = tal(p, struct short_channel_id);
|
||||||
|
fromwire_short_channel_id(&cursor, &max, p->forward_channel);
|
||||||
|
p->total_msat = NULL;
|
||||||
|
p->amt_to_forward = fromwire_amount_msat(&cursor, &max);
|
||||||
|
p->outgoing_cltv = fromwire_u32(&cursor, &max);
|
||||||
|
p->payment_secret = NULL;
|
||||||
|
p->blinding = NULL;
|
||||||
|
/* We can't handle blinding with a legacy payload */
|
||||||
|
if (blinding)
|
||||||
|
return tal_free(p);
|
||||||
|
/* If they somehow got an invalid onion this far, fail. */
|
||||||
|
if (!cursor)
|
||||||
|
return tal_free(p);
|
||||||
|
p->tlv = NULL;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
/* We do this manually so we can accept extra types, and get
|
/* We do this manually so we can accept extra types, and get
|
||||||
* error off and type. */
|
* error off and type. */
|
||||||
tlv = tlv_tlv_payload_new(p);
|
tlv = tlv_tlv_payload_new(p);
|
||||||
|
|||||||
@@ -6,7 +6,14 @@
|
|||||||
|
|
||||||
struct route_step;
|
struct route_step;
|
||||||
|
|
||||||
|
enum onion_payload_type {
|
||||||
|
ONION_V0_PAYLOAD = 0,
|
||||||
|
ONION_TLV_PAYLOAD = 1,
|
||||||
|
};
|
||||||
|
|
||||||
struct onion_payload {
|
struct onion_payload {
|
||||||
|
enum onion_payload_type type;
|
||||||
|
|
||||||
struct amount_msat amt_to_forward;
|
struct amount_msat amt_to_forward;
|
||||||
u32 outgoing_cltv;
|
u32 outgoing_cltv;
|
||||||
struct amount_msat *total_msat;
|
struct amount_msat *total_msat;
|
||||||
@@ -43,6 +50,7 @@ u8 *onion_final_hop(const tal_t *ctx,
|
|||||||
* @len: length of @raw_payload in bytes.
|
* @len: length of @raw_payload in bytes.
|
||||||
* @has_realm: used for HTLCs, where first byte 0 is magical.
|
* @has_realm: used for HTLCs, where first byte 0 is magical.
|
||||||
* @valid: set to true if it is valid, false otherwise.
|
* @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,
|
* If @valid is set, there is room for the HMAC immediately following,
|
||||||
* as the return value is <= ROUTING_INFO_SIZE - HMAC_SIZE. Otherwise,
|
* as the return value is <= ROUTING_INFO_SIZE - HMAC_SIZE. Otherwise,
|
||||||
@@ -50,7 +58,8 @@ u8 *onion_final_hop(const tal_t *ctx,
|
|||||||
*/
|
*/
|
||||||
size_t onion_payload_length(const u8 *raw_payload, size_t len,
|
size_t onion_payload_length(const u8 *raw_payload, size_t len,
|
||||||
bool has_realm,
|
bool has_realm,
|
||||||
bool *valid);
|
bool *valid,
|
||||||
|
enum onion_payload_type *type);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* onion_decode: decode payload from a decrypted onion.
|
* onion_decode: decode payload from a decrypted onion.
|
||||||
|
|||||||
@@ -627,7 +627,7 @@ struct route_step *process_onionpacket(
|
|||||||
payload_size = onion_payload_length(paddedheader,
|
payload_size = onion_payload_length(paddedheader,
|
||||||
tal_bytelen(msg->routinginfo),
|
tal_bytelen(msg->routinginfo),
|
||||||
has_realm,
|
has_realm,
|
||||||
&valid);
|
&valid, NULL);
|
||||||
|
|
||||||
/* Can't decode? Treat it as terminal. */
|
/* Can't decode? Treat it as terminal. */
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
|
|||||||
@@ -25,10 +25,6 @@ void towire_bigsize(u8 **pptr UNNEEDED, const bigsize_t val UNNEEDED)
|
|||||||
/* Generated stub for towire_channel_id */
|
/* Generated stub for towire_channel_id */
|
||||||
void towire_channel_id(u8 **pptr UNNEEDED, const struct channel_id *channel_id UNNEEDED)
|
void towire_channel_id(u8 **pptr UNNEEDED, const struct channel_id *channel_id UNNEEDED)
|
||||||
{ fprintf(stderr, "towire_channel_id called!\n"); abort(); }
|
{ fprintf(stderr, "towire_channel_id called!\n"); abort(); }
|
||||||
/* Generated stub for type_to_string_ */
|
|
||||||
const char *type_to_string_(const tal_t *ctx UNNEEDED, const char *typename UNNEEDED,
|
|
||||||
union printable_types u UNNEEDED)
|
|
||||||
{ fprintf(stderr, "type_to_string_ called!\n"); abort(); }
|
|
||||||
/* AUTOGENERATED MOCKS END */
|
/* AUTOGENERATED MOCKS END */
|
||||||
|
|
||||||
/* Canned gossmap, taken from tests/test_gossip.py's
|
/* Canned gossmap, taken from tests/test_gossip.py's
|
||||||
|
|||||||
@@ -51,10 +51,6 @@ void towire_tlv(u8 **pptr UNNEEDED,
|
|||||||
/* Generated stub for towire_wireaddr */
|
/* Generated stub for towire_wireaddr */
|
||||||
void towire_wireaddr(u8 **pptr UNNEEDED, const struct wireaddr *addr UNNEEDED)
|
void towire_wireaddr(u8 **pptr UNNEEDED, const struct wireaddr *addr UNNEEDED)
|
||||||
{ fprintf(stderr, "towire_wireaddr called!\n"); abort(); }
|
{ fprintf(stderr, "towire_wireaddr called!\n"); abort(); }
|
||||||
/* Generated stub for type_to_string_ */
|
|
||||||
const char *type_to_string_(const tal_t *ctx UNNEEDED, const char *typename UNNEEDED,
|
|
||||||
union printable_types u UNNEEDED)
|
|
||||||
{ fprintf(stderr, "type_to_string_ called!\n"); abort(); }
|
|
||||||
/* AUTOGENERATED MOCKS END */
|
/* AUTOGENERATED MOCKS END */
|
||||||
|
|
||||||
static void write_to_store(int store_fd, const u8 *msg)
|
static void write_to_store(int store_fd, const u8 *msg)
|
||||||
|
|||||||
@@ -44,10 +44,6 @@ void towire_tlv(u8 **pptr UNNEEDED,
|
|||||||
/* Generated stub for towire_wireaddr */
|
/* Generated stub for towire_wireaddr */
|
||||||
void towire_wireaddr(u8 **pptr UNNEEDED, const struct wireaddr *addr UNNEEDED)
|
void towire_wireaddr(u8 **pptr UNNEEDED, const struct wireaddr *addr UNNEEDED)
|
||||||
{ fprintf(stderr, "towire_wireaddr called!\n"); abort(); }
|
{ fprintf(stderr, "towire_wireaddr called!\n"); abort(); }
|
||||||
/* Generated stub for type_to_string_ */
|
|
||||||
const char *type_to_string_(const tal_t *ctx UNNEEDED, const char *typename UNNEEDED,
|
|
||||||
union printable_types u UNNEEDED)
|
|
||||||
{ fprintf(stderr, "type_to_string_ called!\n"); abort(); }
|
|
||||||
/* AUTOGENERATED MOCKS END */
|
/* AUTOGENERATED MOCKS END */
|
||||||
|
|
||||||
static void write_to_store(int store_fd, const u8 *msg)
|
static void write_to_store(int store_fd, const u8 *msg)
|
||||||
|
|||||||
@@ -91,7 +91,8 @@ struct onionreply *new_onionreply(const tal_t *ctx UNNEEDED, const u8 *contents
|
|||||||
/* Generated stub for onion_payload_length */
|
/* Generated stub for onion_payload_length */
|
||||||
size_t onion_payload_length(const u8 *raw_payload UNNEEDED, size_t len UNNEEDED,
|
size_t onion_payload_length(const u8 *raw_payload UNNEEDED, size_t len UNNEEDED,
|
||||||
bool has_realm UNNEEDED,
|
bool has_realm UNNEEDED,
|
||||||
bool *valid UNNEEDED)
|
bool *valid UNNEEDED,
|
||||||
|
enum onion_payload_type *type UNNEEDED)
|
||||||
{ fprintf(stderr, "onion_payload_length called!\n"); abort(); }
|
{ fprintf(stderr, "onion_payload_length called!\n"); abort(); }
|
||||||
/* Generated stub for pubkey_from_node_id */
|
/* Generated stub for pubkey_from_node_id */
|
||||||
bool pubkey_from_node_id(struct pubkey *key UNNEEDED, const struct node_id *id UNNEEDED)
|
bool pubkey_from_node_id(struct pubkey *key UNNEEDED, const struct node_id *id UNNEEDED)
|
||||||
|
|||||||
@@ -280,7 +280,7 @@ static void runtest(const char *filename)
|
|||||||
errx(1, "Error serializing message.");
|
errx(1, "Error serializing message.");
|
||||||
onion_payload_length(step->raw_payload,
|
onion_payload_length(step->raw_payload,
|
||||||
tal_bytelen(step->raw_payload),
|
tal_bytelen(step->raw_payload),
|
||||||
true, &valid);
|
true, &valid, NULL);
|
||||||
assert(valid);
|
assert(valid);
|
||||||
printf(" Payload: %s\n", tal_hex(ctx, step->raw_payload));
|
printf(" Payload: %s\n", tal_hex(ctx, step->raw_payload));
|
||||||
printf(" Next onion: %s\n", tal_hex(ctx, serialized));
|
printf(" Next onion: %s\n", tal_hex(ctx, serialized));
|
||||||
|
|||||||
@@ -993,7 +993,15 @@ static void htlc_accepted_hook_serialize(struct htlc_accepted_hook_payload *p,
|
|||||||
|
|
||||||
json_add_hex_talarr(s, "payload", rs->raw_payload);
|
json_add_hex_talarr(s, "payload", rs->raw_payload);
|
||||||
if (p->payload) {
|
if (p->payload) {
|
||||||
json_add_string(s, "type", "tlv");
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
if (p->payload->forward_channel)
|
if (p->payload->forward_channel)
|
||||||
json_add_short_channel_id(s, "short_channel_id",
|
json_add_short_channel_id(s, "short_channel_id",
|
||||||
|
|||||||
@@ -5169,7 +5169,6 @@ def test_sendpay_grouping(node_factory, bitcoind):
|
|||||||
assert([p['status'] for p in pays] == ['failed', 'failed', 'complete'])
|
assert([p['status'] for p in pays] == ['failed', 'failed', 'complete'])
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.xfail("needs lecacy onion support")
|
|
||||||
def test_legacyonion(node_factory, bitcoind):
|
def test_legacyonion(node_factory, bitcoind):
|
||||||
# We have to replicate the topology we created onion with, exactly.
|
# We have to replicate the topology we created onion with, exactly.
|
||||||
l1, l2, l3 = node_factory.line_graph(3, fundchannel=False)
|
l1, l2, l3 = node_factory.line_graph(3, fundchannel=False)
|
||||||
|
|||||||
Reference in New Issue
Block a user