X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;ds=sidebyside;f=lightning%2Fsrc%2Fln%2Fchannelmanager.rs;h=d2ea7dfea798baea181dec19838cf2b55ccaad22;hb=eee1c30ea6592463d41eefad8306223ec5548014;hp=efb2fe9c37bd9a8ec2c9a36d9a521072a6f8c6f3;hpb=021959f822222cd3782a212f0b7ad3819ee56349;p=rust-lightning diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index efb2fe9c..d2ea7dfe 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -19,6 +19,7 @@ //! use bitcoin::blockdata::block::{Block, BlockHeader}; +use bitcoin::blockdata::transaction::Transaction; use bitcoin::blockdata::constants::genesis_block; use bitcoin::network::constants::Network; @@ -337,7 +338,7 @@ pub(super) struct ChannelHolder { } /// Events which we process internally but cannot be procsesed immediately at the generation site -/// for some reason. They are handled in timer_chan_freshness_every_min, so may be processed with +/// for some reason. They are handled in timer_tick_occurred, so may be processed with /// quite some time lag. enum BackgroundEvent { /// Handle a ChannelMonitorUpdate that closes a channel, broadcasting its current latest holder @@ -402,7 +403,7 @@ pub type SimpleRefChannelManager<'a, 'b, 'c, 'd, 'e, M, T, F, L> = ChannelManage /// ChannelUpdate messages informing peers that the channel is temporarily disabled. To avoid /// spam due to quick disconnection/reconnection, updates are not sent until the channel has been /// offline for a full minute. In order to track this, you must call -/// timer_chan_freshness_every_min roughly once per minute, though it doesn't have to be perfect. +/// timer_tick_occurred roughly once per minute, though it doesn't have to be perfect. /// /// Rather than using a plain ChannelManager, it is preferable to use either a SimpleArcChannelManager /// a SimpleRefChannelManager, for conciseness. See their documentation for more details, but @@ -852,10 +853,11 @@ impl ChannelMana /// Creates a new outbound channel to the given remote node and with the given value. /// - /// user_id will be provided back as user_channel_id in FundingGenerationReady and - /// FundingBroadcastSafe events to allow tracking of which events correspond with which - /// create_channel call. Note that user_channel_id defaults to 0 for inbound channels, so you - /// may wish to avoid using 0 for user_id here. + /// user_id will be provided back as user_channel_id in FundingGenerationReady events to allow + /// tracking of which events correspond with which create_channel call. Note that the + /// user_channel_id defaults to 0 for inbound channels, so you may wish to avoid using 0 for + /// user_id here. user_id has no meaning inside of LDK, it is simply copied to events and + /// otherwise ignored. /// /// If successful, will generate a SendOpenChannel message event, so you should probably poll /// PeerManager::process_events afterwards. @@ -1538,32 +1540,75 @@ impl ChannelMana /// Call this upon creation of a funding transaction for the given channel. /// - /// Note that ALL inputs in the transaction pointed to by funding_txo MUST spend SegWit outputs - /// or your counterparty can steal your funds! + /// Returns an [`APIError::APIMisuseError`] if the funding_transaction spent non-SegWit outputs + /// or if no output was found which matches the parameters in [`Event::FundingGenerationReady`]. /// /// Panics if a funding transaction has already been provided for this channel. /// - /// May panic if the funding_txo is duplicative with some other channel (note that this should - /// be trivially prevented by using unique funding transaction keys per-channel). - pub fn funding_transaction_generated(&self, temporary_channel_id: &[u8; 32], funding_txo: OutPoint) { + /// May panic if the output found in the funding transaction is duplicative with some other + /// channel (note that this should be trivially prevented by using unique funding transaction + /// keys per-channel). + /// + /// Do NOT broadcast the funding transaction yourself. When we have safely received our + /// counterparty's signature the funding transaction will automatically be broadcast via the + /// [`BroadcasterInterface`] provided when this `ChannelManager` was constructed. + /// + /// Note that this includes RBF or similar transaction replacement strategies - lightning does + /// not currently support replacing a funding transaction on an existing channel. Instead, + /// create a new channel with a conflicting funding transaction. + pub fn funding_transaction_generated(&self, temporary_channel_id: &[u8; 32], funding_transaction: Transaction) -> Result<(), APIError> { let _persistence_guard = PersistenceNotifierGuard::new(&self.total_consistency_lock, &self.persistence_notifier); + for inp in funding_transaction.input.iter() { + if inp.witness.is_empty() { + return Err(APIError::APIMisuseError { + err: "Funding transaction must be fully signed and spend Segwit outputs".to_owned() + }); + } + } + let (chan, msg) = { let (res, chan) = match self.channel_state.lock().unwrap().by_id.remove(temporary_channel_id) { Some(mut chan) => { - (chan.get_outbound_funding_created(funding_txo, &self.logger) + let mut output_index = None; + let expected_spk = chan.get_funding_redeemscript().to_v0_p2wsh(); + for (idx, outp) in funding_transaction.output.iter().enumerate() { + if outp.script_pubkey == expected_spk && outp.value == chan.get_value_satoshis() { + if output_index.is_some() { + return Err(APIError::APIMisuseError { + err: "Multiple outputs matched the expected script and value".to_owned() + }); + } + if idx > u16::max_value() as usize { + return Err(APIError::APIMisuseError { + err: "Transaction had more than 2^16 outputs, which is not supported".to_owned() + }); + } + output_index = Some(idx as u16); + } + } + if output_index.is_none() { + return Err(APIError::APIMisuseError { + err: "No output matched the script_pubkey and value in the FundingGenerationReady event".to_owned() + }); + } + let funding_txo = OutPoint { txid: funding_transaction.txid(), index: output_index.unwrap() }; + + (chan.get_outbound_funding_created(funding_transaction, funding_txo, &self.logger) .map_err(|e| if let ChannelError::Close(msg) = e { MsgHandleErrInternal::from_finish_shutdown(msg, chan.channel_id(), chan.force_shutdown(true), None) } else { unreachable!(); }) , chan) }, - None => return + None => { return Err(APIError::ChannelUnavailable { err: "No such channel".to_owned() }) }, }; match handle_error!(self, res, chan.get_counterparty_node_id()) { Ok(funding_msg) => { (chan, funding_msg) }, - Err(_) => { return; } + Err(_) => { return Err(APIError::ChannelUnavailable { + err: "Error deriving keys or signing initial commitment transactions - either our RNG or our counterparty's RNG is broken or the Signer refused to sign".to_owned() + }) }, } }; @@ -1580,6 +1625,7 @@ impl ChannelMana e.insert(chan); } } + Ok(()) } fn get_announcement_sigs(&self, chan: &Channel) -> Option { @@ -1913,10 +1959,10 @@ impl ChannelMana events.append(&mut new_events); } - /// Free the background events, generally called from timer_chan_freshness_every_min. + /// Free the background events, generally called from timer_tick_occurred. /// /// Exposed for testing to allow us to process events quickly without generating accidental - /// BroadcastChannelUpdate events in timer_chan_freshness_every_min. + /// BroadcastChannelUpdate events in timer_tick_occurred. /// /// Expects the caller to have a total_consistency_lock read lock. fn process_background_events(&self) { @@ -1945,7 +1991,7 @@ impl ChannelMana /// This method handles all the details, and must be called roughly once per minute. /// /// Note that in some rare cases this may generate a `chain::Watch::update_channel` call. - pub fn timer_chan_freshness_every_min(&self) { + pub fn timer_tick_occurred(&self) { let _persistence_guard = PersistenceNotifierGuard::new(&self.total_consistency_lock, &self.persistence_notifier); self.process_background_events(); @@ -2372,7 +2418,7 @@ impl ChannelMana return; } - let (raa, commitment_update, order, pending_forwards, mut pending_failures, needs_broadcast_safe, funding_locked) = channel.monitor_updating_restored(&self.logger); + let (raa, commitment_update, order, pending_forwards, mut pending_failures, funding_broadcastable, funding_locked) = channel.monitor_updating_restored(&self.logger); if !pending_forwards.is_empty() { htlc_forwards.push((channel.get_short_channel_id().expect("We can't have pending forwards before funding confirmation"), funding_txo.clone(), pending_forwards)); } @@ -2404,11 +2450,8 @@ impl ChannelMana handle_cs!(); }, } - if needs_broadcast_safe { - pending_events.push(events::Event::FundingBroadcastSafe { - funding_txo: channel.get_funding_txo().unwrap(), - user_channel_id: channel.get_user_id(), - }); + if let Some(tx) = funding_broadcastable { + self.tx_broadcaster.broadcast_transaction(&tx); } if let Some(msg) = funding_locked { pending_msg_events.push(events::MessageSendEvent::SendFundingLocked { @@ -2542,7 +2585,7 @@ impl ChannelMana } fn internal_funding_signed(&self, counterparty_node_id: &PublicKey, msg: &msgs::FundingSigned) -> Result<(), MsgHandleErrInternal> { - let (funding_txo, user_id) = { + let funding_tx = { let last_block_hash = *self.last_block_hash.read().unwrap(); let mut channel_lock = self.channel_state.lock().unwrap(); let channel_state = &mut *channel_lock; @@ -2551,23 +2594,19 @@ impl ChannelMana if chan.get().get_counterparty_node_id() != *counterparty_node_id { return Err(MsgHandleErrInternal::send_err_msg_no_close("Got a message for a channel from the wrong node!".to_owned(), msg.channel_id)); } - let monitor = match chan.get_mut().funding_signed(&msg, last_block_hash, &self.logger) { + let (monitor, funding_tx) = match chan.get_mut().funding_signed(&msg, last_block_hash, &self.logger) { Ok(update) => update, Err(e) => try_chan_entry!(self, Err(e), channel_state, chan), }; if let Err(e) = self.chain_monitor.watch_channel(chan.get().get_funding_txo().unwrap(), monitor) { return_monitor_err!(self, e, channel_state, chan, RAACommitmentOrder::RevokeAndACKFirst, false, false); } - (chan.get().get_funding_txo().unwrap(), chan.get().get_user_id()) + funding_tx }, hash_map::Entry::Vacant(_) => return Err(MsgHandleErrInternal::send_err_msg_no_close("Failed to find corresponding channel".to_owned(), msg.channel_id)) } }; - let mut pending_events = self.pending_events.lock().unwrap(); - pending_events.push(events::Event::FundingBroadcastSafe { - funding_txo, - user_channel_id: user_id, - }); + self.tx_broadcaster.broadcast_transaction(&funding_tx); Ok(()) } @@ -3235,7 +3274,7 @@ impl ChannelMana // We cannot broadcast our latest local state via monitor update (as // Channel::force_shutdown tries to make us do) as we may still be in initialization, // so we track the update internally and handle it when the user next calls - // timer_chan_freshness_every_min, guaranteeing we're running normally. + // timer_tick_occurred, guaranteeing we're running normally. if let Some((funding_txo, update)) = failure.0.take() { assert_eq!(update.updates.len(), 1); if let ChannelMonitorUpdateStep::ChannelForceClosed { should_broadcast } = update.updates[0] { @@ -4441,7 +4480,6 @@ pub mod bench { use chain::chainmonitor::ChainMonitor; use chain::channelmonitor::Persist; use chain::keysinterface::{KeysManager, InMemorySigner}; - use chain::transaction::OutPoint; use ln::channelmanager::{ChainParameters, ChannelManager, PaymentHash, PaymentPreimage}; use ln::features::InitFeatures; use ln::functional_test_utils::*; @@ -4519,14 +4557,13 @@ pub mod bench { tx = Transaction { version: 2, lock_time: 0, input: Vec::new(), output: vec![TxOut { value: 8_000_000, script_pubkey: output_script, }]}; - let funding_outpoint = OutPoint { txid: tx.txid(), index: 0 }; - node_a.funding_transaction_generated(&temporary_channel_id, funding_outpoint); + node_a.funding_transaction_generated(&temporary_channel_id, tx.clone()).unwrap(); } else { panic!(); } node_b.handle_funding_created(&node_a.get_our_node_id(), &get_event_msg!(node_a_holder, MessageSendEvent::SendFundingCreated, node_b.get_our_node_id())); node_a.handle_funding_signed(&node_b.get_our_node_id(), &get_event_msg!(node_b_holder, MessageSendEvent::SendFundingSigned, node_a.get_our_node_id())); - get_event!(node_a_holder, Event::FundingBroadcastSafe); + assert_eq!(&tx_broadcaster.txn_broadcasted.lock().unwrap()[..], &[tx.clone()]); let block = Block { header: BlockHeader { version: 0x20000000, prev_blockhash: genesis_hash, merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 },