//! responsible for tracking which channels are open, HTLCs are in flight and reestablishing those
//! upon reconnect to the relevant peer(s).
//!
-//! It does not manage routing logic (see routing::router::get_route for that) nor does it manage constructing
+//! It does not manage routing logic (see [`find_route`] for that) nor does it manage constructing
//! on-chain transactions (it only monitors the chain to watch for any force-closes that might
//! imply it needs to fail HTLCs/payments/channels it manages).
//!
+//! [`find_route`]: crate::routing::router::find_route
use bitcoin::blockdata::block::BlockHeader;
use bitcoin::blockdata::transaction::Transaction;
self.list_channels_with_filter(|_| true)
}
- /// Gets the list of usable channels, in random order. Useful as an argument to
- /// get_route to ensure non-announced channels are used.
+ /// Gets the list of usable channels, in random order. Useful as an argument to [`find_route`]
+ /// to ensure non-announced channels are used.
///
/// These are guaranteed to have their [`ChannelDetails::is_usable`] value set to true, see the
/// documentation for [`ChannelDetails::is_usable`] for more info on exactly what the criteria
/// are.
+ ///
+ /// [`find_route`]: crate::routing::router::find_route
pub fn list_usable_channels(&self) -> Vec<ChannelDetails> {
// Note we use is_live here instead of usable which leads to somewhat confused
// internal/external nomenclature, but that's ok cause that's probably what the user
if route.paths.len() < 1 {
return Err(PaymentSendFailure::ParameterError(APIError::RouteError{err: "There must be at least one path to send over"}));
}
- if route.paths.len() > 10 {
- // This limit is completely arbitrary - there aren't any real fundamental path-count
- // limits. After we support retrying individual paths we should likely bump this, but
- // for now more than 10 paths likely carries too much one-path failure.
- return Err(PaymentSendFailure::ParameterError(APIError::RouteError{err: "Sending over more than 10 paths is not currently supported"}));
- }
if payment_secret.is_none() && route.paths.len() > 1 {
return Err(PaymentSendFailure::ParameterError(APIError::APIMisuseError{err: "Payment secret is required for multi-path payments".to_string()}));
}
// Fail a list of HTLCs that were just freed from the holding cell. The HTLCs need to be
// failed backwards or, if they were one of our outgoing HTLCs, then their failure needs to
// be surfaced to the user.
- fn fail_holding_cell_htlcs(&self, mut htlcs_to_fail: Vec<(HTLCSource, PaymentHash)>, channel_id: [u8; 32]) {
+ fn fail_holding_cell_htlcs(
+ &self, mut htlcs_to_fail: Vec<(HTLCSource, PaymentHash)>, channel_id: [u8; 32],
+ _counterparty_node_id: &PublicKey
+ ) {
for (htlc_src, payment_hash) in htlcs_to_fail.drain(..) {
match htlc_src {
HTLCSource::PreviousHopData(HTLCPreviousHopData { .. }) => {
.. } => {
// we get a fail_malformed_htlc from the first hop
// TODO: We'd like to generate a NetworkUpdate for temporary
- // failures here, but that would be insufficient as get_route
+ // failures here, but that would be insufficient as find_route
// generally ignores its view of our own channels as we provide them via
// ChannelDetails.
// TODO: For non-temporary failures, we really should be closing the
/// [`Event::ChannelClosed::user_channel_id`] to allow tracking of which events correspond
/// with which `accept_inbound_channel`/`accept_inbound_channel_from_trusted_peer_0conf` call.
///
+ /// Note that this method will return an error and reject the channel, if it requires support
+ /// for zero confirmations. Instead, `accept_inbound_channel_from_trusted_peer_0conf` must be
+ /// used to accept such channels.
+ ///
/// [`Event::OpenChannelRequest`]: events::Event::OpenChannelRequest
/// [`Event::ChannelClosed::user_channel_id`]: events::Event::ChannelClosed::user_channel_id
pub fn accept_inbound_channel(&self, temporary_channel_id: &[u8; 32], counterparty_node_id: &PublicKey, user_channel_id: u64) -> Result<(), APIError> {
if *counterparty_node_id != channel.get().get_counterparty_node_id() {
return Err(APIError::APIMisuseError { err: "The passed counterparty_node_id doesn't match the channel's counterparty node_id".to_owned() });
}
- if accept_0conf { channel.get_mut().set_0conf(); }
+ if accept_0conf {
+ channel.get_mut().set_0conf();
+ } else if channel.get().get_channel_type().requires_zero_conf() {
+ let send_msg_err_event = events::MessageSendEvent::HandleError {
+ node_id: channel.get().get_counterparty_node_id(),
+ action: msgs::ErrorAction::SendErrorMessage{
+ msg: msgs::ErrorMessage { channel_id: temporary_channel_id.clone(), data: "No zero confirmation channels accepted".to_owned(), }
+ }
+ };
+ channel_state.pending_msg_events.push(send_msg_err_event);
+ let _ = remove_channel!(self, channel_state, channel);
+ return Err(APIError::APIMisuseError { err: "Please use accept_inbound_channel_from_trusted_peer_0conf to accept channels with zero confirmations.".to_owned() });
+ }
+
channel_state.pending_msg_events.push(events::MessageSendEvent::SendAcceptChannel {
node_id: channel.get().get_counterparty_node_id(),
msg: channel.get_mut().accept_inbound_channel(user_channel_id),
},
hash_map::Entry::Vacant(entry) => {
if !self.default_configuration.manually_accept_inbound_channels {
+ if channel.get_channel_type().requires_zero_conf() {
+ return Err(MsgHandleErrInternal::send_err_msg_no_close("No zero confirmation channels accepted".to_owned(), msg.temporary_channel_id.clone()));
+ }
channel_state.pending_msg_events.push(events::MessageSendEvent::SendAcceptChannel {
node_id: counterparty_node_id.clone(),
msg: channel.accept_inbound_channel(0),
if chan.get().get_counterparty_node_id() != *counterparty_node_id {
return Err(MsgHandleErrInternal::send_err_msg_no_close("Got a message for a channel from the wrong node!".to_owned(), msg.temporary_channel_id));
}
- try_chan_entry!(self, chan.get_mut().accept_channel(&msg, &self.default_configuration.peer_channel_config_limits, &their_features), channel_state, chan);
+ try_chan_entry!(self, chan.get_mut().accept_channel(&msg, &self.default_configuration.channel_handshake_limits, &their_features), channel_state, chan);
(chan.get().get_value_satoshis(), chan.get().get_funding_redeemscript().to_v0_p2wsh(), chan.get().get_user_id())
},
hash_map::Entry::Vacant(_) => return Err(MsgHandleErrInternal::send_err_msg_no_close("Failed to find corresponding channel".to_owned(), msg.temporary_channel_id))
hash_map::Entry::Vacant(_) => break Err(MsgHandleErrInternal::send_err_msg_no_close("Failed to find corresponding channel".to_owned(), msg.channel_id))
}
};
- self.fail_holding_cell_htlcs(htlcs_to_fail, msg.channel_id);
+ self.fail_holding_cell_htlcs(htlcs_to_fail, msg.channel_id, counterparty_node_id);
match res {
Ok((pending_forwards, mut pending_failures, finalized_claim_htlcs,
short_channel_id, channel_outpoint)) =>
}
};
post_handle_chan_restoration!(self, chan_restoration_res);
- self.fail_holding_cell_htlcs(htlcs_failed_forward, msg.channel_id);
+ self.fail_holding_cell_htlcs(htlcs_failed_forward, msg.channel_id, counterparty_node_id);
if let Some(channel_ready_msg) = need_lnd_workaround {
self.internal_channel_ready(counterparty_node_id, &channel_ready_msg)?;
match chan.maybe_free_holding_cell_htlcs(&self.logger) {
Ok((commitment_opt, holding_cell_failed_htlcs)) => {
if !holding_cell_failed_htlcs.is_empty() {
- failed_htlcs.push((holding_cell_failed_htlcs, *channel_id));
+ failed_htlcs.push((
+ holding_cell_failed_htlcs,
+ *channel_id,
+ chan.get_counterparty_node_id()
+ ));
}
if let Some((commitment_update, monitor_update)) = commitment_opt {
if let Err(e) = self.chain_monitor.update_channel(chan.get_funding_txo().unwrap(), monitor_update) {
}
let has_update = has_monitor_update || !failed_htlcs.is_empty() || !handle_errors.is_empty();
- for (failures, channel_id) in failed_htlcs.drain(..) {
- self.fail_holding_cell_htlcs(failures, channel_id);
+ for (failures, channel_id, counterparty_node_id) in failed_htlcs.drain(..) {
+ self.fail_holding_cell_htlcs(failures, channel_id, &counterparty_node_id);
}
for (counterparty_node_id, err) in handle_errors.drain(..) {
final_cltv_expiry_delta: TEST_FINAL_CLTV,
};
let route = find_route(
- &nodes[0].node.get_our_node_id(), &route_params, nodes[0].network_graph, None,
- nodes[0].logger, &scorer, &random_seed_bytes
+ &nodes[0].node.get_our_node_id(), &route_params, &nodes[0].network_graph.read_only(),
+ None, nodes[0].logger, &scorer, &random_seed_bytes
).unwrap();
nodes[0].node.send_spontaneous_payment(&route, Some(payment_preimage)).unwrap();
check_added_monitors!(nodes[0], 1);
// To start (2), send a keysend payment but don't claim it.
let payment_preimage = PaymentPreimage([42; 32]);
let route = find_route(
- &nodes[0].node.get_our_node_id(), &route_params, nodes[0].network_graph, None,
- nodes[0].logger, &scorer, &random_seed_bytes
+ &nodes[0].node.get_our_node_id(), &route_params, &nodes[0].network_graph.read_only(),
+ None, nodes[0].logger, &scorer, &random_seed_bytes
).unwrap();
let (payment_hash, _) = nodes[0].node.send_spontaneous_payment(&route, Some(payment_preimage)).unwrap();
check_added_monitors!(nodes[0], 1);
let scorer = test_utils::TestScorer::with_penalty(0);
let random_seed_bytes = chanmon_cfgs[1].keys_manager.get_secure_random_bytes();
let route = find_route(
- &payer_pubkey, &route_params, network_graph, Some(&first_hops.iter().collect::<Vec<_>>()),
- nodes[0].logger, &scorer, &random_seed_bytes
+ &payer_pubkey, &route_params, &network_graph.read_only(),
+ Some(&first_hops.iter().collect::<Vec<_>>()), nodes[0].logger, &scorer,
+ &random_seed_bytes
).unwrap();
let test_preimage = PaymentPreimage([42; 32]);
let scorer = test_utils::TestScorer::with_penalty(0);
let random_seed_bytes = chanmon_cfgs[1].keys_manager.get_secure_random_bytes();
let route = find_route(
- &payer_pubkey, &route_params, network_graph, Some(&first_hops.iter().collect::<Vec<_>>()),
- nodes[0].logger, &scorer, &random_seed_bytes
+ &payer_pubkey, &route_params, &network_graph.read_only(),
+ Some(&first_hops.iter().collect::<Vec<_>>()), nodes[0].logger, &scorer,
+ &random_seed_bytes
).unwrap();
let test_preimage = PaymentPreimage([42; 32]);
use ln::features::{InitFeatures, InvoiceFeatures};
use ln::functional_test_utils::*;
use ln::msgs::{ChannelMessageHandler, Init};
- use routing::network_graph::NetworkGraph;
+ use routing::gossip::NetworkGraph;
use routing::router::{PaymentParameters, get_route};
use util::test_utils;
use util::config::UserConfig;
let fee_estimator = test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(253) };
let mut config: UserConfig = Default::default();
- config.own_channel_config.minimum_depth = 1;
+ config.channel_handshake_config.minimum_depth = 1;
let logger_a = test_utils::TestLogger::with_id("node a".to_owned());
let chain_monitor_a = ChainMonitor::new(None, &tx_broadcaster, &logger_a, &fee_estimator, &persister_a);
_ => panic!(),
}
- let dummy_graph = NetworkGraph::new(genesis_hash);
+ let dummy_graph = NetworkGraph::new(genesis_hash, &logger_a);
let mut payment_count: u64 = 0;
macro_rules! send_payment {