// looking like probes.
},
events::Event::PaymentForwarded { .. } if $node == 1 => {},
+ events::Event::ChannelReady { .. } => {},
events::Event::PendingHTLCsForwardable { .. } => {
nodes[$node].process_pending_htlc_forwards();
},
// Set up a background event handler for FundingGenerationReady events.
let (sender, receiver) = std::sync::mpsc::sync_channel(1);
- let event_handler = move |event: &Event| {
- sender.send(handle_funding_generation_ready!(event, channel_value)).unwrap();
+ let event_handler = move |event: &Event| match event {
+ Event::FundingGenerationReady { .. } => sender.send(handle_funding_generation_ready!(event, channel_value)).unwrap(),
+ Event::ChannelReady { .. } => {},
+ _ => panic!("Unexpected event: {:?}", event),
};
+
let bg_processor = BackgroundProcessor::start(persister, event_handler, nodes[0].chain_monitor.clone(), nodes[0].node.clone(), nodes[0].no_gossip_sync(), nodes[0].peer_manager.clone(), nodes[0].logger.clone(), Some(nodes[0].scorer.clone()));
// Open a channel and check that the FundingGenerationReady event was handled.
// Set up a background event handler for SpendableOutputs events.
let (sender, receiver) = std::sync::mpsc::sync_channel(1);
- let event_handler = move |event: &Event| sender.send(event.clone()).unwrap();
+ let event_handler = move |event: &Event| match event {
+ Event::SpendableOutputs { .. } => sender.send(event.clone()).unwrap(),
+ Event::ChannelReady { .. } => {},
+ Event::ChannelClosed { .. } => {},
+ _ => panic!("Unexpected event: {:?}", event),
+ };
let persister = Arc::new(Persister::new(data_dir));
let bg_processor = BackgroundProcessor::start(persister, event_handler, nodes[0].chain_monitor.clone(), nodes[0].node.clone(), nodes[0].no_gossip_sync(), nodes[0].peer_manager.clone(), nodes[0].logger.clone(), Some(nodes[0].scorer.clone()));
nodes[0].node.force_close_broadcasting_latest_txn(&nodes[0].node.list_channels()[0].channel_id, &nodes[1].node.get_our_node_id()).unwrap();
let commitment_tx = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().pop().unwrap();
confirm_transaction_depth(&mut nodes[0], &commitment_tx, BREAKDOWN_TIMEOUT as u32);
+
let event = receiver
.recv_timeout(Duration::from_secs(EVENT_DEADLINE))
- .expect("SpendableOutputs not handled within deadline");
+ .expect("Events not handled within deadline");
match event {
Event::SpendableOutputs { .. } => {},
- Event::ChannelClosed { .. } => {},
_ => panic!("Unexpected event: {:?}", event),
}
get_event_msg!(nodes[2], MessageSendEvent::SendChannelUpdate, nodes[0].node.get_our_node_id());
nodes[0].node.handle_channel_ready(&nodes[2].node.get_our_node_id(), &as_channel_ready);
get_event_msg!(nodes[0], MessageSendEvent::SendChannelUpdate, nodes[2].node.get_our_node_id());
+ expect_channel_ready_event(&nodes[0], &nodes[2].node.get_our_node_id());
+ expect_channel_ready_event(&nodes[2], &nodes[0].node.get_our_node_id());
// As `msgs::ChannelUpdate` was never handled for the participating node(s) of the second
// channel, the channel will never be assigned any `counterparty.forwarding_info`.
get_event_msg!(nodes[1], MessageSendEvent::SendChannelUpdate, nodes[3].node.get_our_node_id());
nodes[3].node.handle_channel_ready(&nodes[1].node.get_our_node_id(), &as_channel_ready);
get_event_msg!(nodes[3], MessageSendEvent::SendChannelUpdate, nodes[1].node.get_our_node_id());
+ expect_channel_ready_event(&nodes[1], &nodes[3].node.get_our_node_id());
+ expect_channel_ready_event(&nodes[3], &nodes[1].node.get_our_node_id());
// As `msgs::ChannelUpdate` was never handled for the participating node(s) of the third
// channel, the channel will never be assigned any `counterparty.forwarding_info`.
node.gossip_sync.handle_channel_update(&bs_update).unwrap();
}
+ if !restore_b_before_lock {
+ expect_channel_ready_event(&nodes[1], &nodes[0].node.get_our_node_id());
+ } else {
+ expect_channel_ready_event(&nodes[0], &nodes[1].node.get_our_node_id());
+ }
+
+
send_payment(&nodes[0], &[&nodes[1]], 8000000);
close_channel(&nodes[0], &nodes[1], &channel_id, funding_tx, true);
check_closed_event!(nodes[0], 1, ClosureReason::CooperativeClosure);
// don't currently support node id aliases and eventually privacy should be provided with
// blinded paths instead of simple scid+node_id aliases.
outbound_scid_alias: u64,
+
+ // We track whether we already emitted a `ChannelReady` event.
+ channel_ready_event_emitted: bool,
}
#[cfg(any(test, fuzzing))]
latest_inbound_scid_alias: None,
outbound_scid_alias,
+ channel_ready_event_emitted: false,
+
#[cfg(any(test, fuzzing))]
historical_inbound_htlc_fulfills: HashSet::new(),
latest_inbound_scid_alias: None,
outbound_scid_alias,
+ channel_ready_event_emitted: false,
+
#[cfg(any(test, fuzzing))]
historical_inbound_htlc_fulfills: HashSet::new(),
self.prev_config.map(|prev_config| prev_config.0)
}
+ // Checks whether we should emit a `ChannelReady` event.
+ pub(crate) fn should_emit_channel_ready_event(&mut self) -> bool {
+ self.is_usable() && !self.channel_ready_event_emitted
+ }
+
+ // Remembers that we already emitted a `ChannelReady` event.
+ pub(crate) fn set_channel_ready_event_emitted(&mut self) {
+ self.channel_ready_event_emitted = true;
+ }
+
/// Tracks the number of ticks elapsed since the previous [`ChannelConfig`] was updated. Once
/// [`EXPIRE_PREV_CONFIG_TICKS`] is reached, the previous config is considered expired and will
/// no longer be considered when forwarding HTLCs.
if self.holder_max_htlc_value_in_flight_msat != Self::get_holder_max_htlc_value_in_flight_msat(self.channel_value_satoshis, &old_max_in_flight_percent_config)
{ Some(self.holder_max_htlc_value_in_flight_msat) } else { None };
+ let channel_ready_event_emitted = Some(self.channel_ready_event_emitted);
+
write_tlv_fields!(writer, {
(0, self.announcement_sigs, option),
// minimum_depth and counterparty_selected_channel_reserve_satoshis used to have a
(17, self.announcement_sigs_state, required),
(19, self.latest_inbound_scid_alias, option),
(21, self.outbound_scid_alias, required),
+ (23, channel_ready_event_emitted, option),
});
Ok(())
let mut announcement_sigs_state = Some(AnnouncementSigsState::NotSent);
let mut latest_inbound_scid_alias = None;
let mut outbound_scid_alias = None;
+ let mut channel_ready_event_emitted = None;
read_tlv_fields!(reader, {
(0, announcement_sigs, option),
(17, announcement_sigs_state, option),
(19, latest_inbound_scid_alias, option),
(21, outbound_scid_alias, option),
+ (23, channel_ready_event_emitted, option),
});
if let Some(preimages) = preimages_opt {
// Later in the ChannelManager deserialization phase we scan for channels and assign scid aliases if its missing
outbound_scid_alias: outbound_scid_alias.unwrap_or(0),
+ channel_ready_event_emitted: channel_ready_event_emitted.unwrap_or(true),
+
#[cfg(any(test, fuzzing))]
historical_inbound_htlc_fulfills,
}
}
+macro_rules! emit_channel_ready_event {
+ ($self: expr, $channel: expr) => {
+ if $channel.should_emit_channel_ready_event() {
+ {
+ let mut pending_events = $self.pending_events.lock().unwrap();
+ pending_events.push(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(),
+ });
+ }
+ $channel.set_channel_ready_event_emitted();
+ }
+ }
+}
+
macro_rules! handle_chan_restoration_locked {
($self: ident, $channel_lock: expr, $channel_state: expr, $channel_entry: expr,
$raa: expr, $commitment_update: expr, $order: expr, $chanmon_update: expr,
});
}
+ emit_channel_ready_event!($self, $channel_entry.get_mut());
+
let funding_broadcastable: Option<Transaction> = $funding_broadcastable; // Force type-checking to resolve
if let Some(monitor_update) = chanmon_update {
// We only ever broadcast a funding transaction in response to a funding_signed
});
}
}
+
+ emit_channel_ready_event!(self, chan.get_mut());
+
Ok(())
},
hash_map::Entry::Vacant(_) => Err(MsgHandleErrInternal::send_err_msg_no_close("Failed to find corresponding channel".to_owned(), msg.channel_id))
log_trace!(self.logger, "Sending channel_ready WITHOUT channel_update for {}", log_bytes!(channel.channel_id()));
}
}
+
+ emit_channel_ready_event!(self, channel);
+
if let Some(announcement_sigs) = announcement_sigs {
log_trace!(self.logger, "Sending announcement_signatures for channel {}", log_bytes!(channel.channel_id()));
pending_msg_events.push(events::MessageSendEvent::SendAnnouncementSignatures {
_ => panic!(),
}
+ let events_a = node_a.get_and_clear_pending_events();
+ assert_eq!(events_a.len(), 1);
+ match events_a[0] {
+ Event::ChannelReady{ ref counterparty_node_id, .. } => {
+ assert_eq!(*counterparty_node_id, node_b.get_our_node_id());
+ },
+ _ => panic!("Unexpected event"),
+ }
+
+ let events_b = node_b.get_and_clear_pending_events();
+ assert_eq!(events_b.len(), 1);
+ match events_b[0] {
+ Event::ChannelReady{ ref counterparty_node_id, .. } => {
+ assert_eq!(*counterparty_node_id, node_a.get_our_node_id());
+ },
+ _ => panic!("Unexpected event"),
+ }
+
let dummy_graph = NetworkGraph::new(genesis_hash, &logger_a);
let mut payment_count: u64 = 0;
assert_eq!(initiator.node.list_usable_channels().len(), initiator_channels + 1);
assert_eq!(receiver.node.list_usable_channels().len(), receiver_channels + 1);
+ expect_channel_ready_event(&initiator, &receiver.node.get_our_node_id());
+ expect_channel_ready_event(&receiver, &initiator.node.get_our_node_id());
+
(tx, as_channel_ready.channel_id)
}
create_chan_between_nodes_with_value_confirm_first(node_a, node_b, tx, conf_height);
confirm_transaction_at(node_a, tx, conf_height);
connect_blocks(node_a, CHAN_CONFIRM_DEPTH - 1);
+ expect_channel_ready_event(&node_a, &node_b.node.get_our_node_id());
create_chan_between_nodes_with_value_confirm_second(node_b, node_a)
}
*node_a.network_chan_count.borrow_mut() += 1;
+ expect_channel_ready_event(&node_b, &node_a.node.get_our_node_id());
((*announcement).clone(), (*as_update).clone(), (*bs_update).clone())
}
connect_blocks(&nodes[b], CHAN_CONFIRM_DEPTH - 1);
let as_channel_ready = get_event_msg!(nodes[a], MessageSendEvent::SendChannelReady, nodes[b].node.get_our_node_id());
nodes[a].node.handle_channel_ready(&nodes[b].node.get_our_node_id(), &get_event_msg!(nodes[b], MessageSendEvent::SendChannelReady, nodes[a].node.get_our_node_id()));
+ expect_channel_ready_event(&nodes[a], &nodes[b].node.get_our_node_id());
let as_update = get_event_msg!(nodes[a], MessageSendEvent::SendChannelUpdate, nodes[b].node.get_our_node_id());
nodes[b].node.handle_channel_ready(&nodes[a].node.get_our_node_id(), &as_channel_ready);
+ expect_channel_ready_event(&nodes[b], &nodes[a].node.get_our_node_id());
let bs_update = get_event_msg!(nodes[b], MessageSendEvent::SendChannelUpdate, nodes[a].node.get_our_node_id());
nodes[a].node.handle_channel_update(&nodes[b].node.get_our_node_id(), &bs_update);
}
}
+#[cfg(any(test, feature = "_bench_unstable", feature = "_test_utils"))]
+pub fn expect_channel_ready_event<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, expected_counterparty_node_id: &PublicKey) {
+ let events = node.node.get_and_clear_pending_events();
+ assert_eq!(events.len(), 1);
+ match events[0] {
+ crate::util::events::Event::ChannelReady{ ref counterparty_node_id, .. } => {
+ assert_eq!(*expected_counterparty_node_id, *counterparty_node_id);
+ },
+ _ => panic!("Unexpected event"),
+ }
+}
+
+
pub struct PaymentFailedConditions<'a> {
pub(crate) expected_htlc_error_data: Option<(u16, &'a [u8])>,
pub(crate) expected_blamed_scid: Option<u64>,
confirm_transaction_at(&nodes[0], &tx, 2);
connect_blocks(&nodes[0], CHAN_CONFIRM_DEPTH);
create_chan_between_nodes_with_value_confirm_second(&nodes[1], &nodes[0]);
+ expect_channel_ready_event(&nodes[0], &nodes[1].node.get_our_node_id());
}
#[test]
}
let events_1 = nodes[1].node.get_and_clear_pending_events();
- assert_eq!(events_1.len(), 1);
- match events_1[0] {
- Event::PendingHTLCsForwardable { .. } => { },
- _ => panic!("Unexpected event"),
- };
+ if messages_delivered == 0 {
+ assert_eq!(events_1.len(), 2);
+ match events_1[0] {
+ Event::ChannelReady { .. } => { },
+ _ => panic!("Unexpected event"),
+ };
+ match events_1[1] {
+ Event::PendingHTLCsForwardable { .. } => { },
+ _ => panic!("Unexpected event"),
+ };
+ } else {
+ assert_eq!(events_1.len(), 1);
+ match events_1[0] {
+ Event::PendingHTLCsForwardable { .. } => { },
+ _ => panic!("Unexpected event"),
+ };
+ }
nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false);
},
_ => panic!("Unexpected event {:?}", events_6[0]),
};
+ expect_channel_ready_event(&nodes[0], &nodes[1].node.get_our_node_id());
+ expect_channel_ready_event(&nodes[1], &nodes[0].node.get_our_node_id());
// When we deliver nodes[1]'s announcement_signatures to nodes[0], nodes[0] should immediately
// broadcast the channel announcement globally, as well as re-send its (now-public)
let (channel_ready, _) = create_chan_between_nodes_with_value_confirm(&nodes[0], &nodes[1], &tx);
let (announcement, as_update, bs_update) = create_chan_between_nodes_with_value_b(&nodes[0], &nodes[1], &channel_ready);
update_nodes_with_chan_announce(&nodes, 0, 1, &announcement, &as_update, &bs_update);
+
send_payment(&nodes[0], &[&nodes[1]], 8000000);
}
nodes[1].node.handle_update_fulfill_htlc(&nodes[2].node.get_our_node_id(), &htlc_fulfill_updates.update_fulfill_htlcs[0]);
check_added_monitors!(nodes[1], 1);
commitment_signed_dance!(nodes[1], nodes[2], htlc_fulfill_updates.commitment_signed, false);
+ expect_payment_forwarded!(nodes[1], nodes[0], nodes[2], None, false, false);
if confirm_before_reload {
let best_block = nodes[0].blocks.lock().unwrap().last().unwrap().clone();
let bs_htlc_claim_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0);
assert_eq!(bs_htlc_claim_txn.len(), 1);
check_spends!(bs_htlc_claim_txn[0], as_commitment_tx);
- expect_payment_forwarded!(nodes[1], nodes[0], nodes[2], None, false, false);
if !confirm_before_reload {
mine_transaction(&nodes[0], &as_commitment_tx);
} else { panic!("Unexpected event"); }
nodes[1].node.handle_channel_ready(&nodes[0].node.get_our_node_id(), &as_channel_ready);
+ expect_channel_ready_event(&nodes[0], &nodes[1].node.get_our_node_id());
+ expect_channel_ready_event(&nodes[1], &nodes[0].node.get_our_node_id());
let bs_msg_events = nodes[1].node.get_and_clear_pending_msg_events();
assert_eq!(bs_msg_events.len(), 1);
if let MessageSendEvent::SendChannelUpdate { ref node_id, msg: _ } = bs_msg_events[0] {
connect_blocks(&nodes[2], CHAN_CONFIRM_DEPTH - 1);
let bs_channel_ready = get_event_msg!(nodes[1], MessageSendEvent::SendChannelReady, nodes[2].node.get_our_node_id());
nodes[1].node.handle_channel_ready(&nodes[2].node.get_our_node_id(), &get_event_msg!(nodes[2], MessageSendEvent::SendChannelReady, nodes[1].node.get_our_node_id()));
+ expect_channel_ready_event(&nodes[1], &nodes[2].node.get_our_node_id());
let bs_update = get_event_msg!(nodes[1], MessageSendEvent::SendChannelUpdate, nodes[2].node.get_our_node_id());
nodes[2].node.handle_channel_ready(&nodes[1].node.get_our_node_id(), &bs_channel_ready);
+ expect_channel_ready_event(&nodes[2], &nodes[1].node.get_our_node_id());
let cs_update = get_event_msg!(nodes[2], MessageSendEvent::SendChannelUpdate, nodes[1].node.get_our_node_id());
nodes[1].node.handle_channel_update(&nodes[2].node.get_our_node_id(), &cs_update);
}
_ => panic!("Unexpected event"),
}
+ expect_channel_ready_event(&nodes[0], &nodes[1].node.get_our_node_id());
+ expect_channel_ready_event(&nodes[1], &nodes[0].node.get_our_node_id());
+
let bs_channel_update = get_event_msg!(nodes[1], MessageSendEvent::SendChannelUpdate, nodes[0].node.get_our_node_id());
let as_channel_update = match &as_locked_update[1] {
use crate::ln::msgs::DecodeError;
use crate::ln::{PaymentPreimage, PaymentHash, PaymentSecret};
use crate::routing::gossip::NetworkUpdate;
-use crate::util::ser::{BigSize, FixedLengthReader, Writeable, Writer, MaybeReadable, Readable, VecReadWrapper, VecWriteWrapper};
+use crate::util::ser::{BigSize, FixedLengthReader, Writeable, Writer, MaybeReadable, Readable, VecReadWrapper, VecWriteWrapper, OptionDeserWrapper};
use crate::routing::router::{RouteHop, RouteParameters};
use bitcoin::{PackedLockTime, Transaction, OutPoint};
/// transaction.
claim_from_onchain_tx: bool,
},
+ /// Used to indicate that a channel with the given `channel_id` is ready to
+ /// be used. This event is emitted either when the funding transaction has been confirmed
+ /// on-chain, or, in case of a 0conf channel, when both parties have confirmed the channel
+ /// establishment.
+ ChannelReady {
+ /// The channel_id of the channel that is ready.
+ channel_id: [u8; 32],
+ /// The `user_channel_id` value passed in to [`ChannelManager::create_channel`] for outbound
+ /// channels, or to [`ChannelManager::accept_inbound_channel`] for inbound channels if
+ /// [`UserConfig::manually_accept_inbound_channels`] config flag is set to true. Otherwise
+ /// `user_channel_id` will be 0 for an inbound channel.
+ ///
+ /// [`ChannelManager::create_channel`]: crate::ln::channelmanager::ChannelManager::create_channel
+ /// [`ChannelManager::accept_inbound_channel`]: crate::ln::channelmanager::ChannelManager::accept_inbound_channel
+ /// [`UserConfig::manually_accept_inbound_channels`]: crate::util::config::UserConfig::manually_accept_inbound_channels
+ user_channel_id: u64,
+ /// The node_id of the channel counterparty.
+ counterparty_node_id: PublicKey,
+ /// The features that this channel will operate with.
+ channel_type: ChannelTypeFeatures,
+ },
/// Used to indicate that a previously opened channel with the given `channel_id` is in the
/// process of closure.
ChannelClosed {
BumpTransactionEvent::ChannelClose { .. } => {}
}
}
+ &Event::ChannelReady { ref channel_id, ref user_channel_id, ref counterparty_node_id, ref channel_type } => {
+ 29u8.write(writer)?;
+ write_tlv_fields!(writer, {
+ (0, channel_id, required),
+ (2, user_channel_id, required),
+ (4, counterparty_node_id, required),
+ (6, channel_type, required),
+ });
+ },
// Note that, going forward, all new events must only write data inside of
// `write_tlv_fields`. Versions 0.0.101+ will ignore odd-numbered events that write
// data via `write_tlv_fields`.
};
f()
},
+ 27u8 => Ok(None),
+ 29u8 => {
+ let f = || {
+ let mut channel_id = [0; 32];
+ let mut user_channel_id: u64 = 0;
+ let mut counterparty_node_id = OptionDeserWrapper(None);
+ let mut channel_type = OptionDeserWrapper(None);
+ read_tlv_fields!(reader, {
+ (0, channel_id, required),
+ (2, user_channel_id, required),
+ (4, counterparty_node_id, required),
+ (6, channel_type, required),
+ });
+
+ Ok(Some(Event::ChannelReady {
+ channel_id,
+ user_channel_id,
+ counterparty_node_id: counterparty_node_id.0.unwrap(),
+ channel_type: channel_type.0.unwrap()
+ }))
+ };
+ f()
+ },
// Versions prior to 0.0.100 did not ignore odd types, instead returning InvalidValue.
// Version 0.0.100 failed to properly ignore odd types, possibly resulting in corrupt
// reads.
--- /dev/null
+## API Updates
+- A new `ChannelReady` event is generated whenever a channel becomes ready to
+ be used, i.e., after both sides sent the `channel_ready` message.
+
+## Backwards Compatibilty
+- No `ChannelReady` events will be generated for previously existing channels, including
+ those which become ready after upgrading 0.0.113.