Skip to content

Commit e1acc25

Browse files
committed
Expose APIs to access supported feature flags
With this, we can read the features supported by the node as announced in node and channel announcements, within an init message, and within a BOLT 11 invoice. We write a small integration test to assert that, at minimum, certain features are supported by default, for example, keysend support.
1 parent 7ad0d63 commit e1acc25

3 files changed

Lines changed: 99 additions & 3 deletions

File tree

src/event.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,9 @@ use crate::payment::store::{
4949
PaymentDetails, PaymentDetailsUpdate, PaymentDirection, PaymentKind, PaymentStatus,
5050
};
5151
use crate::runtime::Runtime;
52-
use crate::types::KeysManager;
53-
use crate::types::{CustomTlvRecord, DynStore, OnionMessenger, PaymentStore, Sweeper, Wallet};
52+
use crate::types::{
53+
CustomTlvRecord, DynStore, KeysManager, OnionMessenger, PaymentStore, Sweeper, Wallet,
54+
};
5455
use crate::{
5556
hex_utils, BumpTransactionEventHandler, ChannelManager, Error, Graph, PeerInfo, PeerStore,
5657
UserChannelId,

src/lib.rs

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,12 +141,16 @@ use lightning::chain::BestBlock;
141141
use lightning::impl_writeable_tlv_based;
142142
use lightning::ln::channel_state::{ChannelDetails as LdkChannelDetails, ChannelShutdownState};
143143
use lightning::ln::channelmanager::PaymentId;
144-
use lightning::ln::msgs::SocketAddress;
144+
use lightning::ln::msgs::{BaseMessageHandler, SocketAddress};
145+
use lightning::ln::peer_handler::CustomMessageHandler;
145146
use lightning::routing::gossip::NodeAlias;
146147
use lightning::sign::EntropySource;
147148
use lightning::util::persist::KVStoreSync;
148149
use lightning::util::wallet_utils::Wallet as LdkWallet;
149150
use lightning_background_processor::process_events_async;
151+
use lightning_types::features::{
152+
Bolt11InvoiceFeatures, ChannelFeatures, InitFeatures, NodeFeatures,
153+
};
150154
use liquidity::{LSPS1Liquidity, LiquiditySource};
151155
use logger::{log_debug, log_error, log_info, log_trace, LdkLogger, Logger};
152156
use payment::asynchronous::om_mailbox::OnionMessageMailbox;
@@ -1725,6 +1729,63 @@ impl Node {
17251729
Error::PersistenceFailed
17261730
})
17271731
}
1732+
1733+
/// Return the features used in node announcement.
1734+
pub fn node_features(&self) -> NodeFeatures {
1735+
let gossip_features = match self.gossip_source.as_gossip_sync() {
1736+
lightning_background_processor::GossipSync::P2P(p2p_gossip_sync) => {
1737+
p2p_gossip_sync.provided_node_features()
1738+
},
1739+
lightning_background_processor::GossipSync::Rapid(_) => NodeFeatures::empty(),
1740+
lightning_background_processor::GossipSync::None => {
1741+
unreachable!("We must always have a gossip sync!")
1742+
},
1743+
};
1744+
self.channel_manager.node_features()
1745+
| self.chain_monitor.provided_node_features()
1746+
| self.onion_messenger.provided_node_features()
1747+
| gossip_features
1748+
| self
1749+
.liquidity_source
1750+
.as_ref()
1751+
.map(|ls| ls.liquidity_manager().provided_node_features())
1752+
.unwrap_or_else(NodeFeatures::empty)
1753+
}
1754+
1755+
/// Return the node's init features.
1756+
pub fn init_features(&self) -> InitFeatures {
1757+
let gossip_init_features = match self.gossip_source.as_gossip_sync() {
1758+
lightning_background_processor::GossipSync::P2P(p2p_gossip_sync) => {
1759+
p2p_gossip_sync.provided_init_features(self.node_id())
1760+
},
1761+
lightning_background_processor::GossipSync::Rapid(_) => InitFeatures::empty(),
1762+
lightning_background_processor::GossipSync::None => {
1763+
unreachable!("We must always have a gossip sync!")
1764+
},
1765+
};
1766+
self.channel_manager.init_features()
1767+
| self.chain_monitor.provided_init_features(self.node_id())
1768+
| self.onion_messenger.provided_init_features(self.node_id())
1769+
| gossip_init_features
1770+
| self
1771+
.liquidity_source
1772+
.as_ref()
1773+
.map(|ls| ls.liquidity_manager().provided_init_features(self.node_id()))
1774+
.unwrap_or_else(InitFeatures::empty)
1775+
}
1776+
1777+
/// Return the node's channel features.
1778+
pub fn channel_features(&self) -> ChannelFeatures {
1779+
self.channel_manager.channel_features()
1780+
}
1781+
1782+
/// Return the node's BOLT 11 invoice features.
1783+
pub fn bolt11_invoice_features(&self) -> Bolt11InvoiceFeatures {
1784+
// bolt11_invoice_features() is not public because feature
1785+
// flags can vary due to invoice type, so we convert from
1786+
// context.
1787+
self.channel_manager.init_features().to_context()
1788+
}
17281789
}
17291790

17301791
impl Drop for Node {

tests/integration_tests_rust.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2627,3 +2627,37 @@ async fn onchain_fee_bump_rbf() {
26272627
assert_eq!(node_a_received_payment[0].amount_msat, Some(amount_to_send_sats * 1000));
26282628
assert_eq!(node_a_received_payment[0].status, PaymentStatus::Succeeded);
26292629
}
2630+
2631+
#[test]
2632+
fn node_feature_flags() {
2633+
let (bitcoind, electrsd) = setup_bitcoind_and_electrsd();
2634+
let chain_source = random_chain_source(&bitcoind, &electrsd);
2635+
let config = random_config(true);
2636+
let node = setup_node(&chain_source, config);
2637+
2638+
// NodeFeatures
2639+
let node_features = node.node_features();
2640+
assert!(node_features.supports_variable_length_onion());
2641+
assert!(node_features.supports_payment_secret());
2642+
assert!(node_features.supports_basic_mpp());
2643+
assert!(node_features.supports_keysend());
2644+
assert!(node_features.supports_onion_messages());
2645+
2646+
// InitFeatures
2647+
let init_features = node.init_features();
2648+
assert!(init_features.supports_variable_length_onion());
2649+
assert!(init_features.supports_payment_secret());
2650+
assert!(init_features.supports_basic_mpp());
2651+
assert!(init_features.supports_onion_messages());
2652+
2653+
// ChannelFeatures (non-empty)
2654+
let _channel_features = node.channel_features();
2655+
2656+
// Bolt11InvoiceFeatures
2657+
let bolt11_features = node.bolt11_invoice_features();
2658+
assert!(bolt11_features.supports_variable_length_onion());
2659+
assert!(bolt11_features.supports_payment_secret());
2660+
assert!(bolt11_features.supports_basic_mpp());
2661+
2662+
node.stop().unwrap();
2663+
}

0 commit comments

Comments
 (0)