X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fchain%2Fpackage.rs;h=bd983ecd9163589b19b12f85199c9d851d0fb5f0;hb=05157b1755c1cf33bb80bc7ac41dfb52b58d2a74;hp=2e1e50371dc569d4a1f22b937da2ec7e661bbae6;hpb=f0743433e7e1d302f79bec2fdb3f173560e4e954;p=rust-lightning diff --git a/lightning/src/chain/package.rs b/lightning/src/chain/package.rs index 2e1e5037..bd983ecd 100644 --- a/lightning/src/chain/package.rs +++ b/lightning/src/chain/package.rs @@ -21,7 +21,7 @@ use bitcoin::hash_types::Txid; use bitcoin::secp256k1::key::{SecretKey,PublicKey}; use ln::PaymentPreimage; -use ln::chan_utils::{TxCreationKeys, HTLCOutputInCommitment, HTLC_OUTPUT_IN_COMMITMENT_SIZE}; +use ln::chan_utils::{TxCreationKeys, HTLCOutputInCommitment}; use ln::chan_utils; use ln::msgs::DecodeError; use chain::chaininterface::{FeeEstimator, ConfirmationTarget, MIN_RELAY_FEE_SAT_PER_1000_WEIGHT}; @@ -31,9 +31,9 @@ use util::byte_utils; use util::logger::Logger; use util::ser::{Readable, Writer, Writeable}; -use std::cmp; -use std::mem; -use std::ops::Deref; +use core::cmp; +use core::mem; +use core::ops::Deref; const MAX_ALLOC_SIZE: usize = 64*1024; @@ -86,15 +86,15 @@ impl RevokedOutput { } } -impl_writeable!(RevokedOutput, 33*3 + 32 + 8 + 8 + 2, { - per_commitment_point, - counterparty_delayed_payment_base_key, - counterparty_htlc_base_key, - per_commitment_key, - weight, - amount, - on_counterparty_tx_csv -}); +impl_writeable_tlv_based!(RevokedOutput, { + (0, per_commitment_point), + (2, counterparty_delayed_payment_base_key), + (4, counterparty_htlc_base_key), + (6, per_commitment_key), + (8, weight), + (10, amount), + (12, on_counterparty_tx_csv), +}, {}, {}); /// A struct to describe a revoked offered output and corresponding information to generate a /// solving witness. @@ -130,15 +130,15 @@ impl RevokedHTLCOutput { } } -impl_writeable!(RevokedHTLCOutput, 33*3 + 32 + 8 + 8 + HTLC_OUTPUT_IN_COMMITMENT_SIZE, { - per_commitment_point, - counterparty_delayed_payment_base_key, - counterparty_htlc_base_key, - per_commitment_key, - weight, - amount, - htlc -}); +impl_writeable_tlv_based!(RevokedHTLCOutput, { + (0, per_commitment_point), + (2, counterparty_delayed_payment_base_key), + (4, counterparty_htlc_base_key), + (6, per_commitment_key), + (8, weight), + (10, amount), + (12, htlc), +}, {}, {}); /// A struct to describe a HTLC output on a counterparty commitment transaction. /// @@ -167,13 +167,13 @@ impl CounterpartyOfferedHTLCOutput { } } -impl_writeable!(CounterpartyOfferedHTLCOutput, 33*3 + 32 + HTLC_OUTPUT_IN_COMMITMENT_SIZE, { - per_commitment_point, - counterparty_delayed_payment_base_key, - counterparty_htlc_base_key, - preimage, - htlc -}); +impl_writeable_tlv_based!(CounterpartyOfferedHTLCOutput, { + (0, per_commitment_point), + (2, counterparty_delayed_payment_base_key), + (4, counterparty_htlc_base_key), + (6, preimage), + (8, htlc), +}, {}, {}); /// A struct to describe a HTLC output on a counterparty commitment transaction. /// @@ -198,12 +198,12 @@ impl CounterpartyReceivedHTLCOutput { } } -impl_writeable!(CounterpartyReceivedHTLCOutput, 33*3 + HTLC_OUTPUT_IN_COMMITMENT_SIZE, { - per_commitment_point, - counterparty_delayed_payment_base_key, - counterparty_htlc_base_key, - htlc -}); +impl_writeable_tlv_based!(CounterpartyReceivedHTLCOutput, { + (0, per_commitment_point), + (2, counterparty_delayed_payment_base_key), + (4, counterparty_htlc_base_key), + (6, htlc), +}, {}, {}); /// A struct to describe a HTLC output on holder commitment transaction. /// @@ -213,21 +213,34 @@ impl_writeable!(CounterpartyReceivedHTLCOutput, 33*3 + HTLC_OUTPUT_IN_COMMITMENT pub(crate) struct HolderHTLCOutput { preimage: Option, amount: u64, + /// Defaults to 0 for HTLC-Success transactions, which have no expiry + cltv_expiry: u32, } impl HolderHTLCOutput { - pub(crate) fn build(preimage: Option, amount: u64) -> Self { + pub(crate) fn build_offered(amount: u64, cltv_expiry: u32) -> Self { HolderHTLCOutput { - preimage, - amount + preimage: None, + amount, + cltv_expiry, + } + } + + pub(crate) fn build_accepted(preimage: PaymentPreimage, amount: u64) -> Self { + HolderHTLCOutput { + preimage: Some(preimage), + amount, + cltv_expiry: 0, } } } -impl_writeable!(HolderHTLCOutput, 0, { - preimage, - amount -}); +impl_writeable_tlv_based!(HolderHTLCOutput, { + (0, amount), + (2, cltv_expiry), +}, { + (4, preimage), +}, {}); /// A struct to describe the channel output on the funding transaction. /// @@ -245,9 +258,9 @@ impl HolderFundingOutput { } } -impl_writeable!(HolderFundingOutput, 0, { - funding_redeemscript -}); +impl_writeable_tlv_based!(HolderFundingOutput, { + (0, funding_redeemscript), +}, {}, {}); /// A wrapper encapsulating all in-protocol differing outputs types. /// @@ -273,8 +286,8 @@ impl PackageSolvingData { // Note: Currently, amounts of holder outputs spending witnesses aren't used // as we can't malleate spending package to increase their feerate. This // should change with the remaining anchor output patchset. - PackageSolvingData::HolderHTLCOutput(..) => { 0 }, - PackageSolvingData::HolderFundingOutput(..) => { 0 }, + PackageSolvingData::HolderHTLCOutput(..) => { unreachable!() }, + PackageSolvingData::HolderFundingOutput(..) => { unreachable!() }, }; amt } @@ -287,8 +300,8 @@ impl PackageSolvingData { // Note: Currently, weights of holder outputs spending witnesses aren't used // as we can't malleate spending package to increase their feerate. This // should change with the remaining anchor output patchset. - PackageSolvingData::HolderHTLCOutput(..) => { debug_assert!(false); 0 }, - PackageSolvingData::HolderFundingOutput(..) => { debug_assert!(false); 0 }, + PackageSolvingData::HolderHTLCOutput(..) => { unreachable!() }, + PackageSolvingData::HolderFundingOutput(..) => { unreachable!() }, }; weight } @@ -374,68 +387,32 @@ impl PackageSolvingData { _ => { panic!("API Error!"); } } } -} - -impl Writeable for PackageSolvingData { - fn write(&self, writer: &mut W) -> Result<(), ::std::io::Error> { - match self { - PackageSolvingData::RevokedOutput(ref revoked_outp) => { - 0u8.write(writer)?; - revoked_outp.write(writer)?; - }, - PackageSolvingData::RevokedHTLCOutput(ref revoked_outp) => { - 1u8.write(writer)?; - revoked_outp.write(writer)?; - }, - PackageSolvingData::CounterpartyOfferedHTLCOutput(ref counterparty_outp) => { - 2u8.write(writer)?; - counterparty_outp.write(writer)?; - }, - PackageSolvingData::CounterpartyReceivedHTLCOutput(ref counterparty_outp) => { - 3u8.write(writer)?; - counterparty_outp.write(writer)?; - }, - PackageSolvingData::HolderHTLCOutput(ref holder_outp) => { - 4u8.write(writer)?; - holder_outp.write(writer)?; - }, - PackageSolvingData::HolderFundingOutput(ref funding_outp) => { - 5u8.write(writer)?; - funding_outp.write(writer)?; - } - } - Ok(()) - } -} - -impl Readable for PackageSolvingData { - fn read(reader: &mut R) -> Result { - let byte = ::read(reader)?; - let solving_data = match byte { - 0 => { - PackageSolvingData::RevokedOutput(Readable::read(reader)?) - }, - 1 => { - PackageSolvingData::RevokedHTLCOutput(Readable::read(reader)?) - }, - 2 => { - PackageSolvingData::CounterpartyOfferedHTLCOutput(Readable::read(reader)?) - }, - 3 => { - PackageSolvingData::CounterpartyReceivedHTLCOutput(Readable::read(reader)?) - }, - 4 => { - PackageSolvingData::HolderHTLCOutput(Readable::read(reader)?) - }, - 5 => { - PackageSolvingData::HolderFundingOutput(Readable::read(reader)?) - } - _ => return Err(DecodeError::UnknownVersion) + fn absolute_tx_timelock(&self, output_conf_height: u32) -> u32 { + // Get the absolute timelock at which this output can be spent given the height at which + // this output was confirmed. We use `output_conf_height + 1` as a safe default as we can + // be confirmed in the next block and transactions with time lock `current_height + 1` + // always propagate. + let absolute_timelock = match self { + PackageSolvingData::RevokedOutput(_) => output_conf_height + 1, + PackageSolvingData::RevokedHTLCOutput(_) => output_conf_height + 1, + PackageSolvingData::CounterpartyOfferedHTLCOutput(_) => output_conf_height + 1, + PackageSolvingData::CounterpartyReceivedHTLCOutput(ref outp) => std::cmp::max(outp.htlc.cltv_expiry, output_conf_height + 1), + PackageSolvingData::HolderHTLCOutput(ref outp) => std::cmp::max(outp.cltv_expiry, output_conf_height + 1), + PackageSolvingData::HolderFundingOutput(_) => output_conf_height + 1, }; - Ok(solving_data) + absolute_timelock } } +impl_writeable_tlv_based_enum!(PackageSolvingData, ; + (0, RevokedOutput), + (1, RevokedHTLCOutput), + (2, CounterpartyOfferedHTLCOutput), + (3, CounterpartyReceivedHTLCOutput), + (4, HolderHTLCOutput), + (5, HolderFundingOutput), +); + /// A malleable package might be aggregated with other packages to save on fees. /// A untractable package has been counter-signed and aggregable will break cached counterparty /// signatures. @@ -576,13 +553,19 @@ impl PackageTemplate { } self.height_timer = cmp::min(self.height_timer, merge_from.height_timer); } - pub(crate) fn package_amount(&self) -> u64 { + /// Gets the amount of all outptus being spent by this package, only valid for malleable + /// packages. + fn package_amount(&self) -> u64 { let mut amounts = 0; for (_, outp) in self.inputs.iter() { amounts += outp.amount(); } amounts } + pub(crate) fn package_timelock(&self) -> u32 { + self.inputs.iter().map(|(_, outp)| outp.absolute_tx_timelock(self.height_original)) + .max().expect("There must always be at least one output to spend in a PackageTemplate") + } pub(crate) fn package_weight(&self, destination_script: &Script) -> usize { let mut inputs_weight = 0; let mut witnesses_weight = 2; // count segwit flags @@ -627,6 +610,7 @@ impl PackageTemplate { return Some(bumped_tx); }, PackageMalleability::Untractable => { + debug_assert_eq!(value, 0, "value is ignored for non-malleable packages, should be zero to ensure callsites are correct"); if let Some((outpoint, outp)) = self.inputs.first() { if let Some(final_tx) = outp.get_finalized_tx(outpoint, onchain_handler) { log_trace!(logger, "Adding claiming input for outpoint {}:{}", outpoint.txid, outpoint.vout); @@ -652,10 +636,12 @@ impl PackageTemplate { current_height + LOW_FREQUENCY_BUMP_INTERVAL } /// Returns value in satoshis to be included as package outgoing output amount and feerate with which package finalization should be done. - pub(crate) fn compute_package_output(&self, predicted_weight: usize, input_amounts: u64, fee_estimator: &F, logger: &L) -> Option<(u64, u64)> + pub(crate) fn compute_package_output(&self, predicted_weight: usize, fee_estimator: &F, logger: &L) -> Option<(u64, u64)> where F::Target: FeeEstimator, L::Target: Logger, { + debug_assert!(self.malleability == PackageMalleability::Malleable, "The package output is fixed for non-malleable packages"); + let input_amounts = self.package_amount(); // If old feerate is 0, first iteration of this claim, use normal fee calculation if self.feerate_previous != 0 { if let Some((new_fee, feerate)) = feerate_bump(predicted_weight, input_amounts, self.feerate_previous, fee_estimator, logger) { @@ -703,10 +689,11 @@ impl Writeable for PackageTemplate { outpoint.write(writer)?; rev_outp.write(writer)?; } - self.soonest_conf_deadline.write(writer)?; - self.feerate_previous.write(writer)?; - self.height_timer.write(writer)?; - self.height_original.write(writer)?; + write_tlv_fields!(writer, { + (0, self.soonest_conf_deadline), + (2, self.feerate_previous), + (4, self.height_original), + }, { (6, self.height_timer) }); Ok(()) } } @@ -730,10 +717,15 @@ impl Readable for PackageTemplate { PackageSolvingData::HolderFundingOutput(..) => { (PackageMalleability::Untractable, false) }, } } else { return Err(DecodeError::InvalidValue); }; - let soonest_conf_deadline = Readable::read(reader)?; - let feerate_previous = Readable::read(reader)?; - let height_timer = Readable::read(reader)?; - let height_original = Readable::read(reader)?; + let mut soonest_conf_deadline = 0; + let mut feerate_previous = 0; + let mut height_timer = None; + let mut height_original = 0; + read_tlv_fields!(reader, { + (0, soonest_conf_deadline), + (2, feerate_previous), + (4, height_original) + }, { (6, height_timer) }); Ok(PackageTemplate { inputs, malleability, @@ -867,7 +859,7 @@ mod tests { () => { { let preimage = PaymentPreimage([2;32]); - PackageSolvingData::HolderHTLCOutput(HolderHTLCOutput::build(Some(preimage), 0)) + PackageSolvingData::HolderHTLCOutput(HolderHTLCOutput::build_accepted(preimage, 0)) } } }