Skip to content

Commit 295aa5c

Browse files
committed
sim-lib: add custom records to htlcs
1 parent 0536339 commit 295aa5c

File tree

3 files changed

+81
-14
lines changed

3 files changed

+81
-14
lines changed

sim-cli/src/main.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ use std::sync::Arc;
33
use clap::Parser;
44
use log::LevelFilter;
55
use sim_cli::parsing::{create_simulation, create_simulation_with_network, parse_sim_params, Cli};
6-
use simln_lib::{latency_interceptor::LatencyIntercepor, sim_node::Interceptor};
6+
use simln_lib::{
7+
latency_interceptor::LatencyIntercepor,
8+
sim_node::{CustomRecords, Interceptor},
9+
};
710
use simple_logger::SimpleLogger;
811
use tokio_util::task::TaskTracker;
912

@@ -38,7 +41,14 @@ async fn main() -> anyhow::Result<()> {
3841
} else {
3942
vec![]
4043
};
41-
create_simulation_with_network(&cli, &sim_params, tasks.clone(), interceptors).await?
44+
create_simulation_with_network(
45+
&cli,
46+
&sim_params,
47+
tasks.clone(),
48+
interceptors,
49+
CustomRecords::default(),
50+
)
51+
.await?
4252
};
4353
let sim2 = sim.clone();
4454

sim-cli/src/parsing.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ use log::LevelFilter;
55
use serde::{Deserialize, Serialize};
66
use simln_lib::clock::SimulationClock;
77
use simln_lib::sim_node::{
8-
ln_node_from_graph, populate_network_graph, ChannelPolicy, Interceptor, SimGraph,
9-
SimulatedChannel,
8+
ln_node_from_graph, populate_network_graph, ChannelPolicy, CustomRecords, Interceptor,
9+
SimGraph, SimulatedChannel,
1010
};
1111
use simln_lib::{
1212
cln, cln::ClnNode, eclair, eclair::EclairNode, lnd, lnd::LndNode, serializers,
@@ -229,6 +229,7 @@ pub async fn create_simulation_with_network(
229229
sim_params: &SimParams,
230230
tasks: TaskTracker,
231231
interceptors: Vec<Arc<dyn Interceptor>>,
232+
custom_records: CustomRecords,
232233
) -> Result<(Simulation<SimulationClock>, Vec<ActivityDefinition>), anyhow::Error> {
233234
let cfg: SimulationCfg = SimulationCfg::try_from(cli)?;
234235
let SimParams {
@@ -259,6 +260,7 @@ pub async fn create_simulation_with_network(
259260
channels.clone(),
260261
tasks.clone(),
261262
interceptors,
263+
custom_records,
262264
(shutdown_trigger.clone(), shutdown_listener.clone()),
263265
)
264266
.map_err(|e| SimulationError::SimulatedNetworkError(format!("{:?}", e)))?,

simln-lib/src/sim_node.rs

Lines changed: 65 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -824,7 +824,7 @@ async fn handle_intercepted_htlc(
824824
shutdown_listener: Listener,
825825
) -> Result<Result<CustomRecords, ForwardingError>, CriticalError> {
826826
if interceptors.is_empty() {
827-
return Ok(Ok(HashMap::new()));
827+
return Ok(Ok(request.incoming_custom_records));
828828
}
829829

830830
let mut attached_custom_records: CustomRecords = HashMap::new();
@@ -925,6 +925,9 @@ pub struct SimGraph {
925925
/// trigger a shutdown signal to other interceptors.
926926
interceptors: Vec<Arc<dyn Interceptor>>,
927927

928+
/// Custom records that will be added to the first outgoing HTLC in a payment.
929+
default_custom_records: CustomRecords,
930+
928931
/// Shutdown signal that can be used to trigger a shutdown if a critical error occurs. Listener
929932
/// can be used to listen for shutdown signals coming from upstream.
930933
shutdown_signal: (Trigger, Listener),
@@ -936,6 +939,7 @@ impl SimGraph {
936939
graph_channels: Vec<SimulatedChannel>,
937940
tasks: TaskTracker,
938941
interceptors: Vec<Arc<dyn Interceptor>>,
942+
default_custom_records: CustomRecords,
939943
shutdown_signal: (Trigger, Listener),
940944
) -> Result<Self, SimulationError> {
941945
let mut nodes: HashMap<PublicKey, Vec<u64>> = HashMap::new();
@@ -971,6 +975,7 @@ impl SimGraph {
971975
channels: Arc::new(Mutex::new(channels)),
972976
tasks,
973977
interceptors,
978+
default_custom_records,
974979
shutdown_signal,
975980
})
976981
}
@@ -1098,6 +1103,7 @@ impl SimNetwork for SimGraph {
10981103
payment_hash,
10991104
sender,
11001105
interceptors: self.interceptors.clone(),
1106+
custom_records: self.default_custom_records.clone(),
11011107
shutdown_signal: self.shutdown_signal.clone(),
11021108
}));
11031109
}
@@ -1149,13 +1155,14 @@ async fn add_htlcs(
11491155
route: Path,
11501156
payment_hash: PaymentHash,
11511157
interceptors: Vec<Arc<dyn Interceptor>>,
1158+
custom_records: CustomRecords,
11521159
shutdown_listener: Listener,
11531160
) -> Result<Result<(), (Option<usize>, ForwardingError)>, CriticalError> {
11541161
let mut outgoing_node = source;
11551162
let mut outgoing_amount = route.fee_msat() + route.final_value_msat();
11561163
let mut outgoing_cltv = route.hops.iter().map(|hop| hop.cltv_expiry_delta).sum();
11571164

1158-
let mut incoming_custom_records = HashMap::new();
1165+
let mut incoming_custom_records = custom_records;
11591166

11601167
// Tracks the hop index that we need to remove htlcs from on payment completion (both success and failure).
11611168
// Given a payment from A to C, over the route A -- B -- C, this index has the following meanings:
@@ -1237,7 +1244,7 @@ async fn add_htlcs(
12371244
forwarding_node: hop.pubkey,
12381245
payment_hash,
12391246
incoming_htlc: incoming_htlc.clone(),
1240-
incoming_custom_records: incoming_custom_records.clone(),
1247+
incoming_custom_records,
12411248
outgoing_channel_id: next_scid,
12421249
incoming_amount_msat: outgoing_amount,
12431250
outgoing_amount_msat: outgoing_amount - hop.fee_msat,
@@ -1345,6 +1352,7 @@ struct PropagatePaymentRequest {
13451352
payment_hash: PaymentHash,
13461353
sender: Sender<Result<PaymentResult, LightningError>>,
13471354
interceptors: Vec<Arc<dyn Interceptor>>,
1355+
custom_records: CustomRecords,
13481356
shutdown_signal: (Trigger, Listener),
13491357
}
13501358

@@ -1359,6 +1367,7 @@ async fn propagate_payment(request: PropagatePaymentRequest) {
13591367
request.route.clone(),
13601368
request.payment_hash,
13611369
request.interceptors.clone(),
1370+
request.custom_records,
13621371
request.shutdown_signal.1,
13631372
)
13641373
.await
@@ -1964,7 +1973,11 @@ mod tests {
19641973
/// Alice (100) --- (0) Bob (100) --- (0) Carol (100) --- (0) Dave
19651974
///
19661975
/// The nodes pubkeys in this chain of channels are provided in-order for easy access.
1967-
async fn new(capacity: u64, interceptors: Vec<Arc<dyn Interceptor>>) -> Self {
1976+
async fn new(
1977+
capacity: u64,
1978+
interceptors: Vec<Arc<dyn Interceptor>>,
1979+
custom_records: CustomRecords,
1980+
) -> Self {
19681981
let shutdown_signal = triggered::trigger();
19691982
let channels = create_simulated_channels(3, capacity);
19701983
let routing_graph = Arc::new(
@@ -1991,6 +2004,7 @@ mod tests {
19912004
channels.clone(),
19922005
TaskTracker::new(),
19932006
interceptors,
2007+
custom_records,
19942008
shutdown_signal,
19952009
)
19962010
.expect("could not create test graph"),
@@ -2071,7 +2085,8 @@ mod tests {
20712085
#[tokio::test]
20722086
async fn test_successful_dispatch() {
20732087
let chan_capacity = 500_000_000;
2074-
let mut test_kit = DispatchPaymentTestKit::new(chan_capacity, vec![]).await;
2088+
let mut test_kit =
2089+
DispatchPaymentTestKit::new(chan_capacity, vec![], CustomRecords::default()).await;
20752090

20762091
// Send a payment that should succeed from Alice -> Dave.
20772092
let mut amt = 20_000;
@@ -2136,7 +2151,8 @@ mod tests {
21362151
#[tokio::test]
21372152
async fn test_successful_multi_hop() {
21382153
let chan_capacity = 500_000_000;
2139-
let mut test_kit = DispatchPaymentTestKit::new(chan_capacity, vec![]).await;
2154+
let mut test_kit =
2155+
DispatchPaymentTestKit::new(chan_capacity, vec![], CustomRecords::default()).await;
21402156

21412157
// Send a payment that should succeed from Alice -> Dave.
21422158
let amt = 20_000;
@@ -2166,7 +2182,8 @@ mod tests {
21662182
#[tokio::test]
21672183
async fn test_single_hop_payments() {
21682184
let chan_capacity = 500_000_000;
2169-
let mut test_kit = DispatchPaymentTestKit::new(chan_capacity, vec![]).await;
2185+
let mut test_kit =
2186+
DispatchPaymentTestKit::new(chan_capacity, vec![], CustomRecords::default()).await;
21702187

21712188
// Send a single hop payment from Alice -> Bob, it will succeed because Alice has all the liquidity.
21722189
let amt = 150_000;
@@ -2198,7 +2215,8 @@ mod tests {
21982215
#[tokio::test]
21992216
async fn test_multi_hop_faiulre() {
22002217
let chan_capacity = 500_000_000;
2201-
let mut test_kit = DispatchPaymentTestKit::new(chan_capacity, vec![]).await;
2218+
let mut test_kit =
2219+
DispatchPaymentTestKit::new(chan_capacity, vec![], CustomRecords::default()).await;
22022220

22032221
// Drain liquidity between Bob and Carol to force failures on Bob's outgoing linke.
22042222
test_kit
@@ -2244,7 +2262,7 @@ mod tests {
22442262
channel_id: ShortChannelID(0),
22452263
index: 0,
22462264
},
2247-
incoming_custom_records: CustomRecords::new(),
2265+
incoming_custom_records: CustomRecords::default(),
22482266
outgoing_channel_id: None,
22492267
incoming_amount_msat: 0,
22502268
outgoing_amount_msat: 0,
@@ -2406,7 +2424,8 @@ mod tests {
24062424
.returning(|_| Ok(()));
24072425

24082426
let mock_1 = Arc::new(mock_interceptor_1);
2409-
let mut test_kit = DispatchPaymentTestKit::new(500_000_000, vec![mock_1]).await;
2427+
let mut test_kit =
2428+
DispatchPaymentTestKit::new(500_000_000, vec![mock_1], CustomRecords::default()).await;
24102429
let (_, result) = test_kit
24112430
.send_test_payment(test_kit.nodes[0], test_kit.nodes[3], 150_000_000)
24122431
.await;
@@ -2427,4 +2446,40 @@ mod tests {
24272446
test_kit.graph.tasks.close();
24282447
test_kit.graph.tasks.wait().await;
24292448
}
2449+
2450+
/// Tests custom records set for interceptors in multi-hop payment.
2451+
#[tokio::test]
2452+
async fn test_custom_records() {
2453+
let custom_records = HashMap::from([(1000, vec![1])]);
2454+
2455+
let mut mock_interceptor_1 = MockTestInterceptor::new();
2456+
let custom_records_clone = custom_records.clone();
2457+
mock_interceptor_1
2458+
.expect_intercept_htlc()
2459+
.withf(move |req: &InterceptRequest| {
2460+
// Check custom records passed to interceptor are the default ones set.
2461+
req.incoming_custom_records == custom_records_clone
2462+
})
2463+
.returning(|_| Ok(Ok(CustomRecords::default()))); // Set empty records for 2nd hop.
2464+
mock_interceptor_1
2465+
.expect_notify_resolution()
2466+
.returning(|_| Ok(()))
2467+
.times(2);
2468+
2469+
mock_interceptor_1
2470+
.expect_intercept_htlc()
2471+
.withf(move |req: &InterceptRequest| {
2472+
// On this 2nd hop, the custom records should be empty.
2473+
req.incoming_custom_records == CustomRecords::default()
2474+
})
2475+
.returning(|_| Ok(Ok(CustomRecords::default())));
2476+
2477+
let chan_capacity = 500_000_000;
2478+
let mock_1: Arc<dyn Interceptor> = Arc::new(mock_interceptor_1);
2479+
let mut test_kit =
2480+
DispatchPaymentTestKit::new(chan_capacity, vec![mock_1], custom_records).await;
2481+
let _ = test_kit
2482+
.send_test_payment(test_kit.nodes[0], test_kit.nodes[2], 150_000)
2483+
.await;
2484+
}
24302485
}

0 commit comments

Comments
 (0)