impl Readable for ChannelUpdateInfo {
fn read<R: io::Read>(reader: &mut R) -> Result<Self, DecodeError> {
impl Readable for ChannelUpdateInfo {
fn read<R: io::Read>(reader: &mut R) -> Result<Self, DecodeError> {
- init_tlv_field_var!(last_update, required);
- init_tlv_field_var!(enabled, required);
- init_tlv_field_var!(cltv_expiry_delta, required);
- init_tlv_field_var!(htlc_minimum_msat, required);
- init_tlv_field_var!(htlc_maximum_msat, option);
- init_tlv_field_var!(fees, required);
- init_tlv_field_var!(last_update_message, required);
+ _init_tlv_field_var!(last_update, required);
+ _init_tlv_field_var!(enabled, required);
+ _init_tlv_field_var!(cltv_expiry_delta, required);
+ _init_tlv_field_var!(htlc_minimum_msat, required);
+ _init_tlv_field_var!(htlc_maximum_msat, option);
+ _init_tlv_field_var!(fees, required);
+ _init_tlv_field_var!(last_update_message, required);
read_tlv_fields!(reader, {
(0, last_update, required),
read_tlv_fields!(reader, {
(0, last_update, required),
- last_update: init_tlv_based_struct_field!(last_update, required),
- enabled: init_tlv_based_struct_field!(enabled, required),
- cltv_expiry_delta: init_tlv_based_struct_field!(cltv_expiry_delta, required),
- htlc_minimum_msat: init_tlv_based_struct_field!(htlc_minimum_msat, required),
+ last_update: _init_tlv_based_struct_field!(last_update, required),
+ enabled: _init_tlv_based_struct_field!(enabled, required),
+ cltv_expiry_delta: _init_tlv_based_struct_field!(cltv_expiry_delta, required),
+ htlc_minimum_msat: _init_tlv_based_struct_field!(htlc_minimum_msat, required),
- fees: init_tlv_based_struct_field!(fees, required),
- last_update_message: init_tlv_based_struct_field!(last_update_message, required),
+ fees: _init_tlv_based_struct_field!(fees, required),
+ last_update_message: _init_tlv_based_struct_field!(last_update_message, required),
impl Readable for ChannelInfo {
fn read<R: io::Read>(reader: &mut R) -> Result<Self, DecodeError> {
impl Readable for ChannelInfo {
fn read<R: io::Read>(reader: &mut R) -> Result<Self, DecodeError> {
- init_tlv_field_var!(features, required);
- init_tlv_field_var!(announcement_received_time, (default_value, 0));
- init_tlv_field_var!(node_one, required);
+ _init_tlv_field_var!(features, required);
+ _init_tlv_field_var!(announcement_received_time, (default_value, 0));
+ _init_tlv_field_var!(node_one, required);
- init_tlv_field_var!(capacity_sats, required);
- init_tlv_field_var!(announcement_message, required);
+ _init_tlv_field_var!(capacity_sats, required);
+ _init_tlv_field_var!(announcement_message, required);
read_tlv_fields!(reader, {
(0, features, required),
(1, announcement_received_time, (default_value, 0)),
read_tlv_fields!(reader, {
(0, features, required),
(1, announcement_received_time, (default_value, 0)),
- features: init_tlv_based_struct_field!(features, required),
- node_one: init_tlv_based_struct_field!(node_one, required),
+ features: _init_tlv_based_struct_field!(features, required),
+ node_one: _init_tlv_based_struct_field!(node_one, required),
- capacity_sats: init_tlv_based_struct_field!(capacity_sats, required),
- announcement_message: init_tlv_based_struct_field!(announcement_message, required),
- announcement_received_time: init_tlv_based_struct_field!(announcement_received_time, (default_value, 0)),
+ capacity_sats: _init_tlv_based_struct_field!(capacity_sats, required),
+ announcement_message: _init_tlv_based_struct_field!(announcement_message, required),
+ announcement_received_time: _init_tlv_based_struct_field!(announcement_received_time, (default_value, 0)),
impl Readable for NodeInfo {
fn read<R: io::Read>(reader: &mut R) -> Result<Self, DecodeError> {
impl Readable for NodeInfo {
fn read<R: io::Read>(reader: &mut R) -> Result<Self, DecodeError> {
read_tlv_fields!(reader, {
(0, lowest_inbound_channel_fees, option),
read_tlv_fields!(reader, {
(0, lowest_inbound_channel_fees, option),
+ self.channel_failed_with_time(short_channel_id, is_permanent, current_time_unix)
+ }
+
+ /// Marks a channel in the graph as failed if a corresponding HTLC fail was sent.
+ /// If permanent, removes a channel from the local storage.
+ /// May cause the removal of nodes too, if this was their last channel.
+ /// If not permanent, makes channels unavailable for routing.
+ fn channel_failed_with_time(&self, short_channel_id: u64, is_permanent: bool, current_time_unix: Option<u64>) {
let mut channels = self.channels.write().unwrap();
if is_permanent {
if let Some(chan) = channels.remove(&short_channel_id) {
let mut channels = self.channels.write().unwrap();
if is_permanent {
if let Some(chan) = channels.remove(&short_channel_id) {
use crate::ln::features::InitFeatures;
use crate::routing::gossip::{P2PGossipSync, NetworkGraph, NetworkUpdate, NodeAlias, MAX_EXCESS_BYTES_FOR_RELAY, NodeId, RoutingFees, ChannelUpdateInfo, ChannelInfo, NodeAnnouncementInfo, NodeInfo};
use crate::ln::msgs::{RoutingMessageHandler, UnsignedNodeAnnouncement, NodeAnnouncement,
UnsignedChannelAnnouncement, ChannelAnnouncement, UnsignedChannelUpdate, ChannelUpdate,
ReplyChannelRange, QueryChannelRange, QueryShortChannelIds, MAX_VALUE_MSAT};
use crate::ln::features::InitFeatures;
use crate::routing::gossip::{P2PGossipSync, NetworkGraph, NetworkUpdate, NodeAlias, MAX_EXCESS_BYTES_FOR_RELAY, NodeId, RoutingFees, ChannelUpdateInfo, ChannelInfo, NodeAnnouncementInfo, NodeInfo};
use crate::ln::msgs::{RoutingMessageHandler, UnsignedNodeAnnouncement, NodeAnnouncement,
UnsignedChannelAnnouncement, ChannelAnnouncement, UnsignedChannelUpdate, ChannelUpdate,
ReplyChannelRange, QueryChannelRange, QueryShortChannelIds, MAX_VALUE_MSAT};
use crate::util::test_utils;
use crate::util::ser::{ReadableArgs, Writeable};
use crate::util::events::{MessageSendEvent, MessageSendEventsProvider};
use crate::util::test_utils;
use crate::util::ser::{ReadableArgs, Writeable};
use crate::util::events::{MessageSendEvent, MessageSendEventsProvider};
fn get_signed_node_announcement<F: Fn(&mut UnsignedNodeAnnouncement)>(f: F, node_key: &SecretKey, secp_ctx: &Secp256k1<secp256k1::All>) -> NodeAnnouncement {
let node_id = PublicKey::from_secret_key(&secp_ctx, node_key);
let mut unsigned_announcement = UnsignedNodeAnnouncement {
fn get_signed_node_announcement<F: Fn(&mut UnsignedNodeAnnouncement)>(f: F, node_key: &SecretKey, secp_ctx: &Secp256k1<secp256k1::All>) -> NodeAnnouncement {
let node_id = PublicKey::from_secret_key(&secp_ctx, node_key);
let mut unsigned_announcement = UnsignedNodeAnnouncement {
let node_2_btckey = &SecretKey::from_slice(&[39; 32]).unwrap();
let mut unsigned_announcement = UnsignedChannelAnnouncement {
let node_2_btckey = &SecretKey::from_slice(&[39; 32]).unwrap();
let mut unsigned_announcement = UnsignedChannelAnnouncement {
// Mark the channel as permanently failed. This will also remove the two nodes
// and all of the entries will be tracked as removed.
// Mark the channel as permanently failed. This will also remove the two nodes
// and all of the entries will be tracked as removed.
// Should not remove from tracking if insufficient time has passed
network_graph.remove_stale_channels_and_tracking_with_time(
tracking_time + REMOVED_ENTRIES_TRACKING_AGE_LIMIT_SECS - 1);
// Should not remove from tracking if insufficient time has passed
network_graph.remove_stale_channels_and_tracking_with_time(
tracking_time + REMOVED_ENTRIES_TRACKING_AGE_LIMIT_SECS - 1);
- assert_eq!(network_graph.removed_channels.lock().unwrap().len(), 1);
+ assert_eq!(network_graph.removed_channels.lock().unwrap().len(), 1, "Removed channel count ≠ 1 with tracking_time {}", tracking_time);
// Provide a later time so that sufficient time has passed
network_graph.remove_stale_channels_and_tracking_with_time(
tracking_time + REMOVED_ENTRIES_TRACKING_AGE_LIMIT_SECS);
// Provide a later time so that sufficient time has passed
network_graph.remove_stale_channels_and_tracking_with_time(
tracking_time + REMOVED_ENTRIES_TRACKING_AGE_LIMIT_SECS);
- assert!(network_graph.removed_channels.lock().unwrap().is_empty());
- assert!(network_graph.removed_nodes.lock().unwrap().is_empty());
+ assert!(network_graph.removed_channels.lock().unwrap().is_empty(), "Unexpectedly removed channels with tracking_time {}", tracking_time);
+ assert!(network_graph.removed_nodes.lock().unwrap().is_empty(), "Unexpectedly removed nodes with tracking_time {}", tracking_time);
let node_cfgs = crate::ln::functional_test_utils::create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = crate::ln::functional_test_utils::create_node_chanmgrs(2, &node_cfgs, &[None, None, None, None]);
let nodes = crate::ln::functional_test_utils::create_network(2, &node_cfgs, &node_chanmgrs);
let node_cfgs = crate::ln::functional_test_utils::create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = crate::ln::functional_test_utils::create_node_chanmgrs(2, &node_cfgs, &[None, None, None, None]);
let nodes = crate::ln::functional_test_utils::create_network(2, &node_cfgs, &node_chanmgrs);
// 2. Test encoding/decoding of ChannelInfo
// Check we can encode/decode ChannelInfo without ChannelUpdateInfo fields present.
let chan_info_none_updates = ChannelInfo {
// 2. Test encoding/decoding of ChannelInfo
// Check we can encode/decode ChannelInfo without ChannelUpdateInfo fields present.
let chan_info_none_updates = ChannelInfo {
node_one: NodeId::from_pubkey(&nodes[0].node.get_our_node_id()),
one_to_two: None,
node_two: NodeId::from_pubkey(&nodes[1].node.get_our_node_id()),
node_one: NodeId::from_pubkey(&nodes[0].node.get_our_node_id()),
one_to_two: None,
node_two: NodeId::from_pubkey(&nodes[1].node.get_our_node_id()),
// Check we can encode/decode ChannelInfo with ChannelUpdateInfo fields present.
let chan_info_some_updates = ChannelInfo {
// Check we can encode/decode ChannelInfo with ChannelUpdateInfo fields present.
let chan_info_some_updates = ChannelInfo {
node_one: NodeId::from_pubkey(&nodes[0].node.get_our_node_id()),
one_to_two: Some(chan_update_info.clone()),
node_two: NodeId::from_pubkey(&nodes[1].node.get_our_node_id()),
node_one: NodeId::from_pubkey(&nodes[0].node.get_our_node_id()),
one_to_two: Some(chan_update_info.clone()),
node_two: NodeId::from_pubkey(&nodes[1].node.get_our_node_id()),
// 1. Check we can read a valid NodeAnnouncementInfo and fail on an invalid one
let valid_netaddr = crate::ln::msgs::NetAddress::Hostname { hostname: crate::util::ser::Hostname::try_from("A".to_string()).unwrap(), port: 1234 };
let valid_node_ann_info = NodeAnnouncementInfo {
// 1. Check we can read a valid NodeAnnouncementInfo and fail on an invalid one
let valid_netaddr = crate::ln::msgs::NetAddress::Hostname { hostname: crate::util::ser::Hostname::try_from("A".to_string()).unwrap(), port: 1234 };
let valid_node_ann_info = NodeAnnouncementInfo {