Skip to content

Commit 13a6604

Browse files
author
Antoine Riard
committed
Remove SecretKey from DynamicOutputP2WSH descriptor
Add sign_delayed_transaction in ChanSigner to be able to spend SpendableOutputDescriptor in test framework.
1 parent 4fd727f commit 13a6604

File tree

4 files changed

+59
-34
lines changed

4 files changed

+59
-34
lines changed

lightning/src/chain/keysinterface.rs

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,8 @@ pub enum SpendableOutputDescriptor {
6565
DynamicOutputP2WSH {
6666
/// The outpoint which is spendable
6767
outpoint: OutPoint,
68-
/// The secret key which must be used to sign the spending transaction
69-
key: SecretKey,
68+
/// Per commitment point to derive delayed_payment_key by key holder
69+
per_commitment_point: PublicKey,
7070
/// The witness redeemScript which is hashed to create the script_pubkey in the given output
7171
witness_script: Script,
7272
/// The nSequence value which must be set in the spending input to satisfy the OP_CSV in
@@ -98,10 +98,10 @@ impl Writeable for SpendableOutputDescriptor {
9898
outpoint.write(writer)?;
9999
output.write(writer)?;
100100
},
101-
&SpendableOutputDescriptor::DynamicOutputP2WSH { ref outpoint, ref key, ref witness_script, ref to_self_delay, ref output } => {
101+
&SpendableOutputDescriptor::DynamicOutputP2WSH { ref outpoint, ref per_commitment_point, ref witness_script, ref to_self_delay, ref output } => {
102102
1u8.write(writer)?;
103103
outpoint.write(writer)?;
104-
key.write(writer)?;
104+
per_commitment_point.write(writer)?;
105105
witness_script.write(writer)?;
106106
to_self_delay.write(writer)?;
107107
output.write(writer)?;
@@ -126,7 +126,7 @@ impl Readable for SpendableOutputDescriptor {
126126
}),
127127
1u8 => Ok(SpendableOutputDescriptor::DynamicOutputP2WSH {
128128
outpoint: Readable::read(reader)?,
129-
key: Readable::read(reader)?,
129+
per_commitment_point: Readable::read(reader)?,
130130
witness_script: Readable::read(reader)?,
131131
to_self_delay: Readable::read(reader)?,
132132
output: Readable::read(reader)?,
@@ -258,6 +258,9 @@ pub trait ChannelKeys : Send+Clone {
258258
/// chosen to forgo their output as dust.
259259
fn sign_closing_transaction<T: secp256k1::Signing>(&self, closing_tx: &Transaction, secp_ctx: &Secp256k1<T>) -> Result<Signature, ()>;
260260

261+
/// Create a signature for a delayed transaction.
262+
fn sign_delayed_transaction<T: secp256k1::Signing>(&self, spend_tx: &mut Transaction, input: usize, witness_script: &Script, amount: u64, per_commitment_point: &PublicKey, secp_ctx: &Secp256k1<T>);
263+
261264
/// Signs a channel announcement message with our funding key, proving it comes from one
262265
/// of the channel participants.
263266
///
@@ -446,6 +449,18 @@ impl ChannelKeys for InMemoryChannelKeys {
446449
Ok(secp_ctx.sign(&sighash, &self.funding_key))
447450
}
448451

452+
fn sign_delayed_transaction<T: secp256k1::Signing>(&self, spend_tx: &mut Transaction, input: usize, witness_script: &Script, amount: u64, per_commitment_point: &PublicKey, secp_ctx: &Secp256k1<T>) {
453+
if let Ok(htlc_key) = chan_utils::derive_private_key(&secp_ctx, &per_commitment_point, &self.delayed_payment_base_key) {
454+
let sighash_parts = bip143::SighashComponents::new(&spend_tx);
455+
let sighash = hash_to_message!(&sighash_parts.sighash_all(&spend_tx.input[input], witness_script, amount)[..]);
456+
let local_delaysig = secp_ctx.sign(&sighash, &htlc_key);
457+
spend_tx.input[0].witness.push(local_delaysig.serialize_der().to_vec());
458+
spend_tx.input[0].witness[0].push(SigHashType::All as u8);
459+
spend_tx.input[0].witness.push(vec!(0));
460+
spend_tx.input[0].witness.push(witness_script.clone().into_bytes());
461+
}
462+
}
463+
449464
fn sign_channel_announcement<T: secp256k1::Signing>(&self, msg: &msgs::UnsignedChannelAnnouncement, secp_ctx: &Secp256k1<T>) -> Result<Signature, ()> {
450465
let msghash = hash_to_message!(&Sha256dHash::hash(&msg.encode()[..])[..]);
451466
Ok(secp_ctx.sign(&msghash, &self.funding_key))

lightning/src/ln/channelmonitor.rs

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -713,7 +713,7 @@ pub struct ChannelMonitor<ChanSigner: ChannelKeys> {
713713
commitment_transaction_number_obscure_factor: u64,
714714

715715
destination_script: Script,
716-
broadcasted_local_revokable_script: Option<(Script, SecretKey, Script)>,
716+
broadcasted_local_revokable_script: Option<(Script, PublicKey, Script)>,
717717
broadcasted_remote_payment_script: Option<(Script, SecretKey)>,
718718
shutdown_script: Script,
719719

@@ -1650,14 +1650,12 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
16501650
(claimable_outpoints, Some((htlc_txid, tx.output.clone())))
16511651
}
16521652

1653-
fn broadcast_by_local_state(&self, commitment_tx: &Transaction, local_tx: &LocalSignedTx) -> (Vec<ClaimRequest>, Vec<TxOut>, Option<(Script, SecretKey, Script)>) {
1653+
fn broadcast_by_local_state(&self, commitment_tx: &Transaction, local_tx: &LocalSignedTx) -> (Vec<ClaimRequest>, Vec<TxOut>, Option<(Script, PublicKey, Script)>) {
16541654
let mut claim_requests = Vec::with_capacity(local_tx.htlc_outputs.len());
16551655
let mut watch_outputs = Vec::with_capacity(local_tx.htlc_outputs.len());
16561656

16571657
let redeemscript = chan_utils::get_revokeable_redeemscript(&local_tx.revocation_key, self.their_to_self_delay, &local_tx.delayed_payment_key);
1658-
let broadcasted_local_revokable_script = if let Ok(local_delayedkey) = chan_utils::derive_private_key(&self.secp_ctx, &local_tx.per_commitment_point, self.keys.delayed_payment_base_key()) {
1659-
Some((redeemscript.to_v0_p2wsh(), local_delayedkey, redeemscript))
1660-
} else { None };
1658+
let broadcasted_local_revokable_script = Some((redeemscript.to_v0_p2wsh(), local_tx.per_commitment_point.clone(), redeemscript));
16611659

16621660
for &(ref htlc, _, _) in local_tx.htlc_outputs.iter() {
16631661
if let Some(transaction_output_index) = htlc.transaction_output_index {
@@ -2161,7 +2159,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
21612159
if broadcasted_local_revokable_script.0 == outp.script_pubkey {
21622160
spendable_output = Some(SpendableOutputDescriptor::DynamicOutputP2WSH {
21632161
outpoint: BitcoinOutPoint { txid: tx.txid(), vout: i as u32 },
2164-
key: broadcasted_local_revokable_script.1,
2162+
per_commitment_point: broadcasted_local_revokable_script.1,
21652163
witness_script: broadcasted_local_revokable_script.2.clone(),
21662164
to_self_delay: self.their_to_self_delay,
21672165
output: outp.clone(),
@@ -2225,9 +2223,9 @@ impl<ChanSigner: ChannelKeys + Readable> ReadableArgs<Arc<Logger>> for (Sha256dH
22252223
let broadcasted_local_revokable_script = match <u8 as Readable>::read(reader)? {
22262224
0 => {
22272225
let revokable_address = Readable::read(reader)?;
2228-
let local_delayedkey = Readable::read(reader)?;
2226+
let per_commitment_point = Readable::read(reader)?;
22292227
let revokable_script = Readable::read(reader)?;
2230-
Some((revokable_address, local_delayedkey, revokable_script))
2228+
Some((revokable_address, per_commitment_point, revokable_script))
22312229
},
22322230
1 => { None },
22332231
_ => return Err(DecodeError::InvalidValue),

lightning/src/ln/functional_tests.rs

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4087,7 +4087,7 @@ fn test_manager_serialize_deserialize_inconsistent_monitor() {
40874087
}
40884088

40894089
macro_rules! check_spendable_outputs {
4090-
($node: expr, $der_idx: expr) => {
4090+
($node: expr, $der_idx: expr, $chan_signer: expr) => {
40914091
{
40924092
let events = $node.chan_monitor.simple_monitor.get_and_clear_pending_events();
40934093
let mut txn = Vec::new();
@@ -4123,7 +4123,7 @@ macro_rules! check_spendable_outputs {
41234123
spend_tx.input[0].witness.push(remotepubkey.serialize().to_vec());
41244124
txn.push(spend_tx);
41254125
},
4126-
SpendableOutputDescriptor::DynamicOutputP2WSH { ref outpoint, ref key, ref witness_script, ref to_self_delay, ref output } => {
4126+
SpendableOutputDescriptor::DynamicOutputP2WSH { ref outpoint, ref per_commitment_point, ref witness_script, ref to_self_delay, ref output } => {
41274127
let input = TxIn {
41284128
previous_output: outpoint.clone(),
41294129
script_sig: Script::new(),
@@ -4141,12 +4141,7 @@ macro_rules! check_spendable_outputs {
41414141
output: vec![outp],
41424142
};
41434143
let secp_ctx = Secp256k1::new();
4144-
let sighash = Message::from_slice(&bip143::SighashComponents::new(&spend_tx).sighash_all(&spend_tx.input[0], witness_script, output.value)[..]).unwrap();
4145-
let local_delaysig = secp_ctx.sign(&sighash, key);
4146-
spend_tx.input[0].witness.push(local_delaysig.serialize_der().to_vec());
4147-
spend_tx.input[0].witness[0].push(SigHashType::All as u8);
4148-
spend_tx.input[0].witness.push(vec!());
4149-
spend_tx.input[0].witness.push(witness_script.clone().into_bytes());
4144+
$chan_signer.sign_delayed_transaction(&mut spend_tx, 0, &witness_script, output.value, per_commitment_point, &secp_ctx);
41504145
txn.push(spend_tx);
41514146
},
41524147
SpendableOutputDescriptor::StaticOutput { ref outpoint, ref output } => {
@@ -4219,7 +4214,8 @@ fn test_claim_sizeable_push_msat() {
42194214
nodes[1].block_notifier.block_connected(&Block { header, txdata: vec![node_txn[0].clone()] }, 0);
42204215
connect_blocks(&nodes[1].block_notifier, ANTI_REORG_DELAY - 1, 1, true, header.bitcoin_hash());
42214216

4222-
let spend_txn = check_spendable_outputs!(nodes[1], 1);
4217+
let chan_signer = get_chan_signer!(nodes[1], chan.2);
4218+
let spend_txn = check_spendable_outputs!(nodes[1], 1, chan_signer);
42234219
assert_eq!(spend_txn.len(), 1);
42244220
check_spends!(spend_txn[0], node_txn[0]);
42254221
}
@@ -4249,7 +4245,8 @@ fn test_claim_on_remote_sizeable_push_msat() {
42494245
check_added_monitors!(nodes[1], 1);
42504246
connect_blocks(&nodes[1].block_notifier, ANTI_REORG_DELAY - 1, 1, true, header.bitcoin_hash());
42514247

4252-
let spend_txn = check_spendable_outputs!(nodes[1], 1);
4248+
let chan_signer = get_chan_signer!(nodes[1], chan.2);
4249+
let spend_txn = check_spendable_outputs!(nodes[1], 1, chan_signer);
42534250
assert_eq!(spend_txn.len(), 2);
42544251
assert_eq!(spend_txn[0], spend_txn[1]);
42554252
check_spends!(spend_txn[0], node_txn[0]);
@@ -4282,7 +4279,8 @@ fn test_claim_on_remote_revoked_sizeable_push_msat() {
42824279
nodes[1].block_notifier.block_connected(&Block { header: header_1, txdata: vec![node_txn[0].clone()] }, 1);
42834280
connect_blocks(&nodes[1].block_notifier, ANTI_REORG_DELAY - 1, 1, true, header.bitcoin_hash());
42844281

4285-
let spend_txn = check_spendable_outputs!(nodes[1], 1);
4282+
let chan_signer = get_chan_signer!(nodes[1], chan.2);
4283+
let spend_txn = check_spendable_outputs!(nodes[1], 1, chan_signer);
42864284
assert_eq!(spend_txn.len(), 3);
42874285
assert_eq!(spend_txn[0], spend_txn[1]); // to_remote output on revoked remote commitment_tx
42884286
check_spends!(spend_txn[0], revoked_local_txn[0]);
@@ -4333,7 +4331,8 @@ fn test_static_spendable_outputs_preimage_tx() {
43334331
nodes[1].block_notifier.block_connected(&Block { header: header_1, txdata: vec![node_txn[0].clone()] }, 1);
43344332
connect_blocks(&nodes[1].block_notifier, ANTI_REORG_DELAY - 1, 1, true, header.bitcoin_hash());
43354333

4336-
let spend_txn = check_spendable_outputs!(nodes[1], 1);
4334+
let chan_signer = get_chan_signer!(nodes[1], chan_1.2);
4335+
let spend_txn = check_spendable_outputs!(nodes[1], 1, chan_signer);
43374336
assert_eq!(spend_txn.len(), 1);
43384337
check_spends!(spend_txn[0], node_txn[0]);
43394338
}
@@ -4380,7 +4379,8 @@ fn test_static_spendable_outputs_timeout_tx() {
43804379
connect_blocks(&nodes[1].block_notifier, ANTI_REORG_DELAY - 1, 1, true, header.bitcoin_hash());
43814380
expect_payment_failed!(nodes[1], our_payment_hash, true);
43824381

4383-
let spend_txn = check_spendable_outputs!(nodes[1], 1);
4382+
let chan_signer = get_chan_signer!(nodes[1], chan_1.2);
4383+
let spend_txn = check_spendable_outputs!(nodes[1], 1, chan_signer);
43844384
assert_eq!(spend_txn.len(), 3); // SpendableOutput: remote_commitment_tx.to_remote (*2), timeout_tx.output (*1)
43854385
check_spends!(spend_txn[2], node_txn[0].clone());
43864386
}
@@ -4416,7 +4416,8 @@ fn test_static_spendable_outputs_justice_tx_revoked_commitment_tx() {
44164416
nodes[1].block_notifier.block_connected(&Block { header: header_1, txdata: vec![node_txn[0].clone()] }, 1);
44174417
connect_blocks(&nodes[1].block_notifier, ANTI_REORG_DELAY - 1, 1, true, header.bitcoin_hash());
44184418

4419-
let spend_txn = check_spendable_outputs!(nodes[1], 1);
4419+
let chan_signer = get_chan_signer!(nodes[1], chan_1.2);
4420+
let spend_txn = check_spendable_outputs!(nodes[1], 1, chan_signer);
44204421
assert_eq!(spend_txn.len(), 1);
44214422
check_spends!(spend_txn[0], node_txn[0]);
44224423
}
@@ -4471,7 +4472,8 @@ fn test_static_spendable_outputs_justice_tx_revoked_htlc_timeout_tx() {
44714472
connect_blocks(&nodes[1].block_notifier, ANTI_REORG_DELAY - 1, 1, true, header.bitcoin_hash());
44724473

44734474
// Check B's ChannelMonitor was able to generate the right spendable output descriptor
4474-
let spend_txn = check_spendable_outputs!(nodes[1], 1);
4475+
let chan_signer = get_chan_signer!(nodes[1], chan_1.2);
4476+
let spend_txn = check_spendable_outputs!(nodes[1], 1, chan_signer);
44754477
assert_eq!(spend_txn.len(), 2);
44764478
check_spends!(spend_txn[0], node_txn[0]);
44774479
check_spends!(spend_txn[1], node_txn[2]);
@@ -4521,7 +4523,8 @@ fn test_static_spendable_outputs_justice_tx_revoked_htlc_success_tx() {
45214523
connect_blocks(&nodes[0].block_notifier, ANTI_REORG_DELAY - 1, 1, true, header.bitcoin_hash());
45224524

45234525
// Check A's ChannelMonitor was able to generate the right spendable output descriptor
4524-
let spend_txn = check_spendable_outputs!(nodes[0], 1);
4526+
let chan_signer = get_chan_signer!(nodes[0], chan_1.2);
4527+
let spend_txn = check_spendable_outputs!(nodes[0], 1, chan_signer);
45254528
assert_eq!(spend_txn.len(), 5); // Duplicated SpendableOutput due to block rescan after revoked htlc output tracking
45264529
assert_eq!(spend_txn[0], spend_txn[1]);
45274530
assert_eq!(spend_txn[0], spend_txn[2]);
@@ -4791,7 +4794,8 @@ fn test_dynamic_spendable_outputs_local_htlc_success_tx() {
47914794
connect_blocks(&nodes[1].block_notifier, ANTI_REORG_DELAY - 1, 201, true, header_201.bitcoin_hash());
47924795

47934796
// Verify that B is able to spend its own HTLC-Success tx thanks to spendable output event given back by its ChannelMonitor
4794-
let spend_txn = check_spendable_outputs!(nodes[1], 1);
4797+
let chan_signer = get_chan_signer!(nodes[1], chan_1.2);
4798+
let spend_txn = check_spendable_outputs!(nodes[1], 1, chan_signer);
47954799
assert_eq!(spend_txn.len(), 2);
47964800
check_spends!(spend_txn[0], node_txn[0]);
47974801
check_spends!(spend_txn[1], node_txn[1]);
@@ -5085,7 +5089,8 @@ fn test_dynamic_spendable_outputs_local_htlc_timeout_tx() {
50855089
expect_payment_failed!(nodes[0], our_payment_hash, true);
50865090

50875091
// Verify that A is able to spend its own HTLC-Timeout tx thanks to spendable output event given back by its ChannelMonitor
5088-
let spend_txn = check_spendable_outputs!(nodes[0], 1);
5092+
let chan_signer = get_chan_signer!(nodes[0], chan_1.2);
5093+
let spend_txn = check_spendable_outputs!(nodes[0], 1, chan_signer);
50895094
assert_eq!(spend_txn.len(), 3);
50905095
assert_eq!(spend_txn[0], spend_txn[1]);
50915096
check_spends!(spend_txn[0], local_txn[0]);
@@ -5108,14 +5113,16 @@ fn test_static_output_closing_tx() {
51085113
nodes[0].block_notifier.block_connected(&Block { header, txdata: vec![closing_tx.clone()] }, 0);
51095114
connect_blocks(&nodes[0].block_notifier, ANTI_REORG_DELAY - 1, 0, true, header.bitcoin_hash());
51105115

5111-
let spend_txn = check_spendable_outputs!(nodes[0], 2);
5116+
let chan_signer = get_chan_signer!(nodes[0], chan.2);
5117+
let spend_txn = check_spendable_outputs!(nodes[0], 2, chan_signer);
51125118
assert_eq!(spend_txn.len(), 1);
51135119
check_spends!(spend_txn[0], closing_tx);
51145120

51155121
nodes[1].block_notifier.block_connected(&Block { header, txdata: vec![closing_tx.clone()] }, 0);
51165122
connect_blocks(&nodes[1].block_notifier, ANTI_REORG_DELAY - 1, 0, true, header.bitcoin_hash());
51175123

5118-
let spend_txn = check_spendable_outputs!(nodes[1], 2);
5124+
let chan_signer = get_chan_signer!(nodes[1], chan.2);
5125+
let spend_txn = check_spendable_outputs!(nodes[1], 2, chan_signer);
51195126
assert_eq!(spend_txn.len(), 1);
51205127
check_spends!(spend_txn[0], closing_tx);
51215128
}
@@ -6909,7 +6916,8 @@ fn test_data_loss_protect() {
69096916
let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42};
69106917
nodes[0].block_notifier.block_connected(&Block { header, txdata: vec![node_txn[0].clone()]}, 0);
69116918
connect_blocks(&nodes[0].block_notifier, ANTI_REORG_DELAY - 1, 0, true, header.bitcoin_hash());
6912-
let spend_txn = check_spendable_outputs!(nodes[0], 1);
6919+
let chan_signer = get_chan_signer!(nodes[0], chan.2);
6920+
let spend_txn = check_spendable_outputs!(nodes[0], 1, chan_signer);
69136921
assert_eq!(spend_txn.len(), 1);
69146922
check_spends!(spend_txn[0], node_txn[0]);
69156923
}

lightning/src/util/enforcing_trait_impls.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,10 @@ impl ChannelKeys for EnforcingChannelKeys {
115115
self.inner.sign_remote_htlc_transaction(bumped_tx, input, witness_script, amount, per_commitment_point, preimage, secp_ctx);
116116
}
117117

118+
fn sign_delayed_transaction<T: secp256k1::Signing>(&self, spend_tx: &mut Transaction, input: usize, witness_script: &Script, amount: u64, per_commitment_point: &PublicKey, secp_ctx: &Secp256k1<T>) {
119+
self.inner.sign_delayed_transaction(spend_tx, input, witness_script, amount, per_commitment_point, secp_ctx);
120+
}
121+
118122
fn sign_closing_transaction<T: secp256k1::Signing>(&self, closing_tx: &Transaction, secp_ctx: &Secp256k1<T>) -> Result<Signature, ()> {
119123
Ok(self.inner.sign_closing_transaction(closing_tx, secp_ctx).unwrap())
120124
}

0 commit comments

Comments
 (0)