HTLCUpdate {
htlc_update: (HTLCSource, PaymentHash),
},
+ MaturingOutput {
+ descriptor: SpendableOutputDescriptor,
+ },
}
const SERIALIZATION_VERSION: u8 = 1;
htlc_update.0.write(writer)?;
htlc_update.1.write(writer)?;
},
+ OnchainEvent::MaturingOutput { ref descriptor } => {
+ 1u8.write(writer)?;
+ descriptor.write(writer)?;
+ },
}
}
}
OnchainEvent::HTLCUpdate { ref htlc_update } => {
return htlc_update.0 != **source
},
+ _ => true
}
});
e.push(OnchainEvent::HTLCUpdate { htlc_update: ((**source).clone(), htlc.payment_hash.clone())});
OnchainEvent::HTLCUpdate { ref htlc_update } => {
return htlc_update.0 != **source
},
+ _ => true
}
});
e.push(OnchainEvent::HTLCUpdate { htlc_update: ((**source).clone(), htlc.payment_hash.clone())});
OnchainEvent::HTLCUpdate { ref htlc_update } => {
return htlc_update.0 != $source
},
+ _ => true
}
});
e.push(OnchainEvent::HTLCUpdate { htlc_update: ($source, $payment_hash)});
log_trace!(self, "Block {} at height {} connected with {} txn matched", block_hash, height, txn_matched.len());
let mut watch_outputs = Vec::new();
- let mut spendable_outputs = Vec::new();
let mut claimable_outpoints = Vec::new();
for tx in txn_matched {
if tx.input.len() == 1 {
// we call is_resolving_htlc_output here outside of the tx.input.len() == 1 check.
self.is_resolving_htlc_output(&tx, height);
- if let Some(spendable_output) = self.is_paying_spendable_output(&tx) {
- spendable_outputs.push(spendable_output);
- }
+ self.is_paying_spendable_output(&tx, height);
}
let should_broadcast = if let Some(_) = self.current_local_signed_commitment_tx {
self.would_broadcast_at_height(height)
source: htlc_update.0,
});
},
+ OnchainEvent::MaturingOutput { descriptor } => {
+ log_trace!(self, "Descriptor {} has got enough confirmations to be passed upstream", log_spendable!(descriptor));
+ self.pending_events.push(events::Event::SpendableOutputs {
+ outputs: vec![descriptor]
+ });
+ }
}
}
}
self.outputs_to_watch.insert(txid.clone(), output_scripts.iter().map(|o| o.script_pubkey.clone()).collect());
}
- for spend in spendable_outputs.iter() {
- log_trace!(self, "Announcing spendable output to user: {}", log_spendable!(spend));
- }
-
- if spendable_outputs.len() > 0 {
- self.pending_events.push(events::Event::SpendableOutputs {
- outputs: spendable_outputs,
- });
- }
-
watch_outputs
}
if let Some(_) = self.onchain_events_waiting_threshold_conf.remove(&(height + ANTI_REORG_DELAY - 1)) {
//We may discard:
//- htlc update there as failure-trigger tx (revoked commitment tx, non-revoked commitment tx, HTLC-timeout tx) has been disconnected
+ //- maturing spendable output has transaction paying us has been disconnected
}
self.onchain_tx_handler.block_disconnected(height, broadcaster, fee_estimator);
OnchainEvent::HTLCUpdate { ref htlc_update } => {
return htlc_update.0 != source
},
+ _ => true
}
});
e.push(OnchainEvent::HTLCUpdate { htlc_update: (source, payment_hash)});
}
/// Check if any transaction broadcasted is paying fund back to some address we can assume to own
- fn is_paying_spendable_output(&self, tx: &Transaction) -> Option<SpendableOutputDescriptor> {
+ fn is_paying_spendable_output(&mut self, tx: &Transaction, height: u32) {
+ let mut spendable_output = None;
for (i, outp) in tx.output.iter().enumerate() { // There is max one spendable output for any channel tx, including ones generated by us
if outp.script_pubkey == self.destination_script {
- return Some(SpendableOutputDescriptor::StaticOutput {
+ spendable_output = Some(SpendableOutputDescriptor::StaticOutput {
outpoint: BitcoinOutPoint { txid: tx.txid(), vout: i as u32 },
output: outp.clone(),
});
+ break;
} else if let Some(ref broadcasted_local_revokable_script) = self.broadcasted_local_revokable_script {
if broadcasted_local_revokable_script.0 == outp.script_pubkey {
- return Some(SpendableOutputDescriptor::DynamicOutputP2WSH {
+ spendable_output = Some(SpendableOutputDescriptor::DynamicOutputP2WSH {
outpoint: BitcoinOutPoint { txid: tx.txid(), vout: i as u32 },
key: broadcasted_local_revokable_script.1,
witness_script: broadcasted_local_revokable_script.2.clone(),
to_self_delay: self.their_to_self_delay.unwrap(),
output: outp.clone(),
});
+ break;
}
} else if let Some(ref broadcasted_remote_payment_script) = self.broadcasted_remote_payment_script {
if broadcasted_remote_payment_script.0 == outp.script_pubkey {
- return Some(SpendableOutputDescriptor::DynamicOutputP2WPKH {
+ spendable_output = Some(SpendableOutputDescriptor::DynamicOutputP2WPKH {
outpoint: BitcoinOutPoint { txid: tx.txid(), vout: i as u32 },
key: broadcasted_remote_payment_script.1,
output: outp.clone(),
});
+ break;
}
} else if outp.script_pubkey == self.shutdown_script {
- return Some(SpendableOutputDescriptor::StaticOutput {
- outpoint: BitcoinOutPoint { txid: tx.txid(), vout: i as u32 },
- output: outp.clone(),
+ spendable_output = Some(SpendableOutputDescriptor::StaticOutput {
+ outpoint: BitcoinOutPoint { txid: tx.txid(), vout: i as u32 },
+ output: outp.clone(),
});
}
}
- None
+ if let Some(spendable_output) = spendable_output {
+ log_trace!(self, "Maturing {} until {}", log_spendable!(spendable_output), height + ANTI_REORG_DELAY - 1);
+ match self.onchain_events_waiting_threshold_conf.entry(height + ANTI_REORG_DELAY - 1) {
+ hash_map::Entry::Occupied(mut entry) => {
+ let e = entry.get_mut();
+ e.push(OnchainEvent::MaturingOutput { descriptor: spendable_output });
+ }
+ hash_map::Entry::Vacant(entry) => {
+ entry.insert(vec![OnchainEvent::MaturingOutput { descriptor: spendable_output }]);
+ }
+ }
+ }
}
}
htlc_update: (htlc_source, hash)
}
},
+ 1 => {
+ let descriptor = Readable::read(reader)?;
+ OnchainEvent::MaturingOutput {
+ descriptor
+ }
+ },
_ => return Err(DecodeError::InvalidValue),
};
events.push(ev);