use util::byte_utils;
use util::events::Event;
+use prelude::*;
use std::collections::{HashMap, HashSet};
use core::{cmp, mem};
use std::io::Error;
/// inbound HTLC in backward channel. Note, in case of preimage, we pass info to upstream without delay as we can
/// only win from it, so it's never an OnchainEvent
HTLCUpdate {
- htlc_update: (HTLCSource, PaymentHash),
+ source: HTLCSource,
+ payment_hash: PaymentHash,
},
MaturingOutput {
descriptor: SpendableOutputDescriptor,
entry.txid.write(writer)?;
writer.write_all(&byte_utils::be32_to_array(entry.height))?;
match entry.event {
- OnchainEvent::HTLCUpdate { ref htlc_update } => {
+ OnchainEvent::HTLCUpdate { ref source, ref payment_hash } => {
0u8.write(writer)?;
- htlc_update.0.write(writer)?;
- htlc_update.1.write(writer)?;
+ source.write(writer)?;
+ payment_hash.write(writer)?;
},
OnchainEvent::MaturingOutput { ref descriptor } => {
1u8.write(writer)?;
macro_rules! claim_htlcs {
($commitment_number: expr, $txid: expr) => {
let htlc_claim_reqs = self.get_counterparty_htlc_output_claim_reqs($commitment_number, $txid, None);
- self.onchain_tx_handler.update_claims_view(&Vec::new(), htlc_claim_reqs, None, broadcaster, fee_estimator, logger);
+ self.onchain_tx_handler.update_claims_view(&Vec::new(), htlc_claim_reqs, self.best_block.height(), broadcaster, fee_estimator, logger);
}
}
if let Some(txid) = self.current_counterparty_commitment_txid {
// holder commitment transactions.
if self.broadcasted_holder_revokable_script.is_some() {
let (claim_reqs, _) = self.get_broadcasted_holder_claims(&self.current_holder_commitment_tx, 0);
- self.onchain_tx_handler.update_claims_view(&Vec::new(), claim_reqs, None, broadcaster, fee_estimator, logger);
+ self.onchain_tx_handler.update_claims_view(&Vec::new(), claim_reqs, self.best_block.height(), broadcaster, fee_estimator, logger);
if let Some(ref tx) = self.prev_holder_signed_commitment_tx {
let (claim_reqs, _) = self.get_broadcasted_holder_claims(&tx, 0);
- self.onchain_tx_handler.update_claims_view(&Vec::new(), claim_reqs, None, broadcaster, fee_estimator, logger);
+ self.onchain_tx_handler.update_claims_view(&Vec::new(), claim_reqs, self.best_block.height(), broadcaster, fee_estimator, logger);
}
}
}
self.onchain_events_awaiting_threshold_conf.retain(|ref entry| {
if entry.height != height { return true; }
match entry.event {
- OnchainEvent::HTLCUpdate { ref htlc_update } => {
- htlc_update.0 != **source
- },
- _ => true,
+ OnchainEvent::HTLCUpdate { source: ref update_source, .. } => {
+ *update_source != **source
+ },
+ _ => true,
}
});
let entry = OnchainEventEntry {
txid: *$txid,
height,
event: OnchainEvent::HTLCUpdate {
- htlc_update: ((**source).clone(), htlc.payment_hash.clone())
+ source: (**source).clone(),
+ payment_hash: htlc.payment_hash.clone(),
},
};
log_info!(logger, "Failing HTLC with payment_hash {} from {} counterparty commitment tx due to broadcast of revoked counterparty commitment transaction, waiting for confirmation (at height {})", log_bytes!(htlc.payment_hash.0), $commitment_tx, entry.confirmation_threshold());
self.onchain_events_awaiting_threshold_conf.retain(|ref entry| {
if entry.height != height { return true; }
match entry.event {
- OnchainEvent::HTLCUpdate { ref htlc_update } => {
- htlc_update.0 != **source
- },
- _ => true,
+ OnchainEvent::HTLCUpdate { source: ref update_source, .. } => {
+ *update_source != **source
+ },
+ _ => true,
}
});
self.onchain_events_awaiting_threshold_conf.push(OnchainEventEntry {
txid: *$txid,
height,
event: OnchainEvent::HTLCUpdate {
- htlc_update: ((**source).clone(), htlc.payment_hash.clone())
+ source: (**source).clone(),
+ payment_hash: htlc.payment_hash.clone(),
},
});
}
for &(ref htlc, _, _) in holder_tx.htlc_outputs.iter() {
if let Some(transaction_output_index) = htlc.transaction_output_index {
- let htlc_output = HolderHTLCOutput::build(if !htlc.offered {
- if let Some(preimage) = self.payment_preimages.get(&htlc.payment_hash) {
- Some(preimage.clone())
+ let htlc_output = if htlc.offered {
+ HolderHTLCOutput::build_offered(htlc.amount_msat, htlc.cltv_expiry)
} else {
- // We can't build an HTLC-Success transaction without the preimage
- continue;
- }
- } else { None }, htlc.amount_msat);
+ let payment_preimage = if let Some(preimage) = self.payment_preimages.get(&htlc.payment_hash) {
+ preimage.clone()
+ } else {
+ // We can't build an HTLC-Success transaction without the preimage
+ continue;
+ };
+ HolderHTLCOutput::build_accepted(payment_preimage, htlc.amount_msat)
+ };
let htlc_package = PackageTemplate::build_package(holder_tx.txid, transaction_output_index, PackageSolvingData::HolderHTLCOutput(htlc_output), height, false, height);
claim_requests.push(htlc_package);
}
self.onchain_events_awaiting_threshold_conf.retain(|ref entry| {
if entry.height != height { return true; }
match entry.event {
- OnchainEvent::HTLCUpdate { ref htlc_update } => {
- htlc_update.0 != $source
- },
- _ => true,
+ OnchainEvent::HTLCUpdate { source: ref update_source, .. } => {
+ *update_source != $source
+ },
+ _ => true,
}
});
let entry = OnchainEventEntry {
txid: commitment_txid,
height,
- event: OnchainEvent::HTLCUpdate { htlc_update: ($source, $payment_hash) },
+ event: OnchainEvent::HTLCUpdate { source: $source, payment_hash: $payment_hash },
};
log_trace!(logger, "Failing HTLC with payment_hash {} from {} holder commitment tx due to broadcast of transaction, waiting confirmation (at height{})", log_bytes!($payment_hash.0), $commitment_tx, entry.confirmation_threshold());
self.onchain_events_awaiting_threshold_conf.push(entry);
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();
- let mut res = vec![commitment_tx];
+ let mut holder_transactions = vec![commitment_tx];
for htlc in self.current_holder_commitment_tx.htlc_outputs.iter() {
if let Some(vout) = htlc.0.transaction_output_index {
let preimage = if !htlc.0.offered {
// We can't build an HTLC-Success transaction without the preimage
continue;
}
+ } else if htlc.0.cltv_expiry > self.best_block.height() + 1 {
+ // Don't broadcast HTLC-Timeout transactions immediately as they don't meet the
+ // current locktime requirements on-chain. We will broadcast them in
+ // `block_confirmed` when `would_broadcast_at_height` returns true.
+ // Note that we add + 1 as transactions are broadcastable when they can be
+ // confirmed in the next block.
+ continue;
} else { None };
if let Some(htlc_tx) = self.onchain_tx_handler.get_fully_signed_htlc_tx(
&::bitcoin::OutPoint { txid, vout }, &preimage) {
- res.push(htlc_tx);
+ holder_transactions.push(htlc_tx);
}
}
}
// We throw away the generated waiting_first_conf data as we aren't (yet) confirmed and we don't actually know what the caller wants to do.
// The data will be re-generated and tracked in check_spend_holder_transaction if we get a confirmation.
- return res;
+ holder_transactions
}
#[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!");
let commitment_tx = self.onchain_tx_handler.get_fully_signed_copy_holder_tx(&self.funding_redeemscript);
let txid = commitment_tx.txid();
- let mut res = vec![commitment_tx];
+ let mut holder_transactions = vec![commitment_tx];
for htlc in self.current_holder_commitment_tx.htlc_outputs.iter() {
if let Some(vout) = htlc.0.transaction_output_index {
let preimage = if !htlc.0.offered {
} else { None };
if let Some(htlc_tx) = self.onchain_tx_handler.unsafe_get_fully_signed_htlc_tx(
&::bitcoin::OutPoint { txid, vout }, &preimage) {
- res.push(htlc_tx);
+ holder_transactions.push(htlc_tx);
}
}
}
- return res
+ holder_transactions
}
pub fn block_connected<B: Deref, F: Deref, L: Deref>(&mut self, header: &BlockHeader, txdata: &TransactionData, height: u32, broadcaster: B, fee_estimator: F, logger: L) -> Vec<TransactionOutputs>
let unmatured_htlcs: Vec<_> = self.onchain_events_awaiting_threshold_conf
.iter()
.filter_map(|entry| match &entry.event {
- OnchainEvent::HTLCUpdate { htlc_update } => Some(htlc_update.0.clone()),
+ OnchainEvent::HTLCUpdate { source, .. } => Some(source),
OnchainEvent::MaturingOutput { .. } => None,
})
.collect();
// Produce actionable events from on-chain events having reached their threshold.
for entry in onchain_events_reaching_threshold_conf.drain(..) {
match entry.event {
- OnchainEvent::HTLCUpdate { htlc_update } => {
+ OnchainEvent::HTLCUpdate { ref source, payment_hash } => {
// Check for duplicate HTLC resolutions.
#[cfg(debug_assertions)]
{
debug_assert!(
- unmatured_htlcs.iter().find(|&htlc| htlc == &htlc_update.0).is_none(),
+ unmatured_htlcs.iter().find(|&htlc| htlc == &source).is_none(),
"An unmature HTLC transaction conflicts with a maturing one; failed to \
call either transaction_unconfirmed for the conflicting transaction \
or block_disconnected for a block containing it.");
debug_assert!(
- matured_htlcs.iter().find(|&htlc| htlc == &htlc_update.0).is_none(),
+ matured_htlcs.iter().find(|&htlc| htlc == source).is_none(),
"A matured HTLC transaction conflicts with a maturing one; failed to \
call either transaction_unconfirmed for the conflicting transaction \
or block_disconnected for a block containing it.");
- matured_htlcs.push(htlc_update.0.clone());
+ matured_htlcs.push(source.clone());
}
- log_trace!(logger, "HTLC {} failure update has got enough confirmations to be passed upstream", log_bytes!((htlc_update.1).0));
+ log_trace!(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: htlc_update.1,
+ payment_hash: payment_hash,
payment_preimage: None,
- source: htlc_update.0,
+ source: source.clone(),
}));
},
OnchainEvent::MaturingOutput { descriptor } => {
}
}
- self.onchain_tx_handler.update_claims_view(&txn_matched, claimable_outpoints, Some(height), &&*broadcaster, &&*fee_estimator, &&*logger);
+ self.onchain_tx_handler.update_claims_view(&txn_matched, claimable_outpoints, height, &&*broadcaster, &&*fee_estimator, &&*logger);
// Determine new outputs to watch by comparing against previously known outputs to watch,
// updating the latter in the process.
self.onchain_events_awaiting_threshold_conf.retain(|ref entry| {
if entry.height != height { return true; }
match entry.event {
- OnchainEvent::HTLCUpdate { ref htlc_update } => {
- htlc_update.0 != source
- },
- _ => true,
+ OnchainEvent::HTLCUpdate { source: ref htlc_source, .. } => {
+ *htlc_source != source
+ },
+ _ => true,
}
});
let entry = OnchainEventEntry {
txid: tx.txid(),
height,
- event: OnchainEvent::HTLCUpdate { htlc_update: (source, payment_hash) },
+ 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());
self.onchain_events_awaiting_threshold_conf.push(entry);
let htlc_source = Readable::read(reader)?;
let hash = Readable::read(reader)?;
OnchainEvent::HTLCUpdate {
- htlc_update: (htlc_source, hash)
+ source: htlc_source,
+ payment_hash: hash,
}
},
1 => {
use bitcoin::secp256k1::Secp256k1;
use std::sync::{Arc, Mutex};
use chain::keysinterface::InMemorySigner;
+ use prelude::*;
#[test]
fn test_prune_preimages() {
let secp_ctx = Secp256k1::new();
let logger = Arc::new(TestLogger::new());
- let broadcaster = Arc::new(TestBroadcaster{txn_broadcasted: Mutex::new(Vec::new())});
+ let broadcaster = Arc::new(TestBroadcaster{txn_broadcasted: Mutex::new(Vec::new()), blocks: Arc::new(Mutex::new(Vec::new()))});
let fee_estimator = Arc::new(TestFeeEstimator { sat_per_kw: 253 });
let dummy_key = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());