mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-19 07:04:22 +01:00
common/sphinx: handle decoding of TLV payload.
We add routines to decode the expected fields from both legacy and tlv hop formats. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
committed by
Christian Decker
parent
a76518a029
commit
b7bbccd6fa
102
common/sphinx.c
102
common/sphinx.c
@@ -477,16 +477,31 @@ static void sphinx_parse_payload(struct route_step *step, const u8 *src)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Legacy hop_data support */
|
||||
/* BOLT #4:
|
||||
*
|
||||
* The `length` field determines both the length and the format of the
|
||||
* `hop_payload` field; the following formats are defined:
|
||||
*
|
||||
* - 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.
|
||||
*
|
||||
* - `tlv_payload` format, identified by any length over `1`. In this
|
||||
* case the `hop_payload_length` is equal to the numeric value of
|
||||
* `length`.
|
||||
*/
|
||||
if (src[0] == 0x00) {
|
||||
vsize = 1;
|
||||
raw_size = 32;
|
||||
hop_size = FRAME_SIZE;
|
||||
step->type = SPHINX_V0_PAYLOAD;
|
||||
} else {
|
||||
} else if (src[0] > 1) {
|
||||
vsize = bigsize_get(src, 3, &raw_size);
|
||||
hop_size = raw_size + vsize + HMAC_SIZE;
|
||||
step->type = SPHINX_TLV_PAYLOAD;
|
||||
} else {
|
||||
step->type = SPHINX_INVALID_PAYLOAD;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Copy common pieces over */
|
||||
@@ -497,6 +512,18 @@ static void sphinx_parse_payload(struct route_step *step, const u8 *src)
|
||||
* later. */
|
||||
if (step->type == SPHINX_V0_PAYLOAD)
|
||||
deserialize_hop_data(&step->payload.v0, src);
|
||||
else if (step->type == SPHINX_TLV_PAYLOAD) {
|
||||
const u8 *tlv = step->raw_payload;
|
||||
size_t max = tal_bytelen(tlv);
|
||||
step->payload.tlv = tlv_tlv_payload_new(step);
|
||||
if (!fromwire_tlvs(&tlv, &max, tlvs_tlv_payload,
|
||||
TLVS_TLV_PAYLOAD_ARRAY_SIZE,
|
||||
step->payload.tlv)) {
|
||||
/* FIXME: record offset of violation for error! */
|
||||
step->type = SPHINX_INVALID_PAYLOAD;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct onionpacket *create_onionpacket(
|
||||
@@ -781,3 +808,74 @@ struct onionreply *unwrap_onionreply(const tal_t *ctx,
|
||||
return oreply;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to extract fields from ONION_END.
|
||||
*/
|
||||
bool route_step_decode_end(const struct route_step *rs,
|
||||
struct amount_msat *amt_forward,
|
||||
u32 *outgoing_cltv)
|
||||
{
|
||||
assert(rs->nextcase == ONION_END);
|
||||
|
||||
switch (rs->type) {
|
||||
case SPHINX_V0_PAYLOAD:
|
||||
*amt_forward = rs->payload.v0.amt_forward;
|
||||
*outgoing_cltv = rs->payload.v0.outgoing_cltv;
|
||||
return true;
|
||||
case SPHINX_TLV_PAYLOAD:
|
||||
if (!rs->payload.tlv->amt_to_forward)
|
||||
return false;
|
||||
amt_forward->millisatoshis /* Raw: tu64 -> millisatoshis */
|
||||
= rs->payload.tlv->amt_to_forward->amt_to_forward;
|
||||
if (!rs->payload.tlv->outgoing_cltv_value)
|
||||
return false;
|
||||
*outgoing_cltv = rs->payload.tlv->outgoing_cltv_value->outgoing_cltv_value;
|
||||
return true;
|
||||
case SPHINX_INVALID_PAYLOAD:
|
||||
return false;
|
||||
|
||||
/* This should probably be removed, as it's just for testing */
|
||||
case SPHINX_RAW_PAYLOAD:
|
||||
abort();
|
||||
}
|
||||
abort();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to extract fields from ONION_FORWARD.
|
||||
*/
|
||||
bool route_step_decode_forward(const struct route_step *rs,
|
||||
struct amount_msat *amt_forward,
|
||||
u32 *outgoing_cltv,
|
||||
struct short_channel_id *scid)
|
||||
{
|
||||
assert(rs->nextcase == ONION_FORWARD);
|
||||
|
||||
switch (rs->type) {
|
||||
case SPHINX_V0_PAYLOAD:
|
||||
*amt_forward = rs->payload.v0.amt_forward;
|
||||
*outgoing_cltv = rs->payload.v0.outgoing_cltv;
|
||||
*scid = rs->payload.v0.channel_id;
|
||||
return true;
|
||||
case SPHINX_TLV_PAYLOAD:
|
||||
if (!rs->payload.tlv->amt_to_forward)
|
||||
return false;
|
||||
amt_forward->millisatoshis /* Raw: tu64 -> millisatoshis */
|
||||
= rs->payload.tlv->amt_to_forward->amt_to_forward;
|
||||
if (!rs->payload.tlv->outgoing_cltv_value)
|
||||
return false;
|
||||
*outgoing_cltv = rs->payload.tlv->outgoing_cltv_value->outgoing_cltv_value;
|
||||
if (!rs->payload.tlv->short_channel_id)
|
||||
return false;
|
||||
*scid = rs->payload.tlv->short_channel_id->short_channel_id;
|
||||
return true;
|
||||
case SPHINX_INVALID_PAYLOAD:
|
||||
return false;
|
||||
|
||||
/* This should probably be removed, as it's just for testing */
|
||||
case SPHINX_RAW_PAYLOAD:
|
||||
abort();
|
||||
}
|
||||
abort();
|
||||
}
|
||||
|
||||
@@ -81,6 +81,7 @@ struct route_step {
|
||||
enum sphinx_payload_type type;
|
||||
union {
|
||||
struct hop_data_legacy v0;
|
||||
struct tlv_tlv_payload *tlv;
|
||||
} payload;
|
||||
u8 *raw_payload;
|
||||
};
|
||||
@@ -230,4 +231,18 @@ void sphinx_add_v0_hop(struct sphinx_path *path, const struct pubkey *pubkey,
|
||||
void sphinx_add_raw_hop(struct sphinx_path *path, const struct pubkey *pubkey,
|
||||
enum sphinx_payload_type type, const u8 *payload);
|
||||
|
||||
/**
|
||||
* Helper to extract fields from ONION_END.
|
||||
*/
|
||||
bool route_step_decode_end(const struct route_step *rs,
|
||||
struct amount_msat *amt_forward,
|
||||
u32 *outgoing_cltv);
|
||||
|
||||
/**
|
||||
* Helper to extract fields from ONION_FORWARD.
|
||||
*/
|
||||
bool route_step_decode_forward(const struct route_step *rs,
|
||||
struct amount_msat *amt_forward,
|
||||
u32 *outgoing_cltv,
|
||||
struct short_channel_id *scid);
|
||||
#endif /* LIGHTNING_COMMON_SPHINX_H */
|
||||
|
||||
@@ -11,6 +11,9 @@ $(COMMON_TEST_OBJS): $(COMMON_HEADERS) $(WIRE_HEADERS) $(COMMON_SRC)
|
||||
ALL_TEST_PROGRAMS += $(COMMON_TEST_PROGRAMS)
|
||||
ALL_OBJS += $(COMMON_TEST_PROGRAMS:=.o)
|
||||
|
||||
# Sphinx test wants to decode TLVs.
|
||||
common/test/run-sphinx: wire/gen_onion_wire.o
|
||||
|
||||
update-mocks: $(COMMON_TEST_SRC:%=update-mocks/%)
|
||||
|
||||
check-units: $(COMMON_TEST_PROGRAMS:%=unittest/%)
|
||||
|
||||
@@ -43,13 +43,31 @@ const u8 *fromwire(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, void *copy
|
||||
/* Generated stub for fromwire_amount_msat */
|
||||
struct amount_msat fromwire_amount_msat(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
|
||||
{ fprintf(stderr, "fromwire_amount_msat called!\n"); abort(); }
|
||||
/* Generated stub for fromwire_bigsize */
|
||||
bigsize_t fromwire_bigsize(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
|
||||
{ fprintf(stderr, "fromwire_bigsize called!\n"); abort(); }
|
||||
/* Generated stub for fromwire_fail */
|
||||
const void *fromwire_fail(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
|
||||
{ fprintf(stderr, "fromwire_fail called!\n"); abort(); }
|
||||
/* Generated stub for fromwire_sha256 */
|
||||
void fromwire_sha256(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct sha256 *sha256 UNNEEDED)
|
||||
{ fprintf(stderr, "fromwire_sha256 called!\n"); abort(); }
|
||||
/* Generated stub for fromwire_short_channel_id */
|
||||
void fromwire_short_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED,
|
||||
struct short_channel_id *short_channel_id UNNEEDED)
|
||||
{ fprintf(stderr, "fromwire_short_channel_id called!\n"); abort(); }
|
||||
/* Generated stub for fromwire_tlvs */
|
||||
bool fromwire_tlvs(const u8 **cursor UNNEEDED, size_t *max UNNEEDED,
|
||||
const struct tlv_record_type types[] UNNEEDED,
|
||||
size_t num_types UNNEEDED,
|
||||
void *record UNNEEDED)
|
||||
{ fprintf(stderr, "fromwire_tlvs called!\n"); abort(); }
|
||||
/* Generated stub for fromwire_tu32 */
|
||||
u32 fromwire_tu32(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
|
||||
{ fprintf(stderr, "fromwire_tu32 called!\n"); abort(); }
|
||||
/* Generated stub for fromwire_tu64 */
|
||||
u64 fromwire_tu64(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
|
||||
{ fprintf(stderr, "fromwire_tu64 called!\n"); abort(); }
|
||||
/* Generated stub for fromwire_u16 */
|
||||
u16 fromwire_u16(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
|
||||
{ fprintf(stderr, "fromwire_u16 called!\n"); abort(); }
|
||||
@@ -59,16 +77,34 @@ u32 fromwire_u32(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
|
||||
/* Generated stub for fromwire_u8 */
|
||||
u8 fromwire_u8(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
|
||||
{ fprintf(stderr, "fromwire_u8 called!\n"); abort(); }
|
||||
/* Generated stub for fromwire_u8_array */
|
||||
void fromwire_u8_array(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, u8 *arr UNNEEDED, size_t num UNNEEDED)
|
||||
{ fprintf(stderr, "fromwire_u8_array called!\n"); abort(); }
|
||||
/* Generated stub for towire */
|
||||
void towire(u8 **pptr UNNEEDED, const void *data UNNEEDED, size_t len UNNEEDED)
|
||||
{ fprintf(stderr, "towire called!\n"); abort(); }
|
||||
/* Generated stub for towire_amount_msat */
|
||||
void towire_amount_msat(u8 **pptr UNNEEDED, const struct amount_msat msat UNNEEDED)
|
||||
{ fprintf(stderr, "towire_amount_msat called!\n"); abort(); }
|
||||
/* Generated stub for towire_bigsize */
|
||||
void towire_bigsize(u8 **pptr UNNEEDED, const bigsize_t val UNNEEDED)
|
||||
{ fprintf(stderr, "towire_bigsize called!\n"); abort(); }
|
||||
/* Generated stub for towire_pad */
|
||||
void towire_pad(u8 **pptr UNNEEDED, size_t num UNNEEDED)
|
||||
{ fprintf(stderr, "towire_pad called!\n"); abort(); }
|
||||
/* Generated stub for towire_sha256 */
|
||||
void towire_sha256(u8 **pptr UNNEEDED, const struct sha256 *sha256 UNNEEDED)
|
||||
{ fprintf(stderr, "towire_sha256 called!\n"); abort(); }
|
||||
/* Generated stub for towire_short_channel_id */
|
||||
void towire_short_channel_id(u8 **pptr UNNEEDED,
|
||||
const struct short_channel_id *short_channel_id UNNEEDED)
|
||||
{ fprintf(stderr, "towire_short_channel_id called!\n"); abort(); }
|
||||
/* Generated stub for towire_tu32 */
|
||||
void towire_tu32(u8 **pptr UNNEEDED, u32 v UNNEEDED)
|
||||
{ fprintf(stderr, "towire_tu32 called!\n"); abort(); }
|
||||
/* Generated stub for towire_tu64 */
|
||||
void towire_tu64(u8 **pptr UNNEEDED, u64 v UNNEEDED)
|
||||
{ fprintf(stderr, "towire_tu64 called!\n"); abort(); }
|
||||
/* Generated stub for towire_u16 */
|
||||
void towire_u16(u8 **pptr UNNEEDED, u16 v UNNEEDED)
|
||||
{ fprintf(stderr, "towire_u16 called!\n"); abort(); }
|
||||
@@ -78,6 +114,9 @@ void towire_u32(u8 **pptr UNNEEDED, u32 v UNNEEDED)
|
||||
/* Generated stub for towire_u64 */
|
||||
void towire_u64(u8 **pptr UNNEEDED, u64 v UNNEEDED)
|
||||
{ fprintf(stderr, "towire_u64 called!\n"); abort(); }
|
||||
/* Generated stub for towire_u8_array */
|
||||
void towire_u8_array(u8 **pptr UNNEEDED, const u8 *arr UNNEEDED, size_t num UNNEEDED)
|
||||
{ fprintf(stderr, "towire_u8_array called!\n"); abort(); }
|
||||
/* AUTOGENERATED MOCKS END */
|
||||
|
||||
secp256k1_context *secp256k1_ctx;
|
||||
|
||||
@@ -535,6 +535,17 @@ struct route_step *process_onionpacket(
|
||||
const size_t assocdatalen
|
||||
)
|
||||
{ fprintf(stderr, "process_onionpacket called!\n"); abort(); }
|
||||
/* Generated stub for route_step_decode_end */
|
||||
bool route_step_decode_end(const struct route_step *rs UNNEEDED,
|
||||
struct amount_msat *amt_forward UNNEEDED,
|
||||
u32 *outgoing_cltv UNNEEDED)
|
||||
{ fprintf(stderr, "route_step_decode_end called!\n"); abort(); }
|
||||
/* Generated stub for route_step_decode_forward */
|
||||
bool route_step_decode_forward(const struct route_step *rs UNNEEDED,
|
||||
struct amount_msat *amt_forward UNNEEDED,
|
||||
u32 *outgoing_cltv UNNEEDED,
|
||||
struct short_channel_id *scid UNNEEDED)
|
||||
{ fprintf(stderr, "route_step_decode_forward called!\n"); abort(); }
|
||||
/* Generated stub for serialize_onionpacket */
|
||||
u8 *serialize_onionpacket(
|
||||
const tal_t *ctx UNNEEDED,
|
||||
|
||||
Reference in New Issue
Block a user