X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Fchannel.rs;h=1279f310d4bfdbcfd134a9b53c95674fa0dd21bf;hb=871f4143672b9d8e616dbc2b6df87366590179d0;hp=0040541cbc18dcbc286c8a59040bd855fc1689be;hpb=94bb0c9128c2635ea08ec089f79fab04880dedd0;p=rust-lightning diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index 0040541c..1279f310 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -25,7 +25,7 @@ use bitcoin::secp256k1; use ln::features::{ChannelFeatures, InitFeatures}; use ln::msgs; use ln::msgs::{DecodeError, OptionalField, DataLossProtect}; -use ln::channelmanager::{PendingHTLCStatus, HTLCSource, HTLCFailReason, HTLCFailureMsg, PendingHTLCInfo, RAACommitmentOrder, PaymentPreimage, PaymentHash, BREAKDOWN_TIMEOUT, MAX_LOCAL_BREAKDOWN_TIMEOUT}; +use ln::channelmanager::{PendingHTLCStatus, HTLCSource, HTLCFailReason, HTLCFailureMsg, PendingHTLCInfo, RAACommitmentOrder, PaymentPreimage, PaymentHash, BREAKDOWN_TIMEOUT, MIN_CLTV_EXPIRY_DELTA, MAX_LOCAL_BREAKDOWN_TIMEOUT}; use ln::chan_utils::{CounterpartyCommitmentSecrets, TxCreationKeys, HTLCOutputInCommitment, HTLC_SUCCESS_TX_WEIGHT, HTLC_TIMEOUT_TX_WEIGHT, make_funding_redeemscript, ChannelPublicKeys, CommitmentTransaction, HolderCommitmentTransaction, ChannelTransactionParameters, CounterpartyChannelTransactionParameters, MAX_HTLCS, get_commitment_transaction_number_obscure_factor}; use ln::chan_utils; use chain::chaininterface::{FeeEstimator,ConfirmationTarget}; @@ -37,14 +37,15 @@ use util::ser::{Readable, ReadableArgs, Writeable, Writer, VecWriter}; use util::logger::Logger; use util::errors::APIError; use util::config::{UserConfig,ChannelConfig}; +use util::scid_utils::scid_from_parts; use std; -use std::default::Default; use std::{cmp,mem,fmt}; use std::ops::Deref; #[cfg(any(test, feature = "fuzztarget"))] use std::sync::Mutex; use bitcoin::hashes::hex::ToHex; +use bitcoin::blockdata::opcodes::all::OP_PUSHBYTES_0; #[cfg(test)] pub struct ChannelValueStat { @@ -95,6 +96,7 @@ enum InboundHTLCState { /// is used to derive commitment keys, which are used to construct the /// signatures in a commitment_signed message. /// Implies AwaitingRemoteRevoke. + /// /// [BOLT #2]: https://github.com/lightningnetwork/lightning-rfc/blob/master/02-peer-protocol.md AwaitingRemoteRevokeToAnnounce(PendingHTLCStatus), /// Included in a received commitment_signed message (implying we've revoke_and_ack'd it). @@ -281,6 +283,19 @@ impl HTLCCandidate { } } +/// Information needed for constructing an invoice route hint for this channel. +#[derive(Clone)] +pub struct CounterpartyForwardingInfo { + /// Base routing fee in millisatoshis. + pub fee_base_msat: u32, + /// Amount in millionths of a satoshi the channel will charge per transferred satoshi. + pub fee_proportional_millionths: u32, + /// The minimum difference in cltv_expiry between an ingoing HTLC and its outgoing counterpart, + /// such that the outgoing HTLC is forwardable to this counterparty. See `msgs::ChannelUpdate`'s + /// `cltv_expiry_delta` for more details. + pub cltv_expiry_delta: u16, +} + // TODO: We should refactor this to be an Inbound/OutboundChannel until initial setup handshaking // has been completed, and then turn into a Channel to get compiler-time enforcement of things like // calling channel_id() before we're set up or things like get_outbound_funding_signed on an @@ -361,16 +376,10 @@ pub(super) struct Channel { last_sent_closing_fee: Option<(u32, u64, Signature)>, // (feerate, fee, holder_sig) - /// The hash of the block in which the funding transaction reached our CONF_TARGET. We use this - /// to detect unconfirmation after a serialize-unserialize roundtrip 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. + /// The hash of the block in which the funding transaction was included. funding_tx_confirmed_in: Option, + funding_tx_confirmation_height: u64, short_channel_id: Option, - /// Used to deduplicate block_connected callbacks, also used to verify consistency during - /// ChannelManager deserialization (hence pub(super)) - pub(super) last_block_connected: BlockHash, - funding_tx_confirmations: u64, counterparty_dust_limit_satoshis: u64, #[cfg(test)] @@ -394,6 +403,8 @@ pub(super) struct Channel { //implied by OUR_MAX_HTLCS: max_accepted_htlcs: u16, minimum_depth: u32, + counterparty_forwarding_info: Option, + pub(crate) channel_transaction_parameters: ChannelTransactionParameters, counterparty_cur_commitment_point: Option, @@ -427,10 +438,6 @@ struct CommitmentTxInfoCached { } pub const OUR_MAX_HTLCS: u16 = 50; //TODO -/// Confirmation count threshold at which we close a channel. Ideally we'd keep the channel around -/// 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; const SPENDING_INPUT_FOR_A_OUTPUT_WEIGHT: u64 = 79; // prevout: 36, nSequence: 4, script len: 1, witness lengths: (3+1)/4, sig: 73/4, if-selector: 1, redeemScript: (6 ops + 2*33 pubkeys + 1*2 delay)/4 const B_OUTPUT_PLUS_SPENDING_INPUT_WEIGHT: u64 = 104; // prevout: 40, nSequence: 4, script len: 1, witness lengths: 3/4, sig: 73/4, pubkey: 33/4, output: 31 (TODO: Wrong? Useless?) @@ -520,13 +527,16 @@ impl Channel { let feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Normal); + let mut secp_ctx = Secp256k1::new(); + secp_ctx.seeded_randomize(&keys_provider.get_secure_random_bytes()); + Ok(Channel { user_id, config: config.channel_options.clone(), channel_id: keys_provider.get_secure_random_bytes(), channel_state: ChannelState::OurInitSent as u32, - secp_ctx: Secp256k1::new(), + secp_ctx, channel_value_satoshis, latest_monitor_update_id: 0, @@ -564,9 +574,8 @@ impl Channel { last_sent_closing_fee: None, funding_tx_confirmed_in: None, + funding_tx_confirmation_height: 0, short_channel_id: None, - last_block_connected: Default::default(), - funding_tx_confirmations: 0, feerate_per_kw: feerate, counterparty_dust_limit_satoshis: 0, @@ -578,6 +587,8 @@ impl Channel { counterparty_max_accepted_htlcs: 0, minimum_depth: 0, // Filled in in accept_channel + counterparty_forwarding_info: None, + channel_transaction_parameters: ChannelTransactionParameters { holder_pubkeys: pubkeys, holder_selected_contest_delay: config.own_channel_config.our_to_self_delay, @@ -737,15 +748,14 @@ impl Channel { let counterparty_shutdown_scriptpubkey = if their_features.supports_upfront_shutdown_script() { match &msg.shutdown_scriptpubkey { &OptionalField::Present(ref script) => { - // Peer is signaling upfront_shutdown and has provided a non-accepted scriptpubkey format. We enforce it while receiving shutdown msg - if script.is_p2pkh() || script.is_p2sh() || script.is_v0_p2wsh() || script.is_v0_p2wpkh() { - Some(script.clone()) // Peer is signaling upfront_shutdown and has opt-out with a 0-length script. We don't enforce anything - } else if script.len() == 0 { + if script.len() == 0 { None // Peer is signaling upfront_shutdown and has provided a non-accepted scriptpubkey format. Fail the channel - } else { + } else if is_unsupported_shutdown_script(&their_features, script) { return Err(ChannelError::Close(format!("Peer is signaling upfront_shutdown but has provided a non-accepted scriptpubkey format. script: ({})", script.to_bytes().to_hex()))); + } else { + Some(script.clone()) } }, // Peer is signaling upfront shutdown but don't opt-out with correct mechanism (a.k.a 0-length script). Peer looks buggy, we fail the channel @@ -755,13 +765,16 @@ impl Channel { } } else { None }; + let mut secp_ctx = Secp256k1::new(); + secp_ctx.seeded_randomize(&keys_provider.get_secure_random_bytes()); + let chan = Channel { user_id, config: local_config, channel_id: msg.temporary_channel_id, channel_state: (ChannelState::OurInitSent as u32) | (ChannelState::TheirInitSent as u32), - secp_ctx: Secp256k1::new(), + secp_ctx, latest_monitor_update_id: 0, @@ -798,9 +811,8 @@ impl Channel { last_sent_closing_fee: None, funding_tx_confirmed_in: None, + funding_tx_confirmation_height: 0, short_channel_id: None, - last_block_connected: Default::default(), - funding_tx_confirmations: 0, feerate_per_kw: msg.feerate_per_kw, channel_value_satoshis: msg.funding_satoshis, @@ -813,6 +825,8 @@ impl Channel { counterparty_max_accepted_htlcs: msg.max_accepted_htlcs, minimum_depth: config.own_channel_config.minimum_depth, + counterparty_forwarding_info: None, + channel_transaction_parameters: ChannelTransactionParameters { holder_pubkeys: pubkeys, holder_selected_contest_delay: config.own_channel_config.our_to_self_delay, @@ -1439,15 +1453,14 @@ impl Channel { let counterparty_shutdown_scriptpubkey = if their_features.supports_upfront_shutdown_script() { match &msg.shutdown_scriptpubkey { &OptionalField::Present(ref script) => { - // Peer is signaling upfront_shutdown and has provided a non-accepted scriptpubkey format. We enforce it while receiving shutdown msg - if script.is_p2pkh() || script.is_p2sh() || script.is_v0_p2wsh() || script.is_v0_p2wpkh() { - Some(script.clone()) // Peer is signaling upfront_shutdown and has opt-out with a 0-length script. We don't enforce anything - } else if script.len() == 0 { + if script.len() == 0 { None // Peer is signaling upfront_shutdown and has provided a non-accepted scriptpubkey format. Fail the channel + } else if is_unsupported_shutdown_script(&their_features, script) { + return Err(ChannelError::Close(format!("Peer is signaling upfront_shutdown but has provided a non-accepted scriptpubkey format. script: ({})", script.to_bytes().to_hex()))); } else { - return Err(ChannelError::Close(format!("Peer is signaling upfront_shutdown but has provided a non-accepted scriptpubkey format. scriptpubkey: ({})", script.to_bytes().to_hex()))); + Some(script.clone()) } }, // Peer is signaling upfront shutdown but don't opt-out with correct mechanism (a.k.a 0-length script). Peer looks buggy, we fail the channel @@ -1517,7 +1530,7 @@ impl Channel { &self.get_counterparty_pubkeys().funding_pubkey } - pub fn funding_created(&mut self, msg: &msgs::FundingCreated, logger: &L) -> Result<(msgs::FundingSigned, ChannelMonitor), ChannelError> where L::Target: Logger { + pub fn funding_created(&mut self, msg: &msgs::FundingCreated, last_block_hash: BlockHash, logger: &L) -> Result<(msgs::FundingSigned, ChannelMonitor), ChannelError> where L::Target: Logger { if self.is_outbound() { return Err(ChannelError::Close("Received funding_created for an outbound channel?".to_owned())); } @@ -1565,13 +1578,13 @@ impl Channel { let funding_redeemscript = self.get_funding_redeemscript(); let funding_txo_script = funding_redeemscript.to_v0_p2wsh(); let obscure_factor = get_commitment_transaction_number_obscure_factor(&self.get_holder_pubkeys().payment_point, &self.get_counterparty_pubkeys().payment_point, self.is_outbound()); - let mut channel_monitor = ChannelMonitor::new(self.holder_signer.clone(), - &self.shutdown_pubkey, self.get_holder_selected_contest_delay(), - &self.destination_script, (funding_txo, funding_txo_script.clone()), - &self.channel_transaction_parameters, - funding_redeemscript.clone(), self.channel_value_satoshis, - obscure_factor, - holder_commitment_tx); + let channel_monitor = ChannelMonitor::new(self.secp_ctx.clone(), self.holder_signer.clone(), + &self.shutdown_pubkey, self.get_holder_selected_contest_delay(), + &self.destination_script, (funding_txo, funding_txo_script.clone()), + &self.channel_transaction_parameters, + funding_redeemscript.clone(), self.channel_value_satoshis, + obscure_factor, + holder_commitment_tx, last_block_hash); channel_monitor.provide_latest_counterparty_commitment_tx(counterparty_initial_commitment_txid, Vec::new(), self.cur_counterparty_commitment_transaction_number, self.counterparty_cur_commitment_point.unwrap(), logger); @@ -1588,7 +1601,7 @@ impl Channel { /// Handles a funding_signed message from the remote end. /// If this call is successful, broadcast the funding transaction (and not before!) - pub fn funding_signed(&mut self, msg: &msgs::FundingSigned, logger: &L) -> Result, ChannelError> where L::Target: Logger { + pub fn funding_signed(&mut self, msg: &msgs::FundingSigned, last_block_hash: BlockHash, logger: &L) -> Result, ChannelError> where L::Target: Logger { if !self.is_outbound() { return Err(ChannelError::Close("Received funding_signed for an inbound channel?".to_owned())); } @@ -1635,13 +1648,13 @@ impl Channel { let funding_txo = self.get_funding_txo().unwrap(); let funding_txo_script = funding_redeemscript.to_v0_p2wsh(); let obscure_factor = get_commitment_transaction_number_obscure_factor(&self.get_holder_pubkeys().payment_point, &self.get_counterparty_pubkeys().payment_point, self.is_outbound()); - let mut channel_monitor = ChannelMonitor::new(self.holder_signer.clone(), - &self.shutdown_pubkey, self.get_holder_selected_contest_delay(), - &self.destination_script, (funding_txo, funding_txo_script), - &self.channel_transaction_parameters, - funding_redeemscript.clone(), self.channel_value_satoshis, - obscure_factor, - holder_commitment_tx); + let channel_monitor = ChannelMonitor::new(self.secp_ctx.clone(), self.holder_signer.clone(), + &self.shutdown_pubkey, self.get_holder_selected_contest_delay(), + &self.destination_script, (funding_txo, funding_txo_script), + &self.channel_transaction_parameters, + funding_redeemscript.clone(), self.channel_value_satoshis, + obscure_factor, + holder_commitment_tx, last_block_hash); channel_monitor.provide_latest_counterparty_commitment_tx(counterparty_initial_bitcoin_tx.txid, Vec::new(), self.cur_counterparty_commitment_transaction_number, self.counterparty_cur_commitment_point.unwrap(), logger); @@ -3066,7 +3079,7 @@ impl Channel { }) } - pub fn shutdown(&mut self, fee_estimator: &F, msg: &msgs::Shutdown) -> Result<(Option, Option, Vec<(HTLCSource, PaymentHash)>), ChannelError> + pub fn shutdown(&mut self, fee_estimator: &F, their_features: &InitFeatures, msg: &msgs::Shutdown) -> Result<(Option, Option, Vec<(HTLCSource, PaymentHash)>), ChannelError> where F::Target: FeeEstimator { if self.channel_state & (ChannelState::PeerDisconnected as u32) == ChannelState::PeerDisconnected as u32 { @@ -3085,14 +3098,7 @@ impl Channel { } assert_eq!(self.channel_state & ChannelState::ShutdownComplete as u32, 0); - // BOLT 2 says we must only send a scriptpubkey of certain standard forms, which are up to - // 34 bytes in length, so don't let the remote peer feed us some super fee-heavy script. - if self.is_outbound() && msg.scriptpubkey.len() > 34 { - return Err(ChannelError::Close(format!("Got counterparty shutdown_scriptpubkey ({}) of absurd length from remote peer", msg.scriptpubkey.to_bytes().to_hex()))); - } - - //Check counterparty_shutdown_scriptpubkey form as BOLT says we must - if !msg.scriptpubkey.is_p2pkh() && !msg.scriptpubkey.is_p2sh() && !msg.scriptpubkey.is_v0_p2wpkh() && !msg.scriptpubkey.is_v0_p2wsh() { + if is_unsupported_shutdown_script(&their_features, &msg.scriptpubkey) { return Err(ChannelError::Close(format!("Got a nonstandard scriptpubkey ({}) from remote peer", msg.scriptpubkey.to_bytes().to_hex()))); } @@ -3327,7 +3333,7 @@ impl Channel { // Upper bound by capacity. We make it a bit less than full capacity to prevent attempts // to use full capacity. This is an effort to reduce routing failures, because in many cases // channel might have been used to route very small values (either by honest users or as DoS). - self.channel_value_satoshis * 9 / 10, + self.channel_value_satoshis * 1000 * 9 / 10, Channel::::get_holder_max_htlc_value_in_flight_msat(self.channel_value_satoshis) ); @@ -3346,6 +3352,10 @@ impl Channel { self.config.fee_proportional_millionths } + pub fn get_cltv_expiry_delta(&self) -> u16 { + cmp::max(self.config.cltv_expiry_delta, MIN_CLTV_EXPIRY_DELTA) + } + #[cfg(test)] pub fn get_feerate(&self) -> u32 { self.feerate_per_kw @@ -3492,39 +3502,8 @@ impl Channel { self.network_sync == UpdateStatus::DisabledMarked } - /// When we receive a new block, we (a) check whether the block contains the funding - /// transaction (which would start us counting blocks until we send the funding_signed), and - /// (b) check the height of the block against outbound holding cell HTLCs in case we need to - /// give up on them prematurely and time them out. Everything else (e.g. commitment - /// transaction broadcasts, channel closure detection, HTLC transaction broadcasting, etc) is - /// handled by the ChannelMonitor. - /// - /// If we return Err, the channel may have been closed, at which point the standard - /// requirements apply - no calls may be made except those explicitly stated to be allowed - /// post-shutdown. - /// Only returns an ErrorAction of DisconnectPeer, if Err. - /// - /// May return some HTLCs (and their payment_hash) which have timed out and should be failed - /// back. - pub fn block_connected(&mut self, header: &BlockHeader, txdata: &TransactionData, height: u32) -> Result<(Option, Vec<(HTLCSource, PaymentHash)>), msgs::ErrorMessage> { - let mut timed_out_htlcs = Vec::new(); - self.holding_cell_htlc_updates.retain(|htlc_update| { - match htlc_update { - &HTLCUpdateAwaitingACK::AddHTLC { ref payment_hash, ref source, ref cltv_expiry, .. } => { - if *cltv_expiry <= height + HTLC_FAIL_BACK_BUFFER { - timed_out_htlcs.push((source.clone(), payment_hash.clone())); - false - } else { true } - }, - _ => true - } - }); + pub fn transactions_confirmed(&mut self, block_hash: &BlockHash, height: u32, txdata: &TransactionData) -> Result<(), msgs::ErrorMessage> { let non_shutdown_state = self.channel_state & (!MULTI_STATE_FLAGS); - if header.block_hash() != self.last_block_connected { - if self.funding_tx_confirmations > 0 { - self.funding_tx_confirmations += 1; - } - } if non_shutdown_state & !(ChannelState::TheirFundingLocked as u32) == ChannelState::FundingSent as u32 { for &(index_in_block, tx) in txdata.iter() { let funding_txo = self.get_funding_txo().unwrap(); @@ -3558,78 +3537,129 @@ impl Channel { } } } - if height > 0xff_ff_ff || (index_in_block) > 0xff_ff_ff { - panic!("Block was bogus - either height 16 million or had > 16 million transactions"); + self.funding_tx_confirmation_height = height as u64; + self.funding_tx_confirmed_in = Some(*block_hash); + self.short_channel_id = match scid_from_parts(height as u64, index_in_block as u64, txo_idx as u64) { + Ok(scid) => Some(scid), + Err(_) => panic!("Block was bogus - either height was > 16 million, had > 16 million transactions, or had > 65k outputs"), } - assert!(txo_idx <= 0xffff); // txo_idx is a (u16 as usize), so this is just listed here for completeness - self.funding_tx_confirmations = 1; - self.short_channel_id = Some(((height as u64) << (5*8)) | - ((index_in_block as u64) << (2*8)) | - ((txo_idx as u64) << (0*8))); } } } } - if header.block_hash() != self.last_block_connected { - self.last_block_connected = header.block_hash(); - self.update_time_counter = cmp::max(self.update_time_counter, header.time); - if self.funding_tx_confirmations > 0 { - if self.funding_tx_confirmations == self.minimum_depth as u64 { - 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 & MULTI_STATE_FLAGS); - self.update_time_counter += 1; - true - } else if non_shutdown_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. + Ok(()) + } + + /// When a new block is connected, we check the height of the block against outbound holding + /// cell HTLCs in case we need to give up on them prematurely and time them out. Everything + /// else (e.g. commitment transaction broadcasts, HTLC transaction broadcasting, etc) is + /// handled by the ChannelMonitor. + /// + /// If we return Err, the channel may have been closed, at which point the standard + /// requirements apply - no calls may be made except those explicitly stated to be allowed + /// post-shutdown. + /// + /// May return some HTLCs (and their payment_hash) which have timed out and should be failed + /// back. + pub fn update_best_block(&mut self, height: u32, highest_header_time: u32) -> Result<(Option, Vec<(HTLCSource, PaymentHash)>), msgs::ErrorMessage> { + let mut timed_out_htlcs = Vec::new(); + let unforwarded_htlc_cltv_limit = height + HTLC_FAIL_BACK_BUFFER; + self.holding_cell_htlc_updates.retain(|htlc_update| { + match htlc_update { + &HTLCUpdateAwaitingACK::AddHTLC { ref payment_hash, ref source, ref cltv_expiry, .. } => { + if *cltv_expiry <= unforwarded_htlc_cltv_limit { + timed_out_htlcs.push((source.clone(), payment_hash.clone())); false - } else if self.channel_state < ChannelState::ChannelFunded as u32 { - panic!("Started confirming a channel in a state pre-FundingSent?: {}", self.channel_state); + } else { true } + }, + _ => true + } + }); + + self.update_time_counter = cmp::max(self.update_time_counter, highest_header_time); + if self.funding_tx_confirmation_height > 0 { + let funding_tx_confirmations = height as i64 - self.funding_tx_confirmation_height as i64 + 1; + if funding_tx_confirmations <= 0 { + self.funding_tx_confirmation_height = 0; + } + + let non_shutdown_state = self.channel_state & (!MULTI_STATE_FLAGS); + if (non_shutdown_state >= ChannelState::ChannelFunded as u32 || + (non_shutdown_state & ChannelState::OurFundingLocked as u32) == ChannelState::OurFundingLocked as u32) && + funding_tx_confirmations < self.minimum_depth as i64 / 2 { + return Err(msgs::ErrorMessage { + channel_id: self.channel_id(), + data: format!("Funding transaction was un-confirmed. Locked at {} confs, now have {} confs.", self.minimum_depth, funding_tx_confirmations), + }); + } + + if funding_tx_confirmations == self.minimum_depth as i64 { + 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 & MULTI_STATE_FLAGS); + self.update_time_counter += 1; + true + } else if non_shutdown_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.channel_state); + } else { + // We got a reorg but not enough to trigger a force close, just update + // funding_tx_confirmed_in and return. + false + }; + + //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. + if need_commitment_update { + if self.channel_state & (ChannelState::MonitorUpdateFailed as u32) == 0 { + let next_per_commitment_point = self.holder_signer.get_per_commitment_point(self.cur_holder_commitment_transaction_number, &self.secp_ctx); + return Ok((Some(msgs::FundingLocked { + channel_id: self.channel_id, + next_per_commitment_point, + }), timed_out_htlcs)); } 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(self.last_block_connected); - - //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. - if need_commitment_update { - if self.channel_state & (ChannelState::MonitorUpdateFailed as u32) == 0 { - let next_per_commitment_point = self.holder_signer.get_per_commitment_point(self.cur_holder_commitment_transaction_number, &self.secp_ctx); - return Ok((Some(msgs::FundingLocked { - channel_id: self.channel_id, - next_per_commitment_point, - }), timed_out_htlcs)); - } else { - self.monitor_pending_funding_locked = true; - return Ok((None, timed_out_htlcs)); - } + self.monitor_pending_funding_locked = true; + return Ok((None, timed_out_htlcs)); } } } } + Ok((None, timed_out_htlcs)) } + /// When we receive a new block, we (a) check whether the block contains the funding + /// transaction (which would start us counting blocks until we send the funding_signed), and + /// (b) check the height of the block against outbound holding cell HTLCs in case we need to + /// give up on them prematurely and time them out. Everything else (e.g. commitment + /// transaction broadcasts, channel closure detection, HTLC transaction broadcasting, etc) is + /// handled by the ChannelMonitor. + /// + /// If we return Err, the channel may have been closed, at which point the standard + /// requirements apply - no calls may be made except those explicitly stated to be allowed + /// post-shutdown. + /// Only returns an ErrorAction of DisconnectPeer, if Err. + /// + /// May return some HTLCs (and their payment_hash) which have timed out and should be failed + /// back. + pub fn block_connected(&mut self, header: &BlockHeader, txdata: &TransactionData, height: u32) -> Result<(Option, Vec<(HTLCSource, PaymentHash)>), msgs::ErrorMessage> { + self.transactions_confirmed(&header.block_hash(), height, txdata)?; + self.update_best_block(height, header.time) + } + /// Called by channelmanager based on chain blocks being disconnected. /// Returns true if we need to close the channel now due to funding transaction /// unconfirmation/reorg. - pub fn block_disconnected(&mut self, header: &BlockHeader) -> bool { - if self.funding_tx_confirmations > 0 { - self.funding_tx_confirmations -= 1; - if self.funding_tx_confirmations == UNCONF_THRESHOLD as u64 { - return true; - } - } - self.last_block_connected = header.block_hash(); - if Some(self.last_block_connected) == self.funding_tx_confirmed_in { - self.funding_tx_confirmations = self.minimum_depth as u64 - 1; + pub fn block_disconnected(&mut self, header: &BlockHeader, new_height: u32) -> bool { + if self.update_best_block(new_height, header.time).is_err() { + return true; } false } @@ -4089,7 +4119,8 @@ impl Channel { signature = res.0; htlc_signatures = res.1; - log_trace!(logger, "Signed remote commitment tx {} with redeemscript {} -> {}", + log_trace!(logger, "Signed remote commitment tx {} (txid {}) with redeemscript {} -> {}", + encode::serialize_hex(&counterparty_commitment_tx.0.trust().built_transaction().transaction), &counterparty_commitment_txid, encode::serialize_hex(&self.get_funding_redeemscript()), log_bytes!(signature.serialize_compact()[..])); @@ -4124,6 +4155,25 @@ impl Channel { } } + /// Get forwarding information for the counterparty. + pub fn counterparty_forwarding_info(&self) -> Option { + self.counterparty_forwarding_info.clone() + } + + pub fn channel_update(&mut self, msg: &msgs::ChannelUpdate) -> Result<(), ChannelError> { + let usable_channel_value_msat = (self.channel_value_satoshis - self.counterparty_selected_channel_reserve_satoshis) * 1000; + if msg.contents.htlc_minimum_msat >= usable_channel_value_msat { + return Err(ChannelError::Close("Minimum htlc value is greater than channel value".to_string())); + } + self.counterparty_forwarding_info = Some(CounterpartyForwardingInfo { + fee_base_msat: msg.contents.fee_base_msat, + fee_proportional_millionths: msg.contents.fee_proportional_millionths, + cltv_expiry_delta: msg.contents.cltv_expiry_delta + }); + + Ok(()) + } + /// Begins the shutdown process, getting a message for the remote peer and returning all /// holding cell HTLCs for payment failure. pub fn get_shutdown(&mut self) -> Result<(msgs::Shutdown, Vec<(HTLCSource, PaymentHash)>), APIError> { @@ -4180,7 +4230,11 @@ impl Channel { /// those explicitly stated to be allowed after shutdown completes, eg some simple getters). /// Also returns the list of payment_hashes for channels which we can safely fail backwards /// immediately (others we will have to allow to time out). - pub fn force_shutdown(&mut self, should_broadcast: bool) -> (Option, ChannelMonitorUpdate, Vec<(HTLCSource, PaymentHash)>) { + pub fn force_shutdown(&mut self, should_broadcast: bool) -> (Option<(OutPoint, ChannelMonitorUpdate)>, Vec<(HTLCSource, PaymentHash)>) { + // Note that we MUST only generate a monitor update that indicates force-closure - we're + // called during initialization prior to the chain_monitor in the encompassing ChannelManager + // being fully configured in some cases. Thus, its likely any monitor events we generate will + // be delayed in being processed! See the docs for `ChannelManagerReadArgs` for more. assert!(self.channel_state != ChannelState::ShutdownComplete as u32); // We go ahead and "free" any holding cell HTLCs or HTLCs we haven't yet committed to and @@ -4194,7 +4248,7 @@ impl Channel { _ => {} } } - let funding_txo = if let Some(funding_txo) = self.get_funding_txo() { + let monitor_update = if let Some(funding_txo) = self.get_funding_txo() { // If we haven't yet exchanged funding signatures (ie channel_state < FundingSent), // returning a channel monitor update here would imply a channel monitor update before // we even registered the channel monitor to begin with, which is invalid. @@ -4203,18 +4257,36 @@ impl Channel { // monitor update to the user, even if we return one). // See test_duplicate_chan_id and test_pre_lockin_no_chan_closed_update for more. if self.channel_state & (ChannelState::FundingSent as u32 | ChannelState::ChannelFunded as u32 | ChannelState::ShutdownComplete as u32) != 0 { - Some(funding_txo.clone()) + self.latest_monitor_update_id += 1; + Some((funding_txo, ChannelMonitorUpdate { + update_id: self.latest_monitor_update_id, + updates: vec![ChannelMonitorUpdateStep::ChannelForceClosed { should_broadcast }], + })) } else { None } } else { None }; self.channel_state = ChannelState::ShutdownComplete as u32; self.update_time_counter += 1; - self.latest_monitor_update_id += 1; - (funding_txo, ChannelMonitorUpdate { - update_id: self.latest_monitor_update_id, - updates: vec![ChannelMonitorUpdateStep::ChannelForceClosed { should_broadcast }], - }, dropped_outbound_htlcs) + (monitor_update, dropped_outbound_htlcs) + } +} + +fn is_unsupported_shutdown_script(their_features: &InitFeatures, script: &Script) -> bool { + // We restrain shutdown scripts to standards forms to avoid transactions not propagating on the p2p tx-relay network + + // BOLT 2 says we must only send a scriptpubkey of certain standard forms, + // which for a a BIP-141-compliant witness program is at max 42 bytes in length. + // So don't let the remote peer feed us some super fee-heavy script. + let is_script_too_long = script.len() > 42; + if is_script_too_long { + return true; + } + + if their_features.supports_shutdown_anysegwit() && script.is_witness_program() && script.as_bytes()[0] != OP_PUSHBYTES_0.into_u8() { + return false; } + + return !script.is_p2pkh() && !script.is_p2sh() && !script.is_v0_p2wpkh() && !script.is_v0_p2wsh() } const SERIALIZATION_VERSION: u8 = 1; @@ -4413,11 +4485,9 @@ impl Writeable for Channel { } self.funding_tx_confirmed_in.write(writer)?; + self.funding_tx_confirmation_height.write(writer)?; self.short_channel_id.write(writer)?; - self.last_block_connected.write(writer)?; - self.funding_tx_confirmations.write(writer)?; - self.counterparty_dust_limit_satoshis.write(writer)?; self.holder_dust_limit_satoshis.write(writer)?; self.counterparty_max_htlc_value_in_flight_msat.write(writer)?; @@ -4427,6 +4497,16 @@ impl Writeable for Channel { self.counterparty_max_accepted_htlcs.write(writer)?; self.minimum_depth.write(writer)?; + match &self.counterparty_forwarding_info { + Some(info) => { + 1u8.write(writer)?; + info.fee_base_msat.write(writer)?; + info.fee_proportional_millionths.write(writer)?; + info.cltv_expiry_delta.write(writer)?; + }, + None => 0u8.write(writer)? + } + self.channel_transaction_parameters.write(writer)?; self.counterparty_cur_commitment_point.write(writer)?; @@ -4575,11 +4655,9 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<&'a K> for Channel }; let funding_tx_confirmed_in = Readable::read(reader)?; + let funding_tx_confirmation_height = Readable::read(reader)?; let short_channel_id = Readable::read(reader)?; - let last_block_connected = Readable::read(reader)?; - let funding_tx_confirmations = Readable::read(reader)?; - let counterparty_dust_limit_satoshis = Readable::read(reader)?; let holder_dust_limit_satoshis = Readable::read(reader)?; let counterparty_max_htlc_value_in_flight_msat = Readable::read(reader)?; @@ -4589,6 +4667,16 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<&'a K> for Channel let counterparty_max_accepted_htlcs = Readable::read(reader)?; let minimum_depth = Readable::read(reader)?; + let counterparty_forwarding_info = match ::read(reader)? { + 0 => None, + 1 => Some(CounterpartyForwardingInfo { + fee_base_msat: Readable::read(reader)?, + fee_proportional_millionths: Readable::read(reader)?, + cltv_expiry_delta: Readable::read(reader)?, + }), + _ => return Err(DecodeError::InvalidValue), + }; + let channel_parameters = Readable::read(reader)?; let counterparty_cur_commitment_point = Readable::read(reader)?; @@ -4598,13 +4686,16 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<&'a K> for Channel let counterparty_shutdown_scriptpubkey = Readable::read(reader)?; let commitment_secrets = Readable::read(reader)?; + let mut secp_ctx = Secp256k1::new(); + secp_ctx.seeded_randomize(&keys_source.get_secure_random_bytes()); + Ok(Channel { user_id, config, channel_id, channel_state, - secp_ctx: Secp256k1::new(), + secp_ctx, channel_value_satoshis, latest_monitor_update_id, @@ -4644,9 +4735,8 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<&'a K> for Channel last_sent_closing_fee, funding_tx_confirmed_in, + funding_tx_confirmation_height, short_channel_id, - last_block_connected, - funding_tx_confirmations, counterparty_dust_limit_satoshis, holder_dust_limit_satoshis, @@ -4657,6 +4747,8 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<&'a K> for Channel counterparty_max_accepted_htlcs, minimum_depth, + counterparty_forwarding_info, + channel_transaction_parameters: channel_parameters, counterparty_cur_commitment_point, @@ -4692,7 +4784,7 @@ mod tests { use ln::channel::{Channel,Sign,InboundHTLCOutput,OutboundHTLCOutput,InboundHTLCState,OutboundHTLCState,HTLCOutputInCommitment,HTLCCandidate,HTLCInitiator,TxCreationKeys}; use ln::channel::MAX_FUNDING_SATOSHIS; use ln::features::InitFeatures; - use ln::msgs::{OptionalField, DataLossProtect, DecodeError}; + use ln::msgs::{ChannelUpdate, DataLossProtect, DecodeError, OptionalField, UnsignedChannelUpdate}; use ln::chan_utils; use ln::chan_utils::{ChannelPublicKeys, HolderCommitmentTransaction, CounterpartyChannelTransactionParameters, HTLC_SUCCESS_TX_WEIGHT, HTLC_TIMEOUT_TX_WEIGHT}; use chain::chaininterface::{FeeEstimator,ConfirmationTarget}; @@ -4703,6 +4795,7 @@ mod tests { use util::test_utils; use util::logger::Logger; use bitcoin::secp256k1::{Secp256k1, Message, Signature, All}; + use bitcoin::secp256k1::ffi::Signature as FFISignature; use bitcoin::secp256k1::key::{SecretKey,PublicKey}; use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::hashes::Hash; @@ -4900,6 +4993,8 @@ mod tests { let secp_ctx = Secp256k1::new(); let seed = [42; 32]; let network = Network::Testnet; + let chain_hash = genesis_block(network).header.block_hash(); + let last_block_hash = chain_hash; let keys_provider = test_utils::TestKeysInterface::new(&seed, network); // Go through the flow of opening a channel between two nodes. @@ -4910,7 +5005,7 @@ mod tests { let mut node_a_chan = Channel::::new_outbound(&&feeest, &&keys_provider, node_b_node_id, 10000000, 100000, 42, &config).unwrap(); // Create Node B's channel by receiving Node A's open_channel message - let open_channel_msg = node_a_chan.get_open_channel(genesis_block(network).header.block_hash()); + let open_channel_msg = node_a_chan.get_open_channel(chain_hash); let node_b_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[7; 32]).unwrap()); let mut node_b_chan = Channel::::new_from_req(&&feeest, &&keys_provider, node_b_node_id, InitFeatures::known(), &open_channel_msg, 7, &config).unwrap(); @@ -4925,10 +5020,10 @@ mod tests { }]}; let funding_outpoint = OutPoint{ txid: tx.txid(), index: 0 }; let funding_created_msg = node_a_chan.get_outbound_funding_created(funding_outpoint, &&logger).unwrap(); - let (funding_signed_msg, _) = node_b_chan.funding_created(&funding_created_msg, &&logger).unwrap(); + let (funding_signed_msg, _) = node_b_chan.funding_created(&funding_created_msg, last_block_hash, &&logger).unwrap(); // Node B --> Node A: funding signed - let _ = node_a_chan.funding_signed(&funding_signed_msg, &&logger); + let _ = node_a_chan.funding_signed(&funding_signed_msg, last_block_hash, &&logger); // Now disconnect the two nodes and check that the commitment point in // Node B's channel_reestablish message is sane. @@ -4957,6 +5052,54 @@ mod tests { } } + #[test] + fn channel_update() { + let feeest = TestFeeEstimator{fee_est: 15000}; + let secp_ctx = Secp256k1::new(); + let seed = [42; 32]; + let network = Network::Testnet; + let chain_hash = genesis_block(network).header.block_hash(); + let keys_provider = test_utils::TestKeysInterface::new(&seed, network); + + // Create a channel. + let node_b_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap()); + let config = UserConfig::default(); + let mut node_a_chan = Channel::::new_outbound(&&feeest, &&keys_provider, node_b_node_id, 10000000, 100000, 42, &config).unwrap(); + assert!(node_a_chan.counterparty_forwarding_info.is_none()); + assert_eq!(node_a_chan.holder_htlc_minimum_msat, 1); // the default + assert!(node_a_chan.counterparty_forwarding_info().is_none()); + + // Make sure that receiving a channel update will update the Channel as expected. + let update = ChannelUpdate { + contents: UnsignedChannelUpdate { + chain_hash, + short_channel_id: 0, + timestamp: 0, + flags: 0, + cltv_expiry_delta: 100, + htlc_minimum_msat: 5, + htlc_maximum_msat: OptionalField::Absent, + fee_base_msat: 110, + fee_proportional_millionths: 11, + excess_data: Vec::new(), + }, + signature: Signature::from(unsafe { FFISignature::new() }) + }; + node_a_chan.channel_update(&update).unwrap(); + + // The counterparty can send an update with a higher minimum HTLC, but that shouldn't + // change our official htlc_minimum_msat. + assert_eq!(node_a_chan.holder_htlc_minimum_msat, 1); + match node_a_chan.counterparty_forwarding_info() { + Some(info) => { + assert_eq!(info.cltv_expiry_delta, 100); + assert_eq!(info.fee_base_msat, 110); + assert_eq!(info.fee_proportional_millionths, 11); + }, + None => panic!("expected counterparty forwarding info to be Some") + } + } + #[test] fn outbound_commitment_test() { // Test vectors from BOLT 3 Appendix C: