Skip to content

Commit 9218c57

Browse files
valentinewallaceAntoine Riard
and
Antoine Riard
committed
Expose counterparty forwarding info in ChannelDetails.
Useful for constructing route hints for private channels in invoices. Co-authored-by: Valentine Wallace <[email protected]> Co-authored-by: Antoine Riard <[email protected]>
1 parent 139b9c0 commit 9218c57

File tree

4 files changed

+72
-1
lines changed

4 files changed

+72
-1
lines changed

fuzz/src/router.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
212212
inbound_capacity_msat: 0,
213213
is_live: true,
214214
outbound_capacity_msat: 0,
215+
counterparty_forwarding_info: None,
215216
});
216217
}
217218
Some(&first_hops_vec[..])

lightning/src/ln/channel.rs

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,7 @@ impl HTLCCandidate {
282282
}
283283

284284
/// Information needed for constructing an invoice route hint for this channel.
285+
#[derive(Clone)]
285286
pub struct CounterpartyForwardingInfo {
286287
/// Base routing fee in millisatoshis.
287288
pub fee_base_msat: u32,
@@ -4130,6 +4131,11 @@ impl<Signer: Sign> Channel<Signer> {
41304131
}
41314132
}
41324133

4134+
/// Get forwarding information for the counterparty.
4135+
pub fn get_counterparty_forwarding_info(&self) -> Option<CounterpartyForwardingInfo> {
4136+
self.counterparty_forwarding_info.clone()
4137+
}
4138+
41334139
pub fn channel_update(&mut self, msg: &msgs::ChannelUpdate) -> Result<(), ChannelError> {
41344140
let usable_channel_value_msat = (self.channel_value_satoshis - self.counterparty_selected_channel_reserve_satoshis) * 1000;
41354141
if msg.contents.htlc_minimum_msat > usable_channel_value_msat {
@@ -4754,7 +4760,7 @@ mod tests {
47544760
use ln::channel::{Channel,Sign,InboundHTLCOutput,OutboundHTLCOutput,InboundHTLCState,OutboundHTLCState,HTLCOutputInCommitment,HTLCCandidate,HTLCInitiator,TxCreationKeys};
47554761
use ln::channel::MAX_FUNDING_SATOSHIS;
47564762
use ln::features::InitFeatures;
4757-
use ln::msgs::{OptionalField, DataLossProtect, DecodeError};
4763+
use ln::msgs::{ChannelUpdate, DataLossProtect, DecodeError, OptionalField, UnsignedChannelUpdate};
47584764
use ln::chan_utils;
47594765
use ln::chan_utils::{ChannelPublicKeys, HolderCommitmentTransaction, CounterpartyChannelTransactionParameters, HTLC_SUCCESS_TX_WEIGHT, HTLC_TIMEOUT_TX_WEIGHT};
47604766
use chain::chaininterface::{FeeEstimator,ConfirmationTarget};
@@ -4765,6 +4771,7 @@ mod tests {
47654771
use util::test_utils;
47664772
use util::logger::Logger;
47674773
use bitcoin::secp256k1::{Secp256k1, Message, Signature, All};
4774+
use bitcoin::secp256k1::ffi::Signature as FFISignature;
47684775
use bitcoin::secp256k1::key::{SecretKey,PublicKey};
47694776
use bitcoin::hashes::sha256::Hash as Sha256;
47704777
use bitcoin::hashes::Hash;
@@ -5021,6 +5028,55 @@ mod tests {
50215028
}
50225029
}
50235030

5031+
#[test]
5032+
fn channel_update() {
5033+
let feeest = TestFeeEstimator{fee_est: 15000};
5034+
let secp_ctx = Secp256k1::new();
5035+
let seed = [42; 32];
5036+
let network = Network::Testnet;
5037+
let chain_hash = genesis_block(network).header.block_hash();
5038+
let keys_provider = test_utils::TestKeysInterface::new(&seed, network);
5039+
5040+
// Create a channel.
5041+
let node_b_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
5042+
let config = UserConfig::default();
5043+
let mut node_a_chan = Channel::<EnforcingSigner>::new_outbound(&&feeest, &&keys_provider, node_b_node_id, 10000000, 100000, 42, &config).unwrap();
5044+
assert!(node_a_chan.counterparty_forwarding_info.is_none());
5045+
assert_eq!(node_a_chan.holder_htlc_minimum_msat, 1); // the default
5046+
assert!(node_a_chan.get_counterparty_forwarding_info().is_none());
5047+
5048+
// Make sure that receiving a channel update will update the Channel as expected.
5049+
let update = ChannelUpdate {
5050+
contents: UnsignedChannelUpdate {
5051+
chain_hash,
5052+
short_channel_id: 0,
5053+
timestamp: 0,
5054+
flags: 0,
5055+
cltv_expiry_delta: 100,
5056+
htlc_minimum_msat: 5,
5057+
htlc_maximum_msat: OptionalField::Absent,
5058+
fee_base_msat: 110,
5059+
fee_proportional_millionths: 11,
5060+
excess_data: Vec::new(),
5061+
},
5062+
signature: Signature::from(unsafe { FFISignature::new() })
5063+
};
5064+
node_a_chan.channel_update(&update).unwrap();
5065+
5066+
// The counterparty can send an update with a higher minimum HTLC, but that shouldn't
5067+
// change our official htlc_minimum_msat.
5068+
assert_eq!(node_a_chan.holder_htlc_minimum_msat, 1);
5069+
assert!(node_a_chan.get_counterparty_forwarding_info().is_some());
5070+
match node_a_chan.counterparty_forwarding_info {
5071+
Some(info) => {
5072+
assert_eq!(info.cltv_expiry_delta, 100);
5073+
assert_eq!(info.fee_base_msat, 110);
5074+
assert_eq!(info.fee_proportional_millionths, 11);
5075+
},
5076+
None => panic!("expected counterparty forwarding info to be Some")
5077+
}
5078+
}
5079+
50245080
#[test]
50255081
fn outbound_commitment_test() {
50265082
// Test vectors from BOLT 3 Appendix C:

lightning/src/ln/channelmanager.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ use chain::Watch;
3939
use chain::chaininterface::{BroadcasterInterface, FeeEstimator};
4040
use chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate, ChannelMonitorUpdateStep, ChannelMonitorUpdateErr, HTLC_FAIL_BACK_BUFFER, CLTV_CLAIM_BUFFER, LATENCY_GRACE_PERIOD_BLOCKS, ANTI_REORG_DELAY, MonitorEvent, CLOSED_CHANNEL_UPDATE_ID};
4141
use chain::transaction::{OutPoint, TransactionData};
42+
// Since this struct is returned in `list_channels` methods, expose it here in case users want to
43+
// construct one themselves.
44+
pub use ln::channel::CounterpartyForwardingInfo;
4245
use ln::channel::{Channel, ChannelError};
4346
use ln::features::{InitFeatures, NodeFeatures};
4447
use routing::router::{Route, RouteHop};
@@ -574,6 +577,9 @@ pub struct ChannelDetails {
574577
/// True if the channel is (a) confirmed and funding_locked messages have been exchanged, (b)
575578
/// the peer is connected, and (c) no monitor update failure is pending resolution.
576579
pub is_live: bool,
580+
581+
/// Counterparty forwarding information.
582+
pub counterparty_forwarding_info: Option<CounterpartyForwardingInfo>,
577583
}
578584

579585
/// If a payment fails to send, it can be in one of several states. This enum is returned as the
@@ -892,6 +898,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
892898
outbound_capacity_msat,
893899
user_id: channel.get_user_id(),
894900
is_live: channel.is_live(),
901+
counterparty_forwarding_info: channel.get_counterparty_forwarding_info(),
895902
});
896903
}
897904
}

lightning/src/routing/router.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1473,6 +1473,7 @@ mod tests {
14731473
outbound_capacity_msat: 100000,
14741474
inbound_capacity_msat: 100000,
14751475
is_live: true,
1476+
counterparty_forwarding_info: None,
14761477
}];
14771478

14781479
if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(&our_id, &net_graph_msg_handler.network_graph.read().unwrap(), &nodes[2], None, Some(&our_chans.iter().collect::<Vec<_>>()), &Vec::new(), 100, 42, Arc::clone(&logger)) {
@@ -1790,6 +1791,7 @@ mod tests {
17901791
outbound_capacity_msat: 250_000_000,
17911792
inbound_capacity_msat: 0,
17921793
is_live: true,
1794+
counterparty_forwarding_info: None,
17931795
}];
17941796
let route = get_route(&our_id, &net_graph_msg_handler.network_graph.read().unwrap(), &nodes[2], None, Some(&our_chans.iter().collect::<Vec<_>>()), &Vec::new(), 100, 42, Arc::clone(&logger)).unwrap();
17951797
assert_eq!(route.paths[0].len(), 2);
@@ -1837,6 +1839,7 @@ mod tests {
18371839
outbound_capacity_msat: 250_000_000,
18381840
inbound_capacity_msat: 0,
18391841
is_live: true,
1842+
counterparty_forwarding_info: None,
18401843
}];
18411844
let route = get_route(&our_id, &net_graph_msg_handler.network_graph.read().unwrap(), &nodes[2], None, Some(&our_chans.iter().collect::<Vec<_>>()), &Vec::new(), 100, 42, Arc::clone(&logger)).unwrap();
18421845
assert_eq!(route.paths[0].len(), 2);
@@ -1901,6 +1904,7 @@ mod tests {
19011904
outbound_capacity_msat: 250_000_000,
19021905
inbound_capacity_msat: 0,
19031906
is_live: true,
1907+
counterparty_forwarding_info: None,
19041908
}];
19051909
let route = get_route(&our_id, &net_graph_msg_handler.network_graph.read().unwrap(), &nodes[2], None, Some(&our_chans.iter().collect::<Vec<_>>()), &Vec::new(), 100, 42, Arc::clone(&logger)).unwrap();
19061910
assert_eq!(route.paths[0].len(), 2);
@@ -2037,6 +2041,7 @@ mod tests {
20372041
outbound_capacity_msat: 250_000_000,
20382042
inbound_capacity_msat: 0,
20392043
is_live: true,
2044+
counterparty_forwarding_info: None,
20402045
}];
20412046
let mut last_hops = last_hops(&nodes);
20422047
let route = get_route(&our_id, &net_graph_msg_handler.network_graph.read().unwrap(), &nodes[6], None, Some(&our_chans.iter().collect::<Vec<_>>()), &last_hops.iter().collect::<Vec<_>>(), 100, 42, Arc::clone(&logger)).unwrap();
@@ -2165,6 +2170,7 @@ mod tests {
21652170
outbound_capacity_msat: 100000,
21662171
inbound_capacity_msat: 100000,
21672172
is_live: true,
2173+
counterparty_forwarding_info: None,
21682174
}];
21692175
let route = get_route(&source_node_id, &NetworkGraph::new(genesis_block(Network::Testnet).header.block_hash()), &target_node_id, None, Some(&our_chans.iter().collect::<Vec<_>>()), &last_hops.iter().collect::<Vec<_>>(), 100, 42, Arc::new(test_utils::TestLogger::new())).unwrap();
21702176

@@ -2296,6 +2302,7 @@ mod tests {
22962302
outbound_capacity_msat: 200_000_000,
22972303
inbound_capacity_msat: 0,
22982304
is_live: true,
2305+
counterparty_forwarding_info: None,
22992306
}];
23002307

23012308
{

0 commit comments

Comments
 (0)