/// Note that if this field is non-empty, it will contain strictly increasing TLVs, each
/// represented by a `(u64, Vec<u8>)` for its type number and serialized value respectively.
/// This is validated when setting this field using [`Self::with_custom_tlvs`].
+ #[cfg(not(c_bindings))]
pub fn custom_tlvs(&self) -> &Vec<(u64, Vec<u8>)> {
&self.custom_tlvs
}
+ /// Gets the custom TLVs that will be sent or have been received.
+ ///
+ /// Custom TLVs allow sending extra application-specific data with a payment. They provide
+ /// additional flexibility on top of payment metadata, as while other implementations may
+ /// require `payment_metadata` to reflect metadata provided in an invoice, custom TLVs
+ /// do not have this restriction.
+ ///
+ /// Note that if this field is non-empty, it will contain strictly increasing TLVs, each
+ /// represented by a `(u64, Vec<u8>)` for its type number and serialized value respectively.
+ /// This is validated when setting this field using [`Self::with_custom_tlvs`].
+ #[cfg(c_bindings)]
+ pub fn custom_tlvs(&self) -> Vec<(u64, Vec<u8>)> {
+ self.custom_tlvs.clone()
+ }
+
/// When we have received some HTLC(s) towards an MPP payment, as we receive further HTLC(s) we
/// have to make sure that some fields match exactly across the parts. For those that aren't
/// required to match, if they don't match we should remove them so as to not expose data
RetryableSendFailure::RouteNotFound
})?;
- if let Some(route_route_params) = route.route_params.as_mut() {
- if route_route_params.final_value_msat != route_params.final_value_msat {
- debug_assert!(false,
- "Routers are expected to return a route which includes the requested final_value_msat");
- route_route_params.final_value_msat = route_params.final_value_msat;
- }
+ if route.route_params.as_ref() != Some(&route_params) {
+ debug_assert!(false,
+ "Routers are expected to return a Route which includes the requested RouteParameters");
+ route.route_params = Some(route_params.clone());
}
let onion_session_privs = self.add_new_pending_payment(payment_hash,
}
};
- if let Some(route_route_params) = route.route_params.as_mut() {
- if route_route_params.final_value_msat != route_params.final_value_msat {
- debug_assert!(false,
- "Routers are expected to return a route which includes the requested final_value_msat");
- route_route_params.final_value_msat = route_params.final_value_msat;
- }
+ if route.route_params.as_ref() != Some(&route_params) {
+ debug_assert!(false,
+ "Routers are expected to return a Route which includes the requested RouteParameters");
+ route.route_params = Some(route_params.clone());
}
for path in route.paths.iter() {
&self, pending_events: &Mutex<VecDeque<(events::Event, Option<EventCompletionAction>)>>)
{
let mut pending_outbound_payments = self.pending_outbound_payments.lock().unwrap();
+ #[cfg(not(invreqfailed))]
+ let pending_events = pending_events.lock().unwrap();
+ #[cfg(invreqfailed)]
let mut pending_events = pending_events.lock().unwrap();
pending_outbound_payments.retain(|payment_id, payment| {
// If an outbound payment was completed, and no pending HTLCs remain, we should remove it
if *timer_ticks_without_response <= INVOICE_REQUEST_TIMEOUT_TICKS {
true
} else {
+ #[cfg(invreqfailed)]
pending_events.push_back(
(events::Event::InvoiceRequestFailed { payment_id: *payment_id }, None)
);
payment.remove();
}
} else if let PendingOutboundPayment::AwaitingInvoice { .. } = payment.get() {
+ #[cfg(invreqfailed)]
pending_events.lock().unwrap().push_back((events::Event::InvoiceRequestFailed {
payment_id,
}, None));
use crate::ln::channelmanager::{PaymentId, RecipientOnionFields};
use crate::ln::features::{ChannelFeatures, NodeFeatures};
use crate::ln::msgs::{ErrorAction, LightningError};
- use crate::ln::outbound_payment::{Bolt12PaymentError, INVOICE_REQUEST_TIMEOUT_TICKS, OutboundPayments, Retry, RetryableSendFailure};
+ use crate::ln::outbound_payment::{Bolt12PaymentError, OutboundPayments, Retry, RetryableSendFailure};
+ #[cfg(invreqfailed)]
+ use crate::ln::outbound_payment::INVOICE_REQUEST_TIMEOUT_TICKS;
use crate::offers::invoice::DEFAULT_RELATIVE_EXPIRY;
use crate::offers::offer::OfferBuilder;
use crate::offers::test_utils::*;
router.expect_find_route(route_params.clone(), Ok(route.clone()));
let mut route_params_w_failed_scid = route_params.clone();
route_params_w_failed_scid.payment_params.previously_failed_channels.push(failed_scid);
- router.expect_find_route(route_params_w_failed_scid, Ok(route.clone()));
+ let mut route_w_failed_scid = route.clone();
+ route_w_failed_scid.route_params = Some(route_params_w_failed_scid.clone());
+ router.expect_find_route(route_params_w_failed_scid, Ok(route_w_failed_scid));
router.expect_find_route(route_params.clone(), Ok(route.clone()));
router.expect_find_route(route_params.clone(), Ok(route.clone()));
}
#[test]
+ #[cfg(invreqfailed)]
fn removes_stale_awaiting_invoice() {
let pending_events = Mutex::new(VecDeque::new());
let outbound_payments = OutboundPayments::new();
}
#[test]
+ #[cfg(invreqfailed)]
fn removes_abandoned_awaiting_invoice() {
let pending_events = Mutex::new(VecDeque::new());
let outbound_payments = OutboundPayments::new();
// Check the remaining max total routing fee for the second attempt is 50_000 - 1_000 msat fee
// used by the first path
route_params.max_total_routing_fee_msat = Some(max_total_routing_fee_msat - 1_000);
+ route.route_params = Some(route_params.clone());
nodes[0].router.expect_find_route(route_params, Ok(route));
nodes[0].node.process_pending_htlc_forwards();
check_added_monitors!(nodes[0], 1);
route.paths.remove(0);
route_params.final_value_msat -= first_path_value;
- route.route_params.as_mut().map(|p| p.final_value_msat -= first_path_value);
route_params.payment_params.previously_failed_channels.push(chan_4_update.contents.short_channel_id);
-
// Check the remaining max total routing fee for the second attempt accounts only for 1_000 msat
// base fee, but not for overpaid value of the first try.
route_params.max_total_routing_fee_msat.as_mut().map(|m| *m -= 1000);
+
+ route.route_params = Some(route_params.clone());
nodes[0].router.expect_find_route(route_params, Ok(route));
nodes[0].node.process_pending_htlc_forwards();
// Check for unknown channel id error.
let unknown_chan_id_err = nodes[1].node.forward_intercepted_htlc(intercept_id, &ChannelId::from_bytes([42; 32]), nodes[2].node.get_our_node_id(), expected_outbound_amount_msat).unwrap_err();
assert_eq!(unknown_chan_id_err , APIError::ChannelUnavailable {
- err: format!("Channel with id {} not found for the passed counterparty node_id {}.",
+ err: format!("Channel with id {} not found for the passed counterparty node_id {}",
log_bytes!([42; 32]), nodes[2].node.get_our_node_id()) });
if test == InterceptTest::Fail {
let mut retry_params = RouteParameters::from_payment_params_and_value(pay_params, 100_000_000);
retry_params.max_total_routing_fee_msat = None;
- route.route_params.as_mut().unwrap().final_value_msat = 100_000_000;
+ route.route_params = Some(retry_params.clone());
nodes[0].router.expect_find_route(retry_params, Ok(route.clone()));
{
maybe_announced_channel: true,
}], blinded_tail: None },
],
- route_params: Some(RouteParameters::from_payment_params_and_value(
- PaymentParameters::from_node_id(nodes[1].node.get_our_node_id(), TEST_FINAL_CLTV),
- 100_000_001)),
+ route_params: Some(route_params.clone()),
};
nodes[0].router.expect_find_route(route_params.clone(), Ok(route.clone()));
// On retry, split the payment across both channels.
route.paths[1].hops[0].fee_msat = 50_000_001;
let mut pay_params = route_params.payment_params.clone();
pay_params.previously_failed_channels.push(chans[0].short_channel_id.unwrap());
- nodes[0].router.expect_find_route(
- RouteParameters::from_payment_params_and_value(pay_params, amt_msat),
- Ok(route.clone()));
+ let retry_params = RouteParameters::from_payment_params_and_value(pay_params, amt_msat);
+ route.route_params = Some(retry_params.clone());
+ nodes[0].router.expect_find_route(retry_params, Ok(route.clone()));
nodes[0].node.send_payment(payment_hash, RecipientOnionFields::secret_only(payment_secret),
PaymentId(payment_hash.0), route_params, Retry::Attempts(1)).unwrap();
route.paths[0].hops[1].fee_msat = amt_msat;
let mut retry_params = RouteParameters::from_payment_params_and_value(second_payment_params, amt_msat);
retry_params.max_total_routing_fee_msat = None;
+ route.route_params = Some(retry_params.clone());
nodes[0].router.expect_find_route(retry_params, Ok(route.clone()));
nodes[0].node.send_payment(payment_hash, RecipientOnionFields::secret_only(payment_secret),
route.paths.remove(0);
let mut retry_params = RouteParameters::from_payment_params_and_value(second_payment_params, amt_msat / 2);
retry_params.max_total_routing_fee_msat = None;
- route.route_params.as_mut().unwrap().final_value_msat = amt_msat / 2;
+ route.route_params = Some(retry_params.clone());
nodes[0].router.expect_find_route(retry_params, Ok(route.clone()));
nodes[0].node.send_payment(payment_hash, RecipientOnionFields::secret_only(payment_secret),
// from here on out, the retry `RouteParameters` amount will be amt/1000
route_params.final_value_msat /= 1000;
- route.route_params.as_mut().unwrap().final_value_msat /= 1000;
+ route.route_params = Some(route_params.clone());
route.paths.pop();
let end_time = Instant::now() + Duration::from_secs(1);
new_route_params.payment_params.previously_failed_channels = previously_failed_channels.clone();
new_route_params.max_total_routing_fee_msat.as_mut().map(|m| *m -= 100_000);
route.paths[0].hops[1].short_channel_id += 1;
+ route.route_params = Some(new_route_params.clone());
nodes[0].router.expect_find_route(new_route_params, Ok(route.clone()));
let bs_fail_updates = get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id());
send_payment(&nodes[2], &vec!(&nodes[1])[..], 1_500_000);
let amt_msat = 1_000_000;
- let (route, payment_hash, payment_preimage, payment_secret) =
+ let (mut route, payment_hash, payment_preimage, payment_secret) =
get_route_and_payment_hash!(nodes[0], nodes[2], amt_msat);
// Initiate the payment
// Retry the payment and make sure it succeeds
route_params.payment_params.previously_failed_channels.push(chan_2_update.contents.short_channel_id);
+ route.route_params = Some(route_params.clone());
nodes[0].router.expect_find_route(route_params, Ok(route));
nodes[0].node.process_pending_htlc_forwards();
check_added_monitors!(nodes[0], 1);
payment_hash, Some(payment_secret), events.pop().unwrap(), true, None).unwrap();
match payment_claimable {
Event::PaymentClaimable { onion_fields, .. } => {
- assert_eq!(onion_fields.unwrap().custom_tlvs(), &custom_tlvs);
+ assert_eq!(&onion_fields.unwrap().custom_tlvs()[..], &custom_tlvs[..]);
},
_ => panic!("Unexpected event"),
};
/// [`find_route`].
///
/// [`ScoreLookUp`]: crate::routing::scoring::ScoreLookUp
-pub struct ScorerAccountingForInFlightHtlcs<'a, SP: Sized, Sc: 'a + ScoreLookUp<ScoreParams = SP>, S: Deref<Target = Sc>> {
+pub struct ScorerAccountingForInFlightHtlcs<'a, S: Deref> where S::Target: ScoreLookUp {
scorer: S,
// Maps a channel's short channel id and its direction to the liquidity used up.
inflight_htlcs: &'a InFlightHtlcs,
}
-impl<'a, SP: Sized, Sc: ScoreLookUp<ScoreParams = SP>, S: Deref<Target = Sc>> ScorerAccountingForInFlightHtlcs<'a, SP, Sc, S> {
+impl<'a, S: Deref> ScorerAccountingForInFlightHtlcs<'a, S> where S::Target: ScoreLookUp {
/// Initialize a new `ScorerAccountingForInFlightHtlcs`.
pub fn new(scorer: S, inflight_htlcs: &'a InFlightHtlcs) -> Self {
ScorerAccountingForInFlightHtlcs {
}
}
-#[cfg(c_bindings)]
-impl<'a, SP: Sized, Sc: ScoreLookUp<ScoreParams = SP>, S: Deref<Target = Sc>> Writeable for ScorerAccountingForInFlightHtlcs<'a, SP, Sc, S> {
- fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> { self.scorer.write(writer) }
-}
-
-impl<'a, SP: Sized, Sc: 'a + ScoreLookUp<ScoreParams = SP>, S: Deref<Target = Sc>> ScoreLookUp for ScorerAccountingForInFlightHtlcs<'a, SP, Sc, S> {
- type ScoreParams = Sc::ScoreParams;
+impl<'a, S: Deref> ScoreLookUp for ScorerAccountingForInFlightHtlcs<'a, S> where S::Target: ScoreLookUp {
+ type ScoreParams = <S::Target as ScoreLookUp>::ScoreParams;
fn channel_penalty_msat(&self, short_channel_id: u64, source: &NodeId, target: &NodeId, usage: ChannelUsage, score_params: &Self::ScoreParams) -> u64 {
if let Some(used_liquidity) = self.inflight_htlcs.used_liquidity_msat(
source, target, short_channel_id
inbound_scid_alias: None,
channel_value_satoshis: 0,
user_channel_id: 0,
+ balance_msat: 0,
outbound_capacity_msat,
next_outbound_htlc_limit_msat: outbound_capacity_msat,
next_outbound_htlc_minimum_msat: 0,
assert_eq!(route.paths.len(), 1);
assert_eq!(route.get_total_amount(), amt_msat);
}
+
+ #[test]
+ fn first_hop_preferred_over_hint() {
+ // Check that if we have a first hop to a peer we'd always prefer that over a route hint
+ // they gave us, but we'd still consider all subsequent hints if they are more attractive.
+ let secp_ctx = Secp256k1::new();
+ let logger = Arc::new(ln_test_utils::TestLogger::new());
+ let network_graph = Arc::new(NetworkGraph::new(Network::Testnet, Arc::clone(&logger)));
+ let gossip_sync = P2PGossipSync::new(Arc::clone(&network_graph), None, Arc::clone(&logger));
+ let scorer = ln_test_utils::TestScorer::new();
+ let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+ let random_seed_bytes = keys_manager.get_secure_random_bytes();
+ let config = UserConfig::default();
+
+ let amt_msat = 1_000_000;
+ let (our_privkey, our_node_id, privkeys, nodes) = get_nodes(&secp_ctx);
+
+ add_channel(&gossip_sync, &secp_ctx, &our_privkey, &privkeys[0],
+ ChannelFeatures::from_le_bytes(id_to_feature_flags(1)), 1);
+ update_channel(&gossip_sync, &secp_ctx, &our_privkey, UnsignedChannelUpdate {
+ chain_hash: genesis_block(Network::Testnet).header.block_hash(),
+ short_channel_id: 1,
+ timestamp: 1,
+ flags: 0,
+ cltv_expiry_delta: 42,
+ htlc_minimum_msat: 1_000,
+ htlc_maximum_msat: 10_000_000,
+ fee_base_msat: 800,
+ fee_proportional_millionths: 0,
+ excess_data: Vec::new()
+ });
+ update_channel(&gossip_sync, &secp_ctx, &privkeys[0], UnsignedChannelUpdate {
+ chain_hash: genesis_block(Network::Testnet).header.block_hash(),
+ short_channel_id: 1,
+ timestamp: 1,
+ flags: 1,
+ cltv_expiry_delta: 42,
+ htlc_minimum_msat: 1_000,
+ htlc_maximum_msat: 10_000_000,
+ fee_base_msat: 800,
+ fee_proportional_millionths: 0,
+ excess_data: Vec::new()
+ });
+
+ add_channel(&gossip_sync, &secp_ctx, &privkeys[0], &privkeys[1],
+ ChannelFeatures::from_le_bytes(id_to_feature_flags(1)), 2);
+ update_channel(&gossip_sync, &secp_ctx, &privkeys[0], UnsignedChannelUpdate {
+ chain_hash: genesis_block(Network::Testnet).header.block_hash(),
+ short_channel_id: 2,
+ timestamp: 2,
+ flags: 0,
+ cltv_expiry_delta: 42,
+ htlc_minimum_msat: 1_000,
+ htlc_maximum_msat: 10_000_000,
+ fee_base_msat: 800,
+ fee_proportional_millionths: 0,
+ excess_data: Vec::new()
+ });
+ update_channel(&gossip_sync, &secp_ctx, &privkeys[1], UnsignedChannelUpdate {
+ chain_hash: genesis_block(Network::Testnet).header.block_hash(),
+ short_channel_id: 2,
+ timestamp: 2,
+ flags: 1,
+ cltv_expiry_delta: 42,
+ htlc_minimum_msat: 1_000,
+ htlc_maximum_msat: 10_000_000,
+ fee_base_msat: 800,
+ fee_proportional_millionths: 0,
+ excess_data: Vec::new()
+ });
+
+ let dest_node_id = nodes[2];
+
+ let route_hint = RouteHint(vec![RouteHintHop {
+ src_node_id: our_node_id,
+ short_channel_id: 44,
+ fees: RoutingFees {
+ base_msat: 234,
+ proportional_millionths: 0,
+ },
+ cltv_expiry_delta: 10,
+ htlc_minimum_msat: None,
+ htlc_maximum_msat: Some(5_000_000),
+ },
+ RouteHintHop {
+ src_node_id: nodes[0],
+ short_channel_id: 45,
+ fees: RoutingFees {
+ base_msat: 123,
+ proportional_millionths: 0,
+ },
+ cltv_expiry_delta: 10,
+ htlc_minimum_msat: None,
+ htlc_maximum_msat: None,
+ }]);
+
+ let payment_params = PaymentParameters::from_node_id(dest_node_id, 42)
+ .with_route_hints(vec![route_hint]).unwrap()
+ .with_bolt11_features(channelmanager::provided_invoice_features(&config)).unwrap();
+ let route_params = RouteParameters::from_payment_params_and_value(
+ payment_params, amt_msat);
+
+ // First create an insufficient first hop for channel with SCID 1 and check we'd use the
+ // route hint.
+ let first_hop = get_channel_details(Some(1), nodes[0],
+ channelmanager::provided_init_features(&config), 999_999);
+ let first_hops = vec![first_hop];
+
+ let route = get_route(&our_node_id, &route_params.clone(), &network_graph.read_only(),
+ Some(&first_hops.iter().collect::<Vec<_>>()), Arc::clone(&logger), &scorer,
+ &Default::default(), &random_seed_bytes).unwrap();
+ assert_eq!(route.paths.len(), 1);
+ assert_eq!(route.get_total_amount(), amt_msat);
+ assert_eq!(route.paths[0].hops.len(), 2);
+ assert_eq!(route.paths[0].hops[0].short_channel_id, 44);
+ assert_eq!(route.paths[0].hops[1].short_channel_id, 45);
+ assert_eq!(route.get_total_fees(), 123);
+
+ // Now check we would trust our first hop info, i.e., fail if we detect the route hint is
+ // for a first hop channel.
+ let mut first_hop = get_channel_details(Some(1), nodes[0], channelmanager::provided_init_features(&config), 999_999);
+ first_hop.outbound_scid_alias = Some(44);
+ let first_hops = vec![first_hop];
+
+ let route_res = get_route(&our_node_id, &route_params.clone(), &network_graph.read_only(),
+ Some(&first_hops.iter().collect::<Vec<_>>()), Arc::clone(&logger), &scorer,
+ &Default::default(), &random_seed_bytes);
+ assert!(route_res.is_err());
+
+ // Finally check we'd use the first hop if has sufficient outbound capacity. But we'd stil
+ // use the cheaper second hop of the route hint.
+ let mut first_hop = get_channel_details(Some(1), nodes[0],
+ channelmanager::provided_init_features(&config), 10_000_000);
+ first_hop.outbound_scid_alias = Some(44);
+ let first_hops = vec![first_hop];
+
+ let route = get_route(&our_node_id, &route_params.clone(), &network_graph.read_only(),
+ Some(&first_hops.iter().collect::<Vec<_>>()), Arc::clone(&logger), &scorer,
+ &Default::default(), &random_seed_bytes).unwrap();
+ assert_eq!(route.paths.len(), 1);
+ assert_eq!(route.get_total_amount(), amt_msat);
+ assert_eq!(route.paths[0].hops.len(), 2);
+ assert_eq!(route.paths[0].hops[0].short_channel_id, 1);
+ assert_eq!(route.paths[0].hops[1].short_channel_id, 45);
+ assert_eq!(route.get_total_fees(), 123);
+ }
+
+ #[test]
+ fn allow_us_being_first_hint() {
+ // Check that we consider a route hint even if we are the src of the first hop.
+ let secp_ctx = Secp256k1::new();
+ let logger = Arc::new(ln_test_utils::TestLogger::new());
+ let network_graph = Arc::new(NetworkGraph::new(Network::Testnet, Arc::clone(&logger)));
+ let scorer = ln_test_utils::TestScorer::new();
+ let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
+ let random_seed_bytes = keys_manager.get_secure_random_bytes();
+ let config = UserConfig::default();
+
+ let (_, our_node_id, _, nodes) = get_nodes(&secp_ctx);
+
+ let amt_msat = 1_000_000;
+ let dest_node_id = nodes[1];
+
+ let first_hop = get_channel_details(Some(1), nodes[0], channelmanager::provided_init_features(&config), 10_000_000);
+ let first_hops = vec![first_hop];
+
+ let route_hint = RouteHint(vec![RouteHintHop {
+ src_node_id: our_node_id,
+ short_channel_id: 44,
+ fees: RoutingFees {
+ base_msat: 123,
+ proportional_millionths: 0,
+ },
+ cltv_expiry_delta: 10,
+ htlc_minimum_msat: None,
+ htlc_maximum_msat: None,
+ }]);
+
+ let payment_params = PaymentParameters::from_node_id(dest_node_id, 42)
+ .with_route_hints(vec![route_hint]).unwrap()
+ .with_bolt11_features(channelmanager::provided_invoice_features(&config)).unwrap();
+
+ let route_params = RouteParameters::from_payment_params_and_value(
+ payment_params, amt_msat);
+
+
+ let route = get_route(&our_node_id, &route_params, &network_graph.read_only(),
+ Some(&first_hops.iter().collect::<Vec<_>>()), Arc::clone(&logger), &scorer,
+ &Default::default(), &random_seed_bytes).unwrap();
+
+ assert_eq!(route.paths.len(), 1);
+ assert_eq!(route.get_total_amount(), amt_msat);
+ assert_eq!(route.get_total_fees(), 0);
+ assert_eq!(route.paths[0].hops.len(), 1);
+
+ assert_eq!(route.paths[0].hops[0].short_channel_id, 44);
+ }
}
#[cfg(all(any(test, ldk_bench), not(feature = "no-std")))]
outbound_scid_alias: None,
channel_value_satoshis: 10_000_000_000,
user_channel_id: 0,
+ balance_msat: 10_000_000_000,
outbound_capacity_msat: 10_000_000_000,
next_outbound_htlc_minimum_msat: 0,
next_outbound_htlc_limit_msat: 10_000_000_000,
use crate::chain::chaininterface::ConfirmationTarget;
use crate::chain::chaininterface::FEERATE_FLOOR_SATS_PER_KW;
use crate::chain::chainmonitor;
-use crate::chain::chainmonitor::MonitorUpdateId;
+use crate::chain::chainmonitor::{MonitorUpdateId, UpdateOrigin};
use crate::chain::channelmonitor;
use crate::chain::channelmonitor::MonitorEvent;
use crate::chain::transaction::OutPoint;
if let Some((find_route_query, find_route_res)) = self.next_routes.lock().unwrap().pop_front() {
assert_eq!(find_route_query, *params);
if let Ok(ref route) = find_route_res {
- assert_eq!(route.route_params.as_ref().unwrap().final_value_msat, find_route_query.final_value_msat);
+ assert_eq!(route.route_params, Some(find_route_query));
let scorer = self.scorer.read().unwrap();
let scorer = ScorerAccountingForInFlightHtlcs::new(scorer, &inflight_htlcs);
for path in &route.paths {
// Since the path is reversed, the last element in our iteration is the first
// hop.
if idx == path.hops.len() - 1 {
- scorer.channel_penalty_msat(hop.short_channel_id, &NodeId::from_pubkey(payer), &NodeId::from_pubkey(&hop.pubkey), usage, &());
+ scorer.channel_penalty_msat(hop.short_channel_id, &NodeId::from_pubkey(payer), &NodeId::from_pubkey(&hop.pubkey), usage, &Default::default());
} else {
let curr_hop_path_idx = path.hops.len() - 1 - idx;
- scorer.channel_penalty_msat(hop.short_channel_id, &NodeId::from_pubkey(&path.hops[curr_hop_path_idx - 1].pubkey), &NodeId::from_pubkey(&hop.pubkey), usage, &());
+ scorer.channel_penalty_msat(hop.short_channel_id, &NodeId::from_pubkey(&path.hops[curr_hop_path_idx - 1].pubkey), &NodeId::from_pubkey(&hop.pubkey), usage, &Default::default());
}
}
}
let logger = TestLogger::new();
find_route(
payer, params, &self.network_graph, first_hops, &logger,
- &ScorerAccountingForInFlightHtlcs::new(self.scorer.read().unwrap(), &inflight_htlcs), &(),
+ &ScorerAccountingForInFlightHtlcs::new(self.scorer.read().unwrap(), &inflight_htlcs), &Default::default(),
&[42; 32]
)
}
/// ChannelForceClosed event for the given channel_id with should_broadcast set to the given
/// boolean.
pub expect_channel_force_closed: Mutex<Option<(ChannelId, bool)>>,
+ /// If this is set to Some(), the next round trip serialization check will not hold after an
+ /// update_channel call (not watch_channel) for the given channel_id.
+ pub expect_monitor_round_trip_fail: Mutex<Option<ChannelId>>,
}
impl<'a> TestChainMonitor<'a> {
pub fn new(chain_source: Option<&'a TestChainSource>, broadcaster: &'a chaininterface::BroadcasterInterface, logger: &'a TestLogger, fee_estimator: &'a TestFeeEstimator, persister: &'a chainmonitor::Persist<TestChannelSigner>, keys_manager: &'a TestKeysInterface) -> Self {
chain_monitor: chainmonitor::ChainMonitor::new(chain_source, broadcaster, logger, fee_estimator, persister),
keys_manager,
expect_channel_force_closed: Mutex::new(None),
+ expect_monitor_round_trip_fail: Mutex::new(None),
}
}
monitor.write(&mut w).unwrap();
let new_monitor = <(BlockHash, channelmonitor::ChannelMonitor<TestChannelSigner>)>::read(
&mut io::Cursor::new(&w.0), (self.keys_manager, self.keys_manager)).unwrap().1;
- assert!(new_monitor == *monitor);
+ if let Some(chan_id) = self.expect_monitor_round_trip_fail.lock().unwrap().take() {
+ assert_eq!(chan_id, funding_txo.to_channel_id());
+ assert!(new_monitor != *monitor);
+ } else {
+ assert!(new_monitor == *monitor);
+ }
self.added_monitors.lock().unwrap().push((funding_txo, new_monitor));
update_res
}
chain::ChannelMonitorUpdateStatus::Completed
}
- fn update_persisted_channel(&self, funding_txo: OutPoint, update: Option<&channelmonitor::ChannelMonitorUpdate>, _data: &channelmonitor::ChannelMonitor<Signer>, update_id: MonitorUpdateId) -> chain::ChannelMonitorUpdateStatus {
+ fn update_persisted_channel(&self, funding_txo: OutPoint, _update: Option<&channelmonitor::ChannelMonitorUpdate>, _data: &channelmonitor::ChannelMonitor<Signer>, update_id: MonitorUpdateId) -> chain::ChannelMonitorUpdateStatus {
let mut ret = chain::ChannelMonitorUpdateStatus::Completed;
if let Some(update_ret) = self.update_rets.lock().unwrap().pop_front() {
ret = update_ret;
}
- if update.is_none() {
+ let is_chain_sync = if let UpdateOrigin::ChainSync(_) = update_id.contents { true } else { false };
+ if is_chain_sync {
self.chain_sync_monitor_persistences.lock().unwrap().entry(funding_txo).or_insert(HashSet::new()).insert(update_id);
} else {
self.offchain_monitor_updates.lock().unwrap().entry(funding_txo).or_insert(HashSet::new()).insert(update_id);