@@ -358,7 +358,12 @@ macro_rules! composite_custom_message_handler {
358358 match message_type {
359359 $(
360360 $pattern => match <$type>:: read( & self . $field, message_type, buffer) ? {
361- None => unreachable!( ) ,
361+ // A sub-handler returns `None` for a `message_type` it doesn't
362+ // recognize. The composite's pattern can be broader than the types
363+ // the sub-handler decodes (e.g. a range), and `message_type` is
364+ // peer-provided, so report the message as unknown rather than
365+ // treating this as unreachable and panicking.
366+ None => Ok ( None ) ,
362367 Some ( message) => Ok ( Some ( $message:: $variant( message) ) ) ,
363368 } ,
364369 ) *
@@ -501,6 +506,71 @@ mod tests {
501506 }
502507 ) ;
503508
509+ struct ReservedBlockHandler ;
510+ impl CustomMessageReader for ReservedBlockHandler {
511+ type CustomMessage = Foo ;
512+ fn read < R : LengthLimitedRead > (
513+ & self , message_type : u16 , _b : & mut R ,
514+ ) -> Result < Option < Foo > , DecodeError > {
515+ // This build defines only the message at 32768; the rest of the block its
516+ // protocol reserved (32768..=32777) is for types future versions may add.
517+ // A not-yet-defined type is unknown to this build, so per the
518+ // `CustomMessageReader` contract it returns `Ok(None)` -- a newer peer can
519+ // send one and this older node will treat it as an unknown message.
520+ match message_type {
521+ 32768 => Ok ( Some ( Foo ) ) ,
522+ _ => Ok ( None ) ,
523+ }
524+ }
525+ }
526+ impl CustomMessageHandler for ReservedBlockHandler {
527+ fn handle_custom_message ( & self , _msg : Foo , _: PublicKey ) -> Result < ( ) , LightningError > {
528+ Ok ( ( ) )
529+ }
530+ fn get_and_clear_pending_msg ( & self ) -> Vec < ( PublicKey , Foo ) > {
531+ vec ! [ ]
532+ }
533+ fn peer_disconnected ( & self , _: PublicKey ) { }
534+ fn peer_connected ( & self , _: PublicKey , _: & Init , _: bool ) -> Result < ( ) , ( ) > {
535+ Ok ( ( ) )
536+ }
537+ fn provided_node_features ( & self ) -> NodeFeatures {
538+ NodeFeatures :: empty ( )
539+ }
540+ fn provided_init_features ( & self , _: PublicKey ) -> InitFeatures {
541+ InitFeatures :: empty ( )
542+ }
543+ }
544+
545+ composite_custom_message_handler ! (
546+ struct ReservedBlockComposite {
547+ proto: ReservedBlockHandler ,
548+ }
549+
550+ enum ReservedBlockMessage {
551+ Proto ( 32768 ..=32777 ) ,
552+ }
553+ ) ;
554+
555+ #[ test]
556+ fn read_treats_a_reserved_in_range_type_as_unknown ( ) {
557+ // A sub-handler may own a block of type ids (declared here as a range) yet only
558+ // decode the subset its build defines, returning `Ok(None)` for reserved or
559+ // not-yet-defined types in the block -- exactly what a node does on receiving a
560+ // newer peer's message. `read` must surface that as an unknown message, not
561+ // panic.
562+ let composite = ReservedBlockComposite { proto : ReservedBlockHandler } ;
563+ let mut buffer: & [ u8 ] = & [ ] ;
564+ // The message this build defines decodes to its variant.
565+ assert ! ( matches!(
566+ composite. read( 32768 , & mut buffer) ,
567+ Ok ( Some ( ReservedBlockMessage :: Proto ( _) ) )
568+ ) ) ;
569+ // A reserved type from the same block is reported unknown, not panicked
570+ // (pre-fix the matched arm hit `unreachable!()`).
571+ assert ! ( matches!( composite. read( 32770 , & mut buffer) , Ok ( None ) ) ) ;
572+ }
573+
504574 #[ test]
505575 fn peer_connected_failure_does_not_leak_subhandler_state ( ) {
506576 let composite = CompositeHandler {
0 commit comments