Skip to content

Commit 790d26f

Browse files
authored
Merge pull request #1761 from TheBlueMatt/2022-10-user-idempotency-token
Provide `send_payment` idempotency guarantees
2 parents d15b7cb + 0df712a commit 790d26f

17 files changed

+773
-433
lines changed

fuzz/src/chanmon_consistency.rs

+71-64
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ use lightning::chain::transaction::OutPoint;
3838
use lightning::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator};
3939
use lightning::chain::keysinterface::{KeyMaterial, KeysInterface, InMemorySigner, Recipient};
4040
use lightning::ln::{PaymentHash, PaymentPreimage, PaymentSecret};
41-
use lightning::ln::channelmanager::{self, ChainParameters, ChannelManager, PaymentSendFailure, ChannelManagerReadArgs};
41+
use lightning::ln::channelmanager::{self, ChainParameters, ChannelManager, PaymentSendFailure, ChannelManagerReadArgs, PaymentId};
4242
use lightning::ln::channel::FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE;
4343
use lightning::ln::msgs::{CommitmentUpdate, ChannelMessageHandler, DecodeError, UpdateAddHTLC, Init};
4444
use lightning::ln::script::ShutdownScript;
@@ -308,9 +308,12 @@ fn get_payment_secret_hash(dest: &ChanMan, payment_id: &mut u8) -> Option<(Payme
308308
}
309309

310310
#[inline]
311-
fn send_payment(source: &ChanMan, dest: &ChanMan, dest_chan_id: u64, amt: u64, payment_id: &mut u8) -> bool {
311+
fn send_payment(source: &ChanMan, dest: &ChanMan, dest_chan_id: u64, amt: u64, payment_id: &mut u8, payment_idx: &mut u64) -> bool {
312312
let (payment_secret, payment_hash) =
313313
if let Some((secret, hash)) = get_payment_secret_hash(dest, payment_id) { (secret, hash) } else { return true; };
314+
let mut payment_id = [0; 32];
315+
payment_id[0..8].copy_from_slice(&payment_idx.to_ne_bytes());
316+
*payment_idx += 1;
314317
if let Err(err) = source.send_payment(&Route {
315318
paths: vec![vec![RouteHop {
316319
pubkey: dest.get_our_node_id(),
@@ -321,15 +324,18 @@ fn send_payment(source: &ChanMan, dest: &ChanMan, dest_chan_id: u64, amt: u64, p
321324
cltv_expiry_delta: 200,
322325
}]],
323326
payment_params: None,
324-
}, payment_hash, &Some(payment_secret)) {
327+
}, payment_hash, &Some(payment_secret), PaymentId(payment_id)) {
325328
check_payment_err(err);
326329
false
327330
} else { true }
328331
}
329332
#[inline]
330-
fn send_hop_payment(source: &ChanMan, middle: &ChanMan, middle_chan_id: u64, dest: &ChanMan, dest_chan_id: u64, amt: u64, payment_id: &mut u8) -> bool {
333+
fn send_hop_payment(source: &ChanMan, middle: &ChanMan, middle_chan_id: u64, dest: &ChanMan, dest_chan_id: u64, amt: u64, payment_id: &mut u8, payment_idx: &mut u64) -> bool {
331334
let (payment_secret, payment_hash) =
332335
if let Some((secret, hash)) = get_payment_secret_hash(dest, payment_id) { (secret, hash) } else { return true; };
336+
let mut payment_id = [0; 32];
337+
payment_id[0..8].copy_from_slice(&payment_idx.to_ne_bytes());
338+
*payment_idx += 1;
333339
if let Err(err) = source.send_payment(&Route {
334340
paths: vec![vec![RouteHop {
335341
pubkey: middle.get_our_node_id(),
@@ -347,7 +353,7 @@ fn send_hop_payment(source: &ChanMan, middle: &ChanMan, middle_chan_id: u64, des
347353
cltv_expiry_delta: 200,
348354
}]],
349355
payment_params: None,
350-
}, payment_hash, &Some(payment_secret)) {
356+
}, payment_hash, &Some(payment_secret), PaymentId(payment_id)) {
351357
check_payment_err(err);
352358
false
353359
} else { true }
@@ -553,6 +559,7 @@ pub fn do_test<Out: Output>(data: &[u8], underlying_out: Out) {
553559
let chan_b = nodes[2].list_usable_channels()[0].short_channel_id.unwrap();
554560

555561
let mut payment_id: u8 = 0;
562+
let mut payment_idx: u64 = 0;
556563

557564
let mut chan_a_disconnected = false;
558565
let mut chan_b_disconnected = false;
@@ -1037,61 +1044,61 @@ pub fn do_test<Out: Output>(data: &[u8], underlying_out: Out) {
10371044
},
10381045

10391046
// 1/10th the channel size:
1040-
0x30 => { send_payment(&nodes[0], &nodes[1], chan_a, 10_000_000, &mut payment_id); },
1041-
0x31 => { send_payment(&nodes[1], &nodes[0], chan_a, 10_000_000, &mut payment_id); },
1042-
0x32 => { send_payment(&nodes[1], &nodes[2], chan_b, 10_000_000, &mut payment_id); },
1043-
0x33 => { send_payment(&nodes[2], &nodes[1], chan_b, 10_000_000, &mut payment_id); },
1044-
0x34 => { send_hop_payment(&nodes[0], &nodes[1], chan_a, &nodes[2], chan_b, 10_000_000, &mut payment_id); },
1045-
0x35 => { send_hop_payment(&nodes[2], &nodes[1], chan_b, &nodes[0], chan_a, 10_000_000, &mut payment_id); },
1046-
1047-
0x38 => { send_payment(&nodes[0], &nodes[1], chan_a, 1_000_000, &mut payment_id); },
1048-
0x39 => { send_payment(&nodes[1], &nodes[0], chan_a, 1_000_000, &mut payment_id); },
1049-
0x3a => { send_payment(&nodes[1], &nodes[2], chan_b, 1_000_000, &mut payment_id); },
1050-
0x3b => { send_payment(&nodes[2], &nodes[1], chan_b, 1_000_000, &mut payment_id); },
1051-
0x3c => { send_hop_payment(&nodes[0], &nodes[1], chan_a, &nodes[2], chan_b, 1_000_000, &mut payment_id); },
1052-
0x3d => { send_hop_payment(&nodes[2], &nodes[1], chan_b, &nodes[0], chan_a, 1_000_000, &mut payment_id); },
1053-
1054-
0x40 => { send_payment(&nodes[0], &nodes[1], chan_a, 100_000, &mut payment_id); },
1055-
0x41 => { send_payment(&nodes[1], &nodes[0], chan_a, 100_000, &mut payment_id); },
1056-
0x42 => { send_payment(&nodes[1], &nodes[2], chan_b, 100_000, &mut payment_id); },
1057-
0x43 => { send_payment(&nodes[2], &nodes[1], chan_b, 100_000, &mut payment_id); },
1058-
0x44 => { send_hop_payment(&nodes[0], &nodes[1], chan_a, &nodes[2], chan_b, 100_000, &mut payment_id); },
1059-
0x45 => { send_hop_payment(&nodes[2], &nodes[1], chan_b, &nodes[0], chan_a, 100_000, &mut payment_id); },
1060-
1061-
0x48 => { send_payment(&nodes[0], &nodes[1], chan_a, 10_000, &mut payment_id); },
1062-
0x49 => { send_payment(&nodes[1], &nodes[0], chan_a, 10_000, &mut payment_id); },
1063-
0x4a => { send_payment(&nodes[1], &nodes[2], chan_b, 10_000, &mut payment_id); },
1064-
0x4b => { send_payment(&nodes[2], &nodes[1], chan_b, 10_000, &mut payment_id); },
1065-
0x4c => { send_hop_payment(&nodes[0], &nodes[1], chan_a, &nodes[2], chan_b, 10_000, &mut payment_id); },
1066-
0x4d => { send_hop_payment(&nodes[2], &nodes[1], chan_b, &nodes[0], chan_a, 10_000, &mut payment_id); },
1067-
1068-
0x50 => { send_payment(&nodes[0], &nodes[1], chan_a, 1_000, &mut payment_id); },
1069-
0x51 => { send_payment(&nodes[1], &nodes[0], chan_a, 1_000, &mut payment_id); },
1070-
0x52 => { send_payment(&nodes[1], &nodes[2], chan_b, 1_000, &mut payment_id); },
1071-
0x53 => { send_payment(&nodes[2], &nodes[1], chan_b, 1_000, &mut payment_id); },
1072-
0x54 => { send_hop_payment(&nodes[0], &nodes[1], chan_a, &nodes[2], chan_b, 1_000, &mut payment_id); },
1073-
0x55 => { send_hop_payment(&nodes[2], &nodes[1], chan_b, &nodes[0], chan_a, 1_000, &mut payment_id); },
1074-
1075-
0x58 => { send_payment(&nodes[0], &nodes[1], chan_a, 100, &mut payment_id); },
1076-
0x59 => { send_payment(&nodes[1], &nodes[0], chan_a, 100, &mut payment_id); },
1077-
0x5a => { send_payment(&nodes[1], &nodes[2], chan_b, 100, &mut payment_id); },
1078-
0x5b => { send_payment(&nodes[2], &nodes[1], chan_b, 100, &mut payment_id); },
1079-
0x5c => { send_hop_payment(&nodes[0], &nodes[1], chan_a, &nodes[2], chan_b, 100, &mut payment_id); },
1080-
0x5d => { send_hop_payment(&nodes[2], &nodes[1], chan_b, &nodes[0], chan_a, 100, &mut payment_id); },
1081-
1082-
0x60 => { send_payment(&nodes[0], &nodes[1], chan_a, 10, &mut payment_id); },
1083-
0x61 => { send_payment(&nodes[1], &nodes[0], chan_a, 10, &mut payment_id); },
1084-
0x62 => { send_payment(&nodes[1], &nodes[2], chan_b, 10, &mut payment_id); },
1085-
0x63 => { send_payment(&nodes[2], &nodes[1], chan_b, 10, &mut payment_id); },
1086-
0x64 => { send_hop_payment(&nodes[0], &nodes[1], chan_a, &nodes[2], chan_b, 10, &mut payment_id); },
1087-
0x65 => { send_hop_payment(&nodes[2], &nodes[1], chan_b, &nodes[0], chan_a, 10, &mut payment_id); },
1088-
1089-
0x68 => { send_payment(&nodes[0], &nodes[1], chan_a, 1, &mut payment_id); },
1090-
0x69 => { send_payment(&nodes[1], &nodes[0], chan_a, 1, &mut payment_id); },
1091-
0x6a => { send_payment(&nodes[1], &nodes[2], chan_b, 1, &mut payment_id); },
1092-
0x6b => { send_payment(&nodes[2], &nodes[1], chan_b, 1, &mut payment_id); },
1093-
0x6c => { send_hop_payment(&nodes[0], &nodes[1], chan_a, &nodes[2], chan_b, 1, &mut payment_id); },
1094-
0x6d => { send_hop_payment(&nodes[2], &nodes[1], chan_b, &nodes[0], chan_a, 1, &mut payment_id); },
1047+
0x30 => { send_payment(&nodes[0], &nodes[1], chan_a, 10_000_000, &mut payment_id, &mut payment_idx); },
1048+
0x31 => { send_payment(&nodes[1], &nodes[0], chan_a, 10_000_000, &mut payment_id, &mut payment_idx); },
1049+
0x32 => { send_payment(&nodes[1], &nodes[2], chan_b, 10_000_000, &mut payment_id, &mut payment_idx); },
1050+
0x33 => { send_payment(&nodes[2], &nodes[1], chan_b, 10_000_000, &mut payment_id, &mut payment_idx); },
1051+
0x34 => { send_hop_payment(&nodes[0], &nodes[1], chan_a, &nodes[2], chan_b, 10_000_000, &mut payment_id, &mut payment_idx); },
1052+
0x35 => { send_hop_payment(&nodes[2], &nodes[1], chan_b, &nodes[0], chan_a, 10_000_000, &mut payment_id, &mut payment_idx); },
1053+
1054+
0x38 => { send_payment(&nodes[0], &nodes[1], chan_a, 1_000_000, &mut payment_id, &mut payment_idx); },
1055+
0x39 => { send_payment(&nodes[1], &nodes[0], chan_a, 1_000_000, &mut payment_id, &mut payment_idx); },
1056+
0x3a => { send_payment(&nodes[1], &nodes[2], chan_b, 1_000_000, &mut payment_id, &mut payment_idx); },
1057+
0x3b => { send_payment(&nodes[2], &nodes[1], chan_b, 1_000_000, &mut payment_id, &mut payment_idx); },
1058+
0x3c => { send_hop_payment(&nodes[0], &nodes[1], chan_a, &nodes[2], chan_b, 1_000_000, &mut payment_id, &mut payment_idx); },
1059+
0x3d => { send_hop_payment(&nodes[2], &nodes[1], chan_b, &nodes[0], chan_a, 1_000_000, &mut payment_id, &mut payment_idx); },
1060+
1061+
0x40 => { send_payment(&nodes[0], &nodes[1], chan_a, 100_000, &mut payment_id, &mut payment_idx); },
1062+
0x41 => { send_payment(&nodes[1], &nodes[0], chan_a, 100_000, &mut payment_id, &mut payment_idx); },
1063+
0x42 => { send_payment(&nodes[1], &nodes[2], chan_b, 100_000, &mut payment_id, &mut payment_idx); },
1064+
0x43 => { send_payment(&nodes[2], &nodes[1], chan_b, 100_000, &mut payment_id, &mut payment_idx); },
1065+
0x44 => { send_hop_payment(&nodes[0], &nodes[1], chan_a, &nodes[2], chan_b, 100_000, &mut payment_id, &mut payment_idx); },
1066+
0x45 => { send_hop_payment(&nodes[2], &nodes[1], chan_b, &nodes[0], chan_a, 100_000, &mut payment_id, &mut payment_idx); },
1067+
1068+
0x48 => { send_payment(&nodes[0], &nodes[1], chan_a, 10_000, &mut payment_id, &mut payment_idx); },
1069+
0x49 => { send_payment(&nodes[1], &nodes[0], chan_a, 10_000, &mut payment_id, &mut payment_idx); },
1070+
0x4a => { send_payment(&nodes[1], &nodes[2], chan_b, 10_000, &mut payment_id, &mut payment_idx); },
1071+
0x4b => { send_payment(&nodes[2], &nodes[1], chan_b, 10_000, &mut payment_id, &mut payment_idx); },
1072+
0x4c => { send_hop_payment(&nodes[0], &nodes[1], chan_a, &nodes[2], chan_b, 10_000, &mut payment_id, &mut payment_idx); },
1073+
0x4d => { send_hop_payment(&nodes[2], &nodes[1], chan_b, &nodes[0], chan_a, 10_000, &mut payment_id, &mut payment_idx); },
1074+
1075+
0x50 => { send_payment(&nodes[0], &nodes[1], chan_a, 1_000, &mut payment_id, &mut payment_idx); },
1076+
0x51 => { send_payment(&nodes[1], &nodes[0], chan_a, 1_000, &mut payment_id, &mut payment_idx); },
1077+
0x52 => { send_payment(&nodes[1], &nodes[2], chan_b, 1_000, &mut payment_id, &mut payment_idx); },
1078+
0x53 => { send_payment(&nodes[2], &nodes[1], chan_b, 1_000, &mut payment_id, &mut payment_idx); },
1079+
0x54 => { send_hop_payment(&nodes[0], &nodes[1], chan_a, &nodes[2], chan_b, 1_000, &mut payment_id, &mut payment_idx); },
1080+
0x55 => { send_hop_payment(&nodes[2], &nodes[1], chan_b, &nodes[0], chan_a, 1_000, &mut payment_id, &mut payment_idx); },
1081+
1082+
0x58 => { send_payment(&nodes[0], &nodes[1], chan_a, 100, &mut payment_id, &mut payment_idx); },
1083+
0x59 => { send_payment(&nodes[1], &nodes[0], chan_a, 100, &mut payment_id, &mut payment_idx); },
1084+
0x5a => { send_payment(&nodes[1], &nodes[2], chan_b, 100, &mut payment_id, &mut payment_idx); },
1085+
0x5b => { send_payment(&nodes[2], &nodes[1], chan_b, 100, &mut payment_id, &mut payment_idx); },
1086+
0x5c => { send_hop_payment(&nodes[0], &nodes[1], chan_a, &nodes[2], chan_b, 100, &mut payment_id, &mut payment_idx); },
1087+
0x5d => { send_hop_payment(&nodes[2], &nodes[1], chan_b, &nodes[0], chan_a, 100, &mut payment_id, &mut payment_idx); },
1088+
1089+
0x60 => { send_payment(&nodes[0], &nodes[1], chan_a, 10, &mut payment_id, &mut payment_idx); },
1090+
0x61 => { send_payment(&nodes[1], &nodes[0], chan_a, 10, &mut payment_id, &mut payment_idx); },
1091+
0x62 => { send_payment(&nodes[1], &nodes[2], chan_b, 10, &mut payment_id, &mut payment_idx); },
1092+
0x63 => { send_payment(&nodes[2], &nodes[1], chan_b, 10, &mut payment_id, &mut payment_idx); },
1093+
0x64 => { send_hop_payment(&nodes[0], &nodes[1], chan_a, &nodes[2], chan_b, 10, &mut payment_id, &mut payment_idx); },
1094+
0x65 => { send_hop_payment(&nodes[2], &nodes[1], chan_b, &nodes[0], chan_a, 10, &mut payment_id, &mut payment_idx); },
1095+
1096+
0x68 => { send_payment(&nodes[0], &nodes[1], chan_a, 1, &mut payment_id, &mut payment_idx); },
1097+
0x69 => { send_payment(&nodes[1], &nodes[0], chan_a, 1, &mut payment_id, &mut payment_idx); },
1098+
0x6a => { send_payment(&nodes[1], &nodes[2], chan_b, 1, &mut payment_id, &mut payment_idx); },
1099+
0x6b => { send_payment(&nodes[2], &nodes[1], chan_b, 1, &mut payment_id, &mut payment_idx); },
1100+
0x6c => { send_hop_payment(&nodes[0], &nodes[1], chan_a, &nodes[2], chan_b, 1, &mut payment_id, &mut payment_idx); },
1101+
0x6d => { send_hop_payment(&nodes[2], &nodes[1], chan_b, &nodes[0], chan_a, 1, &mut payment_id, &mut payment_idx); },
10951102

10961103
0x80 => {
10971104
let max_feerate = last_htlc_clear_fee_a * FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE as u32;
@@ -1174,11 +1181,11 @@ pub fn do_test<Out: Output>(data: &[u8], underlying_out: Out) {
11741181

11751182
// Finally, make sure that at least one end of each channel can make a substantial payment
11761183
assert!(
1177-
send_payment(&nodes[0], &nodes[1], chan_a, 10_000_000, &mut payment_id) ||
1178-
send_payment(&nodes[1], &nodes[0], chan_a, 10_000_000, &mut payment_id));
1184+
send_payment(&nodes[0], &nodes[1], chan_a, 10_000_000, &mut payment_id, &mut payment_idx) ||
1185+
send_payment(&nodes[1], &nodes[0], chan_a, 10_000_000, &mut payment_id, &mut payment_idx));
11791186
assert!(
1180-
send_payment(&nodes[1], &nodes[2], chan_b, 10_000_000, &mut payment_id) ||
1181-
send_payment(&nodes[2], &nodes[1], chan_b, 10_000_000, &mut payment_id));
1187+
send_payment(&nodes[1], &nodes[2], chan_b, 10_000_000, &mut payment_id, &mut payment_idx) ||
1188+
send_payment(&nodes[2], &nodes[1], chan_b, 10_000_000, &mut payment_id, &mut payment_idx));
11821189

11831190
last_htlc_clear_fee_a = fee_est_a.ret_val.load(atomic::Ordering::Acquire);
11841191
last_htlc_clear_fee_b = fee_est_b.ret_val.load(atomic::Ordering::Acquire);

fuzz/src/full_stack.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ use lightning::chain::chainmonitor;
3535
use lightning::chain::transaction::OutPoint;
3636
use lightning::chain::keysinterface::{InMemorySigner, Recipient, KeyMaterial, KeysInterface};
3737
use lightning::ln::{PaymentHash, PaymentPreimage, PaymentSecret};
38-
use lightning::ln::channelmanager::{ChainParameters, ChannelManager};
38+
use lightning::ln::channelmanager::{ChainParameters, ChannelManager, PaymentId};
3939
use lightning::ln::peer_handler::{MessageHandler,PeerManager,SocketDescriptor,IgnoringMessageHandler};
4040
use lightning::ln::msgs::DecodeError;
4141
use lightning::ln::script::ShutdownScript;
@@ -481,7 +481,7 @@ pub fn do_test(data: &[u8], logger: &Arc<dyn Logger>) {
481481
sha.input(&payment_hash.0[..]);
482482
payment_hash.0 = Sha256::from_engine(sha).into_inner();
483483
payments_sent += 1;
484-
match channelmanager.send_payment(&route, payment_hash, &None) {
484+
match channelmanager.send_payment(&route, payment_hash, &None, PaymentId(payment_hash.0)) {
485485
Ok(_) => {},
486486
Err(_) => return,
487487
}
@@ -509,7 +509,7 @@ pub fn do_test(data: &[u8], logger: &Arc<dyn Logger>) {
509509
let mut payment_secret = PaymentSecret([0; 32]);
510510
payment_secret.0[0..8].copy_from_slice(&be64_to_array(payments_sent));
511511
payments_sent += 1;
512-
match channelmanager.send_payment(&route, payment_hash, &Some(payment_secret)) {
512+
match channelmanager.send_payment(&route, payment_hash, &Some(payment_secret), PaymentId(payment_hash.0)) {
513513
Ok(_) => {},
514514
Err(_) => return,
515515
}

0 commit comments

Comments
 (0)