Merge pull request #1378 from ViktorTigerstrom/2022-03-include-htlc-min-max

Include htlc min/max for ChannelDetails and ChannelCounterparty
This commit is contained in:
Matt Corallo 2022-04-21 18:09:20 +00:00 committed by GitHub
commit 637fb88037
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 98 additions and 5 deletions

View File

@ -213,6 +213,8 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
features: InitFeatures::known(),
unspendable_punishment_reserve: 0,
forwarding_info: None,
outbound_htlc_minimum_msat: None,
outbound_htlc_maximum_msat: None,
},
funding_txo: Some(OutPoint { txid: bitcoin::Txid::from_slice(&[0; 32]).unwrap(), index: 0 }),
channel_type: None,
@ -227,6 +229,8 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
is_usable: true, is_public: true,
balance_msat: 0,
outbound_capacity_msat: 0,
inbound_htlc_minimum_msat: None,
inbound_htlc_maximum_msat: None,
});
}
Some(&first_hops_vec[..])

View File

@ -412,8 +412,8 @@ fn filter_channels(channels: Vec<ChannelDetails>, min_inbound_capacity_msat: Opt
proportional_millionths: forwarding_info.fee_proportional_millionths,
},
cltv_expiry_delta: forwarding_info.cltv_expiry_delta,
htlc_minimum_msat: None,
htlc_maximum_msat: None,}])
htlc_minimum_msat: channel.inbound_htlc_minimum_msat,
htlc_maximum_msat: channel.inbound_htlc_maximum_msat,}])
};
// If all channels are private, return the route hint for the highest inbound capacity channel
// per counterparty node. If channels with an higher inbound capacity than the
@ -535,10 +535,13 @@ mod test {
// Invoice SCIDs should always use inbound SCID aliases over the real channel ID, if one is
// available.
let chan = &nodes[1].node.list_usable_channels()[0];
assert_eq!(invoice.route_hints().len(), 1);
assert_eq!(invoice.route_hints()[0].0.len(), 1);
assert_eq!(invoice.route_hints()[0].0[0].short_channel_id,
nodes[1].node.list_usable_channels()[0].inbound_scid_alias.unwrap());
assert_eq!(invoice.route_hints()[0].0[0].short_channel_id, chan.inbound_scid_alias.unwrap());
assert_eq!(invoice.route_hints()[0].0[0].htlc_minimum_msat, chan.inbound_htlc_minimum_msat);
assert_eq!(invoice.route_hints()[0].0[0].htlc_maximum_msat, chan.inbound_htlc_maximum_msat);
let payment_params = PaymentParameters::from_node_id(invoice.recover_payee_pub_key())
.with_features(invoice.features().unwrap().clone())
@ -879,6 +882,40 @@ mod test {
}
}
#[test]
#[cfg(feature = "std")]
fn test_multi_node_hints_has_htlc_min_max_values() {
let mut chanmon_cfgs = create_chanmon_cfgs(3);
let seed_1 = [42 as u8; 32];
let seed_2 = [43 as u8; 32];
let cross_node_seed = [44 as u8; 32];
chanmon_cfgs[1].keys_manager.backing = PhantomKeysManager::new(&seed_1, 43, 44, &cross_node_seed);
chanmon_cfgs[2].keys_manager.backing = PhantomKeysManager::new(&seed_2, 43, 44, &cross_node_seed);
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
create_unannounced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 10001, InitFeatures::known(), InitFeatures::known());
create_unannounced_chan_between_nodes_with_value(&nodes, 0, 2, 100000, 10001, InitFeatures::known(), InitFeatures::known());
let payment_amt = 20_000;
let (payment_hash, _payment_secret) = nodes[1].node.create_inbound_payment(Some(payment_amt), 3600).unwrap();
let route_hints = vec![
nodes[1].node.get_phantom_route_hints(),
nodes[2].node.get_phantom_route_hints(),
];
let invoice = ::utils::create_phantom_invoice::<EnforcingSigner, &test_utils::TestKeysInterface>(Some(payment_amt), Some(payment_hash), "test".to_string(), 3600, route_hints, &nodes[1].keys_manager, Currency::BitcoinTestnet).unwrap();
let chan_0_1 = &nodes[1].node.list_usable_channels()[0];
assert_eq!(invoice.route_hints()[0].0[0].htlc_minimum_msat, chan_0_1.inbound_htlc_minimum_msat);
assert_eq!(invoice.route_hints()[0].0[0].htlc_maximum_msat, chan_0_1.inbound_htlc_maximum_msat);
let chan_0_2 = &nodes[2].node.list_usable_channels()[0];
assert_eq!(invoice.route_hints()[1].0[0].htlc_minimum_msat, chan_0_2.inbound_htlc_minimum_msat);
assert_eq!(invoice.route_hints()[1].0[0].htlc_maximum_msat, chan_0_2.inbound_htlc_maximum_msat);
}
#[test]
#[cfg(feature = "std")]
fn create_phantom_invoice_with_description_hash() {

View File

@ -4321,11 +4321,15 @@ impl<Signer: Sign> Channel<Signer> {
}
/// Allowed in any state (including after shutdown)
#[cfg(test)]
pub fn get_holder_htlc_minimum_msat(&self) -> u64 {
self.holder_htlc_minimum_msat
}
/// Allowed in any state (including after shutdown), but will return none before TheirInitSent
pub fn get_holder_htlc_maximum_msat(&self) -> Option<u64> {
self.get_htlc_maximum_msat(self.holder_max_htlc_value_in_flight_msat)
}
/// Allowed in any state (including after shutdown)
pub fn get_announced_htlc_max_msat(&self) -> u64 {
return cmp::min(
@ -4343,6 +4347,21 @@ impl<Signer: Sign> Channel<Signer> {
self.counterparty_htlc_minimum_msat
}
/// Allowed in any state (including after shutdown), but will return none before TheirInitSent
pub fn get_counterparty_htlc_maximum_msat(&self) -> Option<u64> {
self.get_htlc_maximum_msat(self.counterparty_max_htlc_value_in_flight_msat)
}
fn get_htlc_maximum_msat(&self, party_max_htlc_value_in_flight_msat: u64) -> Option<u64> {
self.counterparty_selected_channel_reserve_satoshis.map(|counterparty_reserve| {
let holder_reserve = self.holder_selected_channel_reserve_satoshis;
cmp::min(
(self.channel_value_satoshis - counterparty_reserve - holder_reserve) * 1000,
party_max_htlc_value_in_flight_msat
)
})
}
pub fn get_value_satoshis(&self) -> u64 {
self.channel_value_satoshis
}

View File

@ -922,6 +922,12 @@ pub struct ChannelCounterparty {
/// Information on the fees and requirements that the counterparty requires when forwarding
/// payments to us through this channel.
pub forwarding_info: Option<CounterpartyForwardingInfo>,
/// The smallest value HTLC (in msat) the remote peer will accept, for this channel. This field
/// is only `None` before we have received either the `OpenChannel` or `AcceptChannel` message
/// from the remote peer, or for `ChannelCounterparty` objects serialized prior to LDK 0.0.107.
pub outbound_htlc_minimum_msat: Option<u64>,
/// The largest value HTLC (in msat) the remote peer currently will accept, for this channel.
pub outbound_htlc_maximum_msat: Option<u64>,
}
/// Details of a channel, as returned by ChannelManager::list_channels and ChannelManager::list_usable_channels
@ -1046,6 +1052,11 @@ pub struct ChannelDetails {
pub is_usable: bool,
/// True if this channel is (or will be) publicly-announced.
pub is_public: bool,
/// The smallest value HTLC (in msat) we will accept, for this channel. This field
/// is only `None` for `ChannelDetails` objects serialized prior to LDK 0.0.107
pub inbound_htlc_minimum_msat: Option<u64>,
/// The largest value HTLC (in msat) we currently will accept, for this channel.
pub inbound_htlc_maximum_msat: Option<u64>,
}
impl ChannelDetails {
@ -1670,6 +1681,14 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
features: InitFeatures::empty(),
unspendable_punishment_reserve: to_remote_reserve_satoshis,
forwarding_info: channel.counterparty_forwarding_info(),
// Ensures that we have actually received the `htlc_minimum_msat` value
// from the counterparty through the `OpenChannel` or `AcceptChannel`
// message (as they are always the first message from the counterparty).
// Else `Channel::get_counterparty_htlc_minimum_msat` could return the
// default `0` value set by `Channel::new_outbound`.
outbound_htlc_minimum_msat: if channel.have_received_message() {
Some(channel.get_counterparty_htlc_minimum_msat()) } else { None },
outbound_htlc_maximum_msat: channel.get_counterparty_htlc_maximum_msat(),
},
funding_txo: channel.get_funding_txo(),
// Note that accept_channel (or open_channel) is always the first message, so
@ -1689,6 +1708,8 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
is_funding_locked: channel.is_usable(),
is_usable: channel.is_live(),
is_public: channel.should_announce(),
inbound_htlc_minimum_msat: Some(channel.get_holder_htlc_minimum_msat()),
inbound_htlc_maximum_msat: channel.get_holder_htlc_maximum_msat()
});
}
}
@ -5900,6 +5921,8 @@ impl_writeable_tlv_based!(ChannelCounterparty, {
(4, features, required),
(6, unspendable_punishment_reserve, required),
(8, forwarding_info, option),
(9, outbound_htlc_minimum_msat, option),
(11, outbound_htlc_maximum_msat, option),
});
impl_writeable_tlv_based!(ChannelDetails, {
@ -5921,6 +5944,8 @@ impl_writeable_tlv_based!(ChannelDetails, {
(28, is_funding_locked, required),
(30, is_usable, required),
(32, is_public, required),
(33, inbound_htlc_minimum_msat, option),
(35, inbound_htlc_maximum_msat, option),
});
impl_writeable_tlv_based!(PhantomRouteHints, {

View File

@ -1735,6 +1735,8 @@ mod tests {
node_id,
unspendable_punishment_reserve: 0,
forwarding_info: None,
outbound_htlc_minimum_msat: None,
outbound_htlc_maximum_msat: None,
},
funding_txo: Some(OutPoint { txid: bitcoin::Txid::from_slice(&[0; 32]).unwrap(), index: 0 }),
channel_type: None,
@ -1750,6 +1752,8 @@ mod tests {
force_close_spend_delay: None,
is_outbound: true, is_funding_locked: true,
is_usable: true, is_public: true,
inbound_htlc_minimum_msat: None,
inbound_htlc_maximum_msat: None,
}
}
@ -5456,6 +5460,8 @@ mod benches {
node_id,
unspendable_punishment_reserve: 0,
forwarding_info: None,
outbound_htlc_minimum_msat: None,
outbound_htlc_maximum_msat: None,
},
funding_txo: Some(OutPoint {
txid: bitcoin::Txid::from_slice(&[0; 32]).unwrap(), index: 0
@ -5475,6 +5481,8 @@ mod benches {
is_funding_locked: true,
is_usable: true,
is_public: true,
inbound_htlc_minimum_msat: None,
inbound_htlc_maximum_msat: None,
}
}