diff --git a/sim-lib/src/lib.rs b/sim-lib/src/lib.rs index 05520a4b..128cd5cd 100644 --- a/sim-lib/src/lib.rs +++ b/sim-lib/src/lib.rs @@ -133,14 +133,6 @@ pub trait LightningNode { async fn get_node_features(&mut self, node: PublicKey) -> Result; } -/// SimulationEvent describes the set of actions that the simulator can run on nodes that it has execution permissions -/// on. -#[derive(Clone, Copy)] -enum SimulationEvent { - // Dispatch a payment of the specified amount to the public key provided. - SendPayment(PublicKey, u64), -} - #[derive(Debug, Clone, Serialize, Deserialize)] pub struct PaymentResult { pub htlc_count: usize, @@ -180,18 +172,24 @@ pub enum PaymentOutcome { Unknown, } +/// Describes a payment from a source node to a destination node. #[derive(Debug, Clone, Copy, Serialize)] -struct DispatchedPayment { +struct Payment { + /// Pubkey of the source node dispatching the payment. source: PublicKey, + /// Pubkey of the destination node receiving the payment. destination: PublicKey, + /// Amount of the payment in msat. + amount_msat: u64, + /// Hash of the payment if it has been successfully dispatched. #[serde(with = "serializers::serde_option_payment_hash")] hash: Option, - amount_msat: u64, + /// Time at which the payment was dispatched. #[serde(with = "serde_millis")] dispatch_time: SystemTime, } -impl Display for DispatchedPayment { +impl Display for Payment { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { let hash = match self.hash { Some(hash) => hex::encode(hash.0), @@ -210,10 +208,23 @@ impl Display for DispatchedPayment { } } +/// SimulationEvent describes the set of actions that the simulator can run on nodes that it has execution permissions +/// on. +#[derive(Clone, Copy)] +enum SimulationEvent { + /// Dispatch a payment of the specified amount to the public key provided. + /// Results in `SimulationOutput::SendPaymentSuccess` or `SimulationOutput::SendPaymentFailure`. + SendPayment(PublicKey, u64), +} + /// SimulationOutput provides the output of a simulation event. enum SimulationOutput { - // The payment hash that results from a SendPayment SimulationEvent being triggered. - PaymentSent(DispatchedPayment), + /// Intermediate output for when simulator has successfully dispatched a payment. + /// We need to track the result of the payment to report on it. + SendPaymentSuccess(Payment), + /// Final output for when simulator has failed to dispatch a payment. + /// Report this as the final result of simulation event. + SendPaymentFailure(Payment, PaymentResult), } #[derive(Clone)] @@ -445,7 +456,8 @@ async fn consume_events( match event { SimulationEvent::SendPayment(dest, amt_msat) => { let mut node = node.lock().await; - let mut payment = DispatchedPayment { + + let mut payment = Payment { source: node.get_info().pubkey, hash: None, amount_msat: amt_msat, @@ -453,7 +465,7 @@ async fn consume_events( dispatch_time: SystemTime::now(), }; - match node.send_payment(dest, amt_msat).await { + let outcome = match node.send_payment(dest, amt_msat).await { Ok(payment_hash) => { log::debug!( "Send payment: {} -> {}: ({}).", @@ -461,7 +473,9 @@ async fn consume_events( dest, hex::encode(payment_hash.0) ); + // We need to track the payment outcome using the payment hash that we have received. payment.hash = Some(payment_hash); + SimulationOutput::SendPaymentSuccess(payment) } Err(e) => { log::error!( @@ -470,10 +484,10 @@ async fn consume_events( dest, e ); + SimulationOutput::SendPaymentFailure(payment, PaymentResult::default()) } }; - let outcome = SimulationOutput::PaymentSent(payment); match sender.send(outcome).await { Ok(_) => {} Err(e) => { @@ -538,7 +552,7 @@ async fn produce_events( } async fn consume_simulation_results( - receiver: Receiver<(DispatchedPayment, PaymentResult)>, + receiver: Receiver<(Payment, PaymentResult)>, listener: Listener, print_batch_size: u32, ) { @@ -552,7 +566,7 @@ async fn consume_simulation_results( } async fn write_payment_results( - mut receiver: Receiver<(DispatchedPayment, PaymentResult)>, + mut receiver: Receiver<(Payment, PaymentResult)>, listener: Listener, print_batch_size: u32, ) -> Result<(), SimulationError> { @@ -622,7 +636,7 @@ impl PaymentResultLogger { } } - fn report_result(&mut self, details: &DispatchedPayment, result: &PaymentResult) { + fn report_result(&mut self, details: &Payment, result: &PaymentResult) { match result.payment_outcome { PaymentOutcome::Success => self.success_payment += 1, _ => self.failed_payment += 1, @@ -655,7 +669,7 @@ impl PaymentResultLogger { async fn produce_simulation_results( nodes: HashMap>>, mut output_receiver: Receiver, - results: Sender<(DispatchedPayment, PaymentResult)>, + results: Sender<(Payment, PaymentResult)>, shutdown: Listener, ) { log::debug!("Simulation results producer started."); @@ -670,12 +684,17 @@ async fn produce_simulation_results( match output{ Some(simulation_output) => { match simulation_output{ - SimulationOutput::PaymentSent(dispatched_payment) => { + SimulationOutput::SendPaymentSuccess(dispatched_payment) => { let source_node = nodes.get(&dispatched_payment.source).unwrap().clone(); set.spawn(track_payment_result( - source_node,results.clone(),simulation_output, shutdown.clone(), + source_node,results.clone(),dispatched_payment, shutdown.clone(), )); }, + SimulationOutput::SendPaymentFailure(payment, result) => { + if results.clone().send((payment, result)).await.is_err() { + log::debug!("Could not send payment result"); + } + } }; }, @@ -697,43 +716,44 @@ async fn produce_simulation_results( async fn track_payment_result( node: Arc>, - results: Sender<(DispatchedPayment, PaymentResult)>, - output: SimulationOutput, + results: Sender<(Payment, PaymentResult)>, + dispatched_payment: Payment, shutdown: Listener, ) { log::trace!("Payment result tracker starting."); let mut node = node.lock().await; - match output { - SimulationOutput::PaymentSent(payment) => { - let res = match payment.hash { - Some(hash) => { - log::debug!("Tracking payment outcome for: {}.", hex::encode(hash.0)); - let track_payment = node.track_payment(hash, shutdown.clone()); - - match track_payment.await { - Ok(res) => { - log::debug!( - "Track payment {} result: {:?}.", - hex::encode(hash.0), - res.payment_outcome - ); - res - } - Err(e) => { - log::error!("Track payment failed for {}: {e}.", hex::encode(hash.0)); - PaymentResult::default() - } - } + let res = match dispatched_payment.hash { + Some(hash) => { + log::debug!("Tracking payment outcome for: {}.", hex::encode(hash.0)); + let track_payment = node.track_payment(hash, shutdown.clone()); + + match track_payment.await { + Ok(res) => { + log::debug!( + "Track payment {} result: {:?}.", + hex::encode(hash.0), + res.payment_outcome + ); + res + } + Err(e) => { + log::error!("Track payment failed for {}: {e}.", hex::encode(hash.0)); + PaymentResult::default() } - None => PaymentResult::default(), - }; - - if results.clone().send((payment, res)).await.is_err() { - log::debug!("Could not send payment result for"); } } + None => PaymentResult::default(), + }; + + if results + .clone() + .send((dispatched_payment, res)) + .await + .is_err() + { + log::debug!("Could not send payment result"); } log::trace!("Payment result tracker exiting.");