Skip to content

Commit 89cbb6d

Browse files
authored
Merge pull request #1229 from lightning-signer/2021-12-htlc-anchor-sighashtype
anchors: Fix SigHashType and weight calculations for anchors
2 parents a82067d + 9c2270c commit 89cbb6d

9 files changed

+562
-187
lines changed

lightning/src/chain/channelmonitor.rs

+83-69
Original file line numberDiff line numberDiff line change
@@ -2041,7 +2041,7 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
20412041
tx.output[transaction_output_index as usize].value != htlc.amount_msat / 1000 {
20422042
return (claimable_outpoints, (commitment_txid, watch_outputs)); // Corrupted per_commitment_data, fuck this user
20432043
}
2044-
let revk_htlc_outp = RevokedHTLCOutput::build(per_commitment_point, self.counterparty_commitment_params.counterparty_delayed_payment_base_key, self.counterparty_commitment_params.counterparty_htlc_base_key, per_commitment_key, htlc.amount_msat / 1000, htlc.clone());
2044+
let revk_htlc_outp = RevokedHTLCOutput::build(per_commitment_point, self.counterparty_commitment_params.counterparty_delayed_payment_base_key, self.counterparty_commitment_params.counterparty_htlc_base_key, per_commitment_key, htlc.amount_msat / 1000, htlc.clone(), self.onchain_tx_handler.channel_transaction_parameters.opt_anchors.is_some());
20452045
let justice_package = PackageTemplate::build_package(commitment_txid, transaction_output_index, PackageSolvingData::RevokedHTLCOutput(revk_htlc_outp), htlc.cltv_expiry, true, height);
20462046
claimable_outpoints.push(justice_package);
20472047
}
@@ -3307,7 +3307,7 @@ mod tests {
33073307
use ::{check_added_monitors, check_closed_broadcast, check_closed_event, check_spends, get_local_commitment_txn, get_monitor, get_route_and_payment_hash, unwrap_send_err};
33083308
use chain::{BestBlock, Confirm};
33093309
use chain::channelmonitor::ChannelMonitor;
3310-
use chain::package::{WEIGHT_OFFERED_HTLC, WEIGHT_RECEIVED_HTLC, WEIGHT_REVOKED_OFFERED_HTLC, WEIGHT_REVOKED_RECEIVED_HTLC, WEIGHT_REVOKED_OUTPUT};
3310+
use chain::package::{weight_offered_htlc, weight_received_htlc, weight_revoked_offered_htlc, weight_revoked_received_htlc, WEIGHT_REVOKED_OUTPUT};
33113311
use chain::transaction::OutPoint;
33123312
use chain::keysinterface::InMemorySigner;
33133313
use ln::{PaymentPreimage, PaymentHash};
@@ -3564,12 +3564,11 @@ mod tests {
35643564
let secp_ctx = Secp256k1::new();
35653565
let privkey = SecretKey::from_slice(&hex::decode("0101010101010101010101010101010101010101010101010101010101010101").unwrap()[..]).unwrap();
35663566
let pubkey = PublicKey::from_secret_key(&secp_ctx, &privkey);
3567-
let mut sum_actual_sigs = 0;
35683567

35693568
macro_rules! sign_input {
35703569
($sighash_parts: expr, $idx: expr, $amount: expr, $weight: expr, $sum_actual_sigs: expr, $opt_anchors: expr) => {
35713570
let htlc = HTLCOutputInCommitment {
3572-
offered: if *$weight == WEIGHT_REVOKED_OFFERED_HTLC || *$weight == WEIGHT_OFFERED_HTLC { true } else { false },
3571+
offered: if *$weight == weight_revoked_offered_htlc($opt_anchors) || *$weight == weight_offered_htlc($opt_anchors) { true } else { false },
35733572
amount_msat: 0,
35743573
cltv_expiry: 2 << 16,
35753574
payment_hash: PaymentHash([1; 32]),
@@ -3580,12 +3579,12 @@ mod tests {
35803579
let sig = secp_ctx.sign(&sighash, &privkey);
35813580
$sighash_parts.access_witness($idx).push(sig.serialize_der().to_vec());
35823581
$sighash_parts.access_witness($idx)[0].push(SigHashType::All as u8);
3583-
sum_actual_sigs += $sighash_parts.access_witness($idx)[0].len();
3582+
$sum_actual_sigs += $sighash_parts.access_witness($idx)[0].len();
35843583
if *$weight == WEIGHT_REVOKED_OUTPUT {
35853584
$sighash_parts.access_witness($idx).push(vec!(1));
3586-
} else if *$weight == WEIGHT_REVOKED_OFFERED_HTLC || *$weight == WEIGHT_REVOKED_RECEIVED_HTLC {
3585+
} else if *$weight == weight_revoked_offered_htlc($opt_anchors) || *$weight == weight_revoked_received_htlc($opt_anchors) {
35873586
$sighash_parts.access_witness($idx).push(pubkey.clone().serialize().to_vec());
3588-
} else if *$weight == WEIGHT_RECEIVED_HTLC {
3587+
} else if *$weight == weight_received_htlc($opt_anchors) {
35893588
$sighash_parts.access_witness($idx).push(vec![0]);
35903589
} else {
35913590
$sighash_parts.access_witness($idx).push(PaymentPreimage([1; 32]).0.to_vec());
@@ -3601,83 +3600,98 @@ mod tests {
36013600
let txid = Txid::from_hex("56944c5d3f98413ef45cf54545538103cc9f298e0575820ad3591376e2e0f65d").unwrap();
36023601

36033602
// Justice tx with 1 to_holder, 2 revoked offered HTLCs, 1 revoked received HTLCs
3604-
let mut claim_tx = Transaction { version: 0, lock_time: 0, input: Vec::new(), output: Vec::new() };
3605-
for i in 0..4 {
3606-
claim_tx.input.push(TxIn {
3607-
previous_output: BitcoinOutPoint {
3608-
txid,
3609-
vout: i,
3610-
},
3611-
script_sig: Script::new(),
3612-
sequence: 0xfffffffd,
3613-
witness: Vec::new(),
3603+
for &opt_anchors in [false, true].iter() {
3604+
let mut claim_tx = Transaction { version: 0, lock_time: 0, input: Vec::new(), output: Vec::new() };
3605+
let mut sum_actual_sigs = 0;
3606+
for i in 0..4 {
3607+
claim_tx.input.push(TxIn {
3608+
previous_output: BitcoinOutPoint {
3609+
txid,
3610+
vout: i,
3611+
},
3612+
script_sig: Script::new(),
3613+
sequence: 0xfffffffd,
3614+
witness: Vec::new(),
3615+
});
3616+
}
3617+
claim_tx.output.push(TxOut {
3618+
script_pubkey: script_pubkey.clone(),
3619+
value: 0,
36143620
});
3615-
}
3616-
claim_tx.output.push(TxOut {
3617-
script_pubkey: script_pubkey.clone(),
3618-
value: 0,
3619-
});
3620-
let base_weight = claim_tx.get_weight();
3621-
let inputs_weight = vec![WEIGHT_REVOKED_OUTPUT, WEIGHT_REVOKED_OFFERED_HTLC, WEIGHT_REVOKED_OFFERED_HTLC, WEIGHT_REVOKED_RECEIVED_HTLC];
3622-
let mut inputs_total_weight = 2; // count segwit flags
3623-
{
3624-
let mut sighash_parts = bip143::SigHashCache::new(&mut claim_tx);
3625-
for (idx, inp) in inputs_weight.iter().enumerate() {
3626-
sign_input!(sighash_parts, idx, 0, inp, sum_actual_sigs, false);
3627-
inputs_total_weight += inp;
3621+
let base_weight = claim_tx.get_weight();
3622+
let inputs_weight = vec![WEIGHT_REVOKED_OUTPUT, weight_revoked_offered_htlc(opt_anchors), weight_revoked_offered_htlc(opt_anchors), weight_revoked_received_htlc(opt_anchors)];
3623+
let mut inputs_total_weight = 2; // count segwit flags
3624+
{
3625+
let mut sighash_parts = bip143::SigHashCache::new(&mut claim_tx);
3626+
for (idx, inp) in inputs_weight.iter().enumerate() {
3627+
sign_input!(sighash_parts, idx, 0, inp, sum_actual_sigs, opt_anchors);
3628+
inputs_total_weight += inp;
3629+
}
36283630
}
3631+
assert_eq!(base_weight + inputs_total_weight as usize, claim_tx.get_weight() + /* max_length_sig */ (73 * inputs_weight.len() - sum_actual_sigs));
36293632
}
3630-
assert_eq!(base_weight + inputs_total_weight as usize, claim_tx.get_weight() + /* max_length_sig */ (73 * inputs_weight.len() - sum_actual_sigs));
36313633

36323634
// Claim tx with 1 offered HTLCs, 3 received HTLCs
3633-
claim_tx.input.clear();
3634-
sum_actual_sigs = 0;
3635-
for i in 0..4 {
3635+
for &opt_anchors in [false, true].iter() {
3636+
let mut claim_tx = Transaction { version: 0, lock_time: 0, input: Vec::new(), output: Vec::new() };
3637+
let mut sum_actual_sigs = 0;
3638+
for i in 0..4 {
3639+
claim_tx.input.push(TxIn {
3640+
previous_output: BitcoinOutPoint {
3641+
txid,
3642+
vout: i,
3643+
},
3644+
script_sig: Script::new(),
3645+
sequence: 0xfffffffd,
3646+
witness: Vec::new(),
3647+
});
3648+
}
3649+
claim_tx.output.push(TxOut {
3650+
script_pubkey: script_pubkey.clone(),
3651+
value: 0,
3652+
});
3653+
let base_weight = claim_tx.get_weight();
3654+
let inputs_weight = vec![weight_offered_htlc(opt_anchors), weight_received_htlc(opt_anchors), weight_received_htlc(opt_anchors), weight_received_htlc(opt_anchors)];
3655+
let mut inputs_total_weight = 2; // count segwit flags
3656+
{
3657+
let mut sighash_parts = bip143::SigHashCache::new(&mut claim_tx);
3658+
for (idx, inp) in inputs_weight.iter().enumerate() {
3659+
sign_input!(sighash_parts, idx, 0, inp, sum_actual_sigs, opt_anchors);
3660+
inputs_total_weight += inp;
3661+
}
3662+
}
3663+
assert_eq!(base_weight + inputs_total_weight as usize, claim_tx.get_weight() + /* max_length_sig */ (73 * inputs_weight.len() - sum_actual_sigs));
3664+
}
3665+
3666+
// Justice tx with 1 revoked HTLC-Success tx output
3667+
for &opt_anchors in [false, true].iter() {
3668+
let mut claim_tx = Transaction { version: 0, lock_time: 0, input: Vec::new(), output: Vec::new() };
3669+
let mut sum_actual_sigs = 0;
36363670
claim_tx.input.push(TxIn {
36373671
previous_output: BitcoinOutPoint {
36383672
txid,
3639-
vout: i,
3673+
vout: 0,
36403674
},
36413675
script_sig: Script::new(),
36423676
sequence: 0xfffffffd,
36433677
witness: Vec::new(),
36443678
});
3645-
}
3646-
let base_weight = claim_tx.get_weight();
3647-
let inputs_weight = vec![WEIGHT_OFFERED_HTLC, WEIGHT_RECEIVED_HTLC, WEIGHT_RECEIVED_HTLC, WEIGHT_RECEIVED_HTLC];
3648-
let mut inputs_total_weight = 2; // count segwit flags
3649-
{
3650-
let mut sighash_parts = bip143::SigHashCache::new(&mut claim_tx);
3651-
for (idx, inp) in inputs_weight.iter().enumerate() {
3652-
sign_input!(sighash_parts, idx, 0, inp, sum_actual_sigs, false);
3653-
inputs_total_weight += inp;
3654-
}
3655-
}
3656-
assert_eq!(base_weight + inputs_total_weight as usize, claim_tx.get_weight() + /* max_length_sig */ (73 * inputs_weight.len() - sum_actual_sigs));
3657-
3658-
// Justice tx with 1 revoked HTLC-Success tx output
3659-
claim_tx.input.clear();
3660-
sum_actual_sigs = 0;
3661-
claim_tx.input.push(TxIn {
3662-
previous_output: BitcoinOutPoint {
3663-
txid,
3664-
vout: 0,
3665-
},
3666-
script_sig: Script::new(),
3667-
sequence: 0xfffffffd,
3668-
witness: Vec::new(),
3669-
});
3670-
let base_weight = claim_tx.get_weight();
3671-
let inputs_weight = vec![WEIGHT_REVOKED_OUTPUT];
3672-
let mut inputs_total_weight = 2; // count segwit flags
3673-
{
3674-
let mut sighash_parts = bip143::SigHashCache::new(&mut claim_tx);
3675-
for (idx, inp) in inputs_weight.iter().enumerate() {
3676-
sign_input!(sighash_parts, idx, 0, inp, sum_actual_sigs, false);
3677-
inputs_total_weight += inp;
3679+
claim_tx.output.push(TxOut {
3680+
script_pubkey: script_pubkey.clone(),
3681+
value: 0,
3682+
});
3683+
let base_weight = claim_tx.get_weight();
3684+
let inputs_weight = vec![WEIGHT_REVOKED_OUTPUT];
3685+
let mut inputs_total_weight = 2; // count segwit flags
3686+
{
3687+
let mut sighash_parts = bip143::SigHashCache::new(&mut claim_tx);
3688+
for (idx, inp) in inputs_weight.iter().enumerate() {
3689+
sign_input!(sighash_parts, idx, 0, inp, sum_actual_sigs, opt_anchors);
3690+
inputs_total_weight += inp;
3691+
}
36783692
}
3693+
assert_eq!(base_weight + inputs_total_weight as usize, claim_tx.get_weight() + /* max_length_isg */ (73 * inputs_weight.len() - sum_actual_sigs));
36793694
}
3680-
assert_eq!(base_weight + inputs_total_weight as usize, claim_tx.get_weight() + /* max_length_isg */ (73 * inputs_weight.len() - sum_actual_sigs));
36813695
}
36823696

36833697
// Further testing is done in the ChannelManager integration tests.

lightning/src/chain/keysinterface.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -612,7 +612,8 @@ impl BaseSign for InMemorySigner {
612612
for htlc in commitment_tx.htlcs() {
613613
let htlc_tx = chan_utils::build_htlc_transaction(&commitment_txid, commitment_tx.feerate_per_kw(), self.holder_selected_contest_delay(), htlc, self.opt_anchors(), &keys.broadcaster_delayed_payment_key, &keys.revocation_key);
614614
let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, self.opt_anchors(), &keys);
615-
let htlc_sighash = hash_to_message!(&bip143::SigHashCache::new(&htlc_tx).signature_hash(0, &htlc_redeemscript, htlc.amount_msat / 1000, SigHashType::All)[..]);
615+
let htlc_sighashtype = if self.opt_anchors() { SigHashType::SinglePlusAnyoneCanPay } else { SigHashType::All };
616+
let htlc_sighash = hash_to_message!(&bip143::SigHashCache::new(&htlc_tx).signature_hash(0, &htlc_redeemscript, htlc.amount_msat / 1000, htlc_sighashtype)[..]);
616617
let holder_htlc_key = chan_utils::derive_private_key(&secp_ctx, &keys.per_commitment_point, &self.htlc_base_key).map_err(|_| ())?;
617618
htlc_sigs.push(secp_ctx.sign(&htlc_sighash, &holder_htlc_key));
618619
}

lightning/src/chain/onchaintx.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,7 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
387387
// didn't receive confirmation of it before, or not enough reorg-safe depth on top of it).
388388
let new_timer = Some(cached_request.get_height_timer(cur_height));
389389
if cached_request.is_malleable() {
390-
let predicted_weight = cached_request.package_weight(&self.destination_script);
390+
let predicted_weight = cached_request.package_weight(&self.destination_script, self.channel_transaction_parameters.opt_anchors.is_some());
391391
if let Some((output_value, new_feerate)) =
392392
cached_request.compute_package_output(predicted_weight, self.destination_script.dust_value().as_sat(), fee_estimator, logger) {
393393
assert!(new_feerate != 0);

0 commit comments

Comments
 (0)