X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fchain%2Fpackage.rs;h=1cc63a8c8605338875a4ac3c7a95fab7b365d794;hb=61629bc00ef7d64b56b3dad18d40d29c8037e068;hp=a7339468991f93f462ab132ee6104b7860a4fb70;hpb=c05347f48a4ff2789ae261ee8c8f3f4277489420;p=rust-lightning diff --git a/lightning/src/chain/package.rs b/lightning/src/chain/package.rs index a7339468..1cc63a8c 100644 --- a/lightning/src/chain/package.rs +++ b/lightning/src/chain/package.rs @@ -31,6 +31,8 @@ use util::byte_utils; use util::logger::Logger; use util::ser::{Readable, Writer, Writeable}; +use io; +use prelude::*; use core::cmp; use core::mem; use core::ops::Deref; @@ -38,14 +40,34 @@ use core::ops::Deref; const MAX_ALLOC_SIZE: usize = 64*1024; -// number_of_witness_elements + sig_length + revocation_sig + pubkey_length + revocationpubkey + witness_script_length + witness_script -pub(crate) const WEIGHT_REVOKED_OFFERED_HTLC: u64 = 1 + 1 + 73 + 1 + 33 + 1 + 133; -// number_of_witness_elements + sig_length + revocation_sig + pubkey_length + revocationpubkey + witness_script_length + witness_script -pub(crate) const WEIGHT_REVOKED_RECEIVED_HTLC: u64 = 1 + 1 + 73 + 1 + 33 + 1 + 139; -// number_of_witness_elements + sig_length + counterpartyhtlc_sig + preimage_length + preimage + witness_script_length + witness_script -pub(crate) const WEIGHT_OFFERED_HTLC: u64 = 1 + 1 + 73 + 1 + 32 + 1 + 133; -// number_of_witness_elements + sig_length + revocation_sig + pubkey_length + revocationpubkey + witness_script_length + witness_script -pub(crate) const WEIGHT_RECEIVED_HTLC: u64 = 1 + 1 + 73 + 1 + 1 + 1 + 139; +pub(crate) fn weight_revoked_offered_htlc(opt_anchors: bool) -> u64 { + // number_of_witness_elements + sig_length + revocation_sig + pubkey_length + revocationpubkey + witness_script_length + witness_script + const WEIGHT_REVOKED_OFFERED_HTLC: u64 = 1 + 1 + 73 + 1 + 33 + 1 + 133; + const WEIGHT_REVOKED_OFFERED_HTLC_ANCHORS: u64 = WEIGHT_REVOKED_OFFERED_HTLC + 3; // + OP_1 + OP_CSV + OP_DROP + if opt_anchors { WEIGHT_REVOKED_OFFERED_HTLC_ANCHORS } else { WEIGHT_REVOKED_OFFERED_HTLC } +} + +pub(crate) fn weight_revoked_received_htlc(opt_anchors: bool) -> u64 { + // number_of_witness_elements + sig_length + revocation_sig + pubkey_length + revocationpubkey + witness_script_length + witness_script + const WEIGHT_REVOKED_RECEIVED_HTLC: u64 = 1 + 1 + 73 + 1 + 33 + 1 + 139; + const WEIGHT_REVOKED_RECEIVED_HTLC_ANCHORS: u64 = WEIGHT_REVOKED_RECEIVED_HTLC + 3; // + OP_1 + OP_CSV + OP_DROP + if opt_anchors { WEIGHT_REVOKED_RECEIVED_HTLC_ANCHORS } else { WEIGHT_REVOKED_RECEIVED_HTLC } +} + +pub(crate) fn weight_offered_htlc(opt_anchors: bool) -> u64 { + // number_of_witness_elements + sig_length + counterpartyhtlc_sig + preimage_length + preimage + witness_script_length + witness_script + const WEIGHT_OFFERED_HTLC: u64 = 1 + 1 + 73 + 1 + 32 + 1 + 133; + const WEIGHT_OFFERED_HTLC_ANCHORS: u64 = WEIGHT_OFFERED_HTLC + 3; // + OP_1 + OP_CSV + OP_DROP + if opt_anchors { WEIGHT_OFFERED_HTLC_ANCHORS } else { WEIGHT_OFFERED_HTLC } +} + +pub(crate) fn weight_received_htlc(opt_anchors: bool) -> u64 { + // number_of_witness_elements + sig_length + counterpartyhtlc_sig + empty_vec_length + empty_vec + witness_script_length + witness_script + const WEIGHT_RECEIVED_HTLC: u64 = 1 + 1 + 73 + 1 + 1 + 1 + 139; + const WEIGHT_RECEIVED_HTLC_ANCHORS: u64 = WEIGHT_RECEIVED_HTLC + 3; // + OP_1 + OP_CSV + OP_DROP + if opt_anchors { WEIGHT_RECEIVED_HTLC_ANCHORS } else { WEIGHT_RECEIVED_HTLC } +} + // number_of_witness_elements + sig_length + revocation_sig + true_length + op_true + witness_script_length + witness_script pub(crate) const WEIGHT_REVOKED_OUTPUT: u64 = 1 + 1 + 73 + 1 + 1 + 1 + 77; @@ -87,14 +109,14 @@ impl RevokedOutput { } 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), -}, {}, {}); + (0, per_commitment_point, required), + (2, counterparty_delayed_payment_base_key, required), + (4, counterparty_htlc_base_key, required), + (6, per_commitment_key, required), + (8, weight, required), + (10, amount, required), + (12, on_counterparty_tx_csv, required), +}); /// A struct to describe a revoked offered output and corresponding information to generate a /// solving witness. @@ -116,8 +138,8 @@ pub(crate) struct RevokedHTLCOutput { } impl RevokedHTLCOutput { - pub(crate) fn build(per_commitment_point: PublicKey, counterparty_delayed_payment_base_key: PublicKey, counterparty_htlc_base_key: PublicKey, per_commitment_key: SecretKey, amount: u64, htlc: HTLCOutputInCommitment) -> Self { - let weight = if htlc.offered { WEIGHT_REVOKED_OFFERED_HTLC } else { WEIGHT_REVOKED_RECEIVED_HTLC }; + pub(crate) fn build(per_commitment_point: PublicKey, counterparty_delayed_payment_base_key: PublicKey, counterparty_htlc_base_key: PublicKey, per_commitment_key: SecretKey, amount: u64, htlc: HTLCOutputInCommitment, opt_anchors: bool) -> Self { + let weight = if htlc.offered { weight_revoked_offered_htlc(opt_anchors) } else { weight_revoked_received_htlc(opt_anchors) }; RevokedHTLCOutput { per_commitment_point, counterparty_delayed_payment_base_key, @@ -131,14 +153,14 @@ impl RevokedHTLCOutput { } 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), -}, {}, {}); + (0, per_commitment_point, required), + (2, counterparty_delayed_payment_base_key, required), + (4, counterparty_htlc_base_key, required), + (6, per_commitment_key, required), + (8, weight, required), + (10, amount, required), + (12, htlc, required), +}); /// A struct to describe a HTLC output on a counterparty commitment transaction. /// @@ -168,12 +190,12 @@ impl CounterpartyOfferedHTLCOutput { } impl_writeable_tlv_based!(CounterpartyOfferedHTLCOutput, { - (0, per_commitment_point), - (2, counterparty_delayed_payment_base_key), - (4, counterparty_htlc_base_key), - (6, preimage), - (8, htlc), -}, {}, {}); + (0, per_commitment_point, required), + (2, counterparty_delayed_payment_base_key, required), + (4, counterparty_htlc_base_key, required), + (6, preimage, required), + (8, htlc, required), +}); /// A struct to describe a HTLC output on a counterparty commitment transaction. /// @@ -199,11 +221,11 @@ impl CounterpartyReceivedHTLCOutput { } impl_writeable_tlv_based!(CounterpartyReceivedHTLCOutput, { - (0, per_commitment_point), - (2, counterparty_delayed_payment_base_key), - (4, counterparty_htlc_base_key), - (6, htlc), -}, {}, {}); + (0, per_commitment_point, required), + (2, counterparty_delayed_payment_base_key, required), + (4, counterparty_htlc_base_key, required), + (6, htlc, required), +}); /// A struct to describe a HTLC output on holder commitment transaction. /// @@ -236,11 +258,10 @@ impl HolderHTLCOutput { } impl_writeable_tlv_based!(HolderHTLCOutput, { - (0, amount), - (2, cltv_expiry), -}, { - (4, preimage), -}, {}); + (0, amount, required), + (2, cltv_expiry, required), + (4, preimage, option) +}); /// A struct to describe the channel output on the funding transaction. /// @@ -259,8 +280,8 @@ impl HolderFundingOutput { } impl_writeable_tlv_based!(HolderFundingOutput, { - (0, funding_redeemscript), -}, {}, {}); + (0, funding_redeemscript, required), +}); /// A wrapper encapsulating all in-protocol differing outputs types. /// @@ -291,12 +312,12 @@ impl PackageSolvingData { }; amt } - fn weight(&self) -> usize { + fn weight(&self, opt_anchors: bool) -> usize { let weight = match self { PackageSolvingData::RevokedOutput(ref outp) => { outp.weight as usize }, PackageSolvingData::RevokedHTLCOutput(ref outp) => { outp.weight as usize }, - PackageSolvingData::CounterpartyOfferedHTLCOutput(..) => { WEIGHT_OFFERED_HTLC as usize }, - PackageSolvingData::CounterpartyReceivedHTLCOutput(..) => { WEIGHT_RECEIVED_HTLC as usize }, + PackageSolvingData::CounterpartyOfferedHTLCOutput(..) => { weight_offered_htlc(opt_anchors) as usize }, + PackageSolvingData::CounterpartyReceivedHTLCOutput(..) => { weight_received_htlc(opt_anchors) as usize }, // 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. @@ -340,7 +361,7 @@ impl PackageSolvingData { }, PackageSolvingData::RevokedHTLCOutput(ref outp) => { if let Ok(chan_keys) = TxCreationKeys::derive_new(&onchain_handler.secp_ctx, &outp.per_commitment_point, &outp.counterparty_delayed_payment_base_key, &outp.counterparty_htlc_base_key, &onchain_handler.signer.pubkeys().revocation_basepoint, &onchain_handler.signer.pubkeys().htlc_basepoint) { - let witness_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&outp.htlc, &chan_keys.broadcaster_htlc_key, &chan_keys.countersignatory_htlc_key, &chan_keys.revocation_key); + let witness_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&outp.htlc, onchain_handler.opt_anchors(), &chan_keys.broadcaster_htlc_key, &chan_keys.countersignatory_htlc_key, &chan_keys.revocation_key); //TODO: should we panic on signer failure ? if let Ok(sig) = onchain_handler.signer.sign_justice_revoked_htlc(&bumped_tx, i, outp.amount, &outp.per_commitment_key, &outp.htlc, &onchain_handler.secp_ctx) { bumped_tx.input[i].witness.push(sig.serialize_der().to_vec()); @@ -352,7 +373,7 @@ impl PackageSolvingData { }, PackageSolvingData::CounterpartyOfferedHTLCOutput(ref outp) => { if let Ok(chan_keys) = TxCreationKeys::derive_new(&onchain_handler.secp_ctx, &outp.per_commitment_point, &outp.counterparty_delayed_payment_base_key, &outp.counterparty_htlc_base_key, &onchain_handler.signer.pubkeys().revocation_basepoint, &onchain_handler.signer.pubkeys().htlc_basepoint) { - let witness_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&outp.htlc, &chan_keys.broadcaster_htlc_key, &chan_keys.countersignatory_htlc_key, &chan_keys.revocation_key); + let witness_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&outp.htlc, onchain_handler.opt_anchors(), &chan_keys.broadcaster_htlc_key, &chan_keys.countersignatory_htlc_key, &chan_keys.revocation_key); if let Ok(sig) = onchain_handler.signer.sign_counterparty_htlc_transaction(&bumped_tx, i, &outp.htlc.amount_msat / 1000, &outp.per_commitment_point, &outp.htlc, &onchain_handler.secp_ctx) { bumped_tx.input[i].witness.push(sig.serialize_der().to_vec()); @@ -364,7 +385,7 @@ impl PackageSolvingData { }, PackageSolvingData::CounterpartyReceivedHTLCOutput(ref outp) => { if let Ok(chan_keys) = TxCreationKeys::derive_new(&onchain_handler.secp_ctx, &outp.per_commitment_point, &outp.counterparty_delayed_payment_base_key, &outp.counterparty_htlc_base_key, &onchain_handler.signer.pubkeys().revocation_basepoint, &onchain_handler.signer.pubkeys().htlc_basepoint) { - let witness_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&outp.htlc, &chan_keys.broadcaster_htlc_key, &chan_keys.countersignatory_htlc_key, &chan_keys.revocation_key); + let witness_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&outp.htlc, onchain_handler.opt_anchors(), &chan_keys.broadcaster_htlc_key, &chan_keys.countersignatory_htlc_key, &chan_keys.revocation_key); bumped_tx.lock_time = outp.htlc.cltv_expiry; // Right now we don't aggregate time-locked transaction, if we do we should set lock_time before to avoid breaking hash computation if let Ok(sig) = onchain_handler.signer.sign_counterparty_htlc_transaction(&bumped_tx, i, &outp.htlc.amount_msat / 1000, &outp.per_commitment_point, &outp.htlc, &onchain_handler.secp_ctx) { @@ -396,73 +417,22 @@ impl PackageSolvingData { 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::CounterpartyReceivedHTLCOutput(ref outp) => cmp::max(outp.htlc.cltv_expiry, output_conf_height + 1), + PackageSolvingData::HolderHTLCOutput(ref outp) => cmp::max(outp.cltv_expiry, output_conf_height + 1), PackageSolvingData::HolderFundingOutput(_) => output_conf_height + 1, }; absolute_timelock } } -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) - }; - Ok(solving_data) - } -} +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 @@ -617,13 +587,13 @@ impl PackageTemplate { 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 { + pub(crate) fn package_weight(&self, destination_script: &Script, opt_anchors: bool) -> usize { let mut inputs_weight = 0; let mut witnesses_weight = 2; // count segwit flags for (_, outp) in self.inputs.iter() { // previous_out_point: 36 bytes ; var_int: 1 byte ; sequence: 4 bytes inputs_weight += 41 * WITNESS_SCALE_FACTOR; - witnesses_weight += outp.weight(); + witnesses_weight += outp.weight(opt_anchors); } // version: 4 bytes ; count_tx_in: 1 byte ; count_tx_out: 1 byte ; lock_time: 4 bytes let transaction_weight = 10 * WITNESS_SCALE_FACTOR; @@ -654,18 +624,18 @@ impl PackageTemplate { }); } for (i, (outpoint, out)) in self.inputs.iter().enumerate() { - log_trace!(logger, "Adding claiming input for outpoint {}:{}", outpoint.txid, outpoint.vout); + log_debug!(logger, "Adding claiming input for outpoint {}:{}", outpoint.txid, outpoint.vout); if !out.finalize_input(&mut bumped_tx, i, onchain_handler) { return None; } } - log_trace!(logger, "Finalized transaction {} ready to broadcast", bumped_tx.txid()); + log_debug!(logger, "Finalized transaction {} ready to broadcast", bumped_tx.txid()); 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); - log_trace!(logger, "Finalized transaction {} ready to broadcast", final_tx.txid()); + log_debug!(logger, "Adding claiming input for outpoint {}:{}", outpoint.txid, outpoint.vout); + log_debug!(logger, "Finalized transaction {} ready to broadcast", final_tx.txid()); return Some(final_tx); } return None; @@ -686,26 +656,25 @@ 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, fee_estimator: &F, logger: &L) -> Option<(u64, u64)> + + /// Returns value in satoshis to be included as package outgoing output amount and feerate + /// which was used to generate the value. Will not return less than `dust_limit_sats` for the + /// value. + pub(crate) fn compute_package_output(&self, predicted_weight: usize, dust_limit_sats: u64, 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(); + assert!(dust_limit_sats as i64 > 0, "Output script must be broadcastable/have a 'real' dust limit."); // 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) { - // If new computed fee is superior at the whole claimable amount burn all in fees - if new_fee > input_amounts { - return Some((0, feerate)); - } else { - return Some((input_amounts - new_fee, feerate)); - } + return Some((cmp::max(input_amounts as i64 - new_fee as i64, dust_limit_sats as i64) as u64, feerate)); } } else { if let Some((new_fee, feerate)) = compute_fee_from_spent_amounts(input_amounts, predicted_weight, fee_estimator, logger) { - return Some((input_amounts - new_fee, feerate)); + return Some((cmp::max(input_amounts as i64 - new_fee as i64, dust_limit_sats as i64) as u64, feerate)); } } None @@ -734,23 +703,24 @@ impl PackageTemplate { } impl Writeable for PackageTemplate { - fn write(&self, writer: &mut W) -> Result<(), ::std::io::Error> { + fn write(&self, writer: &mut W) -> Result<(), io::Error> { writer.write_all(&byte_utils::be64_to_array(self.inputs.len() as u64))?; for (ref outpoint, ref rev_outp) in self.inputs.iter() { outpoint.write(writer)?; rev_outp.write(writer)?; } write_tlv_fields!(writer, { - (0, self.soonest_conf_deadline), - (2, self.feerate_previous), - (4, self.height_original), - }, { (6, self.height_timer) }); + (0, self.soonest_conf_deadline, required), + (2, self.feerate_previous, required), + (4, self.height_original, required), + (6, self.height_timer, option) + }); Ok(()) } } impl Readable for PackageTemplate { - fn read(reader: &mut R) -> Result { + fn read(reader: &mut R) -> Result { let inputs_count = ::read(reader)?; let mut inputs: Vec<(BitcoinOutPoint, PackageSolvingData)> = Vec::with_capacity(cmp::min(inputs_count as usize, MAX_ALLOC_SIZE / 128)); for _ in 0..inputs_count { @@ -773,10 +743,11 @@ impl Readable for PackageTemplate { 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) }); + (0, soonest_conf_deadline, required), + (2, feerate_previous, required), + (4, height_original, required), + (6, height_timer, option), + }); Ok(PackageTemplate { inputs, malleability, @@ -845,13 +816,13 @@ fn feerate_bump(predicted_weight: usize, input_amounts: u64, // ...else just increase the previous feerate by 25% (because that's a nice number) let new_fee = previous_feerate * (predicted_weight as u64) / 750; if input_amounts <= new_fee { - log_trace!(logger, "Can't 25% bump new claiming tx, amount {} is too small", input_amounts); + log_warn!(logger, "Can't 25% bump new claiming tx, amount {} is too small", input_amounts); return None; } new_fee } } else { - log_trace!(logger, "Can't new-estimation bump new claiming tx, amount {} is too small", input_amounts); + log_warn!(logger, "Can't new-estimation bump new claiming tx, amount {} is too small", input_amounts); return None; }; @@ -870,7 +841,7 @@ fn feerate_bump(predicted_weight: usize, input_amounts: u64, #[cfg(test)] mod tests { - use chain::package::{CounterpartyReceivedHTLCOutput, HolderHTLCOutput, PackageTemplate, PackageSolvingData, RevokedOutput, WEIGHT_REVOKED_OUTPUT}; + use chain::package::{CounterpartyOfferedHTLCOutput, CounterpartyReceivedHTLCOutput, HolderHTLCOutput, PackageTemplate, PackageSolvingData, RevokedOutput, WEIGHT_REVOKED_OUTPUT, weight_offered_htlc, weight_received_htlc}; use chain::Txid; use ln::chan_utils::HTLCOutputInCommitment; use ln::{PaymentPreimage, PaymentHash}; @@ -906,6 +877,19 @@ mod tests { } } + macro_rules! dumb_counterparty_offered_output { + ($secp_ctx: expr, $amt: expr) => { + { + let dumb_scalar = SecretKey::from_slice(&hex::decode("0101010101010101010101010101010101010101010101010101010101010101").unwrap()[..]).unwrap(); + let dumb_point = PublicKey::from_secret_key(&$secp_ctx, &dumb_scalar); + let hash = PaymentHash([1; 32]); + let preimage = PaymentPreimage([2;32]); + let htlc = HTLCOutputInCommitment { offered: false, amount_msat: $amt, cltv_expiry: 1000, payment_hash: hash, transaction_output_index: None }; + PackageSolvingData::CounterpartyOfferedHTLCOutput(CounterpartyOfferedHTLCOutput::build(dumb_point, dumb_point, dumb_point, preimage, htlc)) + } + } + } + macro_rules! dumb_htlc_output { () => { { @@ -1070,11 +1054,32 @@ mod tests { fn test_package_weight() { let txid = Txid::from_hex("c2d4449afa8d26140898dd54d3390b057ba2a5afcf03ba29d7dc0d8b9ffe966e").unwrap(); let secp_ctx = Secp256k1::new(); - let revk_outp = dumb_revk_output!(secp_ctx); - let package = PackageTemplate::build_package(txid, 0, revk_outp, 0, true, 100); - // (nVersion (4) + nLocktime (4) + count_tx_in (1) + prevout (36) + sequence (4) + script_length (1) + count_tx_out (1) + value (8) + var_int (1)) * WITNESS_SCALE_FACTOR - // + witness marker (2) + WEIGHT_REVOKED_OUTPUT - assert_eq!(package.package_weight(&Script::new()), (4 + 4 + 1 + 36 + 4 + 1 + 1 + 8 + 1) * WITNESS_SCALE_FACTOR + 2 + WEIGHT_REVOKED_OUTPUT as usize); + // (nVersion (4) + nLocktime (4) + count_tx_in (1) + prevout (36) + sequence (4) + script_length (1) + count_tx_out (1) + value (8) + var_int (1)) * WITNESS_SCALE_FACTOR + witness marker (2) + let weight_sans_output = (4 + 4 + 1 + 36 + 4 + 1 + 1 + 8 + 1) * WITNESS_SCALE_FACTOR + 2; + + { + let revk_outp = dumb_revk_output!(secp_ctx); + let package = PackageTemplate::build_package(txid, 0, revk_outp, 0, true, 100); + for &opt_anchors in [false, true].iter() { + assert_eq!(package.package_weight(&Script::new(), opt_anchors), weight_sans_output + WEIGHT_REVOKED_OUTPUT as usize); + } + } + + { + let counterparty_outp = dumb_counterparty_output!(secp_ctx, 1_000_000); + let package = PackageTemplate::build_package(txid, 0, counterparty_outp, 1000, true, 100); + for &opt_anchors in [false, true].iter() { + assert_eq!(package.package_weight(&Script::new(), opt_anchors), weight_sans_output + weight_received_htlc(opt_anchors) as usize); + } + } + + { + let counterparty_outp = dumb_counterparty_offered_output!(secp_ctx, 1_000_000); + let package = PackageTemplate::build_package(txid, 0, counterparty_outp, 1000, true, 100); + for &opt_anchors in [false, true].iter() { + assert_eq!(package.package_weight(&Script::new(), opt_anchors), weight_sans_output + weight_offered_htlc(opt_anchors) as usize); + } + } } }