@@ -157,14 +157,20 @@ pub(crate) struct HTLCPreviousHopData {
157
157
outpoint : OutPoint ,
158
158
}
159
159
160
- struct ClaimableHTLC {
161
- prev_hop : HTLCPreviousHopData ,
162
- value : u64 ,
160
+ enum OnionPayload {
163
161
/// Contains a total_msat (which may differ from value if this is a Multi-Path Payment) and a
164
162
/// payment_secret which prevents path-probing attacks and can associate different HTLCs which
165
163
/// are part of the same payment.
166
- payment_data : msgs:: FinalOnionHopData ,
164
+ Invoice ( msgs:: FinalOnionHopData ) ,
165
+ /// Contains the payer-provided preimage.
166
+ Spontaneous ( PaymentPreimage ) ,
167
+ }
168
+
169
+ struct ClaimableHTLC {
170
+ prev_hop : HTLCPreviousHopData ,
167
171
cltv_expiry : u32 ,
172
+ value : u64 ,
173
+ onion_payload : OnionPayload ,
168
174
}
169
175
170
176
/// Tracks the inbound corresponding to an outbound HTLC
@@ -1475,26 +1481,45 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
1475
1481
return_err ! ( "Upstream node set CLTV to the wrong value" , 18 , & byte_utils:: be32_to_array( msg. cltv_expiry) ) ;
1476
1482
}
1477
1483
1478
- let payment_data = match next_hop_data. format {
1479
- msgs:: OnionHopDataFormat :: Legacy { .. } => None ,
1484
+ let routing = match next_hop_data. format {
1485
+ msgs:: OnionHopDataFormat :: Legacy { .. } => return_err ! ( "We require payment_secrets" , 0x4000 | 0x2000 | 3 , & [ 0 ; 0 ] ) ,
1480
1486
msgs:: OnionHopDataFormat :: NonFinalNode { .. } => return_err ! ( "Got non final data with an HMAC of 0" , 0x4000 | 22 , & [ 0 ; 0 ] ) ,
1481
- msgs:: OnionHopDataFormat :: FinalNode { payment_data, .. } => payment_data,
1482
- } ;
1487
+ msgs:: OnionHopDataFormat :: FinalNode { payment_data, keysend_preimage } => {
1488
+ if payment_data. is_some ( ) && keysend_preimage. is_some ( ) {
1489
+ return_err ! ( "We don't support MPP keysend payments" , 0x4000 |22 , & [ 0 ; 0 ] ) ;
1490
+ } else if let Some ( data) = payment_data {
1491
+ PendingHTLCRouting :: Receive {
1492
+ payment_data : data,
1493
+ incoming_cltv_expiry : msg. cltv_expiry ,
1494
+ }
1495
+ } else if let Some ( payment_preimage) = keysend_preimage {
1496
+ // We need to check that the sender knows the keysend preimage before processing this
1497
+ // payment further. Otherwise, an intermediary routing hop forwarding non-keysend-HTLC X
1498
+ // could discover the final destination of X, by probing the adjacent nodes on the route
1499
+ // with a keysend payment of identical payment hash to X and observing the processing
1500
+ // time discrepancies due to a hash collision with X.
1501
+ let hashed_preimage = PaymentHash ( Sha256 :: hash ( & payment_preimage. 0 ) . into_inner ( ) ) ;
1502
+ if hashed_preimage != msg. payment_hash {
1503
+ return_err ! ( "Payment preimage didn't match payment hash" , 0x4000 |22 , & [ 0 ; 0 ] ) ;
1504
+ }
1483
1505
1484
- if payment_data. is_none ( ) {
1485
- return_err ! ( "We require payment_secrets" , 0x4000 |0x2000 |3 , & [ 0 ; 0 ] ) ;
1486
- }
1506
+ PendingHTLCRouting :: ReceiveKeysend {
1507
+ payment_preimage,
1508
+ incoming_cltv_expiry : msg. cltv_expiry ,
1509
+ }
1510
+ } else {
1511
+ return_err ! ( "We require payment_secrets" , 0x4000 |0x2000 |3 , & [ 0 ; 0 ] ) ;
1512
+ }
1513
+ } ,
1514
+ } ;
1487
1515
1488
1516
// Note that we could obviously respond immediately with an update_fulfill_htlc
1489
1517
// message, however that would leak that we are the recipient of this payment, so
1490
1518
// instead we stay symmetric with the forwarding case, only responding (after a
1491
1519
// delay) once they've send us a commitment_signed!
1492
1520
1493
1521
PendingHTLCStatus :: Forward ( PendingHTLCInfo {
1494
- routing : PendingHTLCRouting :: Receive {
1495
- payment_data : payment_data. unwrap ( ) ,
1496
- incoming_cltv_expiry : msg. cltv_expiry ,
1497
- } ,
1522
+ routing,
1498
1523
payment_hash : msg. payment_hash . clone ( ) ,
1499
1524
incoming_shared_secret : shared_secret,
1500
1525
amt_to_forward : next_hop_data. amt_to_forward ,
@@ -2252,9 +2277,17 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
2252
2277
for forward_info in pending_forwards. drain ( ..) {
2253
2278
match forward_info {
2254
2279
HTLCForwardInfo :: AddHTLC { prev_short_channel_id, prev_htlc_id, forward_info : PendingHTLCInfo {
2255
- routing : PendingHTLCRouting :: Receive { payment_data, incoming_cltv_expiry } ,
2256
- incoming_shared_secret, payment_hash, amt_to_forward, .. } ,
2280
+ routing, incoming_shared_secret, payment_hash, amt_to_forward, .. } ,
2257
2281
prev_funding_outpoint } => {
2282
+ let ( cltv_expiry, onion_payload) = match routing {
2283
+ PendingHTLCRouting :: Receive { payment_data, incoming_cltv_expiry } =>
2284
+ ( incoming_cltv_expiry, OnionPayload :: Invoice ( payment_data) ) ,
2285
+ PendingHTLCRouting :: ReceiveKeysend { payment_preimage, incoming_cltv_expiry } =>
2286
+ ( incoming_cltv_expiry, OnionPayload :: Spontaneous ( payment_preimage) ) ,
2287
+ _ => {
2288
+ panic ! ( "short_channel_id == 0 should imply any pending_forward entries are of type Receive" ) ;
2289
+ }
2290
+ } ;
2258
2291
let claimable_htlc = ClaimableHTLC {
2259
2292
prev_hop : HTLCPreviousHopData {
2260
2293
short_channel_id : prev_short_channel_id,
@@ -2263,8 +2296,8 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
2263
2296
incoming_packet_shared_secret : incoming_shared_secret,
2264
2297
} ,
2265
2298
value : amt_to_forward,
2266
- payment_data : payment_data . clone ( ) ,
2267
- cltv_expiry : incoming_cltv_expiry ,
2299
+ cltv_expiry ,
2300
+ onion_payload ,
2268
2301
} ;
2269
2302
2270
2303
macro_rules! fail_htlc {
@@ -2293,10 +2326,38 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
2293
2326
let mut payment_secrets = self . pending_inbound_payments . lock ( ) . unwrap ( ) ;
2294
2327
match payment_secrets. entry ( payment_hash) {
2295
2328
hash_map:: Entry :: Vacant ( _) => {
2296
- log_trace ! ( self . logger, "Failing new HTLC with payment_hash {} as we didn't have a corresponding inbound payment." , log_bytes!( payment_hash. 0 ) ) ;
2297
- fail_htlc ! ( claimable_htlc) ;
2329
+ match claimable_htlc. onion_payload {
2330
+ OnionPayload :: Invoice ( _) => {
2331
+ log_trace ! ( self . logger, "Failing new HTLC with payment_hash {} as we didn't have a corresponding inbound payment." , log_bytes!( payment_hash. 0 ) ) ;
2332
+ fail_htlc ! ( claimable_htlc) ;
2333
+ } ,
2334
+ OnionPayload :: Spontaneous ( preimage) => {
2335
+ match channel_state. claimable_htlcs . entry ( payment_hash) {
2336
+ hash_map:: Entry :: Vacant ( e) => {
2337
+ e. insert ( vec ! [ claimable_htlc] ) ;
2338
+ new_events. push ( events:: Event :: PaymentReceived {
2339
+ payment_hash,
2340
+ amt : amt_to_forward,
2341
+ purpose : events:: PaymentPurpose :: SpontaneousPayment ( preimage) ,
2342
+ } ) ;
2343
+ } ,
2344
+ hash_map:: Entry :: Occupied ( _) => {
2345
+ log_trace ! ( self . logger, "Failing new keysend HTLC with payment_hash {} for a duplicative payment hash" , log_bytes!( payment_hash. 0 ) ) ;
2346
+ fail_htlc ! ( claimable_htlc) ;
2347
+ }
2348
+ }
2349
+ }
2350
+ }
2298
2351
} ,
2299
2352
hash_map:: Entry :: Occupied ( inbound_payment) => {
2353
+ let payment_data =
2354
+ if let OnionPayload :: Invoice ( ref data) = claimable_htlc. onion_payload {
2355
+ data. clone ( )
2356
+ } else {
2357
+ log_trace ! ( self . logger, "Failing new keysend HTLC with payment_hash {} because we already have an inbound payment with the same payment hash" , log_bytes!( payment_hash. 0 ) ) ;
2358
+ fail_htlc ! ( claimable_htlc) ;
2359
+ continue
2360
+ } ;
2300
2361
if inbound_payment. get ( ) . payment_secret != payment_data. payment_secret {
2301
2362
log_trace ! ( self . logger, "Failing new HTLC with payment_hash {} as it didn't match our expected payment secret." , log_bytes!( payment_hash. 0 ) ) ;
2302
2363
fail_htlc ! ( claimable_htlc) ;
@@ -2308,15 +2369,27 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
2308
2369
let mut total_value = 0 ;
2309
2370
let htlcs = channel_state. claimable_htlcs . entry ( payment_hash)
2310
2371
. or_insert ( Vec :: new ( ) ) ;
2372
+ if htlcs. len ( ) == 1 {
2373
+ if let OnionPayload :: Spontaneous ( _) = htlcs[ 0 ] . onion_payload {
2374
+ log_trace ! ( self . logger, "Failing new HTLC with payment_hash {} as we already had an existing keysend HTLC with the same payment hash" , log_bytes!( payment_hash. 0 ) ) ;
2375
+ fail_htlc ! ( claimable_htlc) ;
2376
+ continue
2377
+ }
2378
+ }
2311
2379
htlcs. push ( claimable_htlc) ;
2312
2380
for htlc in htlcs. iter ( ) {
2313
2381
total_value += htlc. value ;
2314
- if htlc. payment_data . total_msat != payment_data. total_msat {
2315
- log_trace ! ( self . logger, "Failing HTLCs with payment_hash {} as the HTLCs had inconsistent total values (eg {} and {})" ,
2316
- log_bytes!( payment_hash. 0 ) , payment_data. total_msat, htlc. payment_data. total_msat) ;
2317
- total_value = msgs:: MAX_VALUE_MSAT ;
2382
+ match & htlc. onion_payload {
2383
+ OnionPayload :: Invoice ( htlc_payment_data) => {
2384
+ if htlc_payment_data. total_msat != payment_data. total_msat {
2385
+ log_trace ! ( self . logger, "Failing HTLCs with payment_hash {} as the HTLCs had inconsistent total values (eg {} and {})" ,
2386
+ log_bytes!( payment_hash. 0 ) , payment_data. total_msat, htlc_payment_data. total_msat) ;
2387
+ total_value = msgs:: MAX_VALUE_MSAT ;
2388
+ }
2389
+ if total_value >= msgs:: MAX_VALUE_MSAT { break ; }
2390
+ } ,
2391
+ _ => unreachable ! ( ) ,
2318
2392
}
2319
- if total_value >= msgs:: MAX_VALUE_MSAT { break ; }
2320
2393
}
2321
2394
if total_value >= msgs:: MAX_VALUE_MSAT || total_value > payment_data. total_msat {
2322
2395
log_trace ! ( self . logger, "Failing HTLCs with payment_hash {} as the total value {} ran over expected value {} (or HTLCs were inconsistent)" ,
@@ -2347,9 +2420,6 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
2347
2420
} ,
2348
2421
} ;
2349
2422
} ,
2350
- HTLCForwardInfo :: AddHTLC { .. } => {
2351
- panic ! ( "short_channel_id == 0 should imply any pending_forward entries are of type Receive" ) ;
2352
- } ,
2353
2423
HTLCForwardInfo :: FailHTLC { .. } => {
2354
2424
panic ! ( "Got pending fail of our own HTLC" ) ;
2355
2425
}
@@ -4509,12 +4579,63 @@ impl_writeable_tlv_based!(HTLCPreviousHopData, {
4509
4579
( 6 , incoming_packet_shared_secret, required)
4510
4580
} ) ;
4511
4581
4512
- impl_writeable_tlv_based ! ( ClaimableHTLC , {
4513
- ( 0 , prev_hop, required) ,
4514
- ( 2 , value, required) ,
4515
- ( 4 , payment_data, required) ,
4516
- ( 6 , cltv_expiry, required) ,
4517
- } ) ;
4582
+ impl Writeable for ClaimableHTLC {
4583
+ fn write < W : Writer > ( & self , writer : & mut W ) -> Result < ( ) , :: std:: io:: Error > {
4584
+ let payment_data = match & self . onion_payload {
4585
+ OnionPayload :: Invoice ( data) => Some ( data. clone ( ) ) ,
4586
+ _ => None ,
4587
+ } ;
4588
+ let keysend_preimage = match self . onion_payload {
4589
+ OnionPayload :: Invoice ( _) => None ,
4590
+ OnionPayload :: Spontaneous ( preimage) => Some ( preimage. clone ( ) ) ,
4591
+ } ;
4592
+ write_tlv_fields !
4593
+ ( writer,
4594
+ {
4595
+ ( 0 , self . prev_hop, required) , ( 2 , self . value, required) ,
4596
+ ( 4 , payment_data, option) , ( 6 , self . cltv_expiry, required) ,
4597
+ ( 8 , keysend_preimage, option) ,
4598
+ } ) ;
4599
+ Ok ( ( ) )
4600
+ }
4601
+ }
4602
+
4603
+ impl Readable for ClaimableHTLC {
4604
+ fn read < R : Read > ( reader : & mut R ) -> Result < Self , DecodeError > {
4605
+ let mut prev_hop = :: util:: ser:: OptionDeserWrapper ( None ) ;
4606
+ let mut value = 0 ;
4607
+ let mut payment_data: Option < msgs:: FinalOnionHopData > = None ;
4608
+ let mut cltv_expiry = 0 ;
4609
+ let mut keysend_preimage: Option < PaymentPreimage > = None ;
4610
+ read_tlv_fields !
4611
+ ( reader,
4612
+ {
4613
+ ( 0 , prev_hop, required) , ( 2 , value, required) ,
4614
+ ( 4 , payment_data, option) , ( 6 , cltv_expiry, required) ,
4615
+ ( 8 , keysend_preimage, option)
4616
+ } ) ;
4617
+ let onion_payload = match keysend_preimage {
4618
+ Some ( p) => {
4619
+ if payment_data. is_some ( ) {
4620
+ return Err ( DecodeError :: InvalidValue )
4621
+ }
4622
+ OnionPayload :: Spontaneous ( p)
4623
+ } ,
4624
+ None => {
4625
+ if payment_data. is_none ( ) {
4626
+ return Err ( DecodeError :: InvalidValue )
4627
+ }
4628
+ OnionPayload :: Invoice ( payment_data. unwrap ( ) )
4629
+ } ,
4630
+ } ;
4631
+ Ok ( Self {
4632
+ prev_hop : prev_hop. 0 . unwrap ( ) ,
4633
+ value,
4634
+ onion_payload,
4635
+ cltv_expiry,
4636
+ } )
4637
+ }
4638
+ }
4518
4639
4519
4640
impl_writeable_tlv_based_enum ! ( HTLCSource ,
4520
4641
( 0 , OutboundRoute ) => {
0 commit comments