X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fchain%2Fchannelmonitor.rs;h=a664c7c794efe019dd82e909c132c1fd839b9ccf;hb=refs%2Fheads%2F2023-02-no-recursive-read-locks;hp=5c1e102aefc8e2cc44350acc052f99ffdab5e224;hpb=8170c84d9d393a4884599e80e9a9ea95016fce8e;p=rust-lightning diff --git a/lightning/src/chain/channelmonitor.rs b/lightning/src/chain/channelmonitor.rs index 5c1e102a..a664c7c7 100644 --- a/lightning/src/chain/channelmonitor.rs +++ b/lightning/src/chain/channelmonitor.rs @@ -42,14 +42,14 @@ use crate::chain; use crate::chain::{BestBlock, WatchedOutput}; use crate::chain::chaininterface::{BroadcasterInterface, FeeEstimator, LowerBoundedFeeEstimator}; use crate::chain::transaction::{OutPoint, TransactionData}; -use crate::chain::keysinterface::{SpendableOutputDescriptor, StaticPaymentOutputDescriptor, DelayedPaymentOutputDescriptor, Sign, KeysInterface}; +use crate::chain::keysinterface::{SpendableOutputDescriptor, StaticPaymentOutputDescriptor, DelayedPaymentOutputDescriptor, WriteableEcdsaChannelSigner, SignerProvider, EntropySource}; #[cfg(anchors)] use crate::chain::onchaintx::ClaimEvent; use crate::chain::onchaintx::OnchainTxHandler; use crate::chain::package::{CounterpartyOfferedHTLCOutput, CounterpartyReceivedHTLCOutput, HolderFundingOutput, HolderHTLCOutput, PackageSolvingData, PackageTemplate, RevokedOutput, RevokedHTLCOutput}; use crate::chain::Filter; use crate::util::logger::Logger; -use crate::util::ser::{Readable, ReadableArgs, MaybeReadable, Writer, Writeable, U48, OptionDeserWrapper}; +use crate::util::ser::{Readable, ReadableArgs, RequiredWrapper, MaybeReadable, UpgradableRequired, Writer, Writeable, U48}; use crate::util::byte_utils; use crate::util::events::Event; #[cfg(anchors)] @@ -60,7 +60,7 @@ use core::{cmp, mem}; use crate::io::{self, Error}; use core::convert::TryInto; use core::ops::Deref; -use crate::sync::Mutex; +use crate::sync::{Mutex, LockTestExt}; /// An update generated by the underlying channel itself which contains some new information the /// [`ChannelMonitor`] should be made aware of. @@ -314,8 +314,8 @@ impl Readable for CounterpartyCommitmentParameters { } } - let mut counterparty_delayed_payment_base_key = OptionDeserWrapper(None); - let mut counterparty_htlc_base_key = OptionDeserWrapper(None); + let mut counterparty_delayed_payment_base_key = RequiredWrapper(None); + let mut counterparty_htlc_base_key = RequiredWrapper(None); let mut on_counterparty_tx_csv: u16 = 0; read_tlv_fields!(r, { (0, counterparty_delayed_payment_base_key, required), @@ -454,19 +454,15 @@ impl MaybeReadable for OnchainEventEntry { let mut transaction = None; let mut block_hash = None; let mut height = 0; - let mut event = None; + let mut event = UpgradableRequired(None); read_tlv_fields!(reader, { (0, txid, required), (1, transaction, option), (2, height, required), (3, block_hash, option), - (4, event, ignorable), + (4, event, upgradable_required), }); - if let Some(ev) = event { - Ok(Some(Self { txid, transaction, height, block_hash, event: ev })) - } else { - Ok(None) - } + Ok(Some(Self { txid, transaction, height, block_hash, event: _init_tlv_based_struct_field!(event, upgradable_required) })) } } @@ -706,14 +702,15 @@ impl Readable for IrrevocablyResolvedHTLC { /// the "reorg path" (ie disconnecting blocks until you find a common ancestor from both the /// returned block hash and the the current chain and then reconnecting blocks to get to the /// best chain) upon deserializing the object! -pub struct ChannelMonitor { +pub struct ChannelMonitor { #[cfg(test)] pub(crate) inner: Mutex>, #[cfg(not(test))] inner: Mutex>, } -pub(crate) struct ChannelMonitorImpl { +#[derive(PartialEq)] +pub(crate) struct ChannelMonitorImpl { latest_update_id: u64, commitment_transaction_number_obscure_factor: u64, @@ -847,72 +844,24 @@ pub(crate) struct ChannelMonitorImpl { /// The node_id of our counterparty counterparty_node_id: Option, - - secp_ctx: Secp256k1, //TODO: dedup this a bit... } /// Transaction outputs to watch for on-chain spends. pub type TransactionOutputs = (Txid, Vec<(u32, TxOut)>); -#[cfg(any(test, fuzzing, feature = "_test_utils"))] -/// Used only in testing and fuzzing to check serialization roundtrips don't change the underlying -/// object -impl PartialEq for ChannelMonitor { +impl PartialEq for ChannelMonitor where Signer: PartialEq { fn eq(&self, other: &Self) -> bool { - let inner = self.inner.lock().unwrap(); - let other = other.inner.lock().unwrap(); - inner.eq(&other) - } -} - -#[cfg(any(test, fuzzing, feature = "_test_utils"))] -/// Used only in testing and fuzzing to check serialization roundtrips don't change the underlying -/// object -impl PartialEq for ChannelMonitorImpl { - fn eq(&self, other: &Self) -> bool { - if self.latest_update_id != other.latest_update_id || - self.commitment_transaction_number_obscure_factor != other.commitment_transaction_number_obscure_factor || - self.destination_script != other.destination_script || - self.broadcasted_holder_revokable_script != other.broadcasted_holder_revokable_script || - self.counterparty_payment_script != other.counterparty_payment_script || - self.channel_keys_id != other.channel_keys_id || - self.holder_revocation_basepoint != other.holder_revocation_basepoint || - self.funding_info != other.funding_info || - self.current_counterparty_commitment_txid != other.current_counterparty_commitment_txid || - self.prev_counterparty_commitment_txid != other.prev_counterparty_commitment_txid || - self.counterparty_commitment_params != other.counterparty_commitment_params || - self.funding_redeemscript != other.funding_redeemscript || - self.channel_value_satoshis != other.channel_value_satoshis || - self.their_cur_per_commitment_points != other.their_cur_per_commitment_points || - self.on_holder_tx_csv != other.on_holder_tx_csv || - self.commitment_secrets != other.commitment_secrets || - self.counterparty_claimable_outpoints != other.counterparty_claimable_outpoints || - self.counterparty_commitment_txn_on_chain != other.counterparty_commitment_txn_on_chain || - self.counterparty_hash_commitment_number != other.counterparty_hash_commitment_number || - self.prev_holder_signed_commitment_tx != other.prev_holder_signed_commitment_tx || - self.current_counterparty_commitment_number != other.current_counterparty_commitment_number || - self.current_holder_commitment_number != other.current_holder_commitment_number || - self.current_holder_commitment_tx != other.current_holder_commitment_tx || - self.payment_preimages != other.payment_preimages || - self.pending_monitor_events != other.pending_monitor_events || - self.pending_events.len() != other.pending_events.len() || // We trust events to round-trip properly - self.onchain_events_awaiting_threshold_conf != other.onchain_events_awaiting_threshold_conf || - self.outputs_to_watch != other.outputs_to_watch || - self.lockdown_from_offchain != other.lockdown_from_offchain || - self.holder_tx_signed != other.holder_tx_signed || - self.funding_spend_seen != other.funding_spend_seen || - self.funding_spend_confirmed != other.funding_spend_confirmed || - self.confirmed_commitment_tx_counterparty_output != other.confirmed_commitment_tx_counterparty_output || - self.htlcs_resolved_on_chain != other.htlcs_resolved_on_chain - { - false - } else { - true - } + // We need some kind of total lockorder. Absent a better idea, we sort by position in + // memory and take locks in that order (assuming that we can't move within memory while a + // lock is held). + let ord = ((self as *const _) as usize) < ((other as *const _) as usize); + let a = if ord { self.inner.unsafe_well_ordered_double_lock_self() } else { other.inner.unsafe_well_ordered_double_lock_self() }; + let b = if ord { other.inner.unsafe_well_ordered_double_lock_self() } else { self.inner.unsafe_well_ordered_double_lock_self() }; + a.eq(&b) } } -impl Writeable for ChannelMonitor { +impl Writeable for ChannelMonitor { fn write(&self, writer: &mut W) -> Result<(), Error> { self.inner.lock().unwrap().write(writer) } @@ -922,7 +871,7 @@ impl Writeable for ChannelMonitor { const SERIALIZATION_VERSION: u8 = 1; const MIN_SERIALIZATION_VERSION: u8 = 1; -impl Writeable for ChannelMonitorImpl { +impl Writeable for ChannelMonitorImpl { fn write(&self, writer: &mut W) -> Result<(), Error> { write_ver_prefix!(writer, SERIALIZATION_VERSION, MIN_SERIALIZATION_VERSION); @@ -1090,7 +1039,7 @@ impl Writeable for ChannelMonitorImpl { } } -impl ChannelMonitor { +impl ChannelMonitor { /// For lockorder enforcement purposes, we need to have a single site which constructs the /// `inner` mutex, otherwise cases where we lock two monitors at the same time (eg in our /// PartialEq implementation) we may decide a lockorder violation has occurred. @@ -1140,7 +1089,7 @@ impl ChannelMonitor { let onchain_tx_handler = OnchainTxHandler::new(destination_script.clone(), keys, - channel_parameters.clone(), initial_holder_commitment_tx, secp_ctx.clone()); + channel_parameters.clone(), initial_holder_commitment_tx, secp_ctx); let mut outputs_to_watch = HashMap::new(); outputs_to_watch.insert(funding_info.0.txid, vec![(funding_info.0.index as u32, funding_info.1.clone())]); @@ -1196,8 +1145,6 @@ impl ChannelMonitor { best_block, counterparty_node_id: Some(counterparty_node_id), - - secp_ctx, }) } @@ -1521,7 +1468,7 @@ impl ChannelMonitor { } } -impl ChannelMonitorImpl { +impl ChannelMonitorImpl { /// Helper for get_claimable_balances which does the work for an individual HTLC, generating up /// to one `Balance` for the HTLC. fn get_htlc_balance(&self, htlc: &HTLCOutputInCommitment, holder_commitment: bool, @@ -1684,7 +1631,7 @@ impl ChannelMonitorImpl { } } -impl ChannelMonitor { +impl ChannelMonitor { /// Gets the balances in this channel which are either claimable by us if we were to /// force-close the channel now or which are claimable on-chain (possibly awaiting /// confirmation). @@ -2082,7 +2029,7 @@ pub fn deliberately_bogus_accepted_htlc_witness() -> Vec> { vec![Vec::new(), Vec::new(), Vec::new(), Vec::new(), deliberately_bogus_accepted_htlc_witness_program().into()].into() } -impl ChannelMonitorImpl { +impl ChannelMonitorImpl { /// Inserts a revocation secret into this channel monitor. Prunes old preimages if neither /// needed by holder commitment transactions HTCLs nor by counterparty ones. Unless we haven't already seen /// counterparty commitment transaction's secret, they are de facto pruned (we can use revocation key). @@ -2325,6 +2272,17 @@ impl ChannelMonitorImpl { log_trace!(logger, "Updating ChannelMonitor: channel force closed, should broadcast: {}", should_broadcast); self.lockdown_from_offchain = true; if *should_broadcast { + // There's no need to broadcast our commitment transaction if we've seen one + // confirmed (even with 1 confirmation) as it'll be rejected as + // duplicate/conflicting. + let detected_funding_spend = self.funding_spend_confirmed.is_some() || + self.onchain_events_awaiting_threshold_conf.iter().find(|event| match event.event { + OnchainEvent::FundingSpendConfirmation { .. } => true, + _ => false, + }).is_some(); + if detected_funding_spend { + continue; + } self.broadcast_latest_holder_commitment_txn(broadcaster, logger); // If the channel supports anchor outputs, we'll need to emit an external // event to be consumed such that a child transaction is broadcast with a @@ -2501,9 +2459,9 @@ impl ChannelMonitorImpl { if commitment_number >= self.get_min_seen_secret() { let secret = self.get_secret(commitment_number).unwrap(); let per_commitment_key = ignore_error!(SecretKey::from_slice(&secret)); - let per_commitment_point = PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_key); - let revocation_pubkey = chan_utils::derive_public_revocation_key(&self.secp_ctx, &per_commitment_point, &self.holder_revocation_basepoint); - let delayed_key = chan_utils::derive_public_key(&self.secp_ctx, &PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_key), &self.counterparty_commitment_params.counterparty_delayed_payment_base_key); + let per_commitment_point = PublicKey::from_secret_key(&self.onchain_tx_handler.secp_ctx, &per_commitment_key); + let revocation_pubkey = chan_utils::derive_public_revocation_key(&self.onchain_tx_handler.secp_ctx, &per_commitment_point, &self.holder_revocation_basepoint); + let delayed_key = chan_utils::derive_public_key(&self.onchain_tx_handler.secp_ctx, &PublicKey::from_secret_key(&self.onchain_tx_handler.secp_ctx, &per_commitment_key), &self.counterparty_commitment_params.counterparty_delayed_payment_base_key); let revokeable_redeemscript = chan_utils::get_revokeable_redeemscript(&revocation_pubkey, self.counterparty_commitment_params.on_counterparty_tx_csv, &delayed_key); let revokeable_p2wsh = revokeable_redeemscript.to_v0_p2wsh(); @@ -2616,8 +2574,8 @@ impl ChannelMonitorImpl { if let Some(transaction) = tx { let revocation_pubkey = chan_utils::derive_public_revocation_key( - &self.secp_ctx, &per_commitment_point, &self.holder_revocation_basepoint); - let delayed_key = chan_utils::derive_public_key(&self.secp_ctx, + &self.onchain_tx_handler.secp_ctx, &per_commitment_point, &self.holder_revocation_basepoint); + let delayed_key = chan_utils::derive_public_key(&self.onchain_tx_handler.secp_ctx, &per_commitment_point, &self.counterparty_commitment_params.counterparty_delayed_payment_base_key); let revokeable_p2wsh = chan_utils::get_revokeable_redeemscript(&revocation_pubkey, @@ -2674,7 +2632,7 @@ impl ChannelMonitorImpl { Ok(key) => key, Err(_) => return (Vec::new(), None) }; - let per_commitment_point = PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_key); + let per_commitment_point = PublicKey::from_secret_key(&self.onchain_tx_handler.secp_ctx, &per_commitment_key); let htlc_txid = tx.txid(); let mut claimable_outpoints = vec![]; @@ -3032,10 +2990,10 @@ impl ChannelMonitorImpl { if let Some(new_outputs) = new_outputs_option { watch_outputs.push(new_outputs); } - // Since there may be multiple HTLCs (all from the same commitment) being - // claimed by the counterparty within the same transaction, and - // `check_spend_counterparty_htlc` already checks for all of them, we can - // safely break from our loop. + // Since there may be multiple HTLCs for this channel (all spending the + // same commitment tx) being claimed by the counterparty within the same + // transaction, and `check_spend_counterparty_htlc` already checks all the + // ones relevant to this channel, we can safely break from our loop. break; } } @@ -3653,7 +3611,7 @@ impl ChannelMonitorImpl { } } -impl chain::Listen for (ChannelMonitor, T, F, L) +impl chain::Listen for (ChannelMonitor, T, F, L) where T::Target: BroadcasterInterface, F::Target: FeeEstimator, @@ -3668,7 +3626,7 @@ where } } -impl chain::Confirm for (ChannelMonitor, T, F, L) +impl chain::Confirm for (ChannelMonitor, T, F, L) where T::Target: BroadcasterInterface, F::Target: FeeEstimator, @@ -3693,9 +3651,9 @@ where const MAX_ALLOC_SIZE: usize = 64*1024; -impl<'a, K: KeysInterface> ReadableArgs<&'a K> - for (BlockHash, ChannelMonitor) { - fn read(reader: &mut R, keys_manager: &'a K) -> Result { +impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP)> + for (BlockHash, ChannelMonitor) { + fn read(reader: &mut R, args: (&'a ES, &'b SP)) -> Result { macro_rules! unwrap_obj { ($key: expr) => { match $key { @@ -3705,6 +3663,8 @@ impl<'a, K: KeysInterface> ReadableArgs<&'a K> } } + let (entropy_source, signer_provider) = args; + let _ver = read_ver_prefix!(reader, SERIALIZATION_VERSION); let latest_update_id: u64 = Readable::read(reader)?; @@ -3878,8 +3838,8 @@ impl<'a, K: KeysInterface> ReadableArgs<&'a K> return Err(DecodeError::InvalidValue); } } - let onchain_tx_handler: OnchainTxHandler = ReadableArgs::read( - reader, (keys_manager, channel_value_satoshis, channel_keys_id) + let onchain_tx_handler: OnchainTxHandler = ReadableArgs::read( + reader, (entropy_source, signer_provider, channel_value_satoshis, channel_keys_id) )?; let lockdown_from_offchain = Readable::read(reader)?; @@ -3918,9 +3878,6 @@ impl<'a, K: KeysInterface> ReadableArgs<&'a K> (13, spendable_txids_confirmed, vec_type), }); - let mut secp_ctx = Secp256k1::new(); - secp_ctx.seeded_randomize(&keys_manager.get_secure_random_bytes()); - Ok((best_block.block_hash(), ChannelMonitor::from_impl(ChannelMonitorImpl { latest_update_id, commitment_transaction_number_obscure_factor, @@ -3972,8 +3929,6 @@ impl<'a, K: KeysInterface> ReadableArgs<&'a K> best_block, counterparty_node_id, - - secp_ctx, }))) } } @@ -4008,7 +3963,7 @@ mod tests { use crate::ln::{PaymentPreimage, PaymentHash}; use crate::ln::chan_utils; use crate::ln::chan_utils::{HTLCOutputInCommitment, ChannelPublicKeys, ChannelTransactionParameters, HolderCommitmentTransaction, CounterpartyChannelTransactionParameters}; - use crate::ln::channelmanager::{self, PaymentSendFailure, PaymentId}; + use crate::ln::channelmanager::{PaymentSendFailure, PaymentId}; use crate::ln::functional_test_utils::*; use crate::ln::script::ShutdownScript; use crate::util::errors::APIError; @@ -4036,10 +3991,8 @@ mod tests { let node_cfgs = create_node_cfgs(3, &chanmon_cfgs); let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]); let nodes = create_network(3, &node_cfgs, &node_chanmgrs); - let channel = create_announced_chan_between_nodes( - &nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features()); - create_announced_chan_between_nodes( - &nodes, 1, 2, channelmanager::provided_init_features(), channelmanager::provided_init_features()); + let channel = create_announced_chan_between_nodes(&nodes, 0, 1); + create_announced_chan_between_nodes(&nodes, 1, 2); // Rebalance somewhat send_payment(&nodes[0], &[&nodes[1]], 10_000_000); @@ -4068,7 +4021,7 @@ mod tests { let (_, pre_update_monitor) = <(BlockHash, ChannelMonitor)>::read( &mut io::Cursor::new(&get_monitor!(nodes[1], channel.2).encode()), - &nodes[1].keys_manager.backing).unwrap(); + (&nodes[1].keys_manager.backing, &nodes[1].keys_manager.backing)).unwrap(); // If the ChannelManager tries to update the channel, however, the ChainMonitor will pass // the update through to the ChannelMonitor which will refuse it (as the channel is closed). @@ -4117,7 +4070,10 @@ mod tests { fn test_prune_preimages() { let secp_ctx = Secp256k1::new(); let logger = Arc::new(TestLogger::new()); - let broadcaster = Arc::new(TestBroadcaster{txn_broadcasted: Mutex::new(Vec::new()), blocks: Arc::new(Mutex::new(Vec::new()))}); + let broadcaster = Arc::new(TestBroadcaster { + txn_broadcasted: Mutex::new(Vec::new()), + blocks: Arc::new(Mutex::new(Vec::new())) + }); let fee_estimator = TestFeeEstimator { sat_per_kw: Mutex::new(253) }; let dummy_key = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap()); @@ -4174,7 +4130,6 @@ mod tests { SecretKey::from_slice(&[41; 32]).unwrap(), SecretKey::from_slice(&[41; 32]).unwrap(), SecretKey::from_slice(&[41; 32]).unwrap(), - SecretKey::from_slice(&[41; 32]).unwrap(), [41; 32], 0, [0; 32], @@ -4203,7 +4158,7 @@ mod tests { // Prune with one old state and a holder commitment tx holding a few overlaps with the // old state. let shutdown_pubkey = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap()); - let best_block = BestBlock::from_genesis(Network::Testnet); + let best_block = BestBlock::from_network(Network::Testnet); let monitor = ChannelMonitor::new(Secp256k1::new(), keys, Some(ShutdownScript::new_p2wpkh_from_pubkey(shutdown_pubkey).into_inner()), 0, &Script::new(), (OutPoint { txid: Txid::from_slice(&[43; 32]).unwrap(), index: 0 }, Script::new()),