Added config file to allow users to specify channel limits as per bolt 2
authorSchalk van Heerden <swvheerden@gmail.com>
Fri, 14 Sep 2018 09:27:47 +0000 (11:27 +0200)
committerSchalk van Heerden <swvheerden@gmail.com>
Wed, 26 Sep 2018 13:31:09 +0000 (15:31 +0200)
fuzz/fuzz_targets/full_stack_target.rs
src/ln/channel.rs
src/ln/channelmanager.rs
src/ln/router.rs
src/util/configurations.rs
src/util/mod.rs

index c74201e5f6ae5a63454f5864fdc1b02095060361..2f3a660c2ffc7ad1d0e637addaad0c284b21dbfa 100644 (file)
@@ -22,6 +22,7 @@ use lightning::util::events::{EventsProvider,Event};
 use lightning::util::reset_rng_state;
 use lightning::util::logger::Logger;
 use lightning::util::sha2::Sha256;
+use lightning::util::UserConfigurations;
 
 mod utils;
 
@@ -235,8 +236,10 @@ pub fn do_test(data: &[u8], logger: &Arc<Logger>) {
        let watch = Arc::new(ChainWatchInterfaceUtil::new(Network::Bitcoin, Arc::clone(&logger)));
        let broadcast = Arc::new(TestBroadcaster{});
        let monitor = channelmonitor::SimpleManyChannelMonitor::new(watch.clone(), broadcast.clone());
-
-       let channelmanager = ChannelManager::new(our_network_key, slice_to_be32(get_slice!(4)), get_slice!(1)[0] != 0, Network::Bitcoin, fee_est.clone(), monitor.clone(), watch.clone(), broadcast.clone(), Arc::clone(&logger)).unwrap();
+       let mut config = UserConfigurations::new();
+       config.channel_options.fee_proportional_millionths =  slice_to_be32(get_slice!(4));
+       config.channel_options.announced_channel = (get_slice!(1)[0] != 0);
+       let channelmanager = ChannelManager::new(our_network_key,Network::Bitcoin, fee_est.clone(), monitor.clone(), watch.clone(), broadcast.clone(), Arc::clone(&logger), config).unwrap();
        let router = Arc::new(Router::new(PublicKey::from_secret_key(&secp_ctx, &our_network_key), watch.clone(), Arc::clone(&logger)));
 
        let peers = RefCell::new([false; 256]);
index e7c395e3d570cbcf5ef177725e053e8ee675b9b4..b40b17fde0e1321379e39552f5450c8dbe4b84df 100644 (file)
@@ -26,7 +26,7 @@ use util::ser::Writeable;
 use util::sha2::Sha256;
 use util::logger::Logger;
 use util::errors::APIError;
-use util::configurations::UserConfigurations;
+use util::configurations::{UserConfigurations,ChannelLimits,ChannelOptions};
 
 use std;
 use std::default::Default;
@@ -266,15 +266,14 @@ const INITIAL_COMMITMENT_NUMBER: u64 = (1 << 48) - 1;
 // calling channel_id() before we're set up or things like get_outbound_funding_signed on an
 // inbound channel.
 pub(super) struct Channel {
+       config :  UserConfigurations,
 
-       config : UserConfigurations,
        user_id: u64,
 
        channel_id: [u8; 32],
        channel_state: u32,
        channel_outbound: bool,
        secp_ctx: Secp256k1<secp256k1::All>,
-       announce_publicly: bool,
        channel_value_satoshis: u64,
 
        local_keys: ChannelKeys,
@@ -407,7 +406,7 @@ impl Channel {
        }
 
        // Constructors:
-       pub fn new_outbound(fee_estimator: &FeeEstimator, chan_keys: ChannelKeys, their_node_id: PublicKey, channel_value_satoshis: u64, push_msat: u64, announce_publicly: bool, user_id: u64, logger: Arc<Logger>, configurations: &UserConfigurations) -> Result<Channel, APIError> {
+       pub fn new_outbound(fee_estimator: &FeeEstimator, chan_keys: ChannelKeys, their_node_id: PublicKey, channel_value_satoshis: u64, push_msat: u64, user_id: u64, logger: Arc<Logger>, configurations: &UserConfigurations) -> Result<Channel, APIError> {
                if channel_value_satoshis >= MAX_FUNDING_SATOSHIS {
                        return Err(APIError::APIMisuseError{err: "funding value > 2^24"});
                }
@@ -434,12 +433,14 @@ impl Channel {
 
                Ok(Channel {
                        user_id: user_id,
-                       config : configurations.clone(),
+                       config: UserConfigurations{
+                               channel_options: configurations.channel_options.clone(),
+                               channel_limits : Arc::clone(&configurations.channel_limits),},
+
                        channel_id: rng::rand_u832(),
                        channel_state: ChannelState::OurInitSent as u32,
                        channel_outbound: true,
                        secp_ctx: secp_ctx,
-                       announce_publicly: announce_publicly,
                        channel_value_satoshis: channel_value_satoshis,
 
                        local_keys: chan_keys,
@@ -504,12 +505,13 @@ impl Channel {
        /// Assumes chain_hash has already been checked and corresponds with what we expect!
        /// Generally prefers to take the DisconnectPeer action on failure, as a notice to the sender
        /// that we're rejecting the new channel.
-       pub fn new_from_req(fee_estimator: &FeeEstimator, chan_keys: ChannelKeys, their_node_id: PublicKey, msg: &msgs::OpenChannel, user_id: u64, require_announce: bool, allow_announce: bool, logger: Arc<Logger>, configurations : &UserConfigurations) -> Result<Channel, HandleError> {
+       pub fn new_from_req(fee_estimator: &FeeEstimator, chan_keys: ChannelKeys, their_node_id: PublicKey, msg: &msgs::OpenChannel, user_id: u64, logger: Arc<Logger>, configurations : &UserConfigurations) -> Result<Channel, HandleError> {
                macro_rules! return_error_message {
                        ( $msg: expr ) => {
                                return Err(HandleError{err: $msg, action: Some(msgs::ErrorAction::SendErrorMessage{ msg: msgs::ErrorMessage { channel_id: msg.temporary_channel_id, data: $msg.to_string() }})});
                        }
                }
+               let mut local_config = (*configurations).channel_options.clone();
 
                // Check sanity of message fields:
                if msg.funding_satoshis >= MAX_FUNDING_SATOSHIS {
@@ -543,7 +545,7 @@ impl Channel {
                if msg.max_accepted_htlcs > 483 {
                        return_error_message!("max_accpted_htlcs > 483");
                }
-               //optional parameter checking 
+               //optional parameter checking
                // MAY fail the channel if
                if msg.funding_satoshis < configurations.channel_limits.funding_satoshis {
                        return_error_message!("funding satoshis is less than the user specified limit");
@@ -567,12 +569,16 @@ impl Channel {
                // Convert things into internal flags and prep our state:
 
                let their_announce = if (msg.channel_flags & 1) == 1 { true } else { false };
-               if require_announce && !their_announce {
-                       return_error_message!("Peer tried to open unannounced channel, but we require public ones");
-               }
-               if !allow_announce && their_announce {
-                       return_error_message!("Peer tried to open announced channel, but we require private ones");
+               if local_config.force_announced_channel_preference{
+                       if local_config.announced_channel && !their_announce {
+                               return_error_message!("Peer tried to open unannounced channel, but we require public ones");
+                       }
+                       if !local_config.announced_channel && their_announce {
+                               return_error_message!("Peer tried to open announced channel, but we require private ones");
+                       }
                }
+               //we either accept their preference or the preferences match
+               local_config.announced_channel = their_announce;
 
                let background_feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Background);
 
@@ -613,12 +619,14 @@ impl Channel {
 
                let mut chan = Channel {
                        user_id: user_id,
-                       config: (*configurations).clone(),
+                       config: UserConfigurations{
+                               channel_options: local_config,
+                               channel_limits : Arc::clone(&configurations.channel_limits),},
+
                        channel_id: msg.temporary_channel_id,
                        channel_state: (ChannelState::OurInitSent as u32) | (ChannelState::TheirInitSent as u32),
                        channel_outbound: false,
                        secp_ctx: secp_ctx,
-                       announce_publicly: their_announce,
 
                        local_keys: chan_keys,
                        cur_local_commitment_transaction_number: INITIAL_COMMITMENT_NUMBER,
@@ -1268,7 +1276,10 @@ impl Channel {
                if msg.max_accepted_htlcs > 483 {
                        return_error_message!("max_accpted_htlcs > 483");
                }
-
+               //Optional user definined limits
+               if msg.minimum_depth > self.config.channel_limits.minimum_depth {
+                       return_error_message!("We consider the minimum depth to be unreasonably large");
+               }
                self.channel_monitor.set_their_base_keys(&msg.htlc_basepoint, &msg.delayed_payment_basepoint);
 
                self.their_dust_limit_satoshis = msg.dust_limit_satoshis;
@@ -2257,7 +2268,7 @@ impl Channel {
        }
 
        pub fn should_announce(&self) -> bool {
-               self.announce_publicly
+               self.config.channel_options.announced_channel
        }
 
        /// Gets the fee we'd want to charge for adding an HTLC output to this Channel
@@ -2443,7 +2454,7 @@ impl Channel {
                        delayed_payment_basepoint: PublicKey::from_secret_key(&self.secp_ctx, &self.local_keys.delayed_payment_base_key),
                        htlc_basepoint: PublicKey::from_secret_key(&self.secp_ctx, &self.local_keys.htlc_base_key),
                        first_per_commitment_point: PublicKey::from_secret_key(&self.secp_ctx, &local_commitment_secret),
-                       channel_flags: if self.announce_publicly {1} else {0},
+                       channel_flags: if self.config.channel_options.announced_channel {1} else {0},
                        shutdown_scriptpubkey: None,
                }
        }
@@ -2547,7 +2558,7 @@ impl Channel {
        /// Note that the "channel must be funded" requirement is stricter than BOLT 7 requires - see
        /// https://github.com/lightningnetwork/lightning-rfc/issues/468
        pub fn get_channel_announcement(&self, our_node_id: PublicKey, chain_hash: Sha256dHash) -> Result<(msgs::UnsignedChannelAnnouncement, Signature), HandleError> {
-               if !self.announce_publicly {
+               if !self.config.channel_options.announced_channel {
                        return Err(HandleError{err: "Channel is not available for public announcements", action: Some(msgs::ErrorAction::IgnoreError)});
                }
                if self.channel_state & (ChannelState::ChannelFunded as u32) == 0 {
@@ -2909,7 +2920,9 @@ mod tests {
                                hex::decode("023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb").unwrap()[..]);
 
                let their_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap());
-               let mut chan = Channel::new_outbound(&feeest, chan_keys, their_node_id, 10000000, 100000, false, 42, Arc::clone(&logger), &UserConfigurations::new()).unwrap(); // Nothing uses their network key in this test
+               let mut config = UserConfigurations::new();
+               config.channel_options.announced_channel= false;
+               let mut chan = Channel::new_outbound(&feeest, chan_keys, their_node_id, 10000000, 100000, 42, Arc::clone(&logger), &config).unwrap(); // Nothing uses their network key in this test
                chan.their_to_self_delay = 144;
                chan.our_dust_limit_satoshis = 546;
 
index 077caa0e7efe4a1d1fc3e47d67660ca9b226ac12..9c85993e09ed6ee0f2a7c84422315c87b3fd9b75 100644 (file)
@@ -237,8 +237,6 @@ pub struct ChannelManager {
        chain_monitor: Arc<ChainWatchInterface>,
        tx_broadcaster: Arc<BroadcasterInterface>,
 
-       announce_channels_publicly: bool,
-       fee_proportional_millionths: u32,
        latest_block_height: AtomicUsize,
        secp_ctx: Secp256k1<secp256k1::All>,
 
@@ -295,23 +293,19 @@ impl ChannelManager {
        /// This is the main "logic hub" for all channel-related actions, and implements
        /// ChannelMessageHandler.
        ///
-       /// fee_proportional_millionths is an optional fee to charge any payments routed through us.
        /// Non-proportional fees are fixed according to our risk using the provided fee estimator.
        ///
        /// panics if channel_value_satoshis is >= `MAX_FUNDING_SATOSHIS`!
-       pub fn new(our_network_key: SecretKey, fee_proportional_millionths: u32, announce_channels_publicly: bool, network: Network, feeest: Arc<FeeEstimator>, monitor: Arc<ManyChannelMonitor>, chain_monitor: Arc<ChainWatchInterface>, tx_broadcaster: Arc<BroadcasterInterface>, logger: Arc<Logger>) -> Result<Arc<ChannelManager>, secp256k1::Error> {
+       pub fn new(our_network_key: SecretKey, network: Network, feeest: Arc<FeeEstimator>, monitor: Arc<ManyChannelMonitor>, chain_monitor: Arc<ChainWatchInterface>, tx_broadcaster: Arc<BroadcasterInterface>, logger: Arc<Logger>, config : UserConfigurations) -> Result<Arc<ChannelManager>, secp256k1::Error> {
                let secp_ctx = Secp256k1::new();
-
                let res = Arc::new(ChannelManager {
-                       configuration : UserConfigurations::new(),
+                       configuration : config.clone(),
                        genesis_hash: genesis_block(network).header.bitcoin_hash(),
                        fee_estimator: feeest.clone(),
                        monitor: monitor.clone(),
                        chain_monitor,
                        tx_broadcaster,
 
-                       announce_channels_publicly,
-                       fee_proportional_millionths,
                        latest_block_height: AtomicUsize::new(0), //TODO: Get an init value (generally need to replay recent chain on chain_monitor registration)
                        secp_ctx,
 
@@ -365,7 +359,7 @@ impl ChannelManager {
                        }
                };
 
-               let channel = Channel::new_outbound(&*self.fee_estimator, chan_keys, their_network_key, channel_value_satoshis, push_msat, self.announce_channels_publicly, user_id, Arc::clone(&self.logger), &self.configuration)?;
+               let channel = Channel::new_outbound(&*self.fee_estimator, chan_keys, their_network_key, channel_value_satoshis, push_msat, user_id, Arc::clone(&self.logger), &self.configuration)?;
                let res = channel.get_open_channel(self.genesis_hash.clone(), &*self.fee_estimator);
                let mut channel_state = self.channel_state.lock().unwrap();
                match channel_state.by_id.insert(channel.channel_id(), channel) {
@@ -910,7 +904,7 @@ impl ChannelManager {
                                        if !chan.is_live() {
                                                Some(("Forwarding channel is not in a ready state.", 0x1000 | 7, self.get_channel_update(chan).unwrap()))
                                        } else {
-                                               let fee = amt_to_forward.checked_mul(self.fee_proportional_millionths as u64).and_then(|prop_fee| { (prop_fee / 1000000).checked_add(chan.get_our_fee_base_msat(&*self.fee_estimator) as u64) });
+                                               let fee = amt_to_forward.checked_mul(self.configuration.channel_options.fee_proportional_millionths as u64).and_then(|prop_fee| { (prop_fee / 1000000).checked_add(chan.get_our_fee_base_msat(&*self.fee_estimator) as u64) });
                                                if fee.is_none() || msg.amount_msat < fee.unwrap() || (msg.amount_msat - fee.unwrap()) < *amt_to_forward {
                                                        Some(("Prior hop has deviated from specified fees parameters or origin node has obsolete ones", 0x1000 | 12, self.get_channel_update(chan).unwrap()))
                                                } else {
@@ -947,7 +941,7 @@ impl ChannelManager {
                        cltv_expiry_delta: CLTV_EXPIRY_DELTA,
                        htlc_minimum_msat: chan.get_our_htlc_minimum_msat(),
                        fee_base_msat: chan.get_our_fee_base_msat(&*self.fee_estimator),
-                       fee_proportional_millionths: self.fee_proportional_millionths,
+                       fee_proportional_millionths: self.configuration.channel_options.fee_proportional_millionths,
                        excess_data: Vec::new(),
                };
 
@@ -1460,7 +1454,7 @@ impl ChannelManager {
                        }
                };
 
-               let channel = Channel::new_from_req(&*self.fee_estimator, chan_keys, their_node_id.clone(), msg, 0, false, self.announce_channels_publicly, Arc::clone(&self.logger), &self.configuration).map_err(|e| MsgHandleErrInternal::from_no_close(e))?;
+               let channel = Channel::new_from_req(&*self.fee_estimator, chan_keys, their_node_id.clone(), msg, 0, Arc::clone(&self.logger), &self.configuration).map_err(|e| MsgHandleErrInternal::from_no_close(e))?;
                let accept_msg = channel.get_accept_channel();
                channel_state.by_id.insert(channel.channel_id(), channel);
                Ok(accept_msg)
@@ -1486,7 +1480,8 @@ impl ChannelManager {
                pending_events.push(events::Event::FundingGenerationReady {
                        temporary_channel_id: msg.temporary_channel_id,
                        channel_value_satoshis: value,
-                       output_script: output_script,                   user_channel_id: user_id,
+                       output_script: output_script,
+                       user_channel_id: user_id,
                });
                Ok(())
        }
@@ -2996,6 +2991,8 @@ mod tests {
        }
 
        fn create_network(node_count: usize) -> Vec<Node> {
+               use util::UserConfigurations;
+
                let mut nodes = Vec::new();
                let mut rng = thread_rng();
                let secp_ctx = Secp256k1::new();
@@ -3014,7 +3011,11 @@ mod tests {
                                rng.fill_bytes(&mut key_slice);
                                SecretKey::from_slice(&secp_ctx, &key_slice).unwrap()
                        };
-                       let node = ChannelManager::new(node_id.clone(), 0, true, Network::Testnet, feeest.clone(), chan_monitor.clone(), chain_monitor.clone(), tx_broadcaster.clone(), Arc::clone(&logger)).unwrap();
+                       let mut config = UserConfigurations::new();
+                       config.channel_options.announced_channel = true;
+                       config.channel_options.fee_proportional_millionths = 0;
+                       config.channel_options.force_announced_channel_preference = false;
+                       let node = ChannelManager::new(node_id.clone(), Network::Testnet, feeest.clone(), chan_monitor.clone(), chain_monitor.clone(), tx_broadcaster.clone(), Arc::clone(&logger), config).unwrap();
                        let router = Router::new(PublicKey::from_secret_key(&secp_ctx, &node_id), chain_monitor.clone(), Arc::clone(&logger));
                        nodes.push(Node { chain_monitor, tx_broadcaster, chan_monitor, node, router,
                                network_payment_count: payment_count.clone(),
index 5d5948dd714ee1b9f483b31de696e033802313c5..4a55df88c6f90fd30d309e506377d819a7720a02 100644 (file)
@@ -77,8 +77,6 @@ impl std::fmt::Display for ChannelInfo {
        }
 }
 
-
-
 struct NodeInfo {
        #[cfg(feature = "non_bitcoin_chain_hash_routing")]
        channels: Vec<(u64, Sha256dHash)>,
index aef81950db258e0f6f4249f1a0d07a2f1c2c04c1..dab09b30f8a0e9819f36dd352bdab8bbe85dde07 100644 (file)
@@ -1,29 +1,47 @@
-#[derive(Copy, Clone)]
+use std::sync::Arc;
+
+/// This is the main user configuration
+/// This struct should contain all user customizable options as this is passed to the channel to be accessed
+#[derive(Clone, Debug)]
 pub struct UserConfigurations{
-    pub channel_limits : ChannelLimits,
+       /// optional user spesefied channel limits
+       /// These are only used on startup of channels, and are referanced to a single instance
+    pub channel_limits : Arc<ChannelLimits>,
+       /// Channel options can change afterwords and are unique to each channel
+       pub channel_options : ChannelOptions,
 }
 
 impl UserConfigurations {
     pub fn new() -> Self{
         UserConfigurations {
-            channel_limits : ChannelLimits::new(),
+            channel_limits : Arc::new(ChannelLimits::new()),
+                       channel_options : ChannelOptions::new(),
         }
     }
 }
 
-#[derive(Copy, Clone)]
-pub struct ChannelLimits
-{
+/// This struct contains all the optional bolt 2 channel limits.
+/// If the user wants to check a value, the value needs to be filled in, as by default they are not checked
+#[derive(Copy, Clone, Debug)]
+pub struct ChannelLimits{
+       /// minimum allowed funding_satoshis
        pub funding_satoshis :u64,
+       /// maximum allowed htlc_minimum_msat
        pub htlc_minimum_msat : u64,
+       /// min allowed max_htlc_value_in_flight_msat
        pub max_htlc_value_in_flight_msat : u64,
+       /// max allowed channel_reserve_satashis
        pub channel_reserve_satoshis : u64,
+       /// min allowed max_accepted_htlcs
        pub max_accepted_htlcs : u16,
+       /// min allowed dust_limit_satashis
        pub dust_limit_satoshis : u64,
+       ///minimum depth to a number of blocks that is considered reasonable to avoid double-spending of the funding transaction
+       pub  minimum_depth : u32,
 }
 
 impl ChannelLimits {
-       //creating max and min possible values because if they are not set, means we should not check them. 
+//creating max and min possible values because if they are not set, means we should not check them.
        pub fn new() -> Self{
                ChannelLimits {
                        funding_satoshis : 0,
@@ -32,6 +50,29 @@ impl ChannelLimits {
                        channel_reserve_satoshis : <u64>::max_value(),
                        max_accepted_htlcs : 0,
                        dust_limit_satoshis : 0,
+                       minimum_depth : <u32>::max_value(),
+               }
+       }
+}
+
+/// This struct contains all the custom channel options.
+#[derive(Copy, Clone, Debug)]
+pub struct ChannelOptions{
+       /// Amount (in millionths of a satoshi) channel will charge per transferred satoshi.
+       pub fee_proportional_millionths : u32,
+       ///Is this channel an annouced channe;
+       pub announced_channel : bool,
+       ///do we force the incomming channel to match our announced channel preference
+       pub force_announced_channel_preference : bool,
+}
+impl ChannelOptions {
+       /// creating a struct with values.
+       /// fee_proportional_millionths should be changed afterwords
+       pub fn new() -> Self{
+               ChannelOptions {
+                       fee_proportional_millionths : 0,
+                       announced_channel : true,
+                       force_announced_channel_preference : false,
                }
        }
 }
\ No newline at end of file
index 02e873aaa4a7f9a5374ebbac9c003c8308175104..eb25dc7e82f7a40c8998674f12067f2dad2c02b3 100644 (file)
@@ -29,5 +29,5 @@ pub use self::rng::reset_rng_state;
 #[cfg(test)]
 pub(crate) mod test_utils;
 
-pub use self::configurations::{UserConfigurations, ChannelLimits};
-pub mod configurations;
+pub use self::configurations::UserConfigurations;
+pub mod configurations;
\ No newline at end of file