#[cfg(any(feature = "_test_utils", test))]
use crate::ln::features::InvoiceFeatures;
use crate::routing::gossip::NetworkGraph;
-use crate::routing::router::{DefaultRouter, InFlightHtlcs, PaymentParameters, Route, RouteHop, RouteParameters, RoutePath, Router};
+use crate::routing::router::{BlindedTail, DefaultRouter, InFlightHtlcs, Path, PaymentParameters, Route, RouteHop, RouteParameters, Router};
use crate::routing::scoring::ProbabilisticScorer;
use crate::ln::msgs;
use crate::ln::onion_utils;
use crate::ln::outbound_payment;
use crate::ln::outbound_payment::{OutboundPayments, PaymentAttempts, PendingOutboundPayment};
use crate::ln::wire::Encode;
-use crate::chain::keysinterface::{EntropySource, KeysManager, NodeSigner, Recipient, SignerProvider, ChannelSigner, WriteableEcdsaChannelSigner};
+use crate::sign::{EntropySource, KeysManager, NodeSigner, Recipient, SignerProvider, ChannelSigner, WriteableEcdsaChannelSigner};
use crate::util::config::{UserConfig, ChannelConfig};
use crate::util::wakers::{Future, Notifier};
use crate::util::scid_utils::fake_scid;
// Re-export this for use in the public API.
pub use crate::ln::outbound_payment::{PaymentSendFailure, Retry, RetryableSendFailure, RecipientOnionFields};
+use crate::ln::script::ShutdownScript;
// We hold various information about HTLC relay in the HTLC objects in Channel itself:
//
pub(crate) enum HTLCSource {
PreviousHopData(HTLCPreviousHopData),
OutboundRoute {
- path: Vec<RouteHop>,
+ path: Path,
session_priv: SecretKey,
/// Technically we can recalculate this from the route, but we cache it here to avoid
/// doing a double-pass on route when we get a failure back
#[cfg(test)]
pub fn dummy() -> Self {
HTLCSource::OutboundRoute {
- path: Vec::new(),
+ path: Path { hops: Vec::new(), blinded_tail: None },
session_priv: SecretKey::from_slice(&[1; 32]).unwrap(),
first_hop_htlc_msat: 0,
payment_id: PaymentId([2; 32]),
(2, EmitEvent) => { (0, event, upgradable_required) },
);
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub(crate) enum EventCompletionAction {
+ ReleaseRAAChannelMonitorUpdate {
+ counterparty_node_id: PublicKey,
+ channel_funding_outpoint: OutPoint,
+ },
+}
+impl_writeable_tlv_based_enum!(EventCompletionAction,
+ (0, ReleaseRAAChannelMonitorUpdate) => {
+ (0, channel_funding_outpoint, required),
+ (2, counterparty_node_id, required),
+ };
+);
+
/// State we hold per-peer.
pub(super) struct PeerState<Signer: ChannelSigner> {
/// `temporary_channel_id` or `channel_id` -> `channel`.
#[cfg(any(test, feature = "_test_utils"))]
pub(super) per_peer_state: FairRwLock<HashMap<PublicKey, Mutex<PeerState<<SP::Target as SignerProvider>::Signer>>>>,
+ /// The set of events which we need to give to the user to handle. In some cases an event may
+ /// require some further action after the user handles it (currently only blocking a monitor
+ /// update from being handed to the user to ensure the included changes to the channel state
+ /// are handled by the user before they're persisted durably to disk). In that case, the second
+ /// element in the tuple is set to `Some` with further details of the action.
+ ///
+ /// Note that events MUST NOT be removed from pending_events after deserialization, as they
+ /// could be in the middle of being processed without the direct mutex held.
+ ///
/// See `ChannelManager` struct-level documentation for lock order requirements.
- pending_events: Mutex<Vec<events::Event>>,
+ pending_events: Mutex<VecDeque<(events::Event, Option<EventCompletionAction>)>>,
/// A simple atomic flag to ensure only one task at a time can be processing events asynchronously.
pending_events_processor: AtomicBool,
/// See `ChannelManager` struct-level documentation for lock order requirements.
/// Route hints used in constructing invoices for [phantom node payents].
///
-/// [phantom node payments]: crate::chain::keysinterface::PhantomKeysManager
+/// [phantom node payments]: crate::sign::PhantomKeysManager
#[derive(Clone)]
pub struct PhantomRouteHints {
/// The list of channels to be included in the invoice route hints.
});
}
if let Some((channel_id, user_channel_id)) = chan_id {
- $self.pending_events.lock().unwrap().push(events::Event::ChannelClosed {
+ $self.pending_events.lock().unwrap().push_back((events::Event::ChannelClosed {
channel_id, user_channel_id,
reason: ClosureReason::ProcessingError { err: err.err.clone() }
- });
+ }, None));
}
}
macro_rules! emit_channel_pending_event {
($locked_events: expr, $channel: expr) => {
if $channel.should_emit_channel_pending_event() {
- $locked_events.push(events::Event::ChannelPending {
+ $locked_events.push_back((events::Event::ChannelPending {
channel_id: $channel.channel_id(),
former_temporary_channel_id: $channel.temporary_channel_id(),
counterparty_node_id: $channel.get_counterparty_node_id(),
user_channel_id: $channel.get_user_id(),
funding_txo: $channel.get_funding_txo().unwrap().into_bitcoin_outpoint(),
- });
+ }, None));
$channel.set_channel_pending_event_emitted();
}
}
($locked_events: expr, $channel: expr) => {
if $channel.should_emit_channel_ready_event() {
debug_assert!($channel.channel_pending_event_emitted());
- $locked_events.push(events::Event::ChannelReady {
+ $locked_events.push_back((events::Event::ChannelReady {
channel_id: $channel.channel_id(),
user_channel_id: $channel.get_user_id(),
counterparty_node_id: $channel.get_counterparty_node_id(),
channel_type: $channel.get_channel_type().clone(),
- });
+ }, None));
$channel.set_channel_ready_event_emitted();
}
}
res
},
ChannelMonitorUpdateStatus::Completed => {
- if ($update_id == 0 || $chan.get_next_monitor_update()
- .expect("We can't be processing a monitor update if it isn't queued")
- .update_id == $update_id) &&
- $chan.get_latest_monitor_update_id() == $update_id
- {
+ $chan.complete_one_mon_update($update_id);
+ if $chan.no_monitor_updates_pending() {
handle_monitor_update_completion!($self, $update_id, $peer_state_lock, $peer_state, $per_peer_state_lock, $chan);
}
Ok(())
result = NotifyOption::DoPersist;
}
- for event in pending_events {
+ let mut post_event_actions = Vec::new();
+
+ for (event, action_opt) in pending_events {
$event_to_handle = event;
$handle_event;
+ if let Some(action) = action_opt {
+ post_event_actions.push(action);
+ }
}
{
$self.pending_events_processor.store(false, Ordering::Release);
}
+ if !post_event_actions.is_empty() {
+ $self.handle_post_event_actions(post_event_actions);
+ // If we had some actions, go around again as we may have more events now
+ processed_all_events = false;
+ }
+
if result == NotifyOption::DoPersist {
$self.persistence_notifier.notify();
}
per_peer_state: FairRwLock::new(HashMap::new()),
- pending_events: Mutex::new(Vec::new()),
+ pending_events: Mutex::new(VecDeque::new()),
pending_events_processor: AtomicBool::new(false),
pending_background_events: Mutex::new(Vec::new()),
total_consistency_lock: RwLock::new(()),
let mut pending_events_lock = self.pending_events.lock().unwrap();
match channel.unbroadcasted_funding() {
Some(transaction) => {
- pending_events_lock.push(events::Event::DiscardFunding { channel_id: channel.channel_id(), transaction })
+ pending_events_lock.push_back((events::Event::DiscardFunding {
+ channel_id: channel.channel_id(), transaction
+ }, None));
},
None => {},
}
- pending_events_lock.push(events::Event::ChannelClosed {
+ pending_events_lock.push_back((events::Event::ChannelClosed {
channel_id: channel.channel_id(),
user_channel_id: channel.get_user_id(),
reason: closure_reason
- });
+ }, None));
}
- fn close_channel_internal(&self, channel_id: &[u8; 32], counterparty_node_id: &PublicKey, target_feerate_sats_per_1000_weight: Option<u32>) -> Result<(), APIError> {
+ fn close_channel_internal(&self, channel_id: &[u8; 32], counterparty_node_id: &PublicKey, target_feerate_sats_per_1000_weight: Option<u32>, override_shutdown_script: Option<ShutdownScript>) -> Result<(), APIError> {
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
let mut failed_htlcs: Vec<(HTLCSource, PaymentHash)>;
let funding_txo_opt = chan_entry.get().get_funding_txo();
let their_features = &peer_state.latest_features;
let (shutdown_msg, mut monitor_update_opt, htlcs) = chan_entry.get_mut()
- .get_shutdown(&self.signer_provider, their_features, target_feerate_sats_per_1000_weight)?;
+ .get_shutdown(&self.signer_provider, their_features, target_feerate_sats_per_1000_weight, override_shutdown_script)?;
failed_htlcs = htlcs;
// We can send the `shutdown` message before updating the `ChannelMonitor`
/// [`Normal`]: crate::chain::chaininterface::ConfirmationTarget::Normal
/// [`SendShutdown`]: crate::events::MessageSendEvent::SendShutdown
pub fn close_channel(&self, channel_id: &[u8; 32], counterparty_node_id: &PublicKey) -> Result<(), APIError> {
- self.close_channel_internal(channel_id, counterparty_node_id, None)
+ self.close_channel_internal(channel_id, counterparty_node_id, None, None)
}
/// Begins the process of closing a channel. After this call (plus some timeout), no new HTLCs
/// transaction feerate below `target_feerate_sat_per_1000_weight` (or the feerate which
/// will appear on a force-closure transaction, whichever is lower).
///
+ /// The `shutdown_script` provided will be used as the `scriptPubKey` for the closing transaction.
+ /// Will fail if a shutdown script has already been set for this channel by
+ /// ['ChannelHandshakeConfig::commit_upfront_shutdown_pubkey`]. The given shutdown script must
+ /// also be compatible with our and the counterparty's features.
+ ///
/// May generate a [`SendShutdown`] message event on success, which should be relayed.
///
/// Raises [`APIError::ChannelUnavailable`] if the channel cannot be closed due to failing to
/// [`Background`]: crate::chain::chaininterface::ConfirmationTarget::Background
/// [`Normal`]: crate::chain::chaininterface::ConfirmationTarget::Normal
/// [`SendShutdown`]: crate::events::MessageSendEvent::SendShutdown
- pub fn close_channel_with_target_feerate(&self, channel_id: &[u8; 32], counterparty_node_id: &PublicKey, target_feerate_sats_per_1000_weight: u32) -> Result<(), APIError> {
- self.close_channel_internal(channel_id, counterparty_node_id, Some(target_feerate_sats_per_1000_weight))
+ pub fn close_channel_with_feerate_and_script(&self, channel_id: &[u8; 32], counterparty_node_id: &PublicKey, target_feerate_sats_per_1000_weight: Option<u32>, shutdown_script: Option<ShutdownScript>) -> Result<(), APIError> {
+ self.close_channel_internal(channel_id, counterparty_node_id, target_feerate_sats_per_1000_weight, shutdown_script)
}
#[inline]
}
#[cfg(test)]
- pub(crate) fn test_send_payment_along_path(&self, path: &Vec<RouteHop>, payment_hash: &PaymentHash, recipient_onion: RecipientOnionFields, total_value: u64, cur_height: u32, payment_id: PaymentId, keysend_preimage: &Option<PaymentPreimage>, session_priv_bytes: [u8; 32]) -> Result<(), APIError> {
+ pub(crate) fn test_send_payment_along_path(&self, path: &Path, payment_hash: &PaymentHash, recipient_onion: RecipientOnionFields, total_value: u64, cur_height: u32, payment_id: PaymentId, keysend_preimage: &Option<PaymentPreimage>, session_priv_bytes: [u8; 32]) -> Result<(), APIError> {
let _lck = self.total_consistency_lock.read().unwrap();
self.send_payment_along_path(path, payment_hash, recipient_onion, total_value, cur_height, payment_id, keysend_preimage, session_priv_bytes)
}
- fn send_payment_along_path(&self, path: &Vec<RouteHop>, payment_hash: &PaymentHash, recipient_onion: RecipientOnionFields, total_value: u64, cur_height: u32, payment_id: PaymentId, keysend_preimage: &Option<PaymentPreimage>, session_priv_bytes: [u8; 32]) -> Result<(), APIError> {
+ fn send_payment_along_path(&self, path: &Path, payment_hash: &PaymentHash, recipient_onion: RecipientOnionFields, total_value: u64, cur_height: u32, payment_id: PaymentId, keysend_preimage: &Option<PaymentPreimage>, session_priv_bytes: [u8; 32]) -> Result<(), APIError> {
// The top-level caller should hold the total_consistency_lock read lock.
debug_assert!(self.total_consistency_lock.try_write().is_err());
- log_trace!(self.logger, "Attempting to send payment for path with next hop {}", path.first().unwrap().short_channel_id);
+ log_trace!(self.logger, "Attempting to send payment for path with next hop {}", path.hops.first().unwrap().short_channel_id);
let prng_seed = self.entropy_source.get_secure_random_bytes();
let session_priv = SecretKey::from_slice(&session_priv_bytes[..]).expect("RNG is busted");
let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, prng_seed, payment_hash);
let err: Result<(), _> = loop {
- let (counterparty_node_id, id) = match self.short_to_chan_info.read().unwrap().get(&path.first().unwrap().short_channel_id) {
+ let (counterparty_node_id, id) = match self.short_to_chan_info.read().unwrap().get(&path.hops.first().unwrap().short_channel_id) {
None => return Err(APIError::ChannelUnavailable{err: "No channel available with first hop!".to_owned()}),
Some((cp_id, chan_id)) => (cp_id.clone(), chan_id.clone()),
};
return Ok(());
};
- match handle_error!(self, err, path.first().unwrap().pubkey) {
+ match handle_error!(self, err, path.hops.first().unwrap().pubkey) {
Ok(_) => unreachable!(),
Err(e) => {
Err(APIError::ChannelUnavailable { err: e.err })
/// Send a payment that is probing the given route for liquidity. We calculate the
/// [`PaymentHash`] of probes based on a static secret and a random [`PaymentId`], which allows
/// us to easily discern them from real payments.
- pub fn send_probe(&self, hops: Vec<RouteHop>) -> Result<(PaymentHash, PaymentId), PaymentSendFailure> {
+ pub fn send_probe(&self, path: Path) -> Result<(PaymentHash, PaymentId), PaymentSendFailure> {
let best_block_height = self.best_block.read().unwrap().height();
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
- self.pending_outbound_payments.send_probe(hops, self.probing_cookie_secret, &self.entropy_source, &self.node_signer, best_block_height,
+ self.pending_outbound_payments.send_probe(path, self.probing_cookie_secret, &self.entropy_source, &self.node_signer, best_block_height,
|path, payment_hash, recipient_onion, total_value, cur_height, payment_id, keysend_preimage, session_priv|
self.send_payment_along_path(path, payment_hash, recipient_onion, total_value, cur_height, payment_id, keysend_preimage, session_priv))
}
}
{
let height = self.best_block.read().unwrap().height();
- // Transactions are evaluated as final by network mempools at the next block. However, the modules
- // constituting our Lightning node might not have perfect sync about their blockchain views. Thus, if
- // the wallet module is in advance on the LDK view, allow one more block of headroom.
- if !funding_transaction.input.iter().all(|input| input.sequence == Sequence::MAX) && LockTime::from(funding_transaction.lock_time).is_block_height() && funding_transaction.lock_time.0 > height + 2 {
+ // Transactions are evaluated as final by network mempools if their locktime is strictly
+ // lower than the next block height. However, the modules constituting our Lightning
+ // node might not have perfect sync about their blockchain views. Thus, if the wallet
+ // module is ahead of LDK, only allow one more block of headroom.
+ if !funding_transaction.input.iter().all(|input| input.sequence == Sequence::MAX) && LockTime::from(funding_transaction.lock_time).is_block_height() && funding_transaction.lock_time.0 > height + 1 {
return Err(APIError::APIMisuseError {
err: "Funding transaction absolute timelock is non-final".to_owned()
});
pub fn process_pending_htlc_forwards(&self) {
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
- let mut new_events = Vec::new();
+ let mut new_events = VecDeque::new();
let mut failed_forwards = Vec::new();
let mut phantom_receives: Vec<(u64, OutPoint, u128, Vec<(PendingHTLCInfo, u64)>)> = Vec::new();
{
htlcs.push(claimable_htlc);
let amount_msat = htlcs.iter().map(|htlc| htlc.value).sum();
htlcs.iter_mut().for_each(|htlc| htlc.total_value_received = Some(amount_msat));
- new_events.push(events::Event::PaymentClaimable {
+ new_events.push_back((events::Event::PaymentClaimable {
receiver_node_id: Some(receiver_node_id),
payment_hash,
purpose: purpose(),
via_user_channel_id: Some(prev_user_channel_id),
claim_deadline: Some(earliest_expiry - HTLC_FAIL_BACK_BUFFER),
onion_fields: claimable_payment.onion_fields.clone(),
- });
+ }, None));
payment_claimable_generated = true;
} else {
// Nothing to do - we haven't reached the total
htlcs: vec![claimable_htlc],
});
let prev_channel_id = prev_funding_outpoint.to_channel_id();
- new_events.push(events::Event::PaymentClaimable {
+ new_events.push_back((events::Event::PaymentClaimable {
receiver_node_id: Some(receiver_node_id),
payment_hash,
amount_msat,
via_user_channel_id: Some(prev_user_channel_id),
claim_deadline,
onion_fields: Some(onion_fields),
- });
+ }, None));
},
hash_map::Entry::Occupied(_) => {
log_trace!(self.logger, "Failing new keysend HTLC with payment_hash {} for a duplicative payment hash", log_bytes!(payment_hash.0));
mem::drop(forward_htlcs);
if push_forward_ev { self.push_pending_forwards_ev(); }
let mut pending_events = self.pending_events.lock().unwrap();
- pending_events.push(events::Event::HTLCHandlingFailed {
+ pending_events.push_back((events::Event::HTLCHandlingFailed {
prev_channel_id: outpoint.to_channel_id(),
failed_next_destination: destination,
- });
+ }, None));
},
}
}
MonitorUpdateCompletionAction::PaymentClaimed { payment_hash } => {
let payment = self.claimable_payments.lock().unwrap().pending_claiming_payments.remove(&payment_hash);
if let Some(ClaimingPayment { amount_msat, payment_purpose: purpose, receiver_node_id }) = payment {
- self.pending_events.lock().unwrap().push(events::Event::PaymentClaimed {
+ self.pending_events.lock().unwrap().push_back((events::Event::PaymentClaimed {
payment_hash, purpose, amount_msat, receiver_node_id: Some(receiver_node_id),
- });
+ }, None));
}
},
MonitorUpdateCompletionAction::EmitEvent { event } => {
- self.pending_events.lock().unwrap().push(event);
+ self.pending_events.lock().unwrap().push_back((event, None));
},
}
}
});
} else {
let mut pending_events = self.pending_events.lock().unwrap();
- pending_events.push(
- events::Event::OpenChannelRequest {
- temporary_channel_id: msg.temporary_channel_id.clone(),
- counterparty_node_id: counterparty_node_id.clone(),
- funding_satoshis: msg.funding_satoshis,
- push_msat: msg.push_msat,
- channel_type: channel.get_channel_type().clone(),
- }
- );
+ pending_events.push_back((events::Event::OpenChannelRequest {
+ temporary_channel_id: msg.temporary_channel_id.clone(),
+ counterparty_node_id: counterparty_node_id.clone(),
+ funding_satoshis: msg.funding_satoshis,
+ push_msat: msg.push_msat,
+ channel_type: channel.get_channel_type().clone(),
+ }, None));
}
entry.insert(channel);
}
};
let mut pending_events = self.pending_events.lock().unwrap();
- pending_events.push(events::Event::FundingGenerationReady {
+ pending_events.push_back((events::Event::FundingGenerationReady {
temporary_channel_id: msg.temporary_channel_id,
counterparty_node_id: *counterparty_node_id,
channel_value_satoshis: value,
output_script,
user_channel_id: user_id,
- });
+ }, None));
Ok(())
}
match peer_state.channel_by_id.entry(msg.channel_id) {
hash_map::Entry::Occupied(mut chan) => {
let funding_txo = chan.get().get_funding_txo();
- let monitor_update = try_chan_entry!(self, chan.get_mut().commitment_signed(&msg, &self.logger), chan);
- let update_res = self.chain_monitor.update_channel(funding_txo.unwrap(), monitor_update);
- let update_id = monitor_update.update_id;
- handle_new_monitor_update!(self, update_res, update_id, peer_state_lock,
- peer_state, per_peer_state, chan)
+ let monitor_update_opt = try_chan_entry!(self, chan.get_mut().commitment_signed(&msg, &self.logger), chan);
+ if let Some(monitor_update) = monitor_update_opt {
+ let update_res = self.chain_monitor.update_channel(funding_txo.unwrap(), monitor_update);
+ let update_id = monitor_update.update_id;
+ handle_new_monitor_update!(self, update_res, update_id, peer_state_lock,
+ peer_state, per_peer_state, chan)
+ } else { Ok(()) }
},
hash_map::Entry::Vacant(_) => return Err(MsgHandleErrInternal::send_err_msg_no_close(format!("Got a message for a channel from the wrong node! No such channel for the passed counterparty_node_id {}", counterparty_node_id), msg.channel_id))
}
fn forward_htlcs(&self, per_source_pending_forwards: &mut [(u64, OutPoint, u128, Vec<(PendingHTLCInfo, u64)>)]) {
for &mut (prev_short_channel_id, prev_funding_outpoint, prev_user_channel_id, ref mut pending_forwards) in per_source_pending_forwards {
let mut push_forward_event = false;
- let mut new_intercept_events = Vec::new();
+ let mut new_intercept_events = VecDeque::new();
let mut failed_intercept_forwards = Vec::new();
if !pending_forwards.is_empty() {
for (forward_info, prev_htlc_id) in pending_forwards.drain(..) {
let mut pending_intercepts = self.pending_intercepted_htlcs.lock().unwrap();
match pending_intercepts.entry(intercept_id) {
hash_map::Entry::Vacant(entry) => {
- new_intercept_events.push(events::Event::HTLCIntercepted {
+ new_intercept_events.push_back((events::Event::HTLCIntercepted {
requested_next_hop_scid: scid,
payment_hash: forward_info.payment_hash,
inbound_amount_msat: forward_info.incoming_amt_msat.unwrap(),
expected_outbound_amount_msat: forward_info.outgoing_amt_msat,
intercept_id
- });
+ }, None));
entry.insert(PendingAddHTLCInfo {
prev_short_channel_id, prev_funding_outpoint, prev_htlc_id, prev_user_channel_id, forward_info });
},
fn push_pending_forwards_ev(&self) {
let mut pending_events = self.pending_events.lock().unwrap();
let forward_ev_exists = pending_events.iter()
- .find(|ev| if let events::Event::PendingHTLCsForwardable { .. } = ev { true } else { false })
+ .find(|(ev, _)| if let events::Event::PendingHTLCsForwardable { .. } = ev { true } else { false })
.is_some();
if !forward_ev_exists {
- pending_events.push(events::Event::PendingHTLCsForwardable {
+ pending_events.push_back((events::Event::PendingHTLCsForwardable {
time_forwardable:
Duration::from_millis(MIN_HTLC_RELAY_HOLDING_CELL_MILLIS),
- });
+ }, None));
}
}
match peer_state.channel_by_id.entry(msg.channel_id) {
hash_map::Entry::Occupied(mut chan) => {
let funding_txo = chan.get().get_funding_txo();
- let (htlcs_to_fail, monitor_update) = try_chan_entry!(self, chan.get_mut().revoke_and_ack(&msg, &self.logger), chan);
- let update_res = self.chain_monitor.update_channel(funding_txo.unwrap(), monitor_update);
- let update_id = monitor_update.update_id;
- let res = handle_new_monitor_update!(self, update_res, update_id,
- peer_state_lock, peer_state, per_peer_state, chan);
+ let (htlcs_to_fail, monitor_update_opt) = try_chan_entry!(self, chan.get_mut().revoke_and_ack(&msg, &self.logger), chan);
+ let res = if let Some(monitor_update) = monitor_update_opt {
+ let update_res = self.chain_monitor.update_channel(funding_txo.unwrap(), monitor_update);
+ let update_id = monitor_update.update_id;
+ handle_new_monitor_update!(self, update_res, update_id,
+ peer_state_lock, peer_state, per_peer_state, chan)
+ } else { Ok(()) };
(htlcs_to_fail, res)
},
hash_map::Entry::Vacant(_) => return Err(MsgHandleErrInternal::send_err_msg_no_close(format!("Got a message for a channel from the wrong node! No such channel for the passed counterparty_node_id {}", counterparty_node_id), msg.channel_id))
/// Gets a fake short channel id for use in receiving [phantom node payments]. These fake scids
/// are used when constructing the phantom invoice's route hints.
///
- /// [phantom node payments]: crate::chain::keysinterface::PhantomKeysManager
+ /// [phantom node payments]: crate::sign::PhantomKeysManager
pub fn get_phantom_scid(&self) -> u64 {
let best_block_height = self.best_block.read().unwrap().height();
let short_to_chan_info = self.short_to_chan_info.read().unwrap();
/// Gets route hints for use in receiving [phantom node payments].
///
- /// [phantom node payments]: crate::chain::keysinterface::PhantomKeysManager
+ /// [phantom node payments]: crate::sign::PhantomKeysManager
pub fn get_phantom_route_hints(&self) -> PhantomRouteHints {
PhantomRouteHints {
channels: self.list_usable_channels(),
#[cfg(feature = "_test_utils")]
pub fn push_pending_event(&self, event: events::Event) {
let mut events = self.pending_events.lock().unwrap();
- events.push(event);
+ events.push_back((event, None));
}
#[cfg(test)]
pub fn pop_pending_event(&self) -> Option<events::Event> {
let mut events = self.pending_events.lock().unwrap();
- if events.is_empty() { None } else { Some(events.remove(0)) }
+ events.pop_front().map(|(e, _)| e)
}
#[cfg(test)]
self.pending_outbound_payments.clear_pending_payments()
}
+ fn handle_monitor_update_release(&self, counterparty_node_id: PublicKey, channel_funding_outpoint: OutPoint) {
+ let mut errors = Vec::new();
+ loop {
+ let per_peer_state = self.per_peer_state.read().unwrap();
+ if let Some(peer_state_mtx) = per_peer_state.get(&counterparty_node_id) {
+ let mut peer_state_lck = peer_state_mtx.lock().unwrap();
+ let peer_state = &mut *peer_state_lck;
+ if self.pending_events.lock().unwrap().iter()
+ .any(|(_ev, action_opt)| action_opt == &Some(EventCompletionAction::ReleaseRAAChannelMonitorUpdate {
+ channel_funding_outpoint, counterparty_node_id
+ }))
+ {
+ // Check that, while holding the peer lock, we don't have another event
+ // blocking any monitor updates for this channel. If we do, let those
+ // events be the ones that ultimately release the monitor update(s).
+ log_trace!(self.logger, "Delaying monitor unlock for channel {} as another event is pending",
+ log_bytes!(&channel_funding_outpoint.to_channel_id()[..]));
+ break;
+ }
+ if let hash_map::Entry::Occupied(mut chan) = peer_state.channel_by_id.entry(channel_funding_outpoint.to_channel_id()) {
+ debug_assert_eq!(chan.get().get_funding_txo().unwrap(), channel_funding_outpoint);
+ if let Some((monitor_update, further_update_exists)) = chan.get_mut().unblock_next_blocked_monitor_update() {
+ log_debug!(self.logger, "Unlocking monitor updating for channel {} and updating monitor",
+ log_bytes!(&channel_funding_outpoint.to_channel_id()[..]));
+ let update_res = self.chain_monitor.update_channel(channel_funding_outpoint, monitor_update);
+ let update_id = monitor_update.update_id;
+ if let Err(e) = handle_new_monitor_update!(self, update_res, update_id,
+ peer_state_lck, peer_state, per_peer_state, chan)
+ {
+ errors.push((e, counterparty_node_id));
+ }
+ if further_update_exists {
+ // If there are more `ChannelMonitorUpdate`s to process, restart at the
+ // top of the loop.
+ continue;
+ }
+ } else {
+ log_trace!(self.logger, "Unlocked monitor updating for channel {} without monitors to update",
+ log_bytes!(&channel_funding_outpoint.to_channel_id()[..]));
+ }
+ }
+ } else {
+ log_debug!(self.logger,
+ "Got a release post-RAA monitor update for peer {} but the channel is gone",
+ log_pubkey!(counterparty_node_id));
+ }
+ break;
+ }
+ for (err, counterparty_node_id) in errors {
+ let res = Err::<(), _>(err);
+ let _ = handle_error!(self, res, counterparty_node_id);
+ }
+ }
+
+ fn handle_post_event_actions(&self, actions: Vec<EventCompletionAction>) {
+ for action in actions {
+ match action {
+ EventCompletionAction::ReleaseRAAChannelMonitorUpdate {
+ channel_funding_outpoint, counterparty_node_id
+ } => {
+ self.handle_monitor_update_release(counterparty_node_id, channel_funding_outpoint);
+ }
+ }
+ }
+ }
+
/// Processes any events asynchronously in the order they were generated since the last call
/// using the given event handler.
///
// should also add the corresponding (optional) bit to the [`ChannelMessageHandler`] impl for
// [`ErroringMessageHandler`].
let mut features = InitFeatures::empty();
- features.set_data_loss_protect_optional();
+ features.set_data_loss_protect_required();
features.set_upfront_shutdown_script_optional();
features.set_variable_length_onion_required();
features.set_static_remote_key_required();
0 => {
let mut session_priv: crate::util::ser::RequiredWrapper<SecretKey> = crate::util::ser::RequiredWrapper(None);
let mut first_hop_htlc_msat: u64 = 0;
- let mut path: Option<Vec<RouteHop>> = Some(Vec::new());
+ let mut path_hops: Option<Vec<RouteHop>> = Some(Vec::new());
let mut payment_id = None;
let mut payment_params: Option<PaymentParameters> = None;
+ let mut blinded_tail: Option<BlindedTail> = None;
read_tlv_fields!(reader, {
(0, session_priv, required),
(1, payment_id, option),
(2, first_hop_htlc_msat, required),
- (4, path, vec_type),
+ (4, path_hops, vec_type),
(5, payment_params, (option: ReadableArgs, 0)),
+ (6, blinded_tail, option),
});
if payment_id.is_none() {
// For backwards compat, if there was no payment_id written, use the session_priv bytes
// instead.
payment_id = Some(PaymentId(*session_priv.0.unwrap().as_ref()));
}
- if path.is_none() || path.as_ref().unwrap().is_empty() {
+ let path = Path { hops: path_hops.ok_or(DecodeError::InvalidValue)?, blinded_tail };
+ if path.hops.len() == 0 {
return Err(DecodeError::InvalidValue);
}
- let path = path.unwrap();
if let Some(params) = payment_params.as_mut() {
if params.final_cltv_expiry_delta == 0 {
- params.final_cltv_expiry_delta = path.last().unwrap().cltv_expiry_delta;
+ params.final_cltv_expiry_delta = path.final_cltv_expiry_delta().ok_or(DecodeError::InvalidValue)?;
}
}
Ok(HTLCSource::OutboundRoute {
(1, payment_id_opt, option),
(2, first_hop_htlc_msat, required),
// 3 was previously used to write a PaymentSecret for the payment.
- (4, *path, vec_type),
+ (4, path.hops, vec_type),
(5, None::<PaymentParameters>, option), // payment_params in LDK versions prior to 0.0.115
+ (6, path.blinded_tail, option),
});
}
HTLCSource::PreviousHopData(ref field) => {
}
let events = self.pending_events.lock().unwrap();
- (events.len() as u64).write(writer)?;
- for event in events.iter() {
- event.write(writer)?;
+ // LDK versions prior to 0.0.115 don't support post-event actions, thus if there's no
+ // actions at all, skip writing the required TLV. Otherwise, pre-0.0.115 versions will
+ // refuse to read the new ChannelManager.
+ let events_not_backwards_compatible = events.iter().any(|(_, action)| action.is_some());
+ if events_not_backwards_compatible {
+ // If we're gonna write a even TLV that will overwrite our events anyway we might as
+ // well save the space and not write any events here.
+ 0u64.write(writer)?;
+ } else {
+ (events.len() as u64).write(writer)?;
+ for (event, _) in events.iter() {
+ event.write(writer)?;
+ }
}
let background_events = self.pending_background_events.lock().unwrap();
(5, self.our_network_pubkey, required),
(6, monitor_update_blocked_actions_per_peer, option),
(7, self.fake_scid_rand_bytes, required),
+ (8, if events_not_backwards_compatible { Some(&*events) } else { None }, option),
(9, htlc_purposes, vec_type),
(11, self.probing_cookie_secret, required),
(13, htlc_onion_fields, optional_vec),
}
}
+impl Writeable for VecDeque<(Event, Option<EventCompletionAction>)> {
+ fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
+ (self.len() as u64).write(w)?;
+ for (event, action) in self.iter() {
+ event.write(w)?;
+ action.write(w)?;
+ #[cfg(debug_assertions)] {
+ // Events are MaybeReadable, in some cases indicating that they shouldn't actually
+ // be persisted and are regenerated on restart. However, if such an event has a
+ // post-event-handling action we'll write nothing for the event and would have to
+ // either forget the action or fail on deserialization (which we do below). Thus,
+ // check that the event is sane here.
+ let event_encoded = event.encode();
+ let event_read: Option<Event> =
+ MaybeReadable::read(&mut &event_encoded[..]).unwrap();
+ if action.is_some() { assert!(event_read.is_some()); }
+ }
+ }
+ Ok(())
+ }
+}
+impl Readable for VecDeque<(Event, Option<EventCompletionAction>)> {
+ fn read<R: Read>(reader: &mut R) -> Result<Self, DecodeError> {
+ let len: u64 = Readable::read(reader)?;
+ const MAX_ALLOC_SIZE: u64 = 1024 * 16;
+ let mut events: Self = VecDeque::with_capacity(cmp::min(
+ MAX_ALLOC_SIZE/mem::size_of::<(events::Event, Option<EventCompletionAction>)>() as u64,
+ len) as usize);
+ for _ in 0..len {
+ let ev_opt = MaybeReadable::read(reader)?;
+ let action = Readable::read(reader)?;
+ if let Some(ev) = ev_opt {
+ events.push_back((ev, action));
+ } else if action.is_some() {
+ return Err(DecodeError::InvalidValue);
+ }
+ }
+ Ok(events)
+ }
+}
+
/// Arguments for the creation of a ChannelManager that are not deserialized.
///
/// At a high-level, the process for deserializing a ChannelManager and resuming normal operation
let mut peer_channels: HashMap<PublicKey, HashMap<[u8; 32], Channel<<SP::Target as SignerProvider>::Signer>>> = HashMap::with_capacity(cmp::min(channel_count as usize, 128));
let mut id_to_peer = HashMap::with_capacity(cmp::min(channel_count as usize, 128));
let mut short_to_chan_info = HashMap::with_capacity(cmp::min(channel_count as usize, 128));
- let mut channel_closures = Vec::new();
+ let mut channel_closures = VecDeque::new();
let mut pending_background_events = Vec::new();
for _ in 0..channel_count {
let mut channel: Channel<<SP::Target as SignerProvider>::Signer> = Channel::read(reader, (
let funding_txo = channel.get_funding_txo().ok_or(DecodeError::InvalidValue)?;
funding_txo_set.insert(funding_txo.clone());
if let Some(ref mut monitor) = args.channel_monitors.get_mut(&funding_txo) {
- if channel.get_cur_holder_commitment_transaction_number() < monitor.get_cur_holder_commitment_number() ||
- channel.get_revoked_counterparty_commitment_transaction_number() < monitor.get_min_seen_secret() ||
- channel.get_cur_counterparty_commitment_transaction_number() < monitor.get_cur_counterparty_commitment_number() ||
- channel.get_latest_monitor_update_id() > monitor.get_latest_update_id() {
+ if channel.get_latest_complete_monitor_update_id() > monitor.get_latest_update_id() {
// If the channel is ahead of the monitor, return InvalidValue:
log_error!(args.logger, "A ChannelMonitor is stale compared to the current ChannelManager! This indicates a potentially-critical violation of the chain::Watch API!");
log_error!(args.logger, " The ChannelMonitor for channel {} is at update_id {} but the ChannelManager is at update_id {}.",
- log_bytes!(channel.channel_id()), monitor.get_latest_update_id(), channel.get_latest_monitor_update_id());
+ log_bytes!(channel.channel_id()), monitor.get_latest_update_id(), channel.get_latest_complete_monitor_update_id());
log_error!(args.logger, " The chain::Watch API *requires* that monitors are persisted durably before returning,");
log_error!(args.logger, " client applications must ensure that ChannelMonitor data is always available and the latest to avoid funds loss!");
log_error!(args.logger, " Without the latest ChannelMonitor we cannot continue without risking funds.");
pending_background_events.push(BackgroundEvent::ClosingMonitorUpdate(monitor_update));
}
failed_htlcs.append(&mut new_failed_htlcs);
- channel_closures.push(events::Event::ChannelClosed {
+ channel_closures.push_back((events::Event::ChannelClosed {
channel_id: channel.channel_id(),
user_channel_id: channel.get_user_id(),
reason: ClosureReason::OutdatedChannelManager
- });
+ }, None));
for (channel_htlc_source, payment_hash) in channel.inflight_htlc_sources() {
let mut found_htlc = false;
for (monitor_htlc_source, _) in monitor.get_all_current_outbound_htlcs() {
// was in-progress, we never broadcasted the funding transaction and can still
// safely discard the channel.
let _ = channel.force_shutdown(false);
- channel_closures.push(events::Event::ChannelClosed {
+ channel_closures.push_back((events::Event::ChannelClosed {
channel_id: channel.channel_id(),
user_channel_id: channel.get_user_id(),
reason: ClosureReason::DisconnectedPeer,
- });
+ }, None));
} else {
log_error!(args.logger, "Missing ChannelMonitor for channel {} needed by ChannelManager.", log_bytes!(channel.channel_id()));
log_error!(args.logger, " The chain::Watch API *requires* that monitors are persisted durably before returning,");
}
let event_count: u64 = Readable::read(reader)?;
- let mut pending_events_read: Vec<events::Event> = Vec::with_capacity(cmp::min(event_count as usize, MAX_ALLOC_SIZE/mem::size_of::<events::Event>()));
+ let mut pending_events_read: VecDeque<(events::Event, Option<EventCompletionAction>)> =
+ VecDeque::with_capacity(cmp::min(event_count as usize, MAX_ALLOC_SIZE/mem::size_of::<(events::Event, Option<EventCompletionAction>)>()));
for _ in 0..event_count {
match MaybeReadable::read(reader)? {
- Some(event) => pending_events_read.push(event),
+ Some(event) => pending_events_read.push_back((event, None)),
None => continue,
}
}
let mut claimable_htlc_onion_fields = None;
let mut pending_claiming_payments = Some(HashMap::new());
let mut monitor_update_blocked_actions_per_peer = Some(Vec::new());
+ let mut events_override = None;
read_tlv_fields!(reader, {
(1, pending_outbound_payments_no_retry, option),
(2, pending_intercepted_htlcs, option),
(5, received_network_pubkey, option),
(6, monitor_update_blocked_actions_per_peer, option),
(7, fake_scid_rand_bytes, option),
+ (8, events_override, option),
(9, claimable_htlc_purposes, vec_type),
(11, probing_cookie_secret, option),
(13, claimable_htlc_onion_fields, optional_vec),
probing_cookie_secret = Some(args.entropy_source.get_secure_random_bytes());
}
+ if let Some(events) = events_override {
+ pending_events_read = events;
+ }
+
if !channel_closures.is_empty() {
pending_events_read.append(&mut channel_closures);
}
if id_to_peer.get(&monitor.get_funding_txo().0.to_channel_id()).is_none() {
for (htlc_source, (htlc, _)) in monitor.get_pending_or_resolved_outbound_htlcs() {
if let HTLCSource::OutboundRoute { payment_id, session_priv, path, .. } = htlc_source {
- if path.is_empty() {
+ if path.hops.is_empty() {
log_error!(args.logger, "Got an empty path for a pending payment");
return Err(DecodeError::InvalidValue);
}
- let path_amt = path.last().unwrap().fee_msat;
+ let path_amt = path.final_value_msat();
let mut session_priv_bytes = [0; 32];
session_priv_bytes[..].copy_from_slice(&session_priv[..]);
match pending_outbounds.pending_outbound_payments.lock().unwrap().entry(payment_id) {
if newly_added { "Added" } else { "Had" }, path_amt, log_bytes!(session_priv_bytes), log_bytes!(htlc.payment_hash.0));
},
hash_map::Entry::Vacant(entry) => {
- let path_fee = path.get_path_fees();
+ let path_fee = path.fee_msat();
entry.insert(PendingOutboundPayment::Retryable {
retry_strategy: None,
attempts: PaymentAttempts::new(),
if pending_forward_matches_htlc(&htlc_info) {
log_info!(args.logger, "Removing pending intercepted HTLC with hash {} as it was forwarded to the closed channel {}",
log_bytes!(htlc.payment_hash.0), log_bytes!(monitor.get_funding_txo().0.to_channel_id()));
- pending_events_read.retain(|event| {
+ pending_events_read.retain(|(event, _)| {
if let Event::HTLCIntercepted { intercept_id: ev_id, .. } = event {
intercepted_id != ev_id
} else { true }
// shut down before the timer hit. Either way, set the time_forwardable to a small
// constant as enough time has likely passed that we should simply handle the forwards
// now, or at least after the user gets a chance to reconnect to our peers.
- pending_events_read.push(events::Event::PendingHTLCsForwardable {
+ pending_events_read.push_back((events::Event::PendingHTLCsForwardable {
time_forwardable: Duration::from_secs(2),
- });
+ }, None));
}
let inbound_pmt_key_material = args.node_signer.get_inbound_payment_key_material();
previous_hop_monitor.provide_payment_preimage(&payment_hash, &payment_preimage, &args.tx_broadcaster, &bounded_fee_estimator, &args.logger);
}
}
- pending_events_read.push(events::Event::PaymentClaimed {
+ pending_events_read.push_back((events::Event::PaymentClaimed {
receiver_node_id,
payment_hash,
purpose: payment.purpose,
amount_msat: claimable_amt_msat,
- });
+ }, None));
}
}
}
use crate::util::errors::APIError;
use crate::util::test_utils;
use crate::util::config::ChannelConfig;
- use crate::chain::keysinterface::EntropySource;
+ use crate::sign::EntropySource;
#[test]
fn test_notify_limits() {
let (mut route, payment_hash, _, _) = get_route_and_payment_hash!(&nodes[0], nodes[3], 100000);
let path = route.paths[0].clone();
route.paths.push(path);
- route.paths[0][0].pubkey = nodes[1].node.get_our_node_id();
- route.paths[0][0].short_channel_id = chan_1_id;
- route.paths[0][1].short_channel_id = chan_3_id;
- route.paths[1][0].pubkey = nodes[2].node.get_our_node_id();
- route.paths[1][0].short_channel_id = chan_2_id;
- route.paths[1][1].short_channel_id = chan_4_id;
+ route.paths[0].hops[0].pubkey = nodes[1].node.get_our_node_id();
+ route.paths[0].hops[0].short_channel_id = chan_1_id;
+ route.paths[0].hops[1].short_channel_id = chan_3_id;
+ route.paths[1].hops[0].pubkey = nodes[2].node.get_our_node_id();
+ route.paths[1].hops[0].short_channel_id = chan_2_id;
+ route.paths[1].hops[1].short_channel_id = chan_4_id;
match nodes[0].node.send_payment_with_route(&route, payment_hash,
RecipientOnionFields::spontaneous_empty(), PaymentId(payment_hash.0))
pub mod bench {
use crate::chain::Listen;
use crate::chain::chainmonitor::{ChainMonitor, Persist};
- use crate::chain::keysinterface::{KeysManager, InMemorySigner};
+ use crate::sign::{KeysManager, InMemorySigner};
use crate::events::{Event, MessageSendEvent, MessageSendEventsProvider};
use crate::ln::channelmanager::{BestBlock, ChainParameters, ChannelManager, PaymentHash, PaymentPreimage, PaymentId, RecipientOnionFields, Retry};
use crate::ln::functional_test_utils::*;
// calls per node.
let network = bitcoin::Network::Testnet;
- let tx_broadcaster = test_utils::TestBroadcaster{txn_broadcasted: Mutex::new(Vec::new()), blocks: Arc::new(Mutex::new(Vec::new()))};
+ let tx_broadcaster = test_utils::TestBroadcaster::new(network);
let fee_estimator = test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(253) };
let logger_a = test_utils::TestLogger::with_id("node a".to_owned());
let scorer = Mutex::new(test_utils::TestScorer::new());