Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 32 additions & 7 deletions lightning/src/ln/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -946,6 +946,10 @@ pub const MAX_CHAN_DUST_LIMIT_SATOSHIS: u64 = MAX_STD_OUTPUT_DUST_LIMIT_SATOSHIS
/// See <https://github.com/lightning/bolts/issues/905> for more details.
pub const MIN_CHAN_DUST_LIMIT_SATOSHIS: u64 = 354;

pub const VIRTUAL_DUST_LIMIT_SATOSHIS: u64 = 1;

pub const VIRTUAL_HTLC_MINIMUM_MSAT: u64 = 1000;

// Just a reasonable implementation-specific safe lower bound, higher than the dust limit.
pub const MIN_THEIR_CHAN_RESERVE_SATOSHIS: u64 = 1000;

Expand Down Expand Up @@ -3470,6 +3474,7 @@ where
current_chain_height: u32,
logger: &'a L,
is_0conf: bool,
is_virtual: bool,
our_funding_satoshis: u64,
counterparty_pubkeys: ChannelPublicKeys,
channel_type: ChannelTypeFeatures,
Expand Down Expand Up @@ -3551,8 +3556,13 @@ where
if open_channel_fields.max_accepted_htlcs < config.channel_handshake_limits.min_max_accepted_htlcs {
return Err(ChannelError::close(format!("max_accepted_htlcs ({}) is less than the user specified limit ({})", open_channel_fields.max_accepted_htlcs, config.channel_handshake_limits.min_max_accepted_htlcs)));
}
if open_channel_fields.dust_limit_satoshis < MIN_CHAN_DUST_LIMIT_SATOSHIS {
return Err(ChannelError::close(format!("dust_limit_satoshis ({}) is less than the implementation limit ({})", open_channel_fields.dust_limit_satoshis, MIN_CHAN_DUST_LIMIT_SATOSHIS)));
let min_dust_limit_satoshis = if is_virtual {
VIRTUAL_DUST_LIMIT_SATOSHIS
} else {
MIN_CHAN_DUST_LIMIT_SATOSHIS
};
if open_channel_fields.dust_limit_satoshis < min_dust_limit_satoshis {
return Err(ChannelError::close(format!("dust_limit_satoshis ({}) is less than the implementation limit ({})", open_channel_fields.dust_limit_satoshis, min_dust_limit_satoshis)));
}
if open_channel_fields.dust_limit_satoshis > MAX_CHAN_DUST_LIMIT_SATOSHIS {
return Err(ChannelError::close(format!("dust_limit_satoshis ({}) is greater than the implementation limit ({})", open_channel_fields.dust_limit_satoshis, MAX_CHAN_DUST_LIMIT_SATOSHIS)));
Expand Down Expand Up @@ -3755,11 +3765,11 @@ where

feerate_per_kw: open_channel_fields.commitment_feerate_sat_per_1000_weight,
counterparty_dust_limit_satoshis: open_channel_fields.dust_limit_satoshis,
holder_dust_limit_satoshis: MIN_CHAN_DUST_LIMIT_SATOSHIS,
holder_dust_limit_satoshis: if is_virtual { VIRTUAL_DUST_LIMIT_SATOSHIS } else { MIN_CHAN_DUST_LIMIT_SATOSHIS },
counterparty_max_htlc_value_in_flight_msat: cmp::min(open_channel_fields.max_htlc_value_in_flight_msat, channel_value_satoshis * 1000),
holder_max_htlc_value_in_flight_msat: get_holder_max_htlc_value_in_flight_msat(channel_value_satoshis, &config.channel_handshake_config),
counterparty_htlc_minimum_msat: open_channel_fields.htlc_minimum_msat,
holder_htlc_minimum_msat: if config.channel_handshake_config.our_htlc_minimum_msat == 0 { 1 } else { config.channel_handshake_config.our_htlc_minimum_msat },
holder_htlc_minimum_msat: if is_virtual { VIRTUAL_HTLC_MINIMUM_MSAT } else if config.channel_handshake_config.our_htlc_minimum_msat == 0 { 1 } else { config.channel_handshake_config.our_htlc_minimum_msat },
counterparty_max_accepted_htlcs: open_channel_fields.max_accepted_htlcs,
holder_max_accepted_htlcs: cmp::min(config.channel_handshake_config.our_max_accepted_htlcs, max_htlcs(&channel_type)),
minimum_depth,
Expand Down Expand Up @@ -4352,8 +4362,13 @@ where
if common_fields.max_accepted_htlcs < peer_limits.min_max_accepted_htlcs {
return Err(ChannelError::close(format!("max_accepted_htlcs ({}) is less than the user specified limit ({})", common_fields.max_accepted_htlcs, peer_limits.min_max_accepted_htlcs)));
}
if common_fields.dust_limit_satoshis < MIN_CHAN_DUST_LIMIT_SATOSHIS {
return Err(ChannelError::close(format!("dust_limit_satoshis ({}) is less than the implementation limit ({})", common_fields.dust_limit_satoshis, MIN_CHAN_DUST_LIMIT_SATOSHIS)));
let min_dust_limit_satoshis = if self.is_virtual_dust_set() {
VIRTUAL_DUST_LIMIT_SATOSHIS
} else {
MIN_CHAN_DUST_LIMIT_SATOSHIS
};
if common_fields.dust_limit_satoshis < min_dust_limit_satoshis {
return Err(ChannelError::close(format!("dust_limit_satoshis ({}) is less than the implementation limit ({})", common_fields.dust_limit_satoshis, min_dust_limit_satoshis)));
}
if common_fields.dust_limit_satoshis > MAX_CHAN_DUST_LIMIT_SATOSHIS {
return Err(ChannelError::close(format!("dust_limit_satoshis ({}) is greater than the implementation limit ({})", common_fields.dust_limit_satoshis, MAX_CHAN_DUST_LIMIT_SATOSHIS)));
Expand Down Expand Up @@ -4480,6 +4495,10 @@ where
self.trusted_no_broadcast
}

pub fn is_virtual_dust_set(&self) -> bool {
self.holder_dust_limit_satoshis == VIRTUAL_DUST_LIMIT_SATOSHIS
}

pub fn get_cltv_expiry_delta(&self) -> u16 {
cmp::max(self.config.options.cltv_expiry_delta, MIN_CLTV_EXPIRY_DELTA)
}
Expand Down Expand Up @@ -4607,6 +4626,10 @@ where
self.trusted_no_broadcast = true;
}

pub fn set_virtual_dust_limit(&mut self) {
self.holder_dust_limit_satoshis = VIRTUAL_DUST_LIMIT_SATOSHIS;
}

fn can_resume_on_reconnect(&self) -> bool {
match self.channel_state {
ChannelState::NegotiatingFunding(_) => false,
Expand Down Expand Up @@ -14042,7 +14065,7 @@ where
fee_estimator: &LowerBoundedFeeEstimator<F>, entropy_source: &ES, signer_provider: &SP,
counterparty_node_id: PublicKey, our_supported_features: &ChannelTypeFeatures,
their_features: &InitFeatures, msg: &msgs::OpenChannel, user_id: u128, config: &UserConfig,
current_chain_height: u32, logger: &L, is_0conf: bool, ldk_data_dir: PathBuf,
current_chain_height: u32, logger: &L, is_0conf: bool, is_virtual: bool, ldk_data_dir: PathBuf,
rgb_kv_store: Arc<dyn KVStoreSync + Send + Sync>,
) -> Result<InboundV1Channel<SP>, ChannelError>
where ES::Target: EntropySource,
Expand Down Expand Up @@ -14075,6 +14098,7 @@ where
current_chain_height,
&&logger,
is_0conf,
is_virtual,
0,

counterparty_pubkeys,
Expand Down Expand Up @@ -14479,6 +14503,7 @@ where
current_chain_height,
logger,
false,
false,
our_funding_contribution_sats,
counterparty_pubkeys,
channel_type,
Expand Down
27 changes: 23 additions & 4 deletions lightning/src/ln/channelmanager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2124,7 +2124,7 @@ where
/// # let channel_manager = channel_manager.get_cm();
/// let value_sats = 1_000_000;
/// let push_msats = 10_000_000;
/// match channel_manager.create_channel(peer_id, value_sats, push_msats, 42, None, None) {
/// match channel_manager.create_channel(peer_id, value_sats, push_msats, 42, None, None, None, None, false) {
/// Ok(channel_id) => println!("Opening channel {}", channel_id),
/// Err(e) => println!("Error opening channel: {:?}", e),
/// }
Expand Down Expand Up @@ -4162,7 +4162,7 @@ where
/// [`Event::FundingGenerationReady::temporary_channel_id`]: events::Event::FundingGenerationReady::temporary_channel_id
/// [`Event::ChannelClosed::channel_id`]: events::Event::ChannelClosed::channel_id
#[rustfmt::skip]
pub fn create_channel(&self, their_network_key: PublicKey, channel_value_satoshis: u64, push_msat: u64, user_channel_id: u128, temporary_channel_id: Option<ChannelId>, override_config: Option<UserConfig>, consignment_endpoint: Option<RgbTransport>, push_asset_amount: Option<u64>) -> Result<ChannelId, APIError> {
pub fn create_channel(&self, their_network_key: PublicKey, channel_value_satoshis: u64, push_msat: u64, user_channel_id: u128, temporary_channel_id: Option<ChannelId>, override_config: Option<UserConfig>, consignment_endpoint: Option<RgbTransport>, push_asset_amount: Option<u64>, is_virtual: bool) -> Result<ChannelId, APIError> {
if channel_value_satoshis < 1000 {
return Err(APIError::APIMisuseError { err: format!("Channel value must be at least 1000 satoshis. It was {}", channel_value_satoshis) });
}
Expand Down Expand Up @@ -4208,6 +4208,9 @@ where
},
}
};
if is_virtual {
channel.context.set_virtual_dust_limit();
}
let logger = WithChannelContext::from(&self.logger, &channel.context, None);
let res = channel.get_open_channel(self.chain_hash, &&logger);

Expand Down Expand Up @@ -6299,6 +6302,12 @@ where
err: format!("Channel {temporary_channel_id} with counterparty {counterparty_node_id} is not an unfunded, outbound channel ready to fund"),
});
}
if chan.get().context().is_virtual_dust_set() && !is_trusted_no_broadcast {
return Err(APIError::APIMisuseError {
err: "Channels opened with virtual dust must be completed with ChannelFundingType::Virtual"
.to_owned(),
});
}
if is_trusted_no_broadcast && chan.get().minimum_depth() != Some(0) {
return Err(APIError::APIMisuseError {
err: "ChannelFundingType::Virtual requires a negotiated 0-conf channel"
Expand Down Expand Up @@ -10205,6 +10214,15 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
let mut peer_state_lock = peer_state_mutex.lock().unwrap();
let peer_state = &mut *peer_state_lock;
let is_only_peer_channel = peer_state.total_channel_count() == 1;
if channel_funding_type == ChannelFundingType::Virtual {
if let Some(unaccepted_channel) = peer_state.inbound_channel_request_by_id.get(temporary_channel_id) {
if matches!(unaccepted_channel.open_channel_msg, OpenChannelMessage::V2(_)) {
return Err(APIError::APIMisuseError {
err: "ChannelFundingType::Virtual is not supported for inbound v2 channels".to_owned(),
});
}
}
}

// Find (and remove) the channel in the unaccepted table. If it's not there, something weird is
// happening and return an error. N.B. that we create channel with an outbound SCID of zero so
Expand All @@ -10218,7 +10236,8 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
InboundV1Channel::new(
&self.fee_estimator, &self.entropy_source, &self.signer_provider, *counterparty_node_id,
&self.channel_type_features(), &peer_state.latest_features, &open_channel_msg,
user_channel_id, &config, best_block_height, &self.logger, accept_0conf, self.ldk_data_dir.clone(),
user_channel_id, &config, best_block_height, &self.logger, accept_0conf,
channel_funding_type == ChannelFundingType::Virtual, self.ldk_data_dir.clone(),
Arc::clone(&self.rgb_kv_store),
).map_err(|err| MsgHandleErrInternal::from_chan_no_close(err, *temporary_channel_id)
).map(|mut channel| {
Expand Down Expand Up @@ -10513,7 +10532,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
let mut channel = InboundV1Channel::new(
&self.fee_estimator, &self.entropy_source, &self.signer_provider, *counterparty_node_id,
&self.channel_type_features(), &peer_state.latest_features, msg, user_channel_id,
&self.config.read().unwrap(), best_block_height, &self.logger, /*is_0conf=*/false, self.ldk_data_dir.clone(),
&self.config.read().unwrap(), best_block_height, &self.logger, /*is_0conf=*/false, false, self.ldk_data_dir.clone(),
Arc::clone(&self.rgb_kv_store),
).map_err(|e| MsgHandleErrInternal::from_chan_no_close(e, msg.common_fields.temporary_channel_id))?;
let logger = WithChannelContext::from(&self.logger, &channel.context, None);
Expand Down
Loading