mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-02-22 06:41:44 +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:
parent
141d4ef675
commit
116a77f1be
10 changed files with 63 additions and 22 deletions
|
@ -109,10 +109,11 @@ u8 *onion_final_hop(const tal_t *ctx,
|
|||
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,
|
||||
size_t *max,
|
||||
bool has_realm,
|
||||
enum onion_payload_type *type,
|
||||
size_t *len)
|
||||
{
|
||||
/* *len will incorporate bytes we read from cursor */
|
||||
|
@ -127,6 +128,19 @@ static bool pull_payload_length(const u8 **cursor,
|
|||
if (!cursor)
|
||||
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:
|
||||
* - `tlv_payload` format, identified by any length over `1`. In this
|
||||
* 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;
|
||||
}
|
||||
|
||||
if (type)
|
||||
*type = ONION_TLV_PAYLOAD;
|
||||
*len += (*cursor - start);
|
||||
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,
|
||||
bool *valid)
|
||||
bool *valid,
|
||||
enum onion_payload_type *type)
|
||||
{
|
||||
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 (!*valid)
|
||||
|
@ -210,12 +227,31 @@ struct onion_payload *onion_decode(const tal_t *ctx,
|
|||
size_t max = tal_bytelen(cursor), len;
|
||||
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;
|
||||
*failtlvpos = tal_bytelen(rs->raw_payload);
|
||||
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
|
||||
* error off and type. */
|
||||
tlv = tlv_tlv_payload_new(p);
|
||||
|
|
|
@ -6,7 +6,14 @@
|
|||
|
||||
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;
|
||||
|
@ -43,6 +50,7 @@ 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,
|
||||
|
@ -50,7 +58,8 @@ u8 *onion_final_hop(const tal_t *ctx,
|
|||
*/
|
||||
size_t onion_payload_length(const u8 *raw_payload, size_t len,
|
||||
bool has_realm,
|
||||
bool *valid);
|
||||
bool *valid,
|
||||
enum onion_payload_type *type);
|
||||
|
||||
/**
|
||||
* onion_decode: decode payload from a decrypted onion.
|
||||
|
|
|
@ -627,7 +627,7 @@ struct route_step *process_onionpacket(
|
|||
payload_size = onion_payload_length(paddedheader,
|
||||
tal_bytelen(msg->routinginfo),
|
||||
has_realm,
|
||||
&valid);
|
||||
&valid, NULL);
|
||||
|
||||
/* Can't decode? Treat it as terminal. */
|
||||
if (!valid) {
|
||||
|
|
|
@ -25,10 +25,6 @@ void towire_bigsize(u8 **pptr UNNEEDED, const bigsize_t val UNNEEDED)
|
|||
/* Generated stub for towire_channel_id */
|
||||
void towire_channel_id(u8 **pptr UNNEEDED, const struct channel_id *channel_id UNNEEDED)
|
||||
{ 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 */
|
||||
|
||||
/* Canned gossmap, taken from tests/test_gossip.py's
|
||||
|
|
|
@ -51,10 +51,6 @@ void towire_tlv(u8 **pptr UNNEEDED,
|
|||
/* Generated stub for towire_wireaddr */
|
||||
void towire_wireaddr(u8 **pptr UNNEEDED, const struct wireaddr *addr UNNEEDED)
|
||||
{ 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 */
|
||||
|
||||
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 */
|
||||
void towire_wireaddr(u8 **pptr UNNEEDED, const struct wireaddr *addr UNNEEDED)
|
||||
{ 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 */
|
||||
|
||||
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 */
|
||||
size_t onion_payload_length(const u8 *raw_payload UNNEEDED, size_t len 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(); }
|
||||
/* Generated stub for pubkey_from_node_id */
|
||||
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.");
|
||||
onion_payload_length(step->raw_payload,
|
||||
tal_bytelen(step->raw_payload),
|
||||
true, &valid);
|
||||
true, &valid, NULL);
|
||||
assert(valid);
|
||||
printf(" Payload: %s\n", tal_hex(ctx, step->raw_payload));
|
||||
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);
|
||||
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)
|
||||
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'])
|
||||
|
||||
|
||||
@pytest.mark.xfail("needs lecacy onion support")
|
||||
def test_legacyonion(node_factory, bitcoind):
|
||||
# We have to replicate the topology we created onion with, exactly.
|
||||
l1, l2, l3 = node_factory.line_graph(3, fundchannel=False)
|
||||
|
|
Loading…
Add table
Reference in a new issue