Correct error when a peer opens a channel with a huge push_msat
[rust-lightning] / lightning / src / ln / channel.rs
index 679ff82e0181d75e8331ccd66bad1ff588cd8f1c..60ff1ded1ad99220686729be383ea8967869ec68 100644 (file)
@@ -1082,14 +1082,13 @@ impl<Signer: Sign> Channel<Signer> {
                if msg.channel_reserve_satoshis > msg.funding_satoshis {
                        return Err(ChannelError::Close(format!("Bogus channel_reserve_satoshis ({}). Must be not greater than funding_satoshis: {}", msg.channel_reserve_satoshis, msg.funding_satoshis)));
                }
-               let funding_value = (msg.funding_satoshis - msg.channel_reserve_satoshis) * 1000;
-               if msg.push_msat > funding_value {
-                       return Err(ChannelError::Close(format!("push_msat {} was larger than funding value {}", msg.push_msat, funding_value)));
+               let full_channel_value_msat = (msg.funding_satoshis - msg.channel_reserve_satoshis) * 1000;
+               if msg.push_msat > full_channel_value_msat {
+                       return Err(ChannelError::Close(format!("push_msat {} was larger than channel amount minus reserve ({})", msg.push_msat, full_channel_value_msat)));
                }
                if msg.dust_limit_satoshis > msg.funding_satoshis {
                        return Err(ChannelError::Close(format!("dust_limit_satoshis {} was larger than funding_satoshis {}. Peer never wants payout outputs?", msg.dust_limit_satoshis, msg.funding_satoshis)));
                }
-               let full_channel_value_msat = (msg.funding_satoshis - msg.channel_reserve_satoshis) * 1000;
                if msg.htlc_minimum_msat >= full_channel_value_msat {
                        return Err(ChannelError::Close(format!("Minimum htlc value ({}) was larger than full channel value ({})", msg.htlc_minimum_msat, full_channel_value_msat)));
                }
@@ -1143,6 +1142,9 @@ impl<Signer: Sign> Channel<Signer> {
                if holder_selected_channel_reserve_satoshis < MIN_CHAN_DUST_LIMIT_SATOSHIS {
                        return Err(ChannelError::Close(format!("Suitable channel reserve not found. remote_channel_reserve was ({}). dust_limit_satoshis is ({}).", holder_selected_channel_reserve_satoshis, MIN_CHAN_DUST_LIMIT_SATOSHIS)));
                }
+               if holder_selected_channel_reserve_satoshis * 1000 >= full_channel_value_msat {
+                       return Err(ChannelError::Close(format!("Suitable channel reserve not found. remote_channel_reserve was ({}). Channel value is ({} - {}).", holder_selected_channel_reserve_satoshis, full_channel_value_msat, msg.push_msat)));
+               }
                if msg.channel_reserve_satoshis < MIN_CHAN_DUST_LIMIT_SATOSHIS {
                        log_debug!(logger, "channel_reserve_satoshis ({}) is smaller than our dust limit ({}). We can broadcast stale states without any risk, implying this channel is very insecure for our counterparty.",
                                msg.channel_reserve_satoshis, MIN_CHAN_DUST_LIMIT_SATOSHIS);
@@ -4321,11 +4323,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 +4349,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
        }
@@ -6289,44 +6310,39 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<(&'a K, u32)> for Channel<Signer>
 
 #[cfg(test)]
 mod tests {
-       use bitcoin::util::bip143;
-       use bitcoin::consensus::encode::serialize;
        use bitcoin::blockdata::script::{Script, Builder};
-       use bitcoin::blockdata::transaction::{Transaction, TxOut, SigHashType};
+       use bitcoin::blockdata::transaction::{Transaction, TxOut};
        use bitcoin::blockdata::constants::genesis_block;
        use bitcoin::blockdata::opcodes;
        use bitcoin::network::constants::Network;
-       use bitcoin::hashes::hex::FromHex;
        use hex;
-       use ln::{PaymentPreimage, PaymentHash};
+       use ln::PaymentHash;
        use ln::channelmanager::{HTLCSource, PaymentId};
-       use ln::channel::{Channel,InboundHTLCOutput,OutboundHTLCOutput,InboundHTLCState,OutboundHTLCState,HTLCOutputInCommitment,HTLCCandidate,HTLCInitiator,TxCreationKeys};
+       use ln::channel::{Channel, InboundHTLCOutput, OutboundHTLCOutput, InboundHTLCState, OutboundHTLCState, HTLCCandidate, HTLCInitiator};
        use ln::channel::MAX_FUNDING_SATOSHIS;
        use ln::features::InitFeatures;
        use ln::msgs::{ChannelUpdate, DataLossProtect, DecodeError, OptionalField, UnsignedChannelUpdate};
        use ln::script::ShutdownScript;
        use ln::chan_utils;
-       use ln::chan_utils::{ChannelPublicKeys, HolderCommitmentTransaction, CounterpartyChannelTransactionParameters, htlc_success_tx_weight, htlc_timeout_tx_weight};
+       use ln::chan_utils::{htlc_success_tx_weight, htlc_timeout_tx_weight};
        use chain::BestBlock;
        use chain::chaininterface::{FeeEstimator,ConfirmationTarget};
-       use chain::keysinterface::{InMemorySigner, Recipient, KeyMaterial, KeysInterface, BaseSign};
+       use chain::keysinterface::{InMemorySigner, Recipient, KeyMaterial, KeysInterface};
        use chain::transaction::OutPoint;
        use util::config::UserConfig;
        use util::enforcing_trait_impls::EnforcingSigner;
        use util::errors::APIError;
        use util::test_utils;
        use util::test_utils::OnGetShutdownScriptpubkey;
-       use util::logger::Logger;
-       use bitcoin::secp256k1::{Secp256k1, Message, Signature, All};
+       use bitcoin::secp256k1::{Secp256k1, Signature};
        use bitcoin::secp256k1::ffi::Signature as FFISignature;
        use bitcoin::secp256k1::key::{SecretKey,PublicKey};
        use bitcoin::secp256k1::recovery::RecoverableSignature;
        use bitcoin::hashes::sha256::Hash as Sha256;
        use bitcoin::hashes::Hash;
-       use bitcoin::hash_types::{Txid, WPubkeyHash};
+       use bitcoin::hash_types::WPubkeyHash;
        use core::num::NonZeroU8;
        use bitcoin::bech32::u5;
-       use sync::Arc;
        use prelude::*;
 
        struct TestFeeEstimator {
@@ -6380,7 +6396,8 @@ mod tests {
                fn sign_invoice(&self, _hrp_bytes: &[u8], _invoice_data: &[u5], _recipient: Recipient) -> Result<RecoverableSignature, ()> { panic!(); }
        }
 
-       fn public_from_secret_hex(secp_ctx: &Secp256k1<All>, hex: &str) -> PublicKey {
+       #[cfg(not(feature = "grind_signatures"))]
+       fn public_from_secret_hex(secp_ctx: &Secp256k1<bitcoin::secp256k1::All>, hex: &str) -> PublicKey {
                PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&hex::decode(hex).unwrap()[..]).unwrap())
        }
 
@@ -6669,6 +6686,19 @@ mod tests {
        #[cfg(not(feature = "grind_signatures"))]
        #[test]
        fn outbound_commitment_test() {
+               use bitcoin::util::bip143;
+               use bitcoin::consensus::encode::serialize;
+               use bitcoin::blockdata::transaction::SigHashType;
+               use bitcoin::hashes::hex::FromHex;
+               use bitcoin::hash_types::Txid;
+               use bitcoin::secp256k1::Message;
+               use chain::keysinterface::BaseSign;
+               use ln::PaymentPreimage;
+               use ln::channel::{HTLCOutputInCommitment ,TxCreationKeys};
+               use ln::chan_utils::{ChannelPublicKeys, HolderCommitmentTransaction, CounterpartyChannelTransactionParameters};
+               use util::logger::Logger;
+               use sync::Arc;
+
                // Test vectors from BOLT 3 Appendices C and F (anchors):
                let feeest = TestFeeEstimator{fee_est: 15000};
                let logger : Arc<Logger> = Arc::new(test_utils::TestLogger::new());