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