@@ -354,58 +354,78 @@ macro_rules! _check_missing_tlv {
354
354
#[ doc( hidden) ]
355
355
#[ macro_export]
356
356
macro_rules! _decode_tlv {
357
- ( $reader: expr, $field: ident, ( default_value, $default: expr) ) => { {
358
- $crate:: _decode_tlv!( $reader, $field, required)
357
+ ( $outer_reader : expr , $ reader: expr, $field: ident, ( default_value, $default: expr) ) => { {
358
+ $crate:: _decode_tlv!( $outer_reader , $ reader, $field, required)
359
359
} } ;
360
- ( $reader: expr, $field: ident, ( static_value, $value: expr) ) => { {
360
+ ( $outer_reader : expr , $ reader: expr, $field: ident, ( static_value, $value: expr) ) => { {
361
361
} } ;
362
- ( $reader: expr, $field: ident, required) => { {
362
+ ( $outer_reader : expr , $ reader: expr, $field: ident, required) => { {
363
363
$field = $crate:: util:: ser:: Readable :: read( & mut $reader) ?;
364
364
} } ;
365
- ( $reader: expr, $field: ident, ( required: $trait: ident $( , $read_arg: expr) ?) ) => { {
365
+ ( $outer_reader : expr , $ reader: expr, $field: ident, ( required: $trait: ident $( , $read_arg: expr) ?) ) => { {
366
366
$field = $trait:: read( & mut $reader $( , $read_arg) * ) ?;
367
367
} } ;
368
- ( $reader: expr, $field: ident, required_vec) => { {
368
+ ( $outer_reader : expr , $ reader: expr, $field: ident, required_vec) => { {
369
369
let f: $crate:: util:: ser:: WithoutLength <Vec <_>> = $crate:: util:: ser:: Readable :: read( & mut $reader) ?;
370
370
$field = f. 0 ;
371
371
} } ;
372
- ( $reader: expr, $field: ident, option) => { {
372
+ ( $outer_reader : expr , $ reader: expr, $field: ident, option) => { {
373
373
$field = Some ( $crate:: util:: ser:: Readable :: read( & mut $reader) ?) ;
374
374
} } ;
375
- ( $reader: expr, $field: ident, optional_vec) => { {
375
+ ( $outer_reader : expr , $ reader: expr, $field: ident, optional_vec) => { {
376
376
let f: $crate:: util:: ser:: WithoutLength <Vec <_>> = $crate:: util:: ser:: Readable :: read( & mut $reader) ?;
377
377
$field = Some ( f. 0 ) ;
378
378
} } ;
379
379
// `upgradable_required` indicates we're reading a required TLV that may have been upgraded
380
380
// without backwards compat. We'll error if the field is missing, and return `Ok(None)` if the
381
381
// field is present but we can no longer understand it.
382
382
// Note that this variant can only be used within a `MaybeReadable` read.
383
- ( $reader: expr, $field: ident, upgradable_required) => { {
383
+ ( $outer_reader : expr , $ reader: expr, $field: ident, upgradable_required) => { {
384
384
$field = match $crate:: util:: ser:: MaybeReadable :: read( & mut $reader) ? {
385
385
Some ( res) => res,
386
- _ => return Ok ( None )
386
+ None => {
387
+ // If we successfully read a value but we don't know how to parse it, we give up
388
+ // and immediately return `None`. However, we need to make sure we read the correct
389
+ // number of bytes for this TLV stream, which is implicitly the end of the stream.
390
+ // Thus, we consume everything left in the `$outer_reader` here, ensuring that if
391
+ // we're being read as a part of another TLV stream we don't spuriously fail to
392
+ // deserialize the outer object due to a TLV length mismatch.
393
+ $crate:: io_extras:: copy( $outer_reader, & mut $crate:: io_extras:: sink( ) ) . unwrap( ) ;
394
+ return Ok ( None )
395
+ } ,
387
396
} ;
388
397
} } ;
389
398
// `upgradable_option` indicates we're reading an Option-al TLV that may have been upgraded
390
399
// without backwards compat. $field will be None if the TLV is missing or if the field is present
391
400
// but we can no longer understand it.
392
- ( $reader: expr, $field: ident, upgradable_option) => { {
401
+ ( $outer_reader : expr , $ reader: expr, $field: ident, upgradable_option) => { {
393
402
$field = $crate:: util:: ser:: MaybeReadable :: read( & mut $reader) ?;
403
+ if $field. is_none( ) {
404
+ #[ cfg( not( debug_assertions) ) ] {
405
+ // In general, MaybeReadable implementations are required to consume all the bytes
406
+ // of the object even if they don't understand it, but due to a bug in the
407
+ // serialization format for `impl_writeable_tlv_based_enum_upgradable` we sometimes
408
+ // don't know how many bytes that is. In such cases, we'd like to spuriously allow
409
+ // TLV length mismatches, which we do here by calling `eat_remaining` so that the
410
+ // `s.bytes_remain()` check in `_decode_tlv_stream_range` doesn't fail.
411
+ $reader. eat_remaining( ) ?;
412
+ }
413
+ }
394
414
} } ;
395
- ( $reader: expr, $field: ident, ( option: $trait: ident $( , $read_arg: expr) ?) ) => { {
415
+ ( $outer_reader : expr , $ reader: expr, $field: ident, ( option: $trait: ident $( , $read_arg: expr) ?) ) => { {
396
416
$field = Some ( $trait:: read( & mut $reader $( , $read_arg) * ) ?) ;
397
417
} } ;
398
- ( $reader: expr, $field: ident, ( option, encoding: ( $fieldty: ty, $encoding: ident, $encoder: ty) ) ) => { {
399
- $crate:: _decode_tlv!( $reader, $field, ( option, encoding: ( $fieldty, $encoding) ) ) ;
418
+ ( $outer_reader : expr , $ reader: expr, $field: ident, ( option, encoding: ( $fieldty: ty, $encoding: ident, $encoder: ty) ) ) => { {
419
+ $crate:: _decode_tlv!( $outer_reader , $ reader, $field, ( option, encoding: ( $fieldty, $encoding) ) ) ;
400
420
} } ;
401
- ( $reader: expr, $field: ident, ( option, encoding: ( $fieldty: ty, $encoding: ident) ) ) => { {
421
+ ( $outer_reader : expr , $ reader: expr, $field: ident, ( option, encoding: ( $fieldty: ty, $encoding: ident) ) ) => { {
402
422
$field = {
403
423
let field: $encoding<$fieldty> = ser:: Readable :: read( & mut $reader) ?;
404
424
Some ( field. 0 )
405
425
} ;
406
426
} } ;
407
- ( $reader: expr, $field: ident, ( option, encoding: $fieldty: ty) ) => { {
408
- $crate:: _decode_tlv!( $reader, $field, option) ;
427
+ ( $outer_reader : expr , $ reader: expr, $field: ident, ( option, encoding: $fieldty: ty) ) => { {
428
+ $crate:: _decode_tlv!( $outer_reader , $ reader, $field, option) ;
409
429
} } ;
410
430
}
411
431
@@ -539,7 +559,7 @@ macro_rules! _decode_tlv_stream_range {
539
559
let mut s = ser:: FixedLengthReader :: new( & mut stream_ref, length. 0 ) ;
540
560
match typ. 0 {
541
561
$( _t if $crate:: _decode_tlv_stream_match_check!( _t, $type, $fieldty) => {
542
- $crate:: _decode_tlv!( s, $field, $fieldty) ;
562
+ $crate:: _decode_tlv!( $stream , s, $field, $fieldty) ;
543
563
if s. bytes_remain( ) {
544
564
s. eat_remaining( ) ?; // Return ShortRead if there's actually not enough bytes
545
565
return Err ( DecodeError :: InvalidValue ) ;
@@ -1065,6 +1085,10 @@ macro_rules! impl_writeable_tlv_based_enum {
1065
1085
/// when [`MaybeReadable`] is practical instead of just [`Readable`] as it provides an upgrade path for
1066
1086
/// new variants to be added which are simply ignored by existing clients.
1067
1087
///
1088
+ /// Note that only struct and unit variants (not tuple variants) will support downgrading, thus any
1089
+ /// new odd variants MUST be non-tuple (i.e. described using `$variant_id` and `$variant_name` not
1090
+ /// `$tuple_variant_id` and `$tuple_variant_name`).
1091
+ ///
1068
1092
/// [`MaybeReadable`]: crate::util::ser::MaybeReadable
1069
1093
/// [`Writeable`]: crate::util::ser::Writeable
1070
1094
/// [`DecodeError::UnknownRequiredFeature`]: crate::ln::msgs::DecodeError::UnknownRequiredFeature
@@ -1102,7 +1126,14 @@ macro_rules! impl_writeable_tlv_based_enum_upgradable {
1102
1126
$( $( $tuple_variant_id => {
1103
1127
Ok ( Some ( $st:: $tuple_variant_name( Readable :: read( reader) ?) ) )
1104
1128
} ) ,* ) *
1105
- _ if id % 2 == 1 => Ok ( None ) ,
1129
+ _ if id % 2 == 1 => {
1130
+ // Assume that a $variant_id was written, not a $tuple_variant_id, and read
1131
+ // the length prefix and discard the correct number of bytes.
1132
+ let tlv_len: $crate:: util:: ser:: BigSize = $crate:: util:: ser:: Readable :: read( reader) ?;
1133
+ let mut rd = $crate:: util:: ser:: FixedLengthReader :: new( reader, tlv_len. 0 ) ;
1134
+ rd. eat_remaining( ) . map_err( |_| $crate:: ln:: msgs:: DecodeError :: ShortRead ) ?;
1135
+ Ok ( None )
1136
+ } ,
1106
1137
_ => Err ( $crate:: ln:: msgs:: DecodeError :: UnknownRequiredFeature ) ,
1107
1138
}
1108
1139
}
0 commit comments