Logging interface
[rust-lightning] / src / ln / channel.rs
index acee06409c3f8479137b1561ac1b2d636cf6c9e2..a1ca7e25e65a5ea8cff9f5d0a27710751ea5ae94 100644 (file)
@@ -23,11 +23,13 @@ use chain::chaininterface::{FeeEstimator,ConfirmationTarget};
 use chain::transaction::OutPoint;
 use util::{transaction_utils,rng};
 use util::sha2::Sha256;
+use util::logger::{Logger, Record};
 
 use std;
 use std::default::Default;
 use std::{cmp,mem};
 use std::time::Instant;
+use std::sync::{Arc};
 
 pub struct ChannelKeys {
        pub funding_key: SecretKey,
@@ -136,7 +138,7 @@ enum HTLCState {
        /// anyway).
        LocalRemoved,
        /// Removed by us, sent a new commitment_signed and got a revoke_and_ack. Just waiting on an
-       /// updated local commitment transaction.
+       /// updated local commitment transaction. Implies local_removed_fulfilled.
        LocalRemovedAwaitingCommitment,
 }
 
@@ -271,7 +273,7 @@ pub struct Channel {
        /// to detect unconfirmation after a serialize-unserialize roudtrip where we may not see a full
        /// series of block_connected/block_disconnected calls. Obviously this is not a guarantee as we
        /// could miss the funding_tx_confirmed_in block as well, but it serves as a useful fallback.
-       funding_tx_confirmed_in: Sha256dHash,
+       funding_tx_confirmed_in: Option<Sha256dHash>,
        short_channel_id: Option<u64>,
        /// Used to deduplicate block_connected callbacks
        last_block_connected: Sha256dHash,
@@ -303,6 +305,8 @@ pub struct Channel {
        their_shutdown_scriptpubkey: Option<Script>,
 
        channel_monitor: ChannelMonitor,
+
+       logger: Arc<Logger>,
 }
 
 const OUR_MAX_HTLCS: u16 = 5; //TODO
@@ -361,7 +365,7 @@ impl Channel {
        // Constructors:
 
        /// panics if channel_value_satoshis is >= `MAX_FUNDING_SATOSHIS`
-       pub fn new_outbound(fee_estimator: &FeeEstimator, chan_keys: ChannelKeys, their_node_id: PublicKey, channel_value_satoshis: u64, announce_publicly: bool, user_id: u64) -> Channel {
+       pub fn new_outbound(fee_estimator: &FeeEstimator, chan_keys: ChannelKeys, their_node_id: PublicKey, channel_value_satoshis: u64, announce_publicly: bool, user_id: u64, logger: Arc<Logger>) -> Channel {
                if channel_value_satoshis >= MAX_FUNDING_SATOSHIS {
                        panic!("funding value > 2^24");
                }
@@ -401,7 +405,7 @@ impl Channel {
 
                        last_sent_closing_fee: None,
 
-                       funding_tx_confirmed_in: Default::default(),
+                       funding_tx_confirmed_in: None,
                        short_channel_id: None,
                        last_block_connected: Default::default(),
                        funding_tx_confirmations: 0,
@@ -429,6 +433,8 @@ impl Channel {
                        their_shutdown_scriptpubkey: None,
 
                        channel_monitor: channel_monitor,
+
+                       logger,
                }
        }
 
@@ -446,7 +452,7 @@ 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) -> Result<Channel, HandleError> {
+       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>) -> Result<Channel, HandleError> {
                // Check sanity of message fields:
                if msg.funding_satoshis >= MAX_FUNDING_SATOSHIS {
                        return Err(HandleError{err: "funding value > 2^24", action: Some(msgs::ErrorAction::DisconnectPeer{ msg: None })});
@@ -519,7 +525,7 @@ impl Channel {
 
                        last_sent_closing_fee: None,
 
-                       funding_tx_confirmed_in: Default::default(),
+                       funding_tx_confirmed_in: None,
                        short_channel_id: None,
                        last_block_connected: Default::default(),
                        funding_tx_confirmations: 0,
@@ -548,6 +554,8 @@ impl Channel {
                        their_shutdown_scriptpubkey: None,
 
                        channel_monitor: channel_monitor,
+
+                       logger,
                };
 
                let obscure_factor = chan.get_commitment_transaction_number_obscure_factor();
@@ -663,7 +671,7 @@ impl Channel {
                        } else {
                                match htlc.state {
                                        HTLCState::AwaitingRemoteRevokeToRemove|HTLCState::AwaitingRemovedRemoteRevoke => {
-                                               if generated_by_local && htlc.fail_reason.is_none() {
+                                               if htlc.fail_reason.is_none() {
                                                        value_to_self_msat_offset -= htlc.amount_msat as i64;
                                                }
                                        },
@@ -678,6 +686,7 @@ impl Channel {
                                                }
                                        },
                                        HTLCState::LocalRemovedAwaitingCommitment => {
+                                               assert!(htlc.local_removed_fulfilled);
                                                value_to_self_msat_offset += htlc.amount_msat as i64;
                                        },
                                        _ => {},
@@ -1747,7 +1756,7 @@ impl Channel {
 
                match self.secp_ctx.verify(&sighash, &msg.signature, &self.their_funding_pubkey) {
                        Ok(_) => {},
-                       Err(_) => {
+                       Err(_e) => {
                                // The remote end may have decided to revoke their output due to inconsistent dust
                                // limits, so check for that case by re-checking the signature here.
                                closing_tx = self.build_closing_transaction(msg.fee_satoshis, true).0;
@@ -1826,6 +1835,7 @@ impl Channel {
                self.user_id
        }
 
+       /// May only be called after funding has been initiated (ie is_funding_initiated() is true)
        pub fn channel_monitor(&self) -> ChannelMonitor {
                if self.channel_state < ChannelState::FundingCreated as u32 {
                        panic!("Can't get a channel monitor until funding has been created");
@@ -1903,6 +1913,11 @@ impl Channel {
                self.is_usable()
        }
 
+       /// Returns true if funding_created was sent/received.
+       pub fn is_funding_initiated(&self) -> bool {
+               self.channel_state >= ChannelState::FundingCreated as u32
+       }
+
        /// Returns true if this channel is fully shut down. True here implies that no further actions
        /// may/will be taken on this channel, and thus this object should be freed. Any future changes
        /// will be handled appropriately by the chain monitor.
@@ -1926,27 +1941,38 @@ impl Channel {
                                self.last_block_connected = header.bitcoin_hash();
                                self.funding_tx_confirmations += 1;
                                if self.funding_tx_confirmations == CONF_TARGET as u64 {
-                                       if non_shutdown_state == ChannelState::FundingSent as u32 {
+                                       let need_commitment_update = if non_shutdown_state == ChannelState::FundingSent as u32 {
                                                self.channel_state |= ChannelState::OurFundingLocked as u32;
+                                               true
                                        } else if non_shutdown_state == (ChannelState::FundingSent as u32 | ChannelState::TheirFundingLocked as u32) {
                                                self.channel_state = ChannelState::ChannelFunded as u32 | (self.channel_state & BOTH_SIDES_SHUTDOWN_MASK);
                                                self.channel_update_count += 1;
-                                               //TODO: Something about a state where we "lost confirmation"
+                                               true
+                                       } else if self.channel_state == (ChannelState::FundingSent as u32 | ChannelState::OurFundingLocked as u32) {
+                                               // We got a reorg but not enough to trigger a force close, just update
+                                               // funding_tx_confirmed_in and return.
+                                               false
                                        } else if self.channel_state < ChannelState::ChannelFunded as u32 {
-                                               panic!("Started confirming a channel in a state pre-FundingSent?");
-                                       }
-                                       self.funding_tx_confirmed_in = header.bitcoin_hash();
+                                               panic!("Started confirming a channel in a state pre-FundingSent?: {}", self.channel_state);
+                                       } else {
+                                               // We got a reorg but not enough to trigger a force close, just update
+                                               // funding_tx_confirmed_in and return.
+                                               false
+                                       };
+                                       self.funding_tx_confirmed_in = Some(header.bitcoin_hash());
 
                                        //TODO: Note that this must be a duplicate of the previous commitment point they sent us,
                                        //as otherwise we will have a commitment transaction that they can't revoke (well, kinda,
                                        //they can by sending two revoke_and_acks back-to-back, but not really). This appears to be
                                        //a protocol oversight, but I assume I'm just missing something.
-                                       let next_per_commitment_secret = self.build_local_commitment_secret(self.cur_local_commitment_transaction_number);
-                                       let next_per_commitment_point = PublicKey::from_secret_key(&self.secp_ctx, &next_per_commitment_secret).unwrap();
-                                       return Ok(Some(msgs::FundingLocked {
-                                               channel_id: self.channel_id,
-                                               next_per_commitment_point: next_per_commitment_point,
-                                       }));
+                                       if need_commitment_update {
+                                               let next_per_commitment_secret = self.build_local_commitment_secret(self.cur_local_commitment_transaction_number);
+                                               let next_per_commitment_point = PublicKey::from_secret_key(&self.secp_ctx, &next_per_commitment_secret).unwrap();
+                                               return Ok(Some(msgs::FundingLocked {
+                                                       channel_id: self.channel_id,
+                                                       next_per_commitment_point: next_per_commitment_point,
+                                               }));
+                                       }
                                }
                        }
                }
@@ -1981,7 +2007,7 @@ impl Channel {
                                return true;
                        }
                }
-               if header.bitcoin_hash() == self.funding_tx_confirmed_in {
+               if Some(header.bitcoin_hash()) == self.funding_tx_confirmed_in {
                        self.funding_tx_confirmations = CONF_TARGET as u64 - 1;
                }
                false
@@ -2093,6 +2119,7 @@ impl Channel {
                let (our_signature, commitment_tx) = match self.get_outbound_funding_created_signature() {
                        Ok(res) => res,
                        Err(e) => {
+                               log_error!(self, "Got bad signatures: {}!", e.err);
                                self.channel_monitor.unset_funding_info();
                                return Err(e);
                        }
@@ -2391,10 +2418,13 @@ mod tests {
        use ln::chan_utils;
        use chain::chaininterface::{FeeEstimator,ConfirmationTarget};
        use chain::transaction::OutPoint;
+       use util::test_utils;
+       use util::logger::Logger;
        use secp256k1::{Secp256k1,Message,Signature};
        use secp256k1::key::{SecretKey,PublicKey};
        use crypto::sha2::Sha256;
        use crypto::digest::Digest;
+       use std::sync::Arc;
 
        struct TestFeeEstimator {
                fee_est: u64
@@ -2415,6 +2445,7 @@ mod tests {
        fn outbound_commitment_test() {
                // Test vectors from BOLT 3 Appendix C:
                let feeest = TestFeeEstimator{fee_est: 15000};
+               let logger : Arc<Logger> = Arc::new(test_utils::TestLogger::new());
                let secp_ctx = Secp256k1::new();
 
                let chan_keys = ChannelKeys {
@@ -2432,7 +2463,7 @@ mod tests {
                assert_eq!(PublicKey::from_secret_key(&secp_ctx, &chan_keys.funding_key).unwrap().serialize()[..],
                                hex::decode("023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb").unwrap()[..]);
 
-               let mut chan = Channel::new_outbound(&feeest, chan_keys, PublicKey::new(), 10000000, false, 42); // Nothing uses their network key in this test
+               let mut chan = Channel::new_outbound(&feeest, chan_keys, PublicKey::new(), 10000000, false, 42, Arc::clone(&logger)); // Nothing uses their network key in this test
                chan.their_to_self_delay = 144;
                chan.our_dust_limit_satoshis = 546;