use ln::msgs;
use ln::msgs::{DecodeError, OptionalField, LocalFeatures};
use ln::channelmonitor::ChannelMonitor;
-use ln::channelmanager::{PendingHTLCStatus, HTLCSource, HTLCFailReason, HTLCFailureMsg, PendingForwardHTLCInfo, RAACommitmentOrder, PaymentPreimage, PaymentHash};
+use ln::channelmanager::{PendingHTLCStatus, HTLCSource, HTLCFailReason, HTLCFailureMsg, PendingForwardHTLCInfo, RAACommitmentOrder, PaymentPreimage, PaymentHash, BREAKDOWN_TIMEOUT, MAX_LOCAL_BREAKDOWN_TIMEOUT};
use ln::chan_utils::{TxCreationKeys,HTLCOutputInCommitment,HTLC_SUCCESS_TX_WEIGHT,HTLC_TIMEOUT_TX_WEIGHT};
use ln::chan_utils;
use chain::chaininterface::{FeeEstimator,ConfirmationTarget};
their_htlc_minimum_msat: u64,
our_htlc_minimum_msat: u64,
their_to_self_delay: u16,
- //implied by BREAKDOWN_TIMEOUT: our_to_self_delay: u16,
+ our_to_self_delay: u16,
#[cfg(test)]
pub their_max_accepted_htlcs: u16,
#[cfg(not(test))]
/// on ice until the funding transaction gets more confirmations, but the LN protocol doesn't
/// really allow for this, so instead we're stuck closing it out at that point.
const UNCONF_THRESHOLD: u32 = 6;
-/// The amount of time we require our counterparty wait to claim their money (ie time between when
-/// we, or our watchtower, must check for them having broadcast a theft transaction).
-#[cfg(not(test))]
-const BREAKDOWN_TIMEOUT: u16 = 6 * 24 * 7; //TODO?
-#[cfg(test)]
-pub const BREAKDOWN_TIMEOUT: u16 = 6 * 24 * 7; //TODO?
-/// The amount of time we're willing to wait to claim money back to us
-const MAX_LOCAL_BREAKDOWN_TIMEOUT: u16 = 6 * 24 * 14;
/// Exposing these two constants for use in test in ChannelMonitor
pub const COMMITMENT_TX_BASE_WEIGHT: u64 = 724;
pub const COMMITMENT_TX_WEIGHT_PER_HTLC: u64 = 172;
if push_msat > channel_value_satoshis * 1000 {
return Err(APIError::APIMisuseError{err: "push value > channel value"});
}
+ if config.own_channel_config.our_to_self_delay < BREAKDOWN_TIMEOUT {
+ return Err(APIError::APIMisuseError{err: "Configured with an unreasonable our_to_self_delay putting user funds at risks"});
+ }
let background_feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Background);
let secp_ctx = Secp256k1::new();
let channel_monitor = ChannelMonitor::new(&chan_keys.revocation_base_key, &chan_keys.delayed_payment_base_key,
- &chan_keys.htlc_base_key, &chan_keys.payment_base_key, &keys_provider.get_shutdown_pubkey(), BREAKDOWN_TIMEOUT,
+ &chan_keys.htlc_base_key, &chan_keys.payment_base_key, &keys_provider.get_shutdown_pubkey(), config.own_channel_config.our_to_self_delay,
keys_provider.get_destination_script(), logger.clone());
Ok(Channel {
their_htlc_minimum_msat: 0,
our_htlc_minimum_msat: Channel::derive_our_htlc_minimum_msat(feerate),
their_to_self_delay: 0,
+ our_to_self_delay: config.own_channel_config.our_to_self_delay,
their_max_accepted_htlcs: 0,
minimum_depth: 0, // Filled in in accept_channel
let chan_keys = keys_provider.get_channel_keys(true);
let mut local_config = (*config).channel_options.clone();
+ if config.own_channel_config.our_to_self_delay < BREAKDOWN_TIMEOUT {
+ return Err(ChannelError::Close("Configured with an unreasonable our_to_self_delay putting user funds at risks"));
+ }
+
// Check sanity of message fields:
if msg.funding_satoshis >= MAX_FUNDING_SATOSHIS {
return Err(ChannelError::Close("funding value > 2^24"));
}
Channel::check_remote_fee(fee_estimator, msg.feerate_per_kw)?;
- if msg.to_self_delay > MAX_LOCAL_BREAKDOWN_TIMEOUT {
+ if msg.to_self_delay > config.peer_channel_config_limits.their_to_self_delay || msg.to_self_delay > MAX_LOCAL_BREAKDOWN_TIMEOUT {
return Err(ChannelError::Close("They wanted our payments to be delayed by a needlessly long period"));
}
if msg.max_accepted_htlcs < 1 {
let secp_ctx = Secp256k1::new();
let mut channel_monitor = ChannelMonitor::new(&chan_keys.revocation_base_key, &chan_keys.delayed_payment_base_key,
- &chan_keys.htlc_base_key, &chan_keys.payment_base_key, &keys_provider.get_shutdown_pubkey(), BREAKDOWN_TIMEOUT,
+ &chan_keys.htlc_base_key, &chan_keys.payment_base_key, &keys_provider.get_shutdown_pubkey(), config.own_channel_config.our_to_self_delay,
keys_provider.get_destination_script(), logger.clone());
channel_monitor.set_their_base_keys(&msg.htlc_basepoint, &msg.delayed_payment_basepoint);
channel_monitor.set_their_to_self_delay(msg.to_self_delay);
their_htlc_minimum_msat: msg.htlc_minimum_msat,
our_htlc_minimum_msat: Channel::derive_our_htlc_minimum_msat(msg.feerate_per_kw as u64),
their_to_self_delay: msg.to_self_delay,
+ our_to_self_delay: config.own_channel_config.our_to_self_delay,
their_max_accepted_htlcs: msg.max_accepted_htlcs,
minimum_depth: config.own_channel_config.minimum_depth,
log_trace!(self, " ...including {} output with value {}", if local { "to_local" } else { "to_remote" }, value_to_a);
txouts.push((TxOut {
script_pubkey: chan_utils::get_revokeable_redeemscript(&keys.revocation_key,
- if local { self.their_to_self_delay } else { BREAKDOWN_TIMEOUT },
+ if local { self.their_to_self_delay } else { self.our_to_self_delay },
&keys.a_delayed_payment_key).to_v0_p2wsh(),
value: value_to_a as u64
}, None));
/// @local is used only to convert relevant internal structures which refer to remote vs local
/// to decide value of outputs and direction of HTLCs.
fn build_htlc_transaction(&self, prev_hash: &Sha256dHash, htlc: &HTLCOutputInCommitment, local: bool, keys: &TxCreationKeys, feerate_per_kw: u64) -> Transaction {
- chan_utils::build_htlc_transaction(prev_hash, feerate_per_kw, if local { self.their_to_self_delay } else { BREAKDOWN_TIMEOUT }, htlc, &keys.a_delayed_payment_key, &keys.revocation_key)
+ chan_utils::build_htlc_transaction(prev_hash, feerate_per_kw, if local { self.their_to_self_delay } else { self.our_to_self_delay }, htlc, &keys.a_delayed_payment_key, &keys.revocation_key)
}
fn create_htlc_tx_signature(&self, tx: &Transaction, htlc: &HTLCOutputInCommitment, keys: &TxCreationKeys) -> Result<(Script, Signature, bool), ChannelError> {
if msg.htlc_minimum_msat >= (self.channel_value_satoshis - msg.channel_reserve_satoshis) * 1000 {
return Err(ChannelError::Close("Minimum htlc value is full channel value"));
}
- if msg.to_self_delay > MAX_LOCAL_BREAKDOWN_TIMEOUT {
+ if msg.to_self_delay > config.peer_channel_config_limits.their_to_self_delay || msg.to_self_delay > MAX_LOCAL_BREAKDOWN_TIMEOUT {
return Err(ChannelError::Close("They wanted our payments to be delayed by a needlessly long period"));
}
if msg.max_accepted_htlcs < 1 {
channel_reserve_satoshis: Channel::get_our_channel_reserve_satoshis(self.channel_value_satoshis),
htlc_minimum_msat: self.our_htlc_minimum_msat,
feerate_per_kw: fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Background) as u32,
- to_self_delay: BREAKDOWN_TIMEOUT,
+ to_self_delay: self.our_to_self_delay,
max_accepted_htlcs: OUR_MAX_HTLCS,
funding_pubkey: PublicKey::from_secret_key(&self.secp_ctx, &self.local_keys.funding_key),
revocation_basepoint: PublicKey::from_secret_key(&self.secp_ctx, &self.local_keys.revocation_base_key),
channel_reserve_satoshis: Channel::get_our_channel_reserve_satoshis(self.channel_value_satoshis),
htlc_minimum_msat: self.our_htlc_minimum_msat,
minimum_depth: self.minimum_depth,
- to_self_delay: BREAKDOWN_TIMEOUT,
+ to_self_delay: self.our_to_self_delay,
max_accepted_htlcs: OUR_MAX_HTLCS,
funding_pubkey: PublicKey::from_secret_key(&self.secp_ctx, &self.local_keys.funding_key),
revocation_basepoint: PublicKey::from_secret_key(&self.secp_ctx, &self.local_keys.revocation_base_key),
self.their_htlc_minimum_msat.write(writer)?;
self.our_htlc_minimum_msat.write(writer)?;
self.their_to_self_delay.write(writer)?;
+ self.our_to_self_delay.write(writer)?;
self.their_max_accepted_htlcs.write(writer)?;
self.minimum_depth.write(writer)?;
let their_htlc_minimum_msat = Readable::read(reader)?;
let our_htlc_minimum_msat = Readable::read(reader)?;
let their_to_self_delay = Readable::read(reader)?;
+ let our_to_self_delay = Readable::read(reader)?;
let their_max_accepted_htlcs = Readable::read(reader)?;
let minimum_depth = Readable::read(reader)?;
their_htlc_minimum_msat,
our_htlc_minimum_msat,
their_to_self_delay,
+ our_to_self_delay,
their_max_accepted_htlcs,
minimum_depth,
logger: Arc<Logger>,
}
+/// The amount of time we require our counterparty wait to claim their money (ie time between when
+/// we, or our watchtower, must check for them having broadcast a theft transaction).
+pub(crate) const BREAKDOWN_TIMEOUT: u16 = 6 * 24;
+/// The amount of time we're willing to wait to claim money back to us
+pub(crate) const MAX_LOCAL_BREAKDOWN_TIMEOUT: u16 = 6 * 24 * 7;
+
/// The minimum number of blocks between an inbound HTLC's CLTV and the corresponding outbound
/// HTLC's CLTV. This should always be a few blocks greater than channelmonitor::CLTV_CLAIM_BUFFER,
/// ie the node we forwarded the payment on to should always have enough room to reliably time out
None => return (None, None),
Some(their_delayed_payment_base_key) => ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, &per_commitment_point, &their_delayed_payment_base_key)),
};
- let redeemscript = chan_utils::get_revokeable_redeemscript(&revocation_pubkey, self.their_to_self_delay.unwrap(), &delayed_key);
+ let redeemscript = chan_utils::get_revokeable_redeemscript(&revocation_pubkey, self.our_to_self_delay, &delayed_key);
let revokeable_p2wsh = redeemscript.to_v0_p2wsh();
let htlc_txid = tx.txid(); //TODO: This is gonna be a performance bottleneck for watchtowers!
use chain::transaction::OutPoint;
use chain::chaininterface::{ChainListener, ChainWatchInterface};
-use chain::keysinterface::{KeysInterface, SpendableOutputDescriptor};
-use ln::channel::{COMMITMENT_TX_BASE_WEIGHT, COMMITMENT_TX_WEIGHT_PER_HTLC, BREAKDOWN_TIMEOUT};
-use ln::channelmanager::{ChannelManager,ChannelManagerReadArgs,HTLCForwardInfo,RAACommitmentOrder, PaymentPreimage, PaymentHash};
+use chain::keysinterface::{KeysInterface, SpendableOutputDescriptor, KeysManager};
+use ln::channel::{COMMITMENT_TX_BASE_WEIGHT, COMMITMENT_TX_WEIGHT_PER_HTLC};
+use ln::channelmanager::{ChannelManager,ChannelManagerReadArgs,HTLCForwardInfo,RAACommitmentOrder, PaymentPreimage, PaymentHash, BREAKDOWN_TIMEOUT};
use ln::channelmonitor::{ChannelMonitor, CLTV_CLAIM_BUFFER, LATENCY_GRACE_PERIOD_BLOCKS, ManyChannelMonitor, ANTI_REORG_DELAY};
-use ln::channel::{ACCEPTED_HTLC_SCRIPT_WEIGHT, OFFERED_HTLC_SCRIPT_WEIGHT};
+use ln::channel::{ACCEPTED_HTLC_SCRIPT_WEIGHT, OFFERED_HTLC_SCRIPT_WEIGHT, Channel, ChannelError};
use ln::onion_utils;
use ln::router::{Route, RouteHop};
use ln::msgs;
fn test_justice_tx() {
// Test justice txn built on revoked HTLC-Success tx, against both sides
- let nodes = create_network(2, &[None, None]);
+ let mut alice_config = UserConfig::new();
+ alice_config.channel_options.announced_channel = true;
+ alice_config.peer_channel_config_limits.force_announced_channel_preference = false;
+ alice_config.own_channel_config.our_to_self_delay = 6 * 24 * 5;
+ let mut bob_config = UserConfig::new();
+ bob_config.channel_options.announced_channel = true;
+ bob_config.peer_channel_config_limits.force_announced_channel_preference = false;
+ bob_config.own_channel_config.our_to_self_delay = 6 * 24 * 3;
+ let nodes = create_network(2, &[Some(alice_config), Some(bob_config)]);
// Create some new channels:
let chan_5 = create_announced_chan_between_nodes(&nodes, 0, 1, LocalFeatures::new(), LocalFeatures::new());
_ => panic!("Unexpected event"),
}
}
+
+#[test]
+fn test_user_configurable_csv_delay() {
+ // We test our channel constructors yield errors when we pass them absurd csv delay
+
+ let mut low_our_to_self_config = UserConfig::new();
+ low_our_to_self_config.own_channel_config.our_to_self_delay = 6;
+ let mut high_their_to_self_config = UserConfig::new();
+ high_their_to_self_config.peer_channel_config_limits.their_to_self_delay = 100;
+ let nodes = create_network(2, &[Some(high_their_to_self_config.clone()), None]);
+
+ // We test config.our_to_self > BREAKDOWN_TIMEOUT is enforced in Channel::new_outbound()
+ let keys_manager: Arc<KeysInterface> = Arc::new(KeysManager::new(&nodes[0].node_seed, Network::Testnet, Arc::new(test_utils::TestLogger::new()), 10, 20));
+ if let Err(error) = Channel::new_outbound(&test_utils::TestFeeEstimator { sat_per_kw: 253 }, &keys_manager, nodes[1].node.get_our_node_id(), 1000000, 1000000, 0, Arc::new(test_utils::TestLogger::new()), &low_our_to_self_config) {
+ match error {
+ APIError::APIMisuseError { err } => { assert_eq!(err, "Configured with an unreasonable our_to_self_delay putting user funds at risks"); },
+ _ => panic!("Unexpected event"),
+ }
+ } else { assert!(false) }
+
+ // We test config.our_to_self > BREAKDOWN_TIMEOUT is enforced in Channel::new_from_req()
+ nodes[1].node.create_channel(nodes[0].node.get_our_node_id(), 1000000, 1000000, 42).unwrap();
+ let mut open_channel = get_event_msg!(nodes[1], MessageSendEvent::SendOpenChannel, nodes[0].node.get_our_node_id());
+ open_channel.to_self_delay = 200;
+ if let Err(error) = Channel::new_from_req(&test_utils::TestFeeEstimator { sat_per_kw: 253 }, &keys_manager, nodes[1].node.get_our_node_id(), LocalFeatures::new(), &open_channel, 0, Arc::new(test_utils::TestLogger::new()), &low_our_to_self_config) {
+ match error {
+ ChannelError::Close(err) => { assert_eq!(err, "Configured with an unreasonable our_to_self_delay putting user funds at risks"); },
+ _ => panic!("Unexpected event"),
+ }
+ } else { assert!(false); }
+
+ // We test msg.to_self_delay <= config.their_to_self_delay is enforced in Chanel::accept_channel()
+ nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 1000000, 1000000, 42).unwrap();
+ nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), LocalFeatures::new(), &get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id())).unwrap();
+ let mut accept_channel = get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id());
+ accept_channel.to_self_delay = 200;
+ if let Err(error) = nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), LocalFeatures::new(), &accept_channel) {
+ if let Some(error) = error.action {
+ match error {
+ ErrorAction::SendErrorMessage { msg } => {
+ assert_eq!(msg.data,"They wanted our payments to be delayed by a needlessly long period");
+ },
+ _ => { assert!(false); }
+ }
+ } else { assert!(false); }
+ } else { assert!(false); }
+
+ // We test msg.to_self_delay <= config.their_to_self_delay is enforced in Channel::new_from_req()
+ nodes[1].node.create_channel(nodes[0].node.get_our_node_id(), 1000000, 1000000, 42).unwrap();
+ let mut open_channel = get_event_msg!(nodes[1], MessageSendEvent::SendOpenChannel, nodes[0].node.get_our_node_id());
+ open_channel.to_self_delay = 200;
+ if let Err(error) = Channel::new_from_req(&test_utils::TestFeeEstimator { sat_per_kw: 253 }, &keys_manager, nodes[1].node.get_our_node_id(), LocalFeatures::new(), &open_channel, 0, Arc::new(test_utils::TestLogger::new()), &high_their_to_self_config) {
+ match error {
+ ChannelError::Close(err) => { assert_eq!(err, "They wanted our payments to be delayed by a needlessly long period"); },
+ _ => panic!("Unexpected event"),
+ }
+ } else { assert!(false); }
+}
//! Various user-configurable channel limits and settings which ChannelManager
//! applies for you.
+use ln::channelmanager::{BREAKDOWN_TIMEOUT, MAX_LOCAL_BREAKDOWN_TIMEOUT};
+
/// Top-level config which holds ChannelHandshakeLimits and ChannelConfig.
#[derive(Clone, Debug)]
pub struct UserConfig {
/// Applied only for inbound channels (see ChannelHandshakeLimits::max_minimum_depth for the
/// equivalent limit applied to outbound channels).
pub minimum_depth: u32,
+ /// Set to the amount of time we require our counterparty to wait to claim their money.
+ ///
+ /// It's one of the main parameter of our security model. We (or one of our watchtowers) MUST
+ /// be online to check for peer having broadcast a revoked transaction to steal our funds
+ /// at least once every our_to_self_delay blocks.
+ /// Default is BREAKDOWN_TIMEOUT, we enforce it as a minimum at channel opening so you can
+ /// tweak config to ask for more security, not less.
+ ///
+ /// Meanwhile, asking for a too high delay, we bother peer to freeze funds for nothing in
+ /// case of an honest unilateral channel close, which implicitly decrease the economic value of
+ /// our channel.
+ pub our_to_self_delay: u16,
}
impl ChannelHandshakeConfig {
pub fn new() -> ChannelHandshakeConfig {
ChannelHandshakeConfig {
minimum_depth: 6,
+ our_to_self_delay: BREAKDOWN_TIMEOUT,
}
}
}
/// Defaults to true to make the default that no announced channels are possible (which is
/// appropriate for any nodes which are not online very reliably).
pub force_announced_channel_preference: bool,
+ /// Set to the amount of time we're willing to wait to claim money back to us.
+ ///
+ /// Not checking this value would be a security issue, as our peer would be able to set it to
+ /// max relative lock-time (a year) and we would "lose" money as it would be locked for a long time.
+ /// Default is MAX_LOCAL_BREAKDOWN_TIMEOUT, which we also enforce as a maximum value
+ /// so you can tweak config to reduce the loss of having useless locked funds (if your peer accepts)
+ pub their_to_self_delay: u16
}
impl ChannelHandshakeLimits {
max_dust_limit_satoshis: <u64>::max_value(),
max_minimum_depth: 144,
force_announced_channel_preference: true,
+ their_to_self_delay: MAX_LOCAL_BREAKDOWN_TIMEOUT,
}
}
}