Make HTLCOutputInCommitment::transaction_output_index an Option

We really shouldn't have split out the with-source HTLCs from the
in-transaction HTLCs when we added back-failing, and will need
almost all of the info in HTLCOutputInCommitment for each HTLC to
fix would_broadcast_at_height, so this is a first step at
recombining them.
This commit is contained in:
Matt Corallo 2019-01-06 17:02:53 -05:00
parent a604cb6763
commit 09919d2af0
3 changed files with 194 additions and 182 deletions

View file

@ -147,7 +147,7 @@ pub struct HTLCOutputInCommitment {
pub amount_msat: u64,
pub cltv_expiry: u32,
pub payment_hash: PaymentHash,
pub transaction_output_index: u32,
pub transaction_output_index: Option<u32>,
}
#[inline]
@ -222,12 +222,13 @@ pub fn get_htlc_redeemscript(htlc: &HTLCOutputInCommitment, keys: &TxCreationKey
get_htlc_redeemscript_with_explicit_keys(htlc, &keys.a_htlc_key, &keys.b_htlc_key, &keys.revocation_key)
}
/// panics if htlc.transaction_output_index.is_none()!
pub fn build_htlc_transaction(prev_hash: &Sha256dHash, feerate_per_kw: u64, to_self_delay: u16, htlc: &HTLCOutputInCommitment, a_delayed_payment_key: &PublicKey, revocation_key: &PublicKey) -> Transaction {
let mut txins: Vec<TxIn> = Vec::new();
txins.push(TxIn {
previous_output: OutPoint {
txid: prev_hash.clone(),
vout: htlc.transaction_output_index,
vout: htlc.transaction_output_index.expect("Can't build an HTLC transaction for a dust output"),
},
script_sig: Script::new(),
sequence: 0,

View file

@ -132,18 +132,6 @@ struct OutboundHTLCOutput {
fail_reason: Option<HTLCFailReason>,
}
macro_rules! get_htlc_in_commitment {
($htlc: expr, $offered: expr) => {
HTLCOutputInCommitment {
offered: $offered,
amount_msat: $htlc.amount_msat,
cltv_expiry: $htlc.cltv_expiry,
payment_hash: $htlc.payment_hash,
transaction_output_index: 0
}
}
}
/// See AwaitingRemoteRevoke ChannelState for more info
enum HTLCUpdateAwaitingACK {
AddHTLC {
@ -775,38 +763,46 @@ impl Channel {
};
let mut txouts: Vec<(TxOut, Option<(HTLCOutputInCommitment, Option<&HTLCSource>)>)> = Vec::with_capacity(self.pending_inbound_htlcs.len() + self.pending_outbound_htlcs.len() + 2);
let mut unincluded_htlc_sources: Vec<(PaymentHash, &HTLCSource, Option<u32>)> = Vec::new();
let mut included_dust_htlcs: Vec<(HTLCOutputInCommitment, Option<&HTLCSource>)> = Vec::new();
let dust_limit_satoshis = if local { self.our_dust_limit_satoshis } else { self.their_dust_limit_satoshis };
let mut remote_htlc_total_msat = 0;
let mut local_htlc_total_msat = 0;
let mut value_to_self_msat_offset = 0;
macro_rules! get_htlc_in_commitment {
($htlc: expr, $offered: expr) => {
HTLCOutputInCommitment {
offered: $offered,
amount_msat: $htlc.amount_msat,
cltv_expiry: $htlc.cltv_expiry,
payment_hash: $htlc.payment_hash,
transaction_output_index: None
}
}
}
macro_rules! add_htlc_output {
($htlc: expr, $outbound: expr, $source: expr) => {
if $outbound == local { // "offered HTLC output"
let htlc_in_tx = get_htlc_in_commitment!($htlc, true);
if $htlc.amount_msat / 1000 >= dust_limit_satoshis + (feerate_per_kw * HTLC_TIMEOUT_TX_WEIGHT / 1000) {
let htlc_in_tx = get_htlc_in_commitment!($htlc, true);
txouts.push((TxOut {
script_pubkey: chan_utils::get_htlc_redeemscript(&htlc_in_tx, &keys).to_v0_p2wsh(),
value: $htlc.amount_msat / 1000
}, Some((htlc_in_tx, $source))));
} else {
if let Some(source) = $source {
unincluded_htlc_sources.push(($htlc.payment_hash, source, None));
}
included_dust_htlcs.push((htlc_in_tx, $source));
}
} else {
let htlc_in_tx = get_htlc_in_commitment!($htlc, false);
if $htlc.amount_msat / 1000 >= dust_limit_satoshis + (feerate_per_kw * HTLC_SUCCESS_TX_WEIGHT / 1000) {
let htlc_in_tx = get_htlc_in_commitment!($htlc, false);
txouts.push((TxOut { // "received HTLC output"
script_pubkey: chan_utils::get_htlc_redeemscript(&htlc_in_tx, &keys).to_v0_p2wsh(),
value: $htlc.amount_msat / 1000
}, Some((htlc_in_tx, $source))));
} else {
if let Some(source) = $source {
unincluded_htlc_sources.push(($htlc.payment_hash, source, None));
}
included_dust_htlcs.push((htlc_in_tx, $source));
}
}
}
@ -920,18 +916,22 @@ impl Channel {
let mut outputs: Vec<TxOut> = Vec::with_capacity(txouts.len());
let mut htlcs_included: Vec<HTLCOutputInCommitment> = Vec::with_capacity(txouts.len());
let mut htlc_sources: Vec<(PaymentHash, &HTLCSource, Option<u32>)> = Vec::with_capacity(txouts.len() + unincluded_htlc_sources.len());
let mut htlc_sources: Vec<(PaymentHash, &HTLCSource, Option<u32>)> = Vec::with_capacity(txouts.len() + included_dust_htlcs.len());
for (idx, out) in txouts.drain(..).enumerate() {
outputs.push(out.0);
if let Some((mut htlc, source_option)) = out.1 {
htlc.transaction_output_index = idx as u32;
htlc.transaction_output_index = Some(idx as u32);
if let Some(source) = source_option {
htlc_sources.push((htlc.payment_hash, source, Some(idx as u32)));
}
htlcs_included.push(htlc);
}
}
htlc_sources.append(&mut unincluded_htlc_sources);
for (htlc, source_option) in included_dust_htlcs.drain(..) {
if let Some(source) = source_option {
htlc_sources.push((htlc.payment_hash, source, None));
}
}
(Transaction {
version: 2,
@ -1720,18 +1720,20 @@ impl Channel {
let mut htlcs_and_sigs = Vec::with_capacity(local_commitment_tx.1.len());
for (idx, htlc) in local_commitment_tx.1.drain(..).enumerate() {
let mut htlc_tx = self.build_htlc_transaction(&local_commitment_txid, &htlc, true, &local_keys, feerate_per_kw);
let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, &local_keys);
let htlc_sighash = Message::from_slice(&bip143::SighashComponents::new(&htlc_tx).sighash_all(&htlc_tx.input[0], &htlc_redeemscript, htlc.amount_msat / 1000)[..]).unwrap();
secp_check!(self.secp_ctx.verify(&htlc_sighash, &msg.htlc_signatures[idx], &local_keys.b_htlc_key), "Invalid HTLC tx signature from peer");
let htlc_sig = if htlc.offered {
let htlc_sig = self.sign_htlc_transaction(&mut htlc_tx, &msg.htlc_signatures[idx], &None, &htlc, &local_keys)?;
new_local_commitment_txn.push(htlc_tx);
htlc_sig
} else {
self.create_htlc_tx_signature(&htlc_tx, &htlc, &local_keys)?.1
};
htlcs_and_sigs.push((htlc, msg.htlc_signatures[idx], htlc_sig));
if let Some(_) = htlc.transaction_output_index {
let mut htlc_tx = self.build_htlc_transaction(&local_commitment_txid, &htlc, true, &local_keys, feerate_per_kw);
let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, &local_keys);
let htlc_sighash = Message::from_slice(&bip143::SighashComponents::new(&htlc_tx).sighash_all(&htlc_tx.input[0], &htlc_redeemscript, htlc.amount_msat / 1000)[..]).unwrap();
secp_check!(self.secp_ctx.verify(&htlc_sighash, &msg.htlc_signatures[idx], &local_keys.b_htlc_key), "Invalid HTLC tx signature from peer");
let htlc_sig = if htlc.offered {
let htlc_sig = self.sign_htlc_transaction(&mut htlc_tx, &msg.htlc_signatures[idx], &None, &htlc, &local_keys)?;
new_local_commitment_txn.push(htlc_tx);
htlc_sig
} else {
self.create_htlc_tx_signature(&htlc_tx, &htlc, &local_keys)?.1
};
htlcs_and_sigs.push((htlc, msg.htlc_signatures[idx], htlc_sig));
}
}
let next_per_commitment_point = PublicKey::from_secret_key(&self.secp_ctx, &self.build_local_commitment_secret(self.cur_local_commitment_transaction_number - 1));
@ -3295,11 +3297,13 @@ impl Channel {
let mut htlc_sigs = Vec::new();
for ref htlc in remote_commitment_tx.1.iter() {
let htlc_tx = self.build_htlc_transaction(&remote_commitment_txid, htlc, false, &remote_keys, feerate_per_kw);
let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, &remote_keys);
let htlc_sighash = Message::from_slice(&bip143::SighashComponents::new(&htlc_tx).sighash_all(&htlc_tx.input[0], &htlc_redeemscript, htlc.amount_msat / 1000)[..]).unwrap();
let our_htlc_key = secp_check!(chan_utils::derive_private_key(&self.secp_ctx, &remote_keys.per_commitment_point, &self.local_keys.htlc_base_key), "Derived invalid key, peer is maliciously selecting parameters");
htlc_sigs.push(self.secp_ctx.sign(&htlc_sighash, &our_htlc_key));
if let Some(_) = htlc.transaction_output_index {
let htlc_tx = self.build_htlc_transaction(&remote_commitment_txid, htlc, false, &remote_keys, feerate_per_kw);
let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, &remote_keys);
let htlc_sighash = Message::from_slice(&bip143::SighashComponents::new(&htlc_tx).sighash_all(&htlc_tx.input[0], &htlc_redeemscript, htlc.amount_msat / 1000)[..]).unwrap();
let our_htlc_key = secp_check!(chan_utils::derive_private_key(&self.secp_ctx, &remote_keys.per_commitment_point, &self.local_keys.htlc_base_key), "Derived invalid key, peer is maliciously selecting parameters");
htlc_sigs.push(self.secp_ctx.sign(&htlc_sighash, &our_htlc_key));
}
}
Ok((msgs::CommitmentSigned {

View file

@ -776,8 +776,20 @@ impl ChannelMonitor {
// Set in initial Channel-object creation, so should always be set by now:
U48(self.commitment_transaction_number_obscure_factor).write(writer)?;
macro_rules! write_option {
($thing: expr) => {
match $thing {
&Some(ref t) => {
1u8.write(writer)?;
t.write(writer)?;
},
&None => 0u8.write(writer)?,
}
}
}
match self.key_storage {
Storage::Local { ref revocation_base_key, ref htlc_base_key, ref delayed_payment_base_key, ref payment_base_key, ref shutdown_pubkey, ref prev_latest_per_commitment_point, ref latest_per_commitment_point, ref funding_info, current_remote_commitment_txid, prev_remote_commitment_txid } => {
Storage::Local { ref revocation_base_key, ref htlc_base_key, ref delayed_payment_base_key, ref payment_base_key, ref shutdown_pubkey, ref prev_latest_per_commitment_point, ref latest_per_commitment_point, ref funding_info, ref current_remote_commitment_txid, ref prev_remote_commitment_txid } => {
writer.write_all(&[0; 1])?;
writer.write_all(&revocation_base_key[..])?;
writer.write_all(&htlc_base_key[..])?;
@ -806,18 +818,8 @@ impl ChannelMonitor {
debug_assert!(false, "Try to serialize a useless Local monitor !");
},
}
if let Some(ref txid) = current_remote_commitment_txid {
writer.write_all(&[1; 1])?;
writer.write_all(&txid[..])?;
} else {
writer.write_all(&[0; 1])?;
}
if let Some(ref txid) = prev_remote_commitment_txid {
writer.write_all(&[1; 1])?;
writer.write_all(&txid[..])?;
} else {
writer.write_all(&[0; 1])?;
}
write_option!(current_remote_commitment_txid);
write_option!(prev_remote_commitment_txid);
},
Storage::Watchtower { .. } => unimplemented!(),
}
@ -857,7 +859,7 @@ impl ChannelMonitor {
writer.write_all(&byte_utils::be64_to_array($htlc_output.amount_msat))?;
writer.write_all(&byte_utils::be32_to_array($htlc_output.cltv_expiry))?;
writer.write_all(&$htlc_output.payment_hash.0[..])?;
writer.write_all(&byte_utils::be32_to_array($htlc_output.transaction_output_index))?;
write_option!(&$htlc_output.transaction_output_index);
}
}
@ -1142,39 +1144,41 @@ impl ChannelMonitor {
inputs.reserve_exact(per_commitment_data.len());
for (idx, ref htlc) in per_commitment_data.iter().enumerate() {
let expected_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&htlc, &a_htlc_key, &b_htlc_key, &revocation_pubkey);
if htlc.transaction_output_index as usize >= tx.output.len() ||
tx.output[htlc.transaction_output_index as usize].value != htlc.amount_msat / 1000 ||
tx.output[htlc.transaction_output_index as usize].script_pubkey != expected_script.to_v0_p2wsh() {
return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs, htlc_updated); // Corrupted per_commitment_data, fuck this user
}
let input = TxIn {
previous_output: BitcoinOutPoint {
txid: commitment_txid,
vout: htlc.transaction_output_index,
},
script_sig: Script::new(),
sequence: 0xfffffffd,
witness: Vec::new(),
};
if htlc.cltv_expiry > height + CLTV_SHARED_CLAIM_BUFFER {
inputs.push(input);
htlc_idxs.push(Some(idx));
values.push(tx.output[htlc.transaction_output_index as usize].value);
total_value += htlc.amount_msat / 1000;
} else {
let mut single_htlc_tx = Transaction {
version: 2,
lock_time: 0,
input: vec![input],
output: vec!(TxOut {
script_pubkey: self.destination_script.clone(),
value: htlc.amount_msat / 1000, //TODO: - fee
}),
if let Some(transaction_output_index) = htlc.transaction_output_index {
let expected_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&htlc, &a_htlc_key, &b_htlc_key, &revocation_pubkey);
if transaction_output_index as usize >= tx.output.len() ||
tx.output[transaction_output_index as usize].value != htlc.amount_msat / 1000 ||
tx.output[transaction_output_index as usize].script_pubkey != expected_script.to_v0_p2wsh() {
return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs, htlc_updated); // Corrupted per_commitment_data, fuck this user
}
let input = TxIn {
previous_output: BitcoinOutPoint {
txid: commitment_txid,
vout: transaction_output_index,
},
script_sig: Script::new(),
sequence: 0xfffffffd,
witness: Vec::new(),
};
let sighash_parts = bip143::SighashComponents::new(&single_htlc_tx);
sign_input!(sighash_parts, single_htlc_tx.input[0], Some(idx), htlc.amount_msat / 1000);
txn_to_broadcast.push(single_htlc_tx);
if htlc.cltv_expiry > height + CLTV_SHARED_CLAIM_BUFFER {
inputs.push(input);
htlc_idxs.push(Some(idx));
values.push(tx.output[transaction_output_index as usize].value);
total_value += htlc.amount_msat / 1000;
} else {
let mut single_htlc_tx = Transaction {
version: 2,
lock_time: 0,
input: vec![input],
output: vec!(TxOut {
script_pubkey: self.destination_script.clone(),
value: htlc.amount_msat / 1000, //TODO: - fee
}),
};
let sighash_parts = bip143::SighashComponents::new(&single_htlc_tx);
sign_input!(sighash_parts, single_htlc_tx.input[0], Some(idx), htlc.amount_msat / 1000);
txn_to_broadcast.push(single_htlc_tx);
}
}
}
}
@ -1351,70 +1355,72 @@ impl ChannelMonitor {
}
for (idx, ref htlc) in per_commitment_data.0.iter().enumerate() {
let expected_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&htlc, &a_htlc_key, &b_htlc_key, &revocation_pubkey);
if htlc.transaction_output_index as usize >= tx.output.len() ||
tx.output[htlc.transaction_output_index as usize].value != htlc.amount_msat / 1000 ||
tx.output[htlc.transaction_output_index as usize].script_pubkey != expected_script.to_v0_p2wsh() {
return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs, htlc_updated); // Corrupted per_commitment_data, fuck this user
}
if let Some(payment_preimage) = self.payment_preimages.get(&htlc.payment_hash) {
let input = TxIn {
previous_output: BitcoinOutPoint {
txid: commitment_txid,
vout: htlc.transaction_output_index,
},
script_sig: Script::new(),
sequence: idx as u32, // reset to 0xfffffffd in sign_input
witness: Vec::new(),
};
if htlc.cltv_expiry > height + CLTV_SHARED_CLAIM_BUFFER {
inputs.push(input);
values.push((tx.output[htlc.transaction_output_index as usize].value, payment_preimage));
total_value += htlc.amount_msat / 1000;
} else {
let mut single_htlc_tx = Transaction {
if let Some(transaction_output_index) = htlc.transaction_output_index {
let expected_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&htlc, &a_htlc_key, &b_htlc_key, &revocation_pubkey);
if transaction_output_index as usize >= tx.output.len() ||
tx.output[transaction_output_index as usize].value != htlc.amount_msat / 1000 ||
tx.output[transaction_output_index as usize].script_pubkey != expected_script.to_v0_p2wsh() {
return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs, htlc_updated); // Corrupted per_commitment_data, fuck this user
}
if let Some(payment_preimage) = self.payment_preimages.get(&htlc.payment_hash) {
let input = TxIn {
previous_output: BitcoinOutPoint {
txid: commitment_txid,
vout: transaction_output_index,
},
script_sig: Script::new(),
sequence: idx as u32, // reset to 0xfffffffd in sign_input
witness: Vec::new(),
};
if htlc.cltv_expiry > height + CLTV_SHARED_CLAIM_BUFFER {
inputs.push(input);
values.push((tx.output[transaction_output_index as usize].value, payment_preimage));
total_value += htlc.amount_msat / 1000;
} else {
let mut single_htlc_tx = Transaction {
version: 2,
lock_time: 0,
input: vec![input],
output: vec!(TxOut {
script_pubkey: self.destination_script.clone(),
value: htlc.amount_msat / 1000, //TODO: - fee
}),
};
let sighash_parts = bip143::SighashComponents::new(&single_htlc_tx);
sign_input!(sighash_parts, single_htlc_tx.input[0], htlc.amount_msat / 1000, payment_preimage.0.to_vec());
spendable_outputs.push(SpendableOutputDescriptor::StaticOutput {
outpoint: BitcoinOutPoint { txid: single_htlc_tx.txid(), vout: 0 },
output: single_htlc_tx.output[0].clone(),
});
txn_to_broadcast.push(single_htlc_tx);
}
}
if !htlc.offered {
// TODO: If the HTLC has already expired, potentially merge it with the
// rest of the claim transaction, as above.
let input = TxIn {
previous_output: BitcoinOutPoint {
txid: commitment_txid,
vout: transaction_output_index,
},
script_sig: Script::new(),
sequence: idx as u32,
witness: Vec::new(),
};
let mut timeout_tx = Transaction {
version: 2,
lock_time: 0,
lock_time: htlc.cltv_expiry,
input: vec![input],
output: vec!(TxOut {
script_pubkey: self.destination_script.clone(),
value: htlc.amount_msat / 1000, //TODO: - fee
value: htlc.amount_msat / 1000,
}),
};
let sighash_parts = bip143::SighashComponents::new(&single_htlc_tx);
sign_input!(sighash_parts, single_htlc_tx.input[0], htlc.amount_msat / 1000, payment_preimage.0.to_vec());
spendable_outputs.push(SpendableOutputDescriptor::StaticOutput {
outpoint: BitcoinOutPoint { txid: single_htlc_tx.txid(), vout: 0 },
output: single_htlc_tx.output[0].clone(),
});
txn_to_broadcast.push(single_htlc_tx);
let sighash_parts = bip143::SighashComponents::new(&timeout_tx);
sign_input!(sighash_parts, timeout_tx.input[0], htlc.amount_msat / 1000, vec![0]);
txn_to_broadcast.push(timeout_tx);
}
}
if !htlc.offered {
// TODO: If the HTLC has already expired, potentially merge it with the
// rest of the claim transaction, as above.
let input = TxIn {
previous_output: BitcoinOutPoint {
txid: commitment_txid,
vout: htlc.transaction_output_index,
},
script_sig: Script::new(),
sequence: idx as u32,
witness: Vec::new(),
};
let mut timeout_tx = Transaction {
version: 2,
lock_time: htlc.cltv_expiry,
input: vec![input],
output: vec!(TxOut {
script_pubkey: self.destination_script.clone(),
value: htlc.amount_msat / 1000,
}),
};
let sighash_parts = bip143::SighashComponents::new(&timeout_tx);
sign_input!(sighash_parts, timeout_tx.input[0], htlc.amount_msat / 1000, vec![0]);
txn_to_broadcast.push(timeout_tx);
}
}
if inputs.is_empty() { return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs, htlc_updated); } // Nothing to be done...probably a false positive/local tx
@ -1570,40 +1576,42 @@ impl ChannelMonitor {
}
for &(ref htlc, ref their_sig, ref our_sig) in local_tx.htlc_outputs.iter() {
if htlc.offered {
let mut htlc_timeout_tx = chan_utils::build_htlc_transaction(&local_tx.txid, local_tx.feerate_per_kw, self.their_to_self_delay.unwrap(), htlc, &local_tx.delayed_payment_key, &local_tx.revocation_key);
if let Some(transaction_output_index) = htlc.transaction_output_index {
if htlc.offered {
let mut htlc_timeout_tx = chan_utils::build_htlc_transaction(&local_tx.txid, local_tx.feerate_per_kw, self.their_to_self_delay.unwrap(), htlc, &local_tx.delayed_payment_key, &local_tx.revocation_key);
htlc_timeout_tx.input[0].witness.push(Vec::new()); // First is the multisig dummy
htlc_timeout_tx.input[0].witness.push(Vec::new()); // First is the multisig dummy
htlc_timeout_tx.input[0].witness.push(their_sig.serialize_der(&self.secp_ctx).to_vec());
htlc_timeout_tx.input[0].witness[1].push(SigHashType::All as u8);
htlc_timeout_tx.input[0].witness.push(our_sig.serialize_der(&self.secp_ctx).to_vec());
htlc_timeout_tx.input[0].witness[2].push(SigHashType::All as u8);
htlc_timeout_tx.input[0].witness.push(their_sig.serialize_der(&self.secp_ctx).to_vec());
htlc_timeout_tx.input[0].witness[1].push(SigHashType::All as u8);
htlc_timeout_tx.input[0].witness.push(our_sig.serialize_der(&self.secp_ctx).to_vec());
htlc_timeout_tx.input[0].witness[2].push(SigHashType::All as u8);
htlc_timeout_tx.input[0].witness.push(Vec::new());
htlc_timeout_tx.input[0].witness.push(chan_utils::get_htlc_redeemscript_with_explicit_keys(htlc, &local_tx.a_htlc_key, &local_tx.b_htlc_key, &local_tx.revocation_key).into_bytes());
htlc_timeout_tx.input[0].witness.push(Vec::new());
htlc_timeout_tx.input[0].witness.push(chan_utils::get_htlc_redeemscript_with_explicit_keys(htlc, &local_tx.a_htlc_key, &local_tx.b_htlc_key, &local_tx.revocation_key).into_bytes());
add_dynamic_output!(htlc_timeout_tx, 0);
res.push(htlc_timeout_tx);
} else {
if let Some(payment_preimage) = self.payment_preimages.get(&htlc.payment_hash) {
let mut htlc_success_tx = chan_utils::build_htlc_transaction(&local_tx.txid, local_tx.feerate_per_kw, self.their_to_self_delay.unwrap(), htlc, &local_tx.delayed_payment_key, &local_tx.revocation_key);
add_dynamic_output!(htlc_timeout_tx, 0);
res.push(htlc_timeout_tx);
} else {
if let Some(payment_preimage) = self.payment_preimages.get(&htlc.payment_hash) {
let mut htlc_success_tx = chan_utils::build_htlc_transaction(&local_tx.txid, local_tx.feerate_per_kw, self.their_to_self_delay.unwrap(), htlc, &local_tx.delayed_payment_key, &local_tx.revocation_key);
htlc_success_tx.input[0].witness.push(Vec::new()); // First is the multisig dummy
htlc_success_tx.input[0].witness.push(Vec::new()); // First is the multisig dummy
htlc_success_tx.input[0].witness.push(their_sig.serialize_der(&self.secp_ctx).to_vec());
htlc_success_tx.input[0].witness[1].push(SigHashType::All as u8);
htlc_success_tx.input[0].witness.push(our_sig.serialize_der(&self.secp_ctx).to_vec());
htlc_success_tx.input[0].witness[2].push(SigHashType::All as u8);
htlc_success_tx.input[0].witness.push(their_sig.serialize_der(&self.secp_ctx).to_vec());
htlc_success_tx.input[0].witness[1].push(SigHashType::All as u8);
htlc_success_tx.input[0].witness.push(our_sig.serialize_der(&self.secp_ctx).to_vec());
htlc_success_tx.input[0].witness[2].push(SigHashType::All as u8);
htlc_success_tx.input[0].witness.push(payment_preimage.0.to_vec());
htlc_success_tx.input[0].witness.push(chan_utils::get_htlc_redeemscript_with_explicit_keys(htlc, &local_tx.a_htlc_key, &local_tx.b_htlc_key, &local_tx.revocation_key).into_bytes());
htlc_success_tx.input[0].witness.push(payment_preimage.0.to_vec());
htlc_success_tx.input[0].witness.push(chan_utils::get_htlc_redeemscript_with_explicit_keys(htlc, &local_tx.a_htlc_key, &local_tx.b_htlc_key, &local_tx.revocation_key).into_bytes());
add_dynamic_output!(htlc_success_tx, 0);
res.push(htlc_success_tx);
add_dynamic_output!(htlc_success_tx, 0);
res.push(htlc_success_tx);
}
}
watch_outputs.push(local_tx.tx.output[transaction_output_index as usize].clone());
}
watch_outputs.push(local_tx.tx.output[htlc.transaction_output_index as usize].clone());
}
(res, spendable_outputs, watch_outputs)
@ -1876,7 +1884,7 @@ impl ChannelMonitor {
}
if payment_data.is_none() {
for htlc_output in $htlc_outputs {
if input.previous_output.vout == htlc_output.transaction_output_index {
if Some(input.previous_output.vout) == htlc_output.transaction_output_index {
log_claim!($source, $local_tx, $local_tx == htlc_output.offered, htlc_output.payment_hash, false);
continue 'outer_loop;
}
@ -1935,6 +1943,13 @@ impl<R: ::std::io::Read> ReadableArgs<R, Arc<Logger>> for (Sha256dHash, ChannelM
}
}
}
macro_rules! read_option { () => {
match <u8 as Readable<R>>::read(reader)? {
0 => None,
1 => Some(Readable::read(reader)?),
_ => return Err(DecodeError::InvalidValue),
}
} }
let _ver: u8 = Readable::read(reader)?;
let min_ver: u8 = Readable::read(reader)?;
@ -1968,16 +1983,8 @@ impl<R: ::std::io::Read> ReadableArgs<R, Arc<Logger>> for (Sha256dHash, ChannelM
index: Readable::read(reader)?,
};
let funding_info = Some((outpoint, Readable::read(reader)?));
let current_remote_commitment_txid = match <u8 as Readable<R>>::read(reader)? {
0 => None,
1 => Some(Readable::read(reader)?),
_ => return Err(DecodeError::InvalidValue),
};
let prev_remote_commitment_txid = match <u8 as Readable<R>>::read(reader)? {
0 => None,
1 => Some(Readable::read(reader)?),
_ => return Err(DecodeError::InvalidValue),
};
let current_remote_commitment_txid = read_option!();
let prev_remote_commitment_txid = read_option!();
Storage::Local {
revocation_base_key,
htlc_base_key,
@ -2028,7 +2035,7 @@ impl<R: ::std::io::Read> ReadableArgs<R, Arc<Logger>> for (Sha256dHash, ChannelM
let amount_msat: u64 = Readable::read(reader)?;
let cltv_expiry: u32 = Readable::read(reader)?;
let payment_hash: PaymentHash = Readable::read(reader)?;
let transaction_output_index: u32 = Readable::read(reader)?;
let transaction_output_index: Option<u32> = read_option!();
HTLCOutputInCommitment {
offered, amount_msat, cltv_expiry, payment_hash, transaction_output_index
@ -2616,7 +2623,7 @@ mod tests {
amount_msat: 0,
cltv_expiry: 0,
payment_hash: preimage.1.clone(),
transaction_output_index: idx as u32,
transaction_output_index: Some(idx as u32),
});
}
res