Skip to content

Commit 8ee7d84

Browse files
committed
Support serializing TLV fields which may or may not be present
1 parent a515eb3 commit 8ee7d84

File tree

6 files changed

+72
-30
lines changed

6 files changed

+72
-30
lines changed

lightning/src/chain/channelmonitor.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -988,7 +988,7 @@ impl<Signer: Sign> Writeable for ChannelMonitorImpl<Signer> {
988988
self.lockdown_from_offchain.write(writer)?;
989989
self.holder_tx_signed.write(writer)?;
990990

991-
write_tlv_fields!(writer, {});
991+
write_tlv_fields!(writer, {}, {});
992992

993993
Ok(())
994994
}

lightning/src/ln/channel.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4565,7 +4565,7 @@ impl<Signer: Sign> Writeable for Channel<Signer> {
45654565

45664566
self.channel_update_status.write(writer)?;
45674567

4568-
write_tlv_fields!(writer, {});
4568+
write_tlv_fields!(writer, {}, {});
45694569

45704570
Ok(())
45714571
}

lightning/src/ln/channelmanager.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4651,7 +4651,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> Writeable f
46514651
session_priv.write(writer)?;
46524652
}
46534653

4654-
write_tlv_fields!(writer, {});
4654+
write_tlv_fields!(writer, {}, {});
46554655

46564656
Ok(())
46574657
}

lightning/src/ln/msgs.rs

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1285,20 +1285,17 @@ impl Writeable for OnionHopData {
12851285
(2, HighZeroBytesDroppedVarInt(self.amt_to_forward)),
12861286
(4, HighZeroBytesDroppedVarInt(self.outgoing_cltv_value)),
12871287
(6, short_channel_id)
1288-
});
1288+
}, { });
12891289
},
1290-
OnionHopDataFormat::FinalNode { payment_data: Some(ref final_data) } => {
1291-
if final_data.total_msat > MAX_VALUE_MSAT { panic!("We should never be sending infinite/overflow onion payments"); }
1292-
encode_varint_length_prefixed_tlv!(w, {
1293-
(2, HighZeroBytesDroppedVarInt(self.amt_to_forward)),
1294-
(4, HighZeroBytesDroppedVarInt(self.outgoing_cltv_value)),
1295-
(8, final_data)
1296-
});
1297-
},
1298-
OnionHopDataFormat::FinalNode { payment_data: None } => {
1290+
OnionHopDataFormat::FinalNode { ref payment_data } => {
1291+
if let Some(final_data) = payment_data {
1292+
if final_data.total_msat > MAX_VALUE_MSAT { panic!("We should never be sending infinite/overflow onion payments"); }
1293+
}
12991294
encode_varint_length_prefixed_tlv!(w, {
13001295
(2, HighZeroBytesDroppedVarInt(self.amt_to_forward)),
13011296
(4, HighZeroBytesDroppedVarInt(self.outgoing_cltv_value))
1297+
}, {
1298+
(8, payment_data)
13021299
});
13031300
},
13041301
}

lightning/src/ln/onchaintx.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
361361
}
362362
self.latest_height.write(writer)?;
363363

364-
write_tlv_fields!(writer, {});
364+
write_tlv_fields!(writer, {}, {});
365365
Ok(())
366366
}
367367
}

lightning/src/util/ser_macros.rs

Lines changed: 61 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,51 @@
88
// licenses.
99

1010
macro_rules! encode_tlv {
11-
($stream: expr, {$(($type: expr, $field: expr)),*}) => { {
11+
($stream: expr, {$(($type: expr, $field: expr)),*}, {$(($optional_type: expr, $optional_field: expr)),*}) => { {
1212
#[allow(unused_imports)]
1313
use util::ser::{BigSize, LengthCalculatingWriter};
14+
// Fields must be serialized in order, so we have to potentially switch between optional
15+
// fields and normal fields while serializing. Thus, we end up having to loop over the type
16+
// counts.
17+
// Sadly, while LLVM does appear smart enough to make `max_field` a constant, it appears to
18+
// refuse to unroll the loop. If we have enough entries that this is slow we can revisit
19+
// this design in the future.
20+
#[allow(unused_mut)]
21+
let mut max_field: u64 = 0;
22+
$(
23+
if $type >= max_field { max_field = $type + 1; }
24+
)*
1425
$(
15-
BigSize($type).write($stream)?;
16-
let mut len_calc = LengthCalculatingWriter(0);
17-
$field.write(&mut len_calc)?;
18-
BigSize(len_calc.0 as u64).write($stream)?;
19-
$field.write($stream)?;
26+
if $optional_type >= max_field { max_field = $optional_type + 1; }
2027
)*
28+
#[allow(unused_variables)]
29+
for i in 0..max_field {
30+
$(
31+
if i == $type {
32+
BigSize($type).write($stream)?;
33+
let mut len_calc = LengthCalculatingWriter(0);
34+
$field.write(&mut len_calc)?;
35+
BigSize(len_calc.0 as u64).write($stream)?;
36+
$field.write($stream)?;
37+
}
38+
)*
39+
$(
40+
if i == $optional_type {
41+
if let Some(ref field) = $optional_field {
42+
BigSize($optional_type).write($stream)?;
43+
let mut len_calc = LengthCalculatingWriter(0);
44+
field.write(&mut len_calc)?;
45+
BigSize(len_calc.0 as u64).write($stream)?;
46+
field.write($stream)?;
47+
}
48+
}
49+
)*
50+
}
2151
} }
2252
}
2353

2454
macro_rules! encode_varint_length_prefixed_tlv {
25-
($stream: expr, {$(($type: expr, $field: expr)),*}) => { {
55+
($stream: expr, {$(($type: expr, $field: expr)),*}, {$(($optional_type: expr, $optional_field: expr)),*}) => { {
2656
use util::ser::{BigSize, LengthCalculatingWriter};
2757
#[allow(unused_mut)]
2858
let mut len = LengthCalculatingWriter(0);
@@ -34,12 +64,19 @@ macro_rules! encode_varint_length_prefixed_tlv {
3464
BigSize(field_len.0 as u64).write(&mut len)?;
3565
len.0 += field_len.0;
3666
)*
67+
$(
68+
if let Some(ref field) = $optional_field {
69+
BigSize($optional_type).write(&mut len)?;
70+
let mut field_len = LengthCalculatingWriter(0);
71+
field.write(&mut field_len)?;
72+
BigSize(field_len.0 as u64).write(&mut len)?;
73+
len.0 += field_len.0;
74+
}
75+
)*
3776
}
3877

3978
BigSize(len.0 as u64).write($stream)?;
40-
encode_tlv!($stream, {
41-
$(($type, $field)),*
42-
});
79+
encode_tlv!($stream, { $(($type, $field)),* }, { $(($optional_type, $optional_field)),* });
4380
} }
4481
}
4582

@@ -209,8 +246,8 @@ macro_rules! write_ver_prefix {
209246
/// This is the preferred method of adding new fields that old nodes can ignore and still function
210247
/// correctly.
211248
macro_rules! write_tlv_fields {
212-
($stream: expr, {$(($type: expr, $field: expr)),*}) => {
213-
encode_varint_length_prefixed_tlv!($stream, {$(($type, $field)),*});
249+
($stream: expr, {$(($type: expr, $field: expr)),*}, {$(($optional_type: expr, $optional_field: expr)),*}) => {
250+
encode_varint_length_prefixed_tlv!($stream, {$(($type, $field)),*} , {$(($optional_type, $optional_field)),*});
214251
}
215252
}
216253

@@ -435,19 +472,27 @@ mod tests {
435472
let mut stream = VecWriter(Vec::new());
436473

437474
stream.0.clear();
438-
encode_varint_length_prefixed_tlv!(&mut stream, { (1, 1u8) });
475+
encode_varint_length_prefixed_tlv!(&mut stream, { (1, 1u8) }, { (42, None::<u64>) });
439476
assert_eq!(stream.0, ::hex::decode("03010101").unwrap());
440477

441478
stream.0.clear();
442-
encode_varint_length_prefixed_tlv!(&mut stream, { (4, 0xabcdu16) });
479+
encode_varint_length_prefixed_tlv!(&mut stream, { }, { (1, Some(1u8)) });
480+
assert_eq!(stream.0, ::hex::decode("03010101").unwrap());
481+
482+
stream.0.clear();
483+
encode_varint_length_prefixed_tlv!(&mut stream, { (4, 0xabcdu16) }, { (42, None::<u64>) });
443484
assert_eq!(stream.0, ::hex::decode("040402abcd").unwrap());
444485

445486
stream.0.clear();
446-
encode_varint_length_prefixed_tlv!(&mut stream, { (0xff, 0xabcdu16) });
487+
encode_varint_length_prefixed_tlv!(&mut stream, { (0xff, 0xabcdu16) }, { (42, None::<u64>) });
447488
assert_eq!(stream.0, ::hex::decode("06fd00ff02abcd").unwrap());
448489

449490
stream.0.clear();
450-
encode_varint_length_prefixed_tlv!(&mut stream, { (0, 1u64), (0xff, HighZeroBytesDroppedVarInt(0u64)) });
491+
encode_varint_length_prefixed_tlv!(&mut stream, { (0, 1u64), (0xff, HighZeroBytesDroppedVarInt(0u64)) }, { (42, None::<u64>) });
492+
assert_eq!(stream.0, ::hex::decode("0e00080000000000000001fd00ff00").unwrap());
493+
494+
stream.0.clear();
495+
encode_varint_length_prefixed_tlv!(&mut stream, { (0xff, HighZeroBytesDroppedVarInt(0u64)) }, { (0, Some(1u64)) });
451496
assert_eq!(stream.0, ::hex::decode("0e00080000000000000001fd00ff00").unwrap());
452497

453498
Ok(())

0 commit comments

Comments
 (0)