@@ -246,6 +246,21 @@ pub trait CustomOnionMessageHandler {
246
246
fn read_custom_message < R : io:: Read > ( & self , message_type : u64 , buffer : & mut R ) -> Result < Option < Self :: CustomMessage > , msgs:: DecodeError > ;
247
247
}
248
248
249
+ /// An processed incoming onion message, containing either a Forward (another onion)
250
+ /// or a Receive payload with decrypted contents
251
+ pub enum PeeledOnion < CMH : Deref > where
252
+ CMH :: Target : CustomOnionMessageHandler ,
253
+ {
254
+ /// Forwarded onion, with the next node id and a new onion
255
+ Forward ( PublicKey , msgs:: OnionMessage ) ,
256
+ /// Received onion message, with decrypted contents, path_id, and reply path
257
+ Receive ( OnionMessageContents < <<CMH as Deref >:: Target as CustomOnionMessageHandler >:: CustomMessage > , Option < [ u8 ; 32 ] > , Option < BlindedPath > )
258
+ }
259
+
260
+ /// Errors that may occur when [receiving an onion message].
261
+ #[ derive( Debug , PartialEq , Eq ) ]
262
+ pub struct ReceiveError { }
263
+
249
264
impl < ES : Deref , NS : Deref , L : Deref , MR : Deref , OMH : Deref , CMH : Deref >
250
265
OnionMessenger < ES , NS , L , MR , OMH , CMH >
251
266
where
@@ -360,6 +375,103 @@ where
360
375
} ) )
361
376
}
362
377
378
+ /// Decode one layer of an incoming onion message
379
+ /// Returns either a Forward (another onion message), or Receive (decrypted content)
380
+ pub fn peel_onion < T : CustomOnionMessageContents > (
381
+ node_signer : & NS ,
382
+ secp_ctx : & Secp256k1 < secp256k1:: All > ,
383
+ logger : & L ,
384
+ custom_handler : & CMH ,
385
+ msg : & msgs:: OnionMessage ,
386
+ ) -> Result < PeeledOnion < CMH > , ReceiveError > {
387
+ let control_tlvs_ss = match node_signer. ecdh ( Recipient :: Node , & msg. blinding_point , None ) {
388
+ Ok ( ss) => ss,
389
+ Err ( e) => {
390
+ log_error ! ( logger, "Failed to retrieve node secret: {:?}" , e) ;
391
+ return Err ( ReceiveError { } ) ;
392
+ }
393
+ } ;
394
+ let onion_decode_ss = {
395
+ let blinding_factor = {
396
+ let mut hmac = HmacEngine :: < Sha256 > :: new ( b"blinded_node_id" ) ;
397
+ hmac. input ( control_tlvs_ss. as_ref ( ) ) ;
398
+ Hmac :: from_engine ( hmac) . into_inner ( )
399
+ } ;
400
+ match node_signer. ecdh ( Recipient :: Node , & msg. onion_routing_packet . public_key ,
401
+ Some ( & Scalar :: from_be_bytes ( blinding_factor) . unwrap ( ) ) )
402
+ {
403
+ Ok ( ss) => ss. secret_bytes ( ) ,
404
+ Err ( ( ) ) => {
405
+ log_trace ! ( logger, "Failed to compute onion packet shared secret" ) ;
406
+ return Err ( ReceiveError { } ) ;
407
+ }
408
+ }
409
+ } ;
410
+ match onion_utils:: decode_next_untagged_hop (
411
+ onion_decode_ss, & msg. onion_routing_packet . hop_data [ ..] , msg. onion_routing_packet . hmac ,
412
+ ( control_tlvs_ss, custom_handler. deref ( ) , logger. deref ( ) )
413
+ ) {
414
+ Ok ( ( Payload :: Receive :: < <<CMH as Deref >:: Target as CustomOnionMessageHandler >:: CustomMessage > {
415
+ message, control_tlvs : ReceiveControlTlvs :: Unblinded ( ReceiveTlvs { path_id } ) , reply_path,
416
+ } , None ) ) => {
417
+ log_trace!( logger,
418
+ "Received an onion message with path_id {:02x?} and {} reply_path" ,
419
+ path_id, if reply_path. is_some ( ) { "a" } else { "no" } ) ;
420
+
421
+ Ok ( PeeledOnion :: Receive ( message, path_id, reply_path) )
422
+ } ,
423
+ Ok ( ( Payload :: Forward ( ForwardControlTlvs :: Unblinded ( ForwardTlvs {
424
+ next_node_id, next_blinding_override
425
+ } ) ) , Some ( ( next_hop_hmac, new_packet_bytes) ) ) ) => {
426
+ // TODO: we need to check whether `next_node_id` is our node, in which case this is a dummy
427
+ // blinded hop and this onion message is destined for us. In this situation, we should keep
428
+ // unwrapping the onion layers to get to the final payload. Since we don't have the option
429
+ // of creating blinded paths with dummy hops currently, we should be ok to not handle this
430
+ // for now.
431
+ let new_pubkey = match onion_utils:: next_hop_pubkey ( & secp_ctx, msg. onion_routing_packet . public_key , & onion_decode_ss) {
432
+ Ok ( pk) => pk,
433
+ Err ( e) => {
434
+ log_trace ! ( logger, "Failed to compute next hop packet pubkey: {}" , e) ;
435
+ return Err ( ReceiveError { } )
436
+ }
437
+ } ;
438
+ let outgoing_packet = Packet {
439
+ version : 0 ,
440
+ public_key : new_pubkey,
441
+ hop_data : new_packet_bytes,
442
+ hmac : next_hop_hmac,
443
+ } ;
444
+ let onion_message = msgs:: OnionMessage {
445
+ blinding_point : match next_blinding_override {
446
+ Some ( blinding_point) => blinding_point,
447
+ None => {
448
+ match onion_utils:: next_hop_pubkey (
449
+ & secp_ctx, msg. blinding_point , control_tlvs_ss. as_ref ( )
450
+ ) {
451
+ Ok ( bp) => bp,
452
+ Err ( e) => {
453
+ log_trace ! ( logger, "Failed to compute next blinding point: {}" , e) ;
454
+ return Err ( ReceiveError { } )
455
+ }
456
+ }
457
+ }
458
+ } ,
459
+ onion_routing_packet : outgoing_packet,
460
+ } ;
461
+
462
+ Ok ( PeeledOnion :: Forward ( next_node_id, onion_message) )
463
+ } ,
464
+ Err ( e) => {
465
+ log_trace ! ( logger, "Errored decoding onion message packet: {:?}" , e) ;
466
+ Err ( ReceiveError { } )
467
+ } ,
468
+ _ => {
469
+ log_trace ! ( logger, "Received bogus onion message packet, either the sender encoded a final hop as a forwarding hop or vice versa" ) ;
470
+ Err ( ReceiveError { } )
471
+ } ,
472
+ }
473
+ }
474
+
363
475
fn respond_with_onion_message < T : CustomOnionMessageContents > (
364
476
& self , response : OnionMessageContents < T > , path_id : Option < [ u8 ; 32 ] > ,
365
477
reply_path : Option < BlindedPath >
@@ -460,40 +572,14 @@ where
460
572
/// soon we'll delegate the onion message to a handler that can generate invoices or send
461
573
/// payments.
462
574
fn handle_onion_message ( & self , _peer_node_id : & PublicKey , msg : & msgs:: OnionMessage ) {
463
- let control_tlvs_ss = match self . node_signer . ecdh ( Recipient :: Node , & msg. blinding_point , None ) {
464
- Ok ( ss) => ss,
465
- Err ( e) => {
466
- log_error ! ( self . logger, "Failed to retrieve node secret: {:?}" , e) ;
467
- return
468
- }
469
- } ;
470
- let onion_decode_ss = {
471
- let blinding_factor = {
472
- let mut hmac = HmacEngine :: < Sha256 > :: new ( b"blinded_node_id" ) ;
473
- hmac. input ( control_tlvs_ss. as_ref ( ) ) ;
474
- Hmac :: from_engine ( hmac) . into_inner ( )
475
- } ;
476
- match self . node_signer . ecdh ( Recipient :: Node , & msg. onion_routing_packet . public_key ,
477
- Some ( & Scalar :: from_be_bytes ( blinding_factor) . unwrap ( ) ) )
478
- {
479
- Ok ( ss) => ss. secret_bytes ( ) ,
480
- Err ( ( ) ) => {
481
- log_trace ! ( self . logger, "Failed to compute onion packet shared secret" ) ;
482
- return
483
- }
484
- }
485
- } ;
486
- match onion_utils:: decode_next_untagged_hop (
487
- onion_decode_ss, & msg. onion_routing_packet . hop_data [ ..] , msg. onion_routing_packet . hmac ,
488
- ( control_tlvs_ss, & * self . custom_handler , & * self . logger )
575
+ match Self :: peel_onion :: < <<CMH as Deref >:: Target as CustomOnionMessageHandler >:: CustomMessage > (
576
+ & self . node_signer ,
577
+ & self . secp_ctx ,
578
+ & self . logger ,
579
+ & self . custom_handler ,
580
+ msg
489
581
) {
490
- Ok ( ( Payload :: Receive :: < <<CMH as Deref >:: Target as CustomOnionMessageHandler >:: CustomMessage > {
491
- message, control_tlvs : ReceiveControlTlvs :: Unblinded ( ReceiveTlvs { path_id } ) , reply_path,
492
- } , None ) ) => {
493
- log_trace!( self . logger,
494
- "Received an onion message with path_id {:02x?} and {} reply_path" ,
495
- path_id, if reply_path. is_some ( ) { "a" } else { "no" } ) ;
496
-
582
+ Ok ( PeeledOnion :: Receive ( message, path_id, reply_path) ) => {
497
583
let response = match message {
498
584
OnionMessageContents :: Offers ( msg) => {
499
585
self . offers_handler . handle_message ( msg)
@@ -504,50 +590,11 @@ where
504
590
. map ( |msg| OnionMessageContents :: Custom ( msg) )
505
591
} ,
506
592
} ;
507
-
508
593
if let Some ( response) = response {
509
594
self . respond_with_onion_message ( response, path_id, reply_path) ;
510
595
}
511
596
} ,
512
- Ok ( ( Payload :: Forward ( ForwardControlTlvs :: Unblinded ( ForwardTlvs {
513
- next_node_id, next_blinding_override
514
- } ) ) , Some ( ( next_hop_hmac, new_packet_bytes) ) ) ) => {
515
- // TODO: we need to check whether `next_node_id` is our node, in which case this is a dummy
516
- // blinded hop and this onion message is destined for us. In this situation, we should keep
517
- // unwrapping the onion layers to get to the final payload. Since we don't have the option
518
- // of creating blinded paths with dummy hops currently, we should be ok to not handle this
519
- // for now.
520
- let new_pubkey = match onion_utils:: next_hop_pubkey ( & self . secp_ctx , msg. onion_routing_packet . public_key , & onion_decode_ss) {
521
- Ok ( pk) => pk,
522
- Err ( e) => {
523
- log_trace ! ( self . logger, "Failed to compute next hop packet pubkey: {}" , e) ;
524
- return
525
- }
526
- } ;
527
- let outgoing_packet = Packet {
528
- version : 0 ,
529
- public_key : new_pubkey,
530
- hop_data : new_packet_bytes,
531
- hmac : next_hop_hmac,
532
- } ;
533
- let onion_message = msgs:: OnionMessage {
534
- blinding_point : match next_blinding_override {
535
- Some ( blinding_point) => blinding_point,
536
- None => {
537
- match onion_utils:: next_hop_pubkey (
538
- & self . secp_ctx , msg. blinding_point , control_tlvs_ss. as_ref ( )
539
- ) {
540
- Ok ( bp) => bp,
541
- Err ( e) => {
542
- log_trace ! ( self . logger, "Failed to compute next blinding point: {}" , e) ;
543
- return
544
- }
545
- }
546
- }
547
- } ,
548
- onion_routing_packet : outgoing_packet,
549
- } ;
550
-
597
+ Ok ( PeeledOnion :: Forward ( next_node_id, onion_message) ) => {
551
598
let mut pending_per_peer_msgs = self . pending_messages . lock ( ) . unwrap ( ) ;
552
599
if outbound_buffer_full ( & next_node_id, & pending_per_peer_msgs) {
553
600
log_trace ! ( self . logger, "Dropping forwarded onion message to peer {:?}: outbound buffer full" , next_node_id) ;
@@ -566,15 +613,12 @@ where
566
613
e. get_mut ( ) . push_back ( onion_message) ;
567
614
log_trace ! ( self . logger, "Forwarding an onion message to peer {}" , next_node_id) ;
568
615
}
569
- } ;
616
+ }
570
617
} ,
571
618
Err ( e) => {
572
- log_trace ! ( self . logger, "Errored decoding onion message packet: {:?}" , e) ;
573
- } ,
574
- _ => {
575
- log_trace ! ( self . logger, "Received bogus onion message packet, either the sender encoded a final hop as a forwarding hop or vice versa" ) ;
576
- } ,
577
- } ;
619
+ log_error ! ( self . logger, "Failed to process onion message {:?}" , e) ;
620
+ }
621
+ }
578
622
}
579
623
580
624
fn peer_connected ( & self , their_node_id : & PublicKey , init : & msgs:: Init , _inbound : bool ) -> Result < ( ) , ( ) > {
0 commit comments