impl OnchainEventEntry {
fn confirmation_threshold(&self) -> u32 {
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);
+ match self.event {
+ OnchainEvent::MaturingOutput {
+ descriptor: SpendableOutputDescriptor::DelayedPaymentOutput(ref descriptor)
+ } => {
+ // 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);
+ },
+ OnchainEvent::FundingSpendConfirmation { on_local_output_csv: Some(csv), .. } => {
+ // 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 + csv as u32 - 1);
+ },
+ _ => {},
}
conf_threshold
}
MaturingOutput {
descriptor: SpendableOutputDescriptor,
},
+ /// A spend of the funding output, either a commitment transaction or a cooperative closing
+ /// transaction.
+ FundingSpendConfirmation {
+ txid: Txid,
+ /// The CSV delay for the output of the funding spend transaction (implying it is a local
+ /// commitment transaction, and this is the delay on the to_self output).
+ on_local_output_csv: Option<u16>,
+ },
}
impl Writeable for OnchainEventEntry {
(1, MaturingOutput) => {
(0, descriptor, required),
},
+ (3, FundingSpendConfirmation) => {
+ (0, txid, required),
+ (2, on_local_output_csv, option),
+ },
);
#[cfg_attr(any(test, feature = "fuzztarget", feature = "_test_utils"), derive(PartialEq))]
// remote monitor out-of-order with regards to the block view.
holder_tx_signed: bool,
+ funding_spend_confirmed: Option<Txid>,
+
// We simply modify best_block in Channel's block_connected so that serialization is
// consistent but hopefully the users' copy handles block_connected in a consistent way.
// (we do *not*, however, update them in update_monitor to ensure any local user copies keep
self.onchain_events_awaiting_threshold_conf != other.onchain_events_awaiting_threshold_conf ||
self.outputs_to_watch != other.outputs_to_watch ||
self.lockdown_from_offchain != other.lockdown_from_offchain ||
- self.holder_tx_signed != other.holder_tx_signed
+ self.holder_tx_signed != other.holder_tx_signed ||
+ self.funding_spend_confirmed != other.funding_spend_confirmed
{
false
} else {
self.lockdown_from_offchain.write(writer)?;
self.holder_tx_signed.write(writer)?;
- write_tlv_fields!(writer, {});
+ write_tlv_fields!(writer, {
+ (1, self.funding_spend_confirmed, option),
+ });
Ok(())
}
lockdown_from_offchain: false,
holder_tx_signed: false,
+ funding_spend_confirmed: None,
best_block,
/// Attempts to claim any claimable HTLCs in a commitment transaction which was not (yet)
/// revoked using data in holder_claimable_outpoints.
/// Should not be used if check_spend_revoked_transaction succeeds.
- fn check_spend_holder_transaction<L: Deref>(&mut self, tx: &Transaction, height: u32, logger: &L) -> (Vec<PackageTemplate>, TransactionOutputs) where L::Target: Logger {
+ /// Returns None unless the transaction is definitely one of our commitment transactions.
+ fn check_spend_holder_transaction<L: Deref>(&mut self, tx: &Transaction, height: u32, logger: &L) -> Option<(Vec<PackageTemplate>, TransactionOutputs)> where L::Target: Logger {
let commitment_txid = tx.txid();
let mut claim_requests = Vec::new();
let mut watch_outputs = Vec::new();
}
if is_holder_tx {
+ Some((claim_requests, (commitment_txid, watch_outputs)))
+ } else {
+ None
}
-
- (claim_requests, (commitment_txid, watch_outputs))
}
pub fn get_latest_holder_commitment_txn<L: Deref>(&mut self, logger: &L) -> Vec<Transaction> where L::Target: Logger {
// filters.
let prevout = &tx.input[0].previous_output;
if prevout.txid == self.funding_info.0.txid && prevout.vout == self.funding_info.0.index as u32 {
+ let mut balance_spendable_csv = None;
+ log_info!(logger, "Channel closed by funding output spend in txid {}.", log_bytes!(tx.txid()));
if (tx.input[0].sequence >> 8*3) as u8 == 0x80 && (tx.lock_time >> 8*3) as u8 == 0x20 {
let (mut new_outpoints, new_outputs) = self.check_spend_counterparty_transaction(&tx, height, &logger);
if !new_outputs.1.is_empty() {
watch_outputs.push(new_outputs);
}
+ claimable_outpoints.append(&mut new_outpoints);
if new_outpoints.is_empty() {
- let (mut new_outpoints, new_outputs) = self.check_spend_holder_transaction(&tx, height, &logger);
- if !new_outputs.1.is_empty() {
- watch_outputs.push(new_outputs);
+ if let Some((mut new_outpoints, new_outputs)) = self.check_spend_holder_transaction(&tx, height, &logger) {
+ if !new_outputs.1.is_empty() {
+ watch_outputs.push(new_outputs);
+ }
+ claimable_outpoints.append(&mut new_outpoints);
+ balance_spendable_csv = Some(self.on_holder_tx_csv);
}
- claimable_outpoints.append(&mut new_outpoints);
}
- claimable_outpoints.append(&mut new_outpoints);
}
+ let txid = tx.txid();
+ self.onchain_events_awaiting_threshold_conf.push(OnchainEventEntry {
+ txid,
+ height: height,
+ event: OnchainEvent::FundingSpendConfirmation {
+ txid,
+ on_local_output_csv: balance_spendable_csv,
+ },
+ });
} else {
if let Some(&commitment_number) = self.counterparty_commitment_txn_on_chain.get(&prevout.txid) {
let (mut new_outpoints, new_outputs_option) = self.check_spend_counterparty_htlc(&tx, commitment_number, height, &logger);
.filter_map(|entry| match &entry.event {
OnchainEvent::HTLCUpdate { source, .. } => Some(source),
OnchainEvent::MaturingOutput { .. } => None,
+ OnchainEvent::FundingSpendConfirmation { .. } => None,
})
.collect();
#[cfg(debug_assertions)]
self.pending_events.push(Event::SpendableOutputs {
outputs: vec![descriptor]
});
- }
+ },
+ OnchainEvent::FundingSpendConfirmation { txid, .. } => {
+ self.funding_spend_confirmed = Some(txid);
+ },
}
}
return Err(DecodeError::InvalidValue);
}
- read_tlv_fields!(reader, {});
+ let mut funding_spend_confirmed = None;
+ read_tlv_fields!(reader, {
+ (1, funding_spend_confirmed, option),
+ });
let mut secp_ctx = Secp256k1::new();
secp_ctx.seeded_randomize(&keys_manager.get_secure_random_bytes());
lockdown_from_offchain,
holder_tx_signed,
+ funding_spend_confirmed,
best_block,