use ln::PaymentPreimage;
use ln::chan_utils;
use ln::chan_utils::{TxCreationKeys, ChannelTransactionParameters, HolderCommitmentTransaction};
+use ln::package::InputDescriptors;
+use ln::package;
use chain::chaininterface::{FeeEstimator, BroadcasterInterface, ConfirmationTarget, MIN_RELAY_FEE_SAT_PER_1000_WEIGHT};
use chain::channelmonitor::{ANTI_REORG_DELAY, CLTV_SHARED_CLAIM_BUFFER, InputMaterial, ClaimRequest};
use chain::keysinterface::{Sign, KeysInterface};
use util::byte_utils;
use std::collections::HashMap;
-use std::cmp;
-use std::ops::Deref;
-use std::mem::replace;
+use core::cmp;
+use core::ops::Deref;
+use core::mem::replace;
const MAX_ALLOC_SIZE: usize = 64*1024;
}
}
-#[derive(PartialEq, Clone, Copy)]
-pub(crate) enum InputDescriptors {
- RevokedOfferedHTLC,
- RevokedReceivedHTLC,
- OfferedHTLC,
- ReceivedHTLC,
- RevokedOutput, // either a revoked to_holder output on commitment tx, a revoked HTLC-Timeout output or a revoked HTLC-Success output
-}
-
-impl Writeable for InputDescriptors {
- fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ::std::io::Error> {
- match self {
- &InputDescriptors::RevokedOfferedHTLC => {
- writer.write_all(&[0; 1])?;
- },
- &InputDescriptors::RevokedReceivedHTLC => {
- writer.write_all(&[1; 1])?;
- },
- &InputDescriptors::OfferedHTLC => {
- writer.write_all(&[2; 1])?;
- },
- &InputDescriptors::ReceivedHTLC => {
- writer.write_all(&[3; 1])?;
- }
- &InputDescriptors::RevokedOutput => {
- writer.write_all(&[4; 1])?;
- }
- }
- Ok(())
- }
-}
-
-impl Readable for InputDescriptors {
- fn read<R: ::std::io::Read>(reader: &mut R) -> Result<Self, DecodeError> {
- let input_descriptor = match <u8 as Readable>::read(reader)? {
- 0 => {
- InputDescriptors::RevokedOfferedHTLC
- },
- 1 => {
- InputDescriptors::RevokedReceivedHTLC
- },
- 2 => {
- InputDescriptors::OfferedHTLC
- },
- 3 => {
- InputDescriptors::ReceivedHTLC
- },
- 4 => {
- InputDescriptors::RevokedOutput
- }
- _ => return Err(DecodeError::InvalidValue),
- };
- Ok(input_descriptor)
- }
-}
-
macro_rules! subtract_high_prio_fee {
($logger: ident, $fee_estimator: expr, $value: expr, $predicted_weight: expr, $used_feerate: expr) => {
{
0u8 => Ok(None),
1u8 => {
let vlen: u64 = Readable::read(reader)?;
- let mut ret = Vec::with_capacity(cmp::min(vlen as usize, MAX_ALLOC_SIZE / ::std::mem::size_of::<Option<(usize, Signature)>>()));
+ let mut ret = Vec::with_capacity(cmp::min(vlen as usize, MAX_ALLOC_SIZE / ::core::mem::size_of::<Option<(usize, Signature)>>()));
for _ in 0..vlen {
ret.push(match Readable::read(reader)? {
0u8 => None,
prev_holder_commitment: Option<HolderCommitmentTransaction>,
prev_holder_htlc_sigs: Option<Vec<Option<(usize, Signature)>>>,
- signer: ChannelSigner,
+ pub(super) signer: ChannelSigner,
pub(crate) channel_transaction_parameters: ChannelTransactionParameters,
// Used to track claiming requests. If claim tx doesn't confirm before height timer expiration we need to bump
latest_height: u32,
- secp_ctx: Secp256k1<secp256k1::All>,
+ pub(super) secp_ctx: Secp256k1<secp256k1::All>,
}
+const SERIALIZATION_VERSION: u8 = 1;
+const MIN_SERIALIZATION_VERSION: u8 = 1;
+
impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
pub(crate) fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ::std::io::Error> {
+ write_ver_prefix!(writer, SERIALIZATION_VERSION, MIN_SERIALIZATION_VERSION);
+
self.destination_script.write(writer)?;
self.holder_commitment.write(writer)?;
self.holder_htlc_sigs.write(writer)?;
let mut key_data = VecWriter(Vec::new());
self.signer.write(&mut key_data)?;
- assert!(key_data.0.len() < std::usize::MAX);
- assert!(key_data.0.len() < std::u32::MAX as usize);
+ assert!(key_data.0.len() < core::usize::MAX);
+ assert!(key_data.0.len() < core::u32::MAX as usize);
(key_data.0.len() as u32).write(writer)?;
writer.write_all(&key_data.0[..])?;
}
}
self.latest_height.write(writer)?;
+
+ write_tlv_fields!(writer, {}, {});
Ok(())
}
}
impl<'a, K: KeysInterface> ReadableArgs<&'a K> for OnchainTxHandler<K::Signer> {
fn read<R: ::std::io::Read>(reader: &mut R, keys_manager: &'a K) -> Result<Self, DecodeError> {
+ let _ver = read_ver_prefix!(reader, SERIALIZATION_VERSION);
+
let destination_script = Readable::read(reader)?;
let holder_commitment = Readable::read(reader)?;
}
let latest_height = Readable::read(reader)?;
+ read_tlv_fields!(reader, {}, {});
+
let mut secp_ctx = Secp256k1::new();
secp_ctx.seeded_randomize(&keys_manager.get_secure_random_bytes());
}
}
- pub(crate) fn get_witnesses_weight(inputs: &[InputDescriptors]) -> usize {
- let mut tx_weight = 2; // count segwit flags
- for inp in inputs {
- // We use expected weight (and not actual) as signatures and time lock delays may vary
- tx_weight += match inp {
- // number_of_witness_elements + sig_length + revocation_sig + pubkey_length + revocationpubkey + witness_script_length + witness_script
- &InputDescriptors::RevokedOfferedHTLC => {
- 1 + 1 + 73 + 1 + 33 + 1 + 133
- },
- // number_of_witness_elements + sig_length + revocation_sig + pubkey_length + revocationpubkey + witness_script_length + witness_script
- &InputDescriptors::RevokedReceivedHTLC => {
- 1 + 1 + 73 + 1 + 33 + 1 + 139
- },
- // number_of_witness_elements + sig_length + counterpartyhtlc_sig + preimage_length + preimage + witness_script_length + witness_script
- &InputDescriptors::OfferedHTLC => {
- 1 + 1 + 73 + 1 + 32 + 1 + 133
- },
- // number_of_witness_elements + sig_length + revocation_sig + pubkey_length + revocationpubkey + witness_script_length + witness_script
- &InputDescriptors::ReceivedHTLC => {
- 1 + 1 + 73 + 1 + 1 + 1 + 139
- },
- // number_of_witness_elements + sig_length + revocation_sig + true_length + op_true + witness_script_length + witness_script
- &InputDescriptors::RevokedOutput => {
- 1 + 1 + 73 + 1 + 1 + 1 + 77
- },
- };
- }
- tx_weight
- }
-
/// In LN, output claimed are time-sensitive, which means we have to spend them before reaching some timelock expiration. At in-channel
/// output detection, we generate a first version of a claim tx and associate to it a height timer. A height timer is an absolute block
/// height than once reached we should generate a new bumped "version" of the claim tx to be sure than we safely claim outputs before
for per_outp_material in cached_claim_datas.per_input_material.values() {
match per_outp_material {
&InputMaterial::Revoked { ref input_descriptor, ref amount, .. } => {
- inputs_witnesses_weight += Self::get_witnesses_weight(&[*input_descriptor]);
+ inputs_witnesses_weight += package::get_witnesses_weight(&[*input_descriptor]);
amt += *amount;
},
&InputMaterial::CounterpartyHTLC { ref preimage, ref htlc, .. } => {
- inputs_witnesses_weight += Self::get_witnesses_weight(if preimage.is_some() { &[InputDescriptors::OfferedHTLC] } else { &[InputDescriptors::ReceivedHTLC] });
+ inputs_witnesses_weight += package::get_witnesses_weight(if preimage.is_some() { &[InputDescriptors::OfferedHTLC] } else { &[InputDescriptors::ReceivedHTLC] });
amt += htlc.amount_msat / 1000;
},
&InputMaterial::HolderHTLC { .. } => {
chan_utils::get_revokeable_redeemscript(&tx_keys.revocation_key, *on_counterparty_tx_csv, &tx_keys.broadcaster_delayed_payment_key)
};
- let sig = self.signer.sign_justice_transaction(&bumped_tx, i, *amount, &per_commitment_key, htlc, &self.secp_ctx).expect("sign justice tx");
+ let sig = if let Some(ref htlc) = *htlc {
+ self.signer.sign_justice_revoked_htlc(&bumped_tx, i, *amount, &per_commitment_key, &htlc, &self.secp_ctx).expect("sign justice tx")
+ } else {
+ self.signer.sign_justice_revoked_output(&bumped_tx, i, *amount, &per_commitment_key, &self.secp_ctx).expect("sign justice tx")
+ };
bumped_tx.input[i].witness.push(sig.serialize_der().to_vec());
bumped_tx.input[i].witness[0].push(SigHashType::All as u8);
if htlc.is_some() {
log_trace!(logger, "Updating claims view at height {} with {} matched transactions and {} claim requests", height, txn_matched.len(), claimable_outpoints.len());
let mut new_claims = Vec::new();
let mut aggregated_claim = HashMap::new();
- let mut aggregated_soonest = ::std::u32::MAX;
+ let mut aggregated_soonest = ::core::u32::MAX;
// Try to aggregate outputs if their timelock expiration isn't imminent (absolute_timelock
// <= CLTV_SHARED_CLAIM_BUFFER) and they don't require an immediate nLockTime (aggregable).
self.claimable_outpoints.insert(k.clone(), (txid, height));
}
self.pending_claim_requests.insert(txid, claim_material);
- log_trace!(logger, "Broadcast onchain {}", log_tx!(tx));
+ log_info!(logger, "Broadcasting onchain {}", log_tx!(tx));
broadcaster.broadcast_transaction(&tx);
}
}
log_trace!(logger, "Bumping {} candidates", bump_candidates.len());
for (first_claim_txid, claim_material) in bump_candidates.iter() {
if let Some((new_timer, new_feerate, bump_tx)) = self.generate_claim_tx(height, &claim_material, &*fee_estimator, &*logger) {
- log_trace!(logger, "Broadcast onchain {}", log_tx!(bump_tx));
+ log_info!(logger, "Broadcasting onchain {}", log_tx!(bump_tx));
broadcaster.broadcast_transaction(&bump_tx);
if let Some(claim_material) = self.pending_claim_requests.get_mut(first_claim_txid) {
claim_material.height_timer = new_timer;
if let Some((new_timer, new_feerate, bump_tx)) = self.generate_claim_tx(height, &claim_material, &&*fee_estimator, &&*logger) {
claim_material.height_timer = new_timer;
claim_material.feerate_previous = new_feerate;
+ log_info!(logger, "Broadcasting onchain {}", log_tx!(bump_tx));
broadcaster.broadcast_transaction(&bump_tx);
}
}