Skip to content

Commit 483eccf

Browse files
committed
Add send_probe and introduce probing cookies
When we send payment probes, we generate the [`PaymentHash`] based on a probing cookie secret and a random [`PaymentId`]. This allows us to discern probes from real payments, without keeping additional state.
1 parent 790abc5 commit 483eccf

File tree

6 files changed

+447
-34
lines changed

6 files changed

+447
-34
lines changed

lightning-invoice/src/payment.rs

+80-12
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@
9494
//! # ) -> u64 { 0 }
9595
//! # fn payment_path_failed(&mut self, _path: &[&RouteHop], _short_channel_id: u64) {}
9696
//! # fn payment_path_successful(&mut self, _path: &[&RouteHop]) {}
97+
//! # fn probe_failed(&mut self, _path: &[&RouteHop], _short_channel_id: u64) {}
98+
//! # fn probe_successful(&mut self, _path: &[&RouteHop]) {}
9799
//! # }
98100
//! #
99101
//! # struct FakeLogger {}
@@ -584,6 +586,18 @@ where
584586
.map_or(1, |attempts| attempts.count + 1);
585587
log_trace!(self.logger, "Payment {} succeeded (attempts: {})", log_bytes!(payment_hash.0), attempts);
586588
},
589+
Event::ProbeSuccessful { payment_hash, path, .. } => {
590+
log_trace!(self.logger, "Probe payment {} of {}msat was successful", log_bytes!(payment_hash.0), path.last().unwrap().fee_msat);
591+
let path = path.iter().collect::<Vec<_>>();
592+
self.scorer.lock().probe_successful(&path);
593+
},
594+
Event::ProbeFailed { payment_hash, path, short_channel_id, .. } => {
595+
if let Some(short_channel_id) = short_channel_id {
596+
log_trace!(self.logger, "Probe payment {} of {}msat failed at channel {}", log_bytes!(payment_hash.0), path.last().unwrap().fee_msat, *short_channel_id);
597+
let path = path.iter().collect::<Vec<_>>();
598+
self.scorer.lock().probe_failed(&path, *short_channel_id);
599+
}
600+
},
587601
_ => {},
588602
}
589603

@@ -1296,7 +1310,7 @@ mod tests {
12961310
.expect_send(Amount::ForInvoice(final_value_msat))
12971311
.expect_send(Amount::OnRetry(final_value_msat / 2));
12981312
let router = TestRouter {};
1299-
let scorer = RefCell::new(TestScorer::new().expect(PaymentPath::Failure {
1313+
let scorer = RefCell::new(TestScorer::new().expect(TestResult::PaymentFailure {
13001314
path: path.clone(), short_channel_id: path[0].short_channel_id,
13011315
}));
13021316
let logger = TestLogger::new();
@@ -1332,8 +1346,8 @@ mod tests {
13321346
let payer = TestPayer::new().expect_send(Amount::ForInvoice(final_value_msat));
13331347
let router = TestRouter {};
13341348
let scorer = RefCell::new(TestScorer::new()
1335-
.expect(PaymentPath::Success { path: route.paths[0].clone() })
1336-
.expect(PaymentPath::Success { path: route.paths[1].clone() })
1349+
.expect(TestResult::PaymentSuccess { path: route.paths[0].clone() })
1350+
.expect(TestResult::PaymentSuccess { path: route.paths[1].clone() })
13371351
);
13381352
let logger = TestLogger::new();
13391353
let invoice_payer =
@@ -1416,13 +1430,15 @@ mod tests {
14161430
}
14171431

14181432
struct TestScorer {
1419-
expectations: Option<VecDeque<PaymentPath>>,
1433+
expectations: Option<VecDeque<TestResult>>,
14201434
}
14211435

14221436
#[derive(Debug)]
1423-
enum PaymentPath {
1424-
Failure { path: Vec<RouteHop>, short_channel_id: u64 },
1425-
Success { path: Vec<RouteHop> },
1437+
enum TestResult {
1438+
PaymentFailure { path: Vec<RouteHop>, short_channel_id: u64 },
1439+
PaymentSuccess { path: Vec<RouteHop> },
1440+
ProbeFailure { path: Vec<RouteHop>, short_channel_id: u64 },
1441+
ProbeSuccess { path: Vec<RouteHop> },
14261442
}
14271443

14281444
impl TestScorer {
@@ -1432,7 +1448,7 @@ mod tests {
14321448
}
14331449
}
14341450

1435-
fn expect(mut self, expectation: PaymentPath) -> Self {
1451+
fn expect(mut self, expectation: TestResult) -> Self {
14361452
self.expectations.get_or_insert_with(|| VecDeque::new()).push_back(expectation);
14371453
self
14381454
}
@@ -1451,13 +1467,19 @@ mod tests {
14511467
fn payment_path_failed(&mut self, actual_path: &[&RouteHop], actual_short_channel_id: u64) {
14521468
if let Some(expectations) = &mut self.expectations {
14531469
match expectations.pop_front() {
1454-
Some(PaymentPath::Failure { path, short_channel_id }) => {
1470+
Some(TestResult::PaymentFailure { path, short_channel_id }) => {
14551471
assert_eq!(actual_path, &path.iter().collect::<Vec<_>>()[..]);
14561472
assert_eq!(actual_short_channel_id, short_channel_id);
14571473
},
1458-
Some(PaymentPath::Success { path }) => {
1474+
Some(TestResult::PaymentSuccess { path }) => {
14591475
panic!("Unexpected successful payment path: {:?}", path)
14601476
},
1477+
Some(TestResult::ProbeFailure { path, .. }) => {
1478+
panic!("Unexpected failed payment probe: {:?}", path)
1479+
},
1480+
Some(TestResult::ProbeSuccess { path }) => {
1481+
panic!("Unexpected successful payment probe: {:?}", path)
1482+
},
14611483
None => panic!("Unexpected payment_path_failed call: {:?}", actual_path),
14621484
}
14631485
}
@@ -1466,10 +1488,56 @@ mod tests {
14661488
fn payment_path_successful(&mut self, actual_path: &[&RouteHop]) {
14671489
if let Some(expectations) = &mut self.expectations {
14681490
match expectations.pop_front() {
1469-
Some(PaymentPath::Failure { path, .. }) => {
1491+
Some(TestResult::PaymentFailure { path, .. }) => {
14701492
panic!("Unexpected payment path failure: {:?}", path)
14711493
},
1472-
Some(PaymentPath::Success { path }) => {
1494+
Some(TestResult::PaymentSuccess { path }) => {
1495+
assert_eq!(actual_path, &path.iter().collect::<Vec<_>>()[..]);
1496+
},
1497+
Some(TestResult::ProbeFailure { path, .. }) => {
1498+
panic!("Unexpected failed payment probe: {:?}", path)
1499+
},
1500+
Some(TestResult::ProbeSuccess { path }) => {
1501+
panic!("Unexpected successful payment probe: {:?}", path)
1502+
},
1503+
None => panic!("Unexpected payment_path_successful call: {:?}", actual_path),
1504+
}
1505+
}
1506+
}
1507+
1508+
fn probe_failed(&mut self, actual_path: &[&RouteHop], actual_short_channel_id: u64) {
1509+
if let Some(expectations) = &mut self.expectations {
1510+
match expectations.pop_front() {
1511+
Some(TestResult::PaymentFailure { path, .. }) => {
1512+
panic!("Unexpected failed payment path: {:?}", path)
1513+
},
1514+
Some(TestResult::PaymentSuccess { path }) => {
1515+
panic!("Unexpected successful payment path: {:?}", path)
1516+
},
1517+
Some(TestResult::ProbeFailure { path, short_channel_id }) => {
1518+
assert_eq!(actual_path, &path.iter().collect::<Vec<_>>()[..]);
1519+
assert_eq!(actual_short_channel_id, short_channel_id);
1520+
},
1521+
Some(TestResult::ProbeSuccess { path }) => {
1522+
panic!("Unexpected successful payment probe: {:?}", path)
1523+
},
1524+
None => panic!("Unexpected payment_path_failed call: {:?}", actual_path),
1525+
}
1526+
}
1527+
}
1528+
fn probe_successful(&mut self, actual_path: &[&RouteHop]) {
1529+
if let Some(expectations) = &mut self.expectations {
1530+
match expectations.pop_front() {
1531+
Some(TestResult::PaymentFailure { path, .. }) => {
1532+
panic!("Unexpected payment path failure: {:?}", path)
1533+
},
1534+
Some(TestResult::PaymentSuccess { path }) => {
1535+
panic!("Unexpected successful payment path: {:?}", path)
1536+
},
1537+
Some(TestResult::ProbeFailure { path, .. }) => {
1538+
panic!("Unexpected failed payment probe: {:?}", path)
1539+
},
1540+
Some(TestResult::ProbeSuccess { path }) => {
14731541
assert_eq!(actual_path, &path.iter().collect::<Vec<_>>()[..]);
14741542
},
14751543
None => panic!("Unexpected payment_path_successful call: {:?}", actual_path),

0 commit comments

Comments
 (0)