X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fevents%2Fbump_transaction.rs;h=dbe539505d6ca733f53a44e4ae0f515523373395;hb=19de4353d52bca8021ba3e1b8f4b036d5f5a8648;hp=0e3152d7b0a4c848c2fe5a4a6f07cd37f83db5cd;hpb=72c42ee786d11ea1913d2898069f2c6b15285a2a;p=rust-lightning diff --git a/lightning/src/events/bump_transaction.rs b/lightning/src/events/bump_transaction.rs index 0e3152d7..dbe53950 100644 --- a/lightning/src/events/bump_transaction.rs +++ b/lightning/src/events/bump_transaction.rs @@ -11,12 +11,13 @@ //! //! [`Event`]: crate::events::Event -use core::convert::TryInto; +use alloc::collections::BTreeMap; use core::ops::Deref; -use crate::chain::chaininterface::BroadcasterInterface; +use crate::chain::chaininterface::{BroadcasterInterface, compute_feerate_sat_per_1000_weight, fee_for_weight}; use crate::chain::ClaimId; use crate::io_extras::sink; +use crate::ln::channel::ANCHOR_OUTPUT_VALUE_SATOSHI; use crate::ln::chan_utils; use crate::ln::chan_utils::{ ANCHOR_INPUT_WITNESS_WEIGHT, HTLC_SUCCESS_INPUT_ANCHOR_WITNESS_WEIGHT, @@ -42,53 +43,83 @@ const BASE_INPUT_SIZE: u64 = 32 /* txid */ + 4 /* vout */ + 4 /* sequence */; const BASE_INPUT_WEIGHT: u64 = BASE_INPUT_SIZE * WITNESS_SCALE_FACTOR as u64; -// TODO: Define typed abstraction over feerates to handle their conversions. -fn compute_feerate_sat_per_1000_weight(fee_sat: u64, weight: u64) -> u32 { - (fee_sat * 1000 / weight).try_into().unwrap_or(u32::max_value()) -} -const fn fee_for_weight(feerate_sat_per_1000_weight: u32, weight: u64) -> u64 { - ((feerate_sat_per_1000_weight as u64 * weight) + 1000 - 1) / 1000 +/// The parameters required to derive a channel signer via [`SignerProvider`]. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct ChannelDerivationParameters { + /// The value in satoshis of the channel we're attempting to spend the anchor output of. + pub value_satoshis: u64, + /// The unique identifier to re-derive the signer for the associated channel. + pub keys_id: [u8; 32], + /// The necessary channel parameters that need to be provided to the re-derived signer through + /// [`ChannelSigner::provide_channel_parameters`]. + /// + /// [`ChannelSigner::provide_channel_parameters`]: crate::sign::ChannelSigner::provide_channel_parameters + pub transaction_parameters: ChannelTransactionParameters, } /// A descriptor used to sign for a commitment transaction's anchor output. #[derive(Clone, Debug, PartialEq, Eq)] pub struct AnchorDescriptor { - /// A unique identifier used along with `channel_value_satoshis` to re-derive the - /// [`InMemorySigner`] required to sign `input`. - /// - /// [`InMemorySigner`]: crate::sign::InMemorySigner - pub channel_keys_id: [u8; 32], - /// The value in satoshis of the channel we're attempting to spend the anchor output of. This is - /// used along with `channel_keys_id` to re-derive the [`InMemorySigner`] required to sign - /// `input`. - /// - /// [`InMemorySigner`]: crate::sign::InMemorySigner - pub channel_value_satoshis: u64, + /// The parameters required to derive the signer for the anchor input. + pub channel_derivation_parameters: ChannelDerivationParameters, /// The transaction input's outpoint corresponding to the commitment transaction's anchor /// output. pub outpoint: OutPoint, } +impl AnchorDescriptor { + /// Returns the UTXO to be spent by the anchor input, which can be obtained via + /// [`Self::unsigned_tx_input`]. + pub fn previous_utxo(&self) -> TxOut { + TxOut { + script_pubkey: self.witness_script().to_v0_p2wsh(), + value: ANCHOR_OUTPUT_VALUE_SATOSHI, + } + } + + /// Returns the unsigned transaction input spending the anchor output in the commitment + /// transaction. + pub fn unsigned_tx_input(&self) -> TxIn { + TxIn { + previous_output: self.outpoint.clone(), + script_sig: Script::new(), + sequence: Sequence::ENABLE_RBF_NO_LOCKTIME, + witness: Witness::new(), + } + } + + /// Returns the witness script of the anchor output in the commitment transaction. + pub fn witness_script(&self) -> Script { + let channel_params = self.channel_derivation_parameters.transaction_parameters.as_holder_broadcastable(); + chan_utils::get_anchor_redeemscript(&channel_params.broadcaster_pubkeys().funding_pubkey) + } + + /// Returns the fully signed witness required to spend the anchor output in the commitment + /// transaction. + pub fn tx_input_witness(&self, signature: &Signature) -> Witness { + let channel_params = self.channel_derivation_parameters.transaction_parameters.as_holder_broadcastable(); + chan_utils::build_anchor_input_witness(&channel_params.broadcaster_pubkeys().funding_pubkey, signature) + } + + /// Derives the channel signer required to sign the anchor input. + pub fn derive_channel_signer(&self, signer_provider: &SP) -> ::Signer + where + SP::Target: SignerProvider + { + let mut signer = signer_provider.derive_channel_signer( + self.channel_derivation_parameters.value_satoshis, + self.channel_derivation_parameters.keys_id, + ); + signer.provide_channel_parameters(&self.channel_derivation_parameters.transaction_parameters); + signer + } +} + /// A descriptor used to sign for a commitment transaction's HTLC output. #[derive(Clone, Debug, PartialEq, Eq)] pub struct HTLCDescriptor { - /// A unique identifier used along with `channel_value_satoshis` to re-derive the - /// [`InMemorySigner`] required to sign `input`. - /// - /// [`InMemorySigner`]: crate::sign::InMemorySigner - pub channel_keys_id: [u8; 32], - /// The value in satoshis of the channel we're attempting to spend the anchor output of. This is - /// used along with `channel_keys_id` to re-derive the [`InMemorySigner`] required to sign - /// `input`. - /// - /// [`InMemorySigner`]: crate::sign::InMemorySigner - pub channel_value_satoshis: u64, - /// The necessary channel parameters that need to be provided to the re-derived - /// [`InMemorySigner`] through [`ChannelSigner::provide_channel_parameters`]. - /// - /// [`InMemorySigner`]: crate::sign::InMemorySigner - /// [`ChannelSigner::provide_channel_parameters`]: crate::sign::ChannelSigner::provide_channel_parameters - pub channel_parameters: ChannelTransactionParameters, + /// The parameters required to derive the signer for the HTLC input. + pub channel_derivation_parameters: ChannelDerivationParameters, /// The txid of the commitment transaction in which the HTLC output lives. pub commitment_txid: Txid, /// The number of the commitment transaction in which the HTLC output lives. @@ -109,6 +140,15 @@ pub struct HTLCDescriptor { } impl HTLCDescriptor { + /// Returns the UTXO to be spent by the HTLC input, which can be obtained via + /// [`Self::unsigned_tx_input`]. + pub fn previous_utxo(&self, secp: &Secp256k1) -> TxOut { + TxOut { + script_pubkey: self.witness_script(secp).to_v0_p2wsh(), + value: self.htlc.amount_msat / 1000, + } + } + /// Returns the unsigned transaction input spending the HTLC output in the commitment /// transaction. pub fn unsigned_tx_input(&self) -> TxIn { @@ -118,7 +158,7 @@ impl HTLCDescriptor { /// Returns the delayed output created as a result of spending the HTLC output in the commitment /// transaction. pub fn tx_output(&self, secp: &Secp256k1) -> TxOut { - let channel_params = self.channel_parameters.as_holder_broadcastable(); + let channel_params = self.channel_derivation_parameters.transaction_parameters.as_holder_broadcastable(); let broadcaster_keys = channel_params.broadcaster_pubkeys(); let counterparty_keys = channel_params.countersignatory_pubkeys(); let broadcaster_delayed_key = chan_utils::derive_public_key( @@ -135,7 +175,7 @@ impl HTLCDescriptor { /// Returns the witness script of the HTLC output in the commitment transaction. pub fn witness_script(&self, secp: &Secp256k1) -> Script { - let channel_params = self.channel_parameters.as_holder_broadcastable(); + let channel_params = self.channel_derivation_parameters.transaction_parameters.as_holder_broadcastable(); let broadcaster_keys = channel_params.broadcaster_pubkeys(); let counterparty_keys = channel_params.countersignatory_pubkeys(); let broadcaster_htlc_key = chan_utils::derive_public_key( @@ -160,6 +200,19 @@ impl HTLCDescriptor { signature, &self.counterparty_sig, &self.preimage, witness_script, &ChannelTypeFeatures::anchors_zero_htlc_fee_and_dependencies() /* opt_anchors */ ) } + + /// Derives the channel signer required to sign the HTLC input. + pub fn derive_channel_signer(&self, signer_provider: &SP) -> ::Signer + where + SP::Target: SignerProvider + { + let mut signer = signer_provider.derive_channel_signer( + self.channel_derivation_parameters.value_satoshis, + self.channel_derivation_parameters.keys_id, + ); + signer.provide_channel_parameters(&self.channel_derivation_parameters.transaction_parameters); + signer + } } /// Represents the different types of transactions, originating from LDK, to be bumped. @@ -178,12 +231,11 @@ pub enum BumpTransactionEvent { /// broadcast first, as the child anchor transaction depends on it. /// /// The consumer should be able to sign for any of the additional inputs included within the - /// child anchor transaction. To sign its anchor input, an [`InMemorySigner`] should be - /// re-derived through [`KeysManager::derive_channel_keys`] with the help of - /// [`AnchorDescriptor::channel_keys_id`] and [`AnchorDescriptor::channel_value_satoshis`]. The - /// anchor input signature can be computed with [`EcdsaChannelSigner::sign_holder_anchor_input`], - /// which can then be provided to [`build_anchor_input_witness`] along with the `funding_pubkey` - /// to obtain the full witness required to spend. + /// child anchor transaction. To sign its anchor input, an [`EcdsaChannelSigner`] should be + /// re-derived through [`AnchorDescriptor::derive_channel_signer`]. The anchor input signature + /// can be computed with [`EcdsaChannelSigner::sign_holder_anchor_input`], which can then be + /// provided to [`build_anchor_input_witness`] along with the `funding_pubkey` to obtain the + /// full witness required to spend. /// /// It is possible to receive more than one instance of this event if a valid child anchor /// transaction is never broadcast or is but not with a sufficient fee to be mined. Care should @@ -202,8 +254,7 @@ pub enum BumpTransactionEvent { /// an empty `pending_htlcs`), confirmation of the commitment transaction can be considered to /// be not urgent. /// - /// [`InMemorySigner`]: crate::sign::InMemorySigner - /// [`KeysManager::derive_channel_keys`]: crate::sign::KeysManager::derive_channel_keys + /// [`EcdsaChannelSigner`]: crate::sign::EcdsaChannelSigner /// [`EcdsaChannelSigner::sign_holder_anchor_input`]: crate::sign::EcdsaChannelSigner::sign_holder_anchor_input /// [`build_anchor_input_witness`]: crate::ln::chan_utils::build_anchor_input_witness ChannelClose { @@ -241,11 +292,11 @@ pub enum BumpTransactionEvent { /// broadcast by the consumer of the event. /// /// The consumer should be able to sign for any of the non-HTLC inputs added to the resulting - /// HTLC transaction. To sign HTLC inputs, an [`InMemorySigner`] should be re-derived through - /// [`KeysManager::derive_channel_keys`] with the help of `channel_keys_id` and - /// `channel_value_satoshis`. Each HTLC input's signature can be computed with - /// [`EcdsaChannelSigner::sign_holder_htlc_transaction`], which can then be provided to - /// [`HTLCDescriptor::tx_input_witness`] to obtain the fully signed witness required to spend. + /// HTLC transaction. To sign HTLC inputs, an [`EcdsaChannelSigner`] should be re-derived + /// through [`HTLCDescriptor::derive_channel_signer`]. Each HTLC input's signature can be + /// computed with [`EcdsaChannelSigner::sign_holder_htlc_transaction`], which can then be + /// provided to [`HTLCDescriptor::tx_input_witness`] to obtain the fully signed witness required + /// to spend. /// /// It is possible to receive more than one instance of this event if a valid HTLC transaction /// is never broadcast or is but not with a sufficient fee to be mined. Care should be taken by @@ -257,8 +308,7 @@ pub enum BumpTransactionEvent { /// longer able to commit external confirmed funds to the HTLC transaction or the fee committed /// to the HTLC transaction is greater in value than the HTLCs being claimed. /// - /// [`InMemorySigner`]: crate::sign::InMemorySigner - /// [`KeysManager::derive_channel_keys`]: crate::sign::KeysManager::derive_channel_keys + /// [`EcdsaChannelSigner`]: crate::sign::EcdsaChannelSigner /// [`EcdsaChannelSigner::sign_holder_htlc_transaction`]: crate::sign::EcdsaChannelSigner::sign_holder_htlc_transaction /// [`HTLCDescriptor::tx_input_witness`]: HTLCDescriptor::tx_input_witness HTLCResolution { @@ -285,6 +335,8 @@ pub enum BumpTransactionEvent { pub struct Input { /// The unique identifier of the input. pub outpoint: OutPoint, + /// The UTXO being spent by the input. + pub previous_utxo: TxOut, /// The upper-bound weight consumed by the input's full [`TxIn::script_sig`] and /// [`TxIn::witness`], each with their lengths included, required to satisfy the output's /// script. @@ -624,6 +676,7 @@ where ) -> Result { let must_spend = vec![Input { outpoint: anchor_descriptor.outpoint, + previous_utxo: anchor_descriptor.previous_utxo(), satisfaction_weight: commitment_tx.weight() as u64 + ANCHOR_INPUT_WITNESS_WEIGHT + EMPTY_SCRIPT_SIG_WEIGHT, }]; let coin_selection = self.utxo_source.select_confirmed_utxos( @@ -633,12 +686,7 @@ where let mut tx = Transaction { version: 2, lock_time: PackedLockTime::ZERO, // TODO: Use next best height. - input: vec![TxIn { - previous_output: anchor_descriptor.outpoint, - script_sig: Script::new(), - sequence: Sequence::ZERO, - witness: Witness::new(), - }], + input: vec![anchor_descriptor.unsigned_tx_input()], output: vec![], }; self.process_coin_selection(&mut tx, coin_selection); @@ -670,12 +718,9 @@ where debug_assert_eq!(anchor_tx.output.len(), 1); self.utxo_source.sign_tx(&mut anchor_tx)?; - let signer = self.signer_provider.derive_channel_signer( - anchor_descriptor.channel_value_satoshis, anchor_descriptor.channel_keys_id, - ); + let signer = anchor_descriptor.derive_channel_signer(&self.signer_provider); let anchor_sig = signer.sign_holder_anchor_input(&anchor_tx, 0, &self.secp)?; - anchor_tx.input[0].witness = - chan_utils::build_anchor_input_witness(&signer.pubkeys().funding_pubkey, &anchor_sig); + anchor_tx.input[0].witness = anchor_descriptor.tx_input_witness(&anchor_sig); self.broadcaster.broadcast_transactions(&[&commitment_tx, &anchor_tx]); Ok(()) @@ -686,28 +731,19 @@ where fn build_htlc_tx( &self, claim_id: ClaimId, target_feerate_sat_per_1000_weight: u32, htlc_descriptors: &[HTLCDescriptor], tx_lock_time: PackedLockTime, - ) -> Result<(Transaction, HashMap<[u8; 32], ::Signer>), ()> { + ) -> Result { let mut tx = Transaction { version: 2, lock_time: tx_lock_time, input: vec![], output: vec![], }; - // Unfortunately, we need to derive the signer for each HTLC ahead of time to obtain its - // input. - let mut signers = HashMap::new(); let mut must_spend = Vec::with_capacity(htlc_descriptors.len()); for htlc_descriptor in htlc_descriptors { - signers.entry(htlc_descriptor.channel_keys_id) - .or_insert_with(|| - self.signer_provider.derive_channel_signer( - htlc_descriptor.channel_value_satoshis, htlc_descriptor.channel_keys_id, - ) - ); - let htlc_input = htlc_descriptor.unsigned_tx_input(); must_spend.push(Input { outpoint: htlc_input.previous_output.clone(), + previous_utxo: htlc_descriptor.previous_utxo(&self.secp), satisfaction_weight: EMPTY_SCRIPT_SIG_WEIGHT + if htlc_descriptor.preimage.is_some() { HTLC_SUCCESS_INPUT_ANCHOR_WITNESS_WEIGHT } else { @@ -723,7 +759,7 @@ where claim_id, &must_spend, &tx.output, target_feerate_sat_per_1000_weight, )?; self.process_coin_selection(&mut tx, coin_selection); - Ok((tx, signers)) + Ok(tx) } /// Handles a [`BumpTransactionEvent::HTLCResolution`] event variant by producing a @@ -732,16 +768,16 @@ where &self, claim_id: ClaimId, target_feerate_sat_per_1000_weight: u32, htlc_descriptors: &[HTLCDescriptor], tx_lock_time: PackedLockTime, ) -> Result<(), ()> { - let (mut htlc_tx, signers) = self.build_htlc_tx( + let mut htlc_tx = self.build_htlc_tx( claim_id, target_feerate_sat_per_1000_weight, htlc_descriptors, tx_lock_time, )?; self.utxo_source.sign_tx(&mut htlc_tx)?; + let mut signers = BTreeMap::new(); for (idx, htlc_descriptor) in htlc_descriptors.iter().enumerate() { - let signer = signers.get(&htlc_descriptor.channel_keys_id).unwrap(); - let htlc_sig = signer.sign_holder_htlc_transaction( - &htlc_tx, idx, htlc_descriptor, &self.secp - )?; + let signer = signers.entry(htlc_descriptor.channel_derivation_parameters.keys_id) + .or_insert_with(|| htlc_descriptor.derive_channel_signer(&self.signer_provider)); + let htlc_sig = signer.sign_holder_htlc_transaction(&htlc_tx, idx, htlc_descriptor, &self.secp)?; let witness_script = htlc_descriptor.witness_script(&self.secp); htlc_tx.input[idx].witness = htlc_descriptor.tx_input_witness(&htlc_sig, &witness_script); }