Add OnchainTxHandler::get_fully_signed_htlc

In case of channel force-closure, access to local commitment
transactions and its dependent HTLCs is needed. Instead of using
broadcast_by_local_state which registers outpoint to claim and
outputs to watch which are going to be discarded in this case,
we simply ask OnchainTxHandler to build and sign HTLC transactions
through new API.
This commit is contained in:
Antoine Riard 2020-03-23 01:30:48 -04:00
parent 6b8a516647
commit 8369541f63
2 changed files with 38 additions and 5 deletions

View file

@ -1819,10 +1819,17 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
pub fn get_latest_local_commitment_txn(&mut self) -> Vec<Transaction> { pub fn get_latest_local_commitment_txn(&mut self) -> Vec<Transaction> {
log_trace!(self, "Getting signed latest local commitment transaction!"); log_trace!(self, "Getting signed latest local commitment transaction!");
if let Some(commitment_tx) = self.onchain_tx_handler.get_fully_signed_local_tx(self.channel_value_satoshis.unwrap()) { if let Some(commitment_tx) = self.onchain_tx_handler.get_fully_signed_local_tx(self.channel_value_satoshis.unwrap()) {
let txid = commitment_tx.txid();
let mut res = vec![commitment_tx]; let mut res = vec![commitment_tx];
if let &Some(ref local_tx) = &self.current_local_signed_commitment_tx { if let &Some(ref local_tx) = &self.current_local_signed_commitment_tx {
let mut htlc_txn = self.broadcast_by_local_state(res.get(0).unwrap(), local_tx).0; for htlc in local_tx.htlc_outputs.iter() {
res.append(&mut htlc_txn); if let Some(htlc_index) = htlc.0.transaction_output_index {
let preimage = if let Some(preimage) = self.payment_preimages.get(&htlc.0.payment_hash) { Some(*preimage) } else { None };
if let Some(htlc_tx) = self.onchain_tx_handler.get_fully_signed_htlc_tx(txid, htlc_index, preimage) {
res.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. // 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_local_transaction if we get a confirmation. // The data will be re-generated and tracked in check_spend_local_transaction if we get a confirmation.
} }
@ -1838,10 +1845,17 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
pub fn unsafe_get_latest_local_commitment_txn(&mut self) -> Vec<Transaction> { pub fn unsafe_get_latest_local_commitment_txn(&mut self) -> Vec<Transaction> {
log_trace!(self, "Getting signed copy of latest local commitment transaction!"); log_trace!(self, "Getting signed copy of latest local commitment transaction!");
if let Some(commitment_tx) = self.onchain_tx_handler.get_fully_signed_copy_local_tx(self.channel_value_satoshis.unwrap()) { if let Some(commitment_tx) = self.onchain_tx_handler.get_fully_signed_copy_local_tx(self.channel_value_satoshis.unwrap()) {
let txid = commitment_tx.txid();
let mut res = vec![commitment_tx]; let mut res = vec![commitment_tx];
if let &Some(ref local_tx) = &self.current_local_signed_commitment_tx { if let &Some(ref local_tx) = &self.current_local_signed_commitment_tx {
let mut htlc_txn = self.broadcast_by_local_state(res.get(0).unwrap(), local_tx).0; for htlc in local_tx.htlc_outputs.iter() {
res.append(&mut htlc_txn); if let Some(htlc_index) = htlc.0.transaction_output_index {
let preimage = if let Some(preimage) = self.payment_preimages.get(&htlc.0.payment_hash) { Some(*preimage) } else { None };
if let Some(htlc_tx) = self.onchain_tx_handler.get_fully_signed_htlc_tx(txid, htlc_index, preimage) {
res.push(htlc_tx);
}
}
}
} }
return res return res
} }

View file

@ -15,7 +15,7 @@ use secp256k1;
use ln::msgs::DecodeError; use ln::msgs::DecodeError;
use ln::channelmonitor::{ANTI_REORG_DELAY, CLTV_SHARED_CLAIM_BUFFER, InputMaterial, ClaimRequest}; use ln::channelmonitor::{ANTI_REORG_DELAY, CLTV_SHARED_CLAIM_BUFFER, InputMaterial, ClaimRequest};
use ln::channelmanager::HTLCSource; use ln::channelmanager::{HTLCSource, PaymentPreimage};
use ln::chan_utils; use ln::chan_utils;
use ln::chan_utils::{HTLCType, LocalCommitmentTransaction, TxCreationKeys, HTLCOutputInCommitment}; use ln::chan_utils::{HTLCType, LocalCommitmentTransaction, TxCreationKeys, HTLCOutputInCommitment};
use chain::chaininterface::{FeeEstimator, BroadcasterInterface, ConfirmationTarget, MIN_RELAY_FEE_SAT_PER_1000_WEIGHT}; use chain::chaininterface::{FeeEstimator, BroadcasterInterface, ConfirmationTarget, MIN_RELAY_FEE_SAT_PER_1000_WEIGHT};
@ -893,4 +893,23 @@ impl<ChanSigner: ChannelKeys> OnchainTxHandler<ChanSigner> {
} }
None None
} }
pub(super) fn get_fully_signed_htlc_tx(&mut self, txid: Sha256dHash, htlc_index: u32, preimage: Option<PaymentPreimage>) -> Option<Transaction> {
//TODO: store preimage in OnchainTxHandler
if let Some(ref local_commitment) = self.local_commitment {
if local_commitment.txid() == txid {
if let Some(ref htlc_cache) = self.current_htlc_cache {
if let Some(htlc) = htlc_cache.per_htlc.get(&htlc_index) {
if !htlc.0.offered && preimage.is_none() { return None; }; // If we don't have preimage for HTLC-Success, don't try to generate
let htlc_secret = if !htlc.0.offered { preimage } else { None }; // If we have a preimage for a HTLC-Timeout, don't use it that's likely a duplicate HTLC hash
let mut htlc_tx = chan_utils::build_htlc_transaction(&txid, htlc_cache.feerate_per_kw, self.local_csv, &htlc.0, &htlc_cache.local_keys.a_delayed_payment_key, &htlc_cache.local_keys.revocation_key);
self.key_storage.sign_htlc_transaction(&mut htlc_tx, htlc.1.as_ref().unwrap(), &htlc_secret, &htlc.0, &htlc_cache.local_keys.a_htlc_key, &htlc_cache.local_keys.b_htlc_key, &htlc_cache.local_keys.revocation_key, &htlc_cache.local_keys.per_commitment_point, &self.secp_ctx);
return Some(htlc_tx);
}
}
}
}
None
}
} }