@@ -935,6 +935,152 @@ pub(crate) fn decode_next_payment_hop<NS: Deref>(
935
935
}
936
936
}
937
937
938
+ /// Build a payment onion, returning the first hop msat and cltv values as well.
939
+ pub fn create_payment_onion < T > (
940
+ secp_ctx : & Secp256k1 < T > , path : & Path , session_priv : & SecretKey , total_msat : u64 ,
941
+ recipient_onion : RecipientOnionFields , starting_htlc_offset : u32 , payment_hash : PaymentHash ,
942
+ keysend_preimage : Option < PaymentPreimage > , prng_seed : [ u8 ; 32 ] ) -> Result < ( u64 , u32 , msgs:: OnionPacket ) , ( ) >
943
+ where
944
+ T : secp256k1:: Signing
945
+ {
946
+ let onion_keys = construct_onion_keys ( & secp_ctx, & path, & session_priv) . map_err ( |_| ( ) ) ?;
947
+ let ( onion_payloads, htlc_msat, htlc_cltv) = build_onion_payloads (
948
+ & path,
949
+ total_msat,
950
+ recipient_onion,
951
+ starting_htlc_offset,
952
+ & keysend_preimage,
953
+ ) . map_err ( |_| ( ) ) ?;
954
+ let onion_packet = construct_onion_packet ( onion_payloads, onion_keys, prng_seed, & payment_hash) ?;
955
+ Ok ( ( htlc_msat, htlc_cltv, onion_packet) )
956
+ }
957
+
958
+ /// Forwarded Payment, including next hop details
959
+ #[ derive( Debug ) ]
960
+ pub struct ForwardedPayment {
961
+ /// short channel id of the next hop
962
+ pub short_channel_id : u64 ,
963
+ /// The value, in msat, of the payment after this hop's fee is deducted.
964
+ pub amt_to_forward : u64 ,
965
+ /// outgoing CLTV for the next hop
966
+ pub outgoing_cltv_value : u32 ,
967
+ /// onion packet for the next hop
968
+ pub onion_packet : msgs:: OnionPacket ,
969
+ }
970
+
971
+ /// Received payment, of either regular or blinded type
972
+ #[ derive( Debug ) ]
973
+ pub enum ReceivedPayment {
974
+ /// Regular (unblinded) payment
975
+ Regular {
976
+ /// payment_secret to authenticate sender to the receiver
977
+ payment_secret : Option < [ u8 ; 32 ] > ,
978
+ /// The total value, in msat, of the payment as received by the ultimate recipient
979
+ total_msat : Option < u64 > ,
980
+ /// custom payment metadata included in the payment
981
+ payment_metadata : Option < Vec < u8 > > ,
982
+ /// preimage used in spontaneous payment
983
+ keysend_preimage : Option < [ u8 ; 32 ] > ,
984
+ /// custom TLV records included in the payment
985
+ custom_tlvs : Vec < ( u64 , Vec < u8 > ) > ,
986
+ /// amount received
987
+ amt_msat : u64 ,
988
+ /// outgoing ctlv
989
+ outgoing_cltv_value : u32 ,
990
+ } ,
991
+ /// Blinded payment
992
+ Blinded {
993
+ /// amount received
994
+ amt_msat : u64 ,
995
+ /// amount received plus fees paid
996
+ total_msat : u64 ,
997
+ /// outgoing cltv
998
+ outgoing_cltv_value : u32 ,
999
+ /// Payment secret
1000
+ payment_secret : [ u8 ; 32 ] ,
1001
+ /// The maximum total CLTV that is acceptable when relaying a payment over this hop
1002
+ max_cltv_expiry : u32 ,
1003
+ /// The minimum value, in msat, that may be accepted by the node corresponding to this hop
1004
+ htlc_minimum_msat : u64 ,
1005
+ /// Blinding point from intro node
1006
+ intro_node_blinding_point : PublicKey ,
1007
+ }
1008
+ }
1009
+
1010
+ impl std:: convert:: TryFrom < msgs:: InboundOnionPayload > for ReceivedPayment {
1011
+ type Error = ( ) ;
1012
+ fn try_from ( pld : msgs:: InboundOnionPayload ) -> Result < Self , Self :: Error > {
1013
+ match pld {
1014
+ msgs:: InboundOnionPayload :: Forward { short_channel_id : _, amt_to_forward : _, outgoing_cltv_value : _ } => {
1015
+ Err ( ( ) )
1016
+ } ,
1017
+ msgs:: InboundOnionPayload :: Receive { payment_data, payment_metadata, keysend_preimage, custom_tlvs, amt_msat, outgoing_cltv_value } => {
1018
+ let ( payment_secret, total_msat) = match payment_data {
1019
+ Some ( p) => ( Some ( p. payment_secret . 0 ) , Some ( p. total_msat ) ) ,
1020
+ None => ( None , None ) ,
1021
+ } ;
1022
+ let keysend_preimage = keysend_preimage. map ( |p| p. 0 ) ;
1023
+ Ok ( Self :: Regular { payment_secret, total_msat, payment_metadata, keysend_preimage, custom_tlvs, amt_msat, outgoing_cltv_value } )
1024
+ } ,
1025
+ msgs:: InboundOnionPayload :: BlindedReceive { amt_msat, total_msat, outgoing_cltv_value, payment_secret, payment_constraints, intro_node_blinding_point } => {
1026
+ let payment_secret = payment_secret. 0 ;
1027
+ let max_cltv_expiry = payment_constraints. max_cltv_expiry ;
1028
+ let htlc_minimum_msat = payment_constraints. htlc_minimum_msat ;
1029
+ Ok ( Self :: Blinded { amt_msat, total_msat, outgoing_cltv_value, payment_secret, max_cltv_expiry, htlc_minimum_msat, intro_node_blinding_point } )
1030
+ }
1031
+ }
1032
+ }
1033
+ }
1034
+
1035
+ /// Received and decrypted onion payment, either of type Receive (for us), or Forward.
1036
+ #[ derive( Debug ) ]
1037
+ pub enum PeeledPayment {
1038
+ /// This onion payload was for us, not for forwarding to a next-hop.
1039
+ Receive ( ReceivedPayment ) ,
1040
+ /// This onion payload to be forwarded to next peer.
1041
+ Forward ( ForwardedPayment ) ,
1042
+ }
1043
+
1044
+ /// Unwrap one layer of an incoming HTLC, returning either or a received payment, or a another
1045
+ /// onion to forward.
1046
+ pub fn peel_payment_onion < NS : Deref > (
1047
+ shared_secret : [ u8 ; 32 ] , onion : & msgs:: OnionPacket , payment_hash : PaymentHash ,
1048
+ node_signer : & NS , secp_ctx : & Secp256k1 < secp256k1:: All >
1049
+ ) -> Result < PeeledPayment , ( ) >
1050
+ where
1051
+ NS :: Target : NodeSigner ,
1052
+ {
1053
+ let hop = decode_next_payment_hop ( shared_secret, & onion. hop_data [ ..] , onion. hmac , payment_hash, node_signer) . map_err ( |_| ( ) ) ?;
1054
+ let peeled = match hop {
1055
+ Hop :: Forward { next_hop_data, next_hop_hmac, new_packet_bytes } => {
1056
+ if let msgs:: InboundOnionPayload :: Forward { short_channel_id, amt_to_forward, outgoing_cltv_value} = next_hop_data {
1057
+
1058
+ let next_packet_pk = next_hop_pubkey ( secp_ctx, onion. public_key . unwrap ( ) , & shared_secret) ;
1059
+
1060
+ let onion_packet = msgs:: OnionPacket {
1061
+ version : 0 ,
1062
+ public_key : next_packet_pk,
1063
+ hop_data : new_packet_bytes,
1064
+ hmac : next_hop_hmac,
1065
+ } ;
1066
+ PeeledPayment :: Forward ( ForwardedPayment {
1067
+ short_channel_id,
1068
+ amt_to_forward,
1069
+ outgoing_cltv_value,
1070
+ onion_packet,
1071
+ } )
1072
+ } else {
1073
+ return Err ( ( ) ) ;
1074
+ }
1075
+ } ,
1076
+ Hop :: Receive ( inbound) => {
1077
+ let payload: ReceivedPayment = inbound. try_into ( ) . map_err ( |_| ( ) ) ?;
1078
+ PeeledPayment :: Receive ( payload)
1079
+ } ,
1080
+ } ;
1081
+ Ok ( peeled)
1082
+ }
1083
+
938
1084
pub ( crate ) fn decode_next_untagged_hop < T , R : ReadableArgs < T > , N : NextPacketBytes > ( shared_secret : [ u8 ; 32 ] , hop_data : & [ u8 ] , hmac_bytes : [ u8 ; 32 ] , read_args : T ) -> Result < ( R , Option < ( [ u8 ; 32 ] , N ) > ) , OnionDecodeErr > {
939
1085
decode_next_hop ( shared_secret, hop_data, hmac_bytes, None , read_args)
940
1086
}
0 commit comments