use chain::package::{CounterpartyOfferedHTLCOutput, CounterpartyReceivedHTLCOutput, HolderFundingOutput, HolderHTLCOutput, PackageSolvingData, PackageTemplate, RevokedOutput, RevokedHTLCOutput};
use chain::Filter;
use util::logger::Logger;
-use util::ser::{Readable, ReadableArgs, MaybeReadable, Writer, Writeable, U48};
+use util::ser::{Readable, ReadableArgs, MaybeReadable, Writer, Writeable, U48, OptionDeserWrapper};
use util::byte_utils;
use util::events::Event;
use prelude::*;
-use std::collections::{HashMap, HashSet};
use core::{cmp, mem};
use std::io::Error;
use core::ops::Deref;
impl Writeable for ChannelMonitorUpdate {
fn write<W: Writer>(&self, w: &mut W) -> Result<(), ::std::io::Error> {
+ write_ver_prefix!(w, SERIALIZATION_VERSION, MIN_SERIALIZATION_VERSION);
self.update_id.write(w)?;
(self.updates.len() as u64).write(w)?;
for update_step in self.updates.iter() {
update_step.write(w)?;
}
+ write_tlv_fields!(w, {});
Ok(())
}
}
impl Readable for ChannelMonitorUpdate {
fn read<R: ::std::io::Read>(r: &mut R) -> Result<Self, DecodeError> {
+ let _ver = read_ver_prefix!(r, SERIALIZATION_VERSION);
let update_id: u64 = Readable::read(r)?;
let len: u64 = Readable::read(r)?;
let mut updates = Vec::with_capacity(cmp::min(len as usize, MAX_ALLOC_SIZE / ::core::mem::size_of::<ChannelMonitorUpdateStep>()));
for _ in 0..len {
updates.push(Readable::read(r)?);
}
+ read_tlv_fields!(r, {});
Ok(Self { update_id, updates })
}
}
pub(crate) payment_preimage: Option<PaymentPreimage>,
pub(crate) source: HTLCSource
}
-impl_writeable!(HTLCUpdate, 0, { payment_hash, payment_preimage, source });
+impl_writeable_tlv_based!(HTLCUpdate, {
+ (0, payment_hash, required),
+ (2, source, required),
+ (4, payment_preimage, option),
+});
/// If an HTLC expires within this many blocks, don't try to claim it in a shared transaction,
/// instead claiming it in its own individual transaction.
feerate_per_kw: u32,
htlc_outputs: Vec<(HTLCOutputInCommitment, Option<Signature>, Option<HTLCSource>)>,
}
+impl_writeable_tlv_based!(HolderSignedTx, {
+ (0, txid, required),
+ (2, revocation_key, required),
+ (4, a_htlc_key, required),
+ (6, b_htlc_key, required),
+ (8, delayed_payment_key, required),
+ (10, per_commitment_point, required),
+ (12, feerate_per_kw, required),
+ (14, htlc_outputs, vec_type)
+});
/// We use this to track counterparty commitment transactions and htlcs outputs and
/// use it to generate any justice or 2nd-stage preimage/timeout transactions.
impl Writeable for CounterpartyCommitmentTransaction {
fn write<W: Writer>(&self, w: &mut W) -> Result<(), ::std::io::Error> {
- self.counterparty_delayed_payment_base_key.write(w)?;
- self.counterparty_htlc_base_key.write(w)?;
- w.write_all(&byte_utils::be16_to_array(self.on_counterparty_tx_csv))?;
w.write_all(&byte_utils::be64_to_array(self.per_htlc.len() as u64))?;
for (ref txid, ref htlcs) in self.per_htlc.iter() {
w.write_all(&txid[..])?;
htlc.write(w)?;
}
}
+ write_tlv_fields!(w, {
+ (0, self.counterparty_delayed_payment_base_key, required),
+ (2, self.counterparty_htlc_base_key, required),
+ (4, self.on_counterparty_tx_csv, required),
+ });
Ok(())
}
}
impl Readable for CounterpartyCommitmentTransaction {
fn read<R: ::std::io::Read>(r: &mut R) -> Result<Self, DecodeError> {
let counterparty_commitment_transaction = {
- let counterparty_delayed_payment_base_key = Readable::read(r)?;
- let counterparty_htlc_base_key = Readable::read(r)?;
- let on_counterparty_tx_csv: u16 = Readable::read(r)?;
let per_htlc_len: u64 = Readable::read(r)?;
let mut per_htlc = HashMap::with_capacity(cmp::min(per_htlc_len as usize, MAX_ALLOC_SIZE / 64));
for _ in 0..per_htlc_len {
return Err(DecodeError::InvalidValue);
}
}
+ let mut counterparty_delayed_payment_base_key = OptionDeserWrapper(None);
+ let mut counterparty_htlc_base_key = OptionDeserWrapper(None);
+ let mut on_counterparty_tx_csv: u16 = 0;
+ read_tlv_fields!(r, {
+ (0, counterparty_delayed_payment_base_key, required),
+ (2, counterparty_htlc_base_key, required),
+ (4, on_counterparty_tx_csv, required),
+ });
CounterpartyCommitmentTransaction {
- counterparty_delayed_payment_base_key,
- counterparty_htlc_base_key,
+ counterparty_delayed_payment_base_key: counterparty_delayed_payment_base_key.0.unwrap(),
+ counterparty_htlc_base_key: counterparty_htlc_base_key.0.unwrap(),
on_counterparty_tx_csv,
per_htlc,
}
impl OnchainEventEntry {
fn confirmation_threshold(&self) -> u32 {
- self.height + ANTI_REORG_DELAY - 1
+ let mut conf_threshold = self.height + ANTI_REORG_DELAY - 1;
+ if let OnchainEvent::MaturingOutput {
+ descriptor: SpendableOutputDescriptor::DelayedPaymentOutput(ref descriptor)
+ } = self.event {
+ // A CSV'd transaction is confirmable in block (input height) + CSV delay, which means
+ // it's broadcastable when we see the previous block.
+ conf_threshold = cmp::max(conf_threshold, self.height + descriptor.to_self_delay as u32 - 1);
+ }
+ conf_threshold
}
fn has_reached_confirmation_threshold(&self, height: u32) -> bool {
},
}
+impl_writeable_tlv_based!(OnchainEventEntry, {
+ (0, txid, required),
+ (2, height, required),
+ (4, event, required),
+});
+
+impl_writeable_tlv_based_enum!(OnchainEvent,
+ (0, HTLCUpdate) => {
+ (0, source, required),
+ (2, payment_hash, required),
+ },
+ (1, MaturingOutput) => {
+ (0, descriptor, required),
+ },
+;);
+
#[cfg_attr(any(test, feature = "fuzztarget", feature = "_test_utils"), derive(PartialEq))]
#[derive(Clone)]
pub(crate) enum ChannelMonitorUpdateStep {
},
}
-impl Writeable for ChannelMonitorUpdateStep {
- fn write<W: Writer>(&self, w: &mut W) -> Result<(), ::std::io::Error> {
- match self {
- &ChannelMonitorUpdateStep::LatestHolderCommitmentTXInfo { ref commitment_tx, ref htlc_outputs } => {
- 0u8.write(w)?;
- commitment_tx.write(w)?;
- (htlc_outputs.len() as u64).write(w)?;
- for &(ref output, ref signature, ref source) in htlc_outputs.iter() {
- output.write(w)?;
- signature.write(w)?;
- source.write(w)?;
- }
- }
- &ChannelMonitorUpdateStep::LatestCounterpartyCommitmentTXInfo { commitment_txid, ref htlc_outputs, ref commitment_number, ref their_revocation_point } => {
- 1u8.write(w)?;
- commitment_txid.write(w)?;
- commitment_number.write(w)?;
- their_revocation_point.write(w)?;
- (htlc_outputs.len() as u64).write(w)?;
- for &(ref output, ref source) in htlc_outputs.iter() {
- output.write(w)?;
- source.as_ref().map(|b| b.as_ref()).write(w)?;
- }
- },
- &ChannelMonitorUpdateStep::PaymentPreimage { ref payment_preimage } => {
- 2u8.write(w)?;
- payment_preimage.write(w)?;
- },
- &ChannelMonitorUpdateStep::CommitmentSecret { ref idx, ref secret } => {
- 3u8.write(w)?;
- idx.write(w)?;
- secret.write(w)?;
- },
- &ChannelMonitorUpdateStep::ChannelForceClosed { ref should_broadcast } => {
- 4u8.write(w)?;
- should_broadcast.write(w)?;
- },
- }
- Ok(())
- }
-}
-impl Readable for ChannelMonitorUpdateStep {
- fn read<R: ::std::io::Read>(r: &mut R) -> Result<Self, DecodeError> {
- match Readable::read(r)? {
- 0u8 => {
- Ok(ChannelMonitorUpdateStep::LatestHolderCommitmentTXInfo {
- commitment_tx: Readable::read(r)?,
- htlc_outputs: {
- let len: u64 = Readable::read(r)?;
- let mut res = Vec::new();
- for _ in 0..len {
- res.push((Readable::read(r)?, Readable::read(r)?, Readable::read(r)?));
- }
- res
- },
- })
- },
- 1u8 => {
- Ok(ChannelMonitorUpdateStep::LatestCounterpartyCommitmentTXInfo {
- commitment_txid: Readable::read(r)?,
- commitment_number: Readable::read(r)?,
- their_revocation_point: Readable::read(r)?,
- htlc_outputs: {
- let len: u64 = Readable::read(r)?;
- let mut res = Vec::new();
- for _ in 0..len {
- res.push((Readable::read(r)?, <Option<HTLCSource> as Readable>::read(r)?.map(|o| Box::new(o))));
- }
- res
- },
- })
- },
- 2u8 => {
- Ok(ChannelMonitorUpdateStep::PaymentPreimage {
- payment_preimage: Readable::read(r)?,
- })
- },
- 3u8 => {
- Ok(ChannelMonitorUpdateStep::CommitmentSecret {
- idx: Readable::read(r)?,
- secret: Readable::read(r)?,
- })
- },
- 4u8 => {
- Ok(ChannelMonitorUpdateStep::ChannelForceClosed {
- should_broadcast: Readable::read(r)?
- })
- },
- _ => Err(DecodeError::InvalidValue),
- }
- }
-}
+impl_writeable_tlv_based_enum!(ChannelMonitorUpdateStep,
+ (0, LatestHolderCommitmentTXInfo) => {
+ (0, commitment_tx, required),
+ (2, htlc_outputs, vec_type),
+ },
+ (1, LatestCounterpartyCommitmentTXInfo) => {
+ (0, commitment_txid, required),
+ (2, commitment_number, required),
+ (4, their_revocation_point, required),
+ (6, htlc_outputs, vec_type),
+ },
+ (2, PaymentPreimage) => {
+ (0, payment_preimage, required),
+ },
+ (3, CommitmentSecret) => {
+ (0, idx, required),
+ (2, secret, required),
+ },
+ (4, ChannelForceClosed) => {
+ (0, should_broadcast, required),
+ },
+;);
/// A ChannelMonitor handles chain events (blocks connected and disconnected) and generates
/// on-chain transactions to ensure no loss of funds occurs.
}
}
+// These are also used for ChannelMonitorUpdate, above.
const SERIALIZATION_VERSION: u8 = 1;
const MIN_SERIALIZATION_VERSION: u8 = 1;
writer.write_all(&byte_utils::be48_to_array(*commitment_number))?;
}
- macro_rules! serialize_holder_tx {
- ($holder_tx: expr) => {
- $holder_tx.txid.write(writer)?;
- writer.write_all(&$holder_tx.revocation_key.serialize())?;
- writer.write_all(&$holder_tx.a_htlc_key.serialize())?;
- writer.write_all(&$holder_tx.b_htlc_key.serialize())?;
- writer.write_all(&$holder_tx.delayed_payment_key.serialize())?;
- writer.write_all(&$holder_tx.per_commitment_point.serialize())?;
-
- writer.write_all(&byte_utils::be32_to_array($holder_tx.feerate_per_kw))?;
- writer.write_all(&byte_utils::be64_to_array($holder_tx.htlc_outputs.len() as u64))?;
- for &(ref htlc_output, ref sig, ref htlc_source) in $holder_tx.htlc_outputs.iter() {
- serialize_htlc_in_commitment!(htlc_output);
- if let &Some(ref their_sig) = sig {
- 1u8.write(writer)?;
- writer.write_all(&their_sig.serialize_compact())?;
- } else {
- 0u8.write(writer)?;
- }
- htlc_source.write(writer)?;
- }
- }
- }
-
if let Some(ref prev_holder_tx) = self.prev_holder_signed_commitment_tx {
writer.write_all(&[1; 1])?;
- serialize_holder_tx!(prev_holder_tx);
+ prev_holder_tx.write(writer)?;
} else {
writer.write_all(&[0; 1])?;
}
- serialize_holder_tx!(self.current_holder_commitment_tx);
+ self.current_holder_commitment_tx.write(writer)?;
writer.write_all(&byte_utils::be48_to_array(self.current_counterparty_commitment_number))?;
writer.write_all(&byte_utils::be48_to_array(self.current_holder_commitment_number))?;
writer.write_all(&byte_utils::be64_to_array(self.onchain_events_awaiting_threshold_conf.len() as u64))?;
for ref entry in self.onchain_events_awaiting_threshold_conf.iter() {
- entry.txid.write(writer)?;
- writer.write_all(&byte_utils::be32_to_array(entry.height))?;
- match entry.event {
- OnchainEvent::HTLCUpdate { ref source, ref payment_hash } => {
- 0u8.write(writer)?;
- source.write(writer)?;
- payment_hash.write(writer)?;
- },
- OnchainEvent::MaturingOutput { ref descriptor } => {
- 1u8.write(writer)?;
- descriptor.write(writer)?;
- },
- }
+ entry.write(writer)?;
}
(self.outputs_to_watch.len() as u64).write(writer)?;
self.lockdown_from_offchain.write(writer)?;
self.holder_tx_signed.write(writer)?;
- write_tlv_fields!(writer, {}, {});
+ write_tlv_fields!(writer, {});
Ok(())
}
// Last, track onchain revoked commitment transaction and fail backward outgoing HTLCs as payment path is broken
if !claimable_outpoints.is_empty() || per_commitment_option.is_some() { // ie we're confident this is actually ours
// We're definitely a counterparty commitment transaction!
- log_trace!(logger, "Got broadcast of revoked counterparty commitment transaction, going to generate general spend tx with {} inputs", claimable_outpoints.len());
+ log_error!(logger, "Got broadcast of revoked counterparty commitment transaction, going to generate general spend tx with {} inputs", claimable_outpoints.len());
for (idx, outp) in tx.output.iter().enumerate() {
watch_outputs.push((idx as u32, outp.clone()));
}
}
self.counterparty_commitment_txn_on_chain.insert(commitment_txid, commitment_number);
- log_trace!(logger, "Got broadcast of non-revoked counterparty commitment transaction {}", commitment_txid);
+ log_info!(logger, "Got broadcast of non-revoked counterparty commitment transaction {}", commitment_txid);
macro_rules! check_htlc_fails {
($txid: expr, $commitment_tx: expr, $id: tt) => {
let per_commitment_key = ignore_error!(SecretKey::from_slice(&secret));
let per_commitment_point = PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_key);
- log_trace!(logger, "Counterparty HTLC broadcast {}:{}", htlc_txid, 0);
+ log_error!(logger, "Got broadcast of revoked counterparty HTLC transaction, spending {}:{}", htlc_txid, 0);
let revk_outp = RevokedOutput::build(per_commitment_point, self.counterparty_tx_cache.counterparty_delayed_payment_base_key, self.counterparty_tx_cache.counterparty_htlc_base_key, per_commitment_key, tx.output[0].value, self.counterparty_tx_cache.on_counterparty_tx_csv);
let justice_package = PackageTemplate::build_package(htlc_txid, 0, PackageSolvingData::RevokedOutput(revk_outp), height + self.counterparty_tx_cache.on_counterparty_tx_csv as u32, true, height);
let claimable_outpoints = vec!(justice_package);
if self.current_holder_commitment_tx.txid == commitment_txid {
is_holder_tx = true;
- log_trace!(logger, "Got latest holder commitment tx broadcast, searching for available HTLCs to claim");
+ log_info!(logger, "Got broadcast of latest holder commitment tx {}, searching for available HTLCs to claim", commitment_txid);
let res = self.get_broadcasted_holder_claims(&self.current_holder_commitment_tx, height);
let mut to_watch = self.get_broadcasted_holder_watch_outputs(&self.current_holder_commitment_tx, tx);
append_onchain_update!(res, to_watch);
} else if let &Some(ref holder_tx) = &self.prev_holder_signed_commitment_tx {
if holder_tx.txid == commitment_txid {
is_holder_tx = true;
- log_trace!(logger, "Got previous holder commitment tx broadcast, searching for available HTLCs to claim");
+ log_info!(logger, "Got broadcast of previous holder commitment tx {}, searching for available HTLCs to claim", commitment_txid);
let res = self.get_broadcasted_holder_claims(holder_tx, height);
let mut to_watch = self.get_broadcasted_holder_watch_outputs(holder_tx, tx);
append_onchain_update!(res, to_watch);
}
pub fn get_latest_holder_commitment_txn<L: Deref>(&mut self, logger: &L) -> Vec<Transaction> where L::Target: Logger {
- log_trace!(logger, "Getting signed latest holder commitment transaction!");
+ log_debug!(logger, "Getting signed latest holder commitment transaction!");
self.holder_tx_signed = true;
let commitment_tx = self.onchain_tx_handler.get_fully_signed_holder_tx(&self.funding_redeemscript);
let txid = commitment_tx.txid();
#[cfg(any(test,feature = "unsafe_revoked_tx_signing"))]
/// Note that this includes possibly-locktimed-in-the-future transactions!
fn unsafe_get_latest_holder_commitment_txn<L: Deref>(&mut self, logger: &L) -> Vec<Transaction> where L::Target: Logger {
- log_trace!(logger, "Getting signed copy of latest holder commitment transaction!");
+ log_debug!(logger, "Getting signed copy of latest holder commitment transaction!");
let commitment_tx = self.onchain_tx_handler.get_fully_signed_copy_holder_tx(&self.funding_redeemscript);
let txid = commitment_tx.txid();
let mut holder_transactions = vec![commitment_tx];
matured_htlcs.push(source.clone());
}
- log_trace!(logger, "HTLC {} failure update has got enough confirmations to be passed upstream", log_bytes!(payment_hash.0));
+ log_debug!(logger, "HTLC {} failure update has got enough confirmations to be passed upstream", log_bytes!(payment_hash.0));
self.pending_monitor_events.push(MonitorEvent::HTLCEvent(HTLCUpdate {
payment_hash: payment_hash,
payment_preimage: None,
}));
},
OnchainEvent::MaturingOutput { descriptor } => {
- log_trace!(logger, "Descriptor {} has got enough confirmations to be passed upstream", log_spendable!(descriptor));
+ log_debug!(logger, "Descriptor {} has got enough confirmations to be passed upstream", log_spendable!(descriptor));
self.pending_events.push(Event::SpendableOutputs {
outputs: vec![descriptor]
});
height,
event: OnchainEvent::HTLCUpdate { source: source, payment_hash: payment_hash },
};
- log_info!(logger, "Failing HTLC with payment_hash {} timeout by a spend tx, waiting for confirmation (at height{})", log_bytes!(payment_hash.0), entry.confirmation_threshold());
+ log_info!(logger, "Failing HTLC with payment_hash {} timeout by a spend tx, waiting for confirmation (at height {})", log_bytes!(payment_hash.0), entry.confirmation_threshold());
self.onchain_events_awaiting_threshold_conf.push(entry);
}
}
height: height,
event: OnchainEvent::MaturingOutput { descriptor: spendable_output.clone() },
};
- log_trace!(logger, "Maturing {} until {}", log_spendable!(spendable_output), entry.confirmation_threshold());
+ log_info!(logger, "Received spendable output {}, spendable at height {}", log_spendable!(spendable_output), entry.confirmation_threshold());
self.onchain_events_awaiting_threshold_conf.push(entry);
}
}
}
}
- macro_rules! read_holder_tx {
- () => {
- {
- let txid = Readable::read(reader)?;
- let revocation_key = Readable::read(reader)?;
- let a_htlc_key = Readable::read(reader)?;
- let b_htlc_key = Readable::read(reader)?;
- let delayed_payment_key = Readable::read(reader)?;
- let per_commitment_point = Readable::read(reader)?;
- let feerate_per_kw: u32 = Readable::read(reader)?;
-
- let htlcs_len: u64 = Readable::read(reader)?;
- let mut htlcs = Vec::with_capacity(cmp::min(htlcs_len as usize, MAX_ALLOC_SIZE / 128));
- for _ in 0..htlcs_len {
- let htlc = read_htlc_in_commitment!();
- let sigs = match <u8 as Readable>::read(reader)? {
- 0 => None,
- 1 => Some(Readable::read(reader)?),
- _ => return Err(DecodeError::InvalidValue),
- };
- htlcs.push((htlc, sigs, Readable::read(reader)?));
- }
-
- HolderSignedTx {
- txid,
- revocation_key, a_htlc_key, b_htlc_key, delayed_payment_key, per_commitment_point, feerate_per_kw,
- htlc_outputs: htlcs
- }
- }
- }
- }
-
let prev_holder_signed_commitment_tx = match <u8 as Readable>::read(reader)? {
0 => None,
1 => {
- Some(read_holder_tx!())
+ Some(Readable::read(reader)?)
},
_ => return Err(DecodeError::InvalidValue),
};
- let current_holder_commitment_tx = read_holder_tx!();
+ let current_holder_commitment_tx = Readable::read(reader)?;
let current_counterparty_commitment_number = <U48 as Readable>::read(reader)?.0;
let current_holder_commitment_number = <U48 as Readable>::read(reader)?.0;
let waiting_threshold_conf_len: u64 = Readable::read(reader)?;
let mut onchain_events_awaiting_threshold_conf = Vec::with_capacity(cmp::min(waiting_threshold_conf_len as usize, MAX_ALLOC_SIZE / 128));
for _ in 0..waiting_threshold_conf_len {
- let txid = Readable::read(reader)?;
- let height = Readable::read(reader)?;
- let event = match <u8 as Readable>::read(reader)? {
- 0 => {
- let htlc_source = Readable::read(reader)?;
- let hash = Readable::read(reader)?;
- OnchainEvent::HTLCUpdate {
- source: htlc_source,
- payment_hash: hash,
- }
- },
- 1 => {
- let descriptor = Readable::read(reader)?;
- OnchainEvent::MaturingOutput {
- descriptor
- }
- },
- _ => return Err(DecodeError::InvalidValue),
- };
- onchain_events_awaiting_threshold_conf.push(OnchainEventEntry { txid, height, event });
+ onchain_events_awaiting_threshold_conf.push(Readable::read(reader)?);
}
let outputs_to_watch_len: u64 = Readable::read(reader)?;
let lockdown_from_offchain = Readable::read(reader)?;
let holder_tx_signed = Readable::read(reader)?;
- read_tlv_fields!(reader, {}, {});
+ read_tlv_fields!(reader, {});
let mut secp_ctx = Secp256k1::new();
secp_ctx.seeded_randomize(&keys_manager.get_secure_random_bytes());