Skip to content

Commit 52d53bb

Browse files
committed
Support all shutdown scripts defined in BOLT 2
KeysInterface::get_shutdown_pubkey is used to form P2WPKH shutdown scripts. However, BOLT 2 allows for a wider variety of scripts. Refactor KeysInterface to allow any supported script while still maintaining serialization backwards compatibility with P2WPKH script pubkeys stored simply as the PublicKey. Add an optional TLV field to Channel and ChannelMonitor to support the new format, but continue to serialize the legacy PublicKey format.
1 parent 9377b16 commit 52d53bb

File tree

7 files changed

+100
-37
lines changed

7 files changed

+100
-37
lines changed

fuzz/src/chanmon_consistency.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ use lightning::ln::{PaymentHash, PaymentPreimage, PaymentSecret};
3939
use lightning::ln::channelmanager::{ChainParameters, ChannelManager, PaymentSendFailure, ChannelManagerReadArgs};
4040
use lightning::ln::features::{ChannelFeatures, InitFeatures, NodeFeatures};
4141
use lightning::ln::msgs::{CommitmentUpdate, ChannelMessageHandler, DecodeError, UpdateAddHTLC, Init};
42+
use lightning::ln::script::ShutdownScript;
4243
use lightning::util::enforcing_trait_impls::{EnforcingSigner, INITIAL_REVOKED_COMMITMENT_NUMBER};
4344
use lightning::util::errors::APIError;
4445
use lightning::util::events;
@@ -164,9 +165,9 @@ impl KeysInterface for KeyProvider {
164165
Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0).push_slice(&our_channel_monitor_claim_key_hash[..]).into_script()
165166
}
166167

167-
fn get_shutdown_pubkey(&self) -> PublicKey {
168+
fn get_shutdown_scriptpubkey(&self) -> ShutdownScript {
168169
let secp_ctx = Secp256k1::signing_only();
169-
PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, self.node_id]).unwrap())
170+
ShutdownScript::from(PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, self.node_id]).unwrap()))
170171
}
171172

172173
fn get_channel_signer(&self, _inbound: bool, channel_value_satoshis: u64) -> EnforcingSigner {

fuzz/src/full_stack.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ use lightning::ln::{PaymentHash, PaymentPreimage, PaymentSecret};
3636
use lightning::ln::channelmanager::{ChainParameters, ChannelManager};
3737
use lightning::ln::peer_handler::{MessageHandler,PeerManager,SocketDescriptor};
3838
use lightning::ln::msgs::DecodeError;
39+
use lightning::ln::script::ShutdownScript;
3940
use lightning::routing::router::get_route;
4041
use lightning::routing::network_graph::NetGraphMsgHandler;
4142
use lightning::util::config::UserConfig;
@@ -271,9 +272,9 @@ impl KeysInterface for KeyProvider {
271272
Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0).push_slice(&our_channel_monitor_claim_key_hash[..]).into_script()
272273
}
273274

274-
fn get_shutdown_pubkey(&self) -> PublicKey {
275+
fn get_shutdown_scriptpubkey(&self) -> ShutdownScript {
275276
let secp_ctx = Secp256k1::signing_only();
276-
PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]).unwrap())
277+
ShutdownScript::from(PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]).unwrap()))
277278
}
278279

279280
fn get_channel_signer(&self, inbound: bool, channel_value_satoshis: u64) -> EnforcingSigner {

lightning/src/chain/channelmonitor.rs

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -489,7 +489,7 @@ pub(crate) struct ChannelMonitorImpl<Signer: Sign> {
489489
destination_script: Script,
490490
broadcasted_holder_revokable_script: Option<(Script, PublicKey, PublicKey)>,
491491
counterparty_payment_script: Script,
492-
shutdown_script: Script,
492+
shutdown_script: Option<Script>,
493493

494494
channel_keys_id: [u8; 32],
495495
holder_revocation_basepoint: PublicKey,
@@ -665,7 +665,10 @@ impl<Signer: Sign> Writeable for ChannelMonitorImpl<Signer> {
665665
}
666666

667667
self.counterparty_payment_script.write(writer)?;
668-
self.shutdown_script.write(writer)?;
668+
match &self.shutdown_script {
669+
Some(script) => script.write(writer)?,
670+
None => Script::new().write(writer)?,
671+
}
669672

670673
self.channel_keys_id.write(writer)?;
671674
self.holder_revocation_basepoint.write(writer)?;
@@ -788,14 +791,16 @@ impl<Signer: Sign> Writeable for ChannelMonitorImpl<Signer> {
788791
self.lockdown_from_offchain.write(writer)?;
789792
self.holder_tx_signed.write(writer)?;
790793

791-
write_tlv_fields!(writer, {});
794+
write_tlv_fields!(writer, {
795+
(1, self.shutdown_script, option),
796+
});
792797

793798
Ok(())
794799
}
795800
}
796801

797802
impl<Signer: Sign> ChannelMonitor<Signer> {
798-
pub(crate) fn new(secp_ctx: Secp256k1<secp256k1::All>, keys: Signer, shutdown_pubkey: &PublicKey,
803+
pub(crate) fn new(secp_ctx: Secp256k1<secp256k1::All>, keys: Signer, shutdown_script: Option<Script>,
799804
on_counterparty_tx_csv: u16, destination_script: &Script, funding_info: (OutPoint, Script),
800805
channel_parameters: &ChannelTransactionParameters,
801806
funding_redeemscript: Script, channel_value_satoshis: u64,
@@ -804,8 +809,6 @@ impl<Signer: Sign> ChannelMonitor<Signer> {
804809
best_block: BestBlock) -> ChannelMonitor<Signer> {
805810

806811
assert!(commitment_transaction_number_obscure_factor <= (1 << 48));
807-
let our_channel_close_key_hash = WPubkeyHash::hash(&shutdown_pubkey.serialize());
808-
let shutdown_script = Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0).push_slice(&our_channel_close_key_hash[..]).into_script();
809812
let payment_key_hash = WPubkeyHash::hash(&keys.pubkeys().payment_point.serialize());
810813
let counterparty_payment_script = Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0).push_slice(&payment_key_hash[..]).into_script();
811814

@@ -2472,7 +2475,7 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
24722475
channel_value_satoshis: self.channel_value_satoshis,
24732476
}));
24742477
break;
2475-
} else if outp.script_pubkey == self.shutdown_script {
2478+
} else if self.shutdown_script.as_ref() == Some(&outp.script_pubkey) {
24762479
spendable_output = Some(SpendableOutputDescriptor::StaticOutput {
24772480
outpoint: OutPoint { txid: tx.txid(), index: i as u16 },
24782481
output: outp.clone(),
@@ -2608,7 +2611,10 @@ impl<'a, Signer: Sign, K: KeysInterface<Signer = Signer>> ReadableArgs<&'a K>
26082611
_ => return Err(DecodeError::InvalidValue),
26092612
};
26102613
let counterparty_payment_script = Readable::read(reader)?;
2611-
let shutdown_script = Readable::read(reader)?;
2614+
let mut shutdown_script = {
2615+
let script = <Script as Readable>::read(reader)?;
2616+
if script.is_empty() { None } else { Some(script) }
2617+
};
26122618

26132619
let channel_keys_id = Readable::read(reader)?;
26142620
let holder_revocation_basepoint = Readable::read(reader)?;
@@ -2762,7 +2768,9 @@ impl<'a, Signer: Sign, K: KeysInterface<Signer = Signer>> ReadableArgs<&'a K>
27622768
let lockdown_from_offchain = Readable::read(reader)?;
27632769
let holder_tx_signed = Readable::read(reader)?;
27642770

2765-
read_tlv_fields!(reader, {});
2771+
read_tlv_fields!(reader, {
2772+
(1, shutdown_script, option),
2773+
});
27662774

27672775
let mut secp_ctx = Secp256k1::new();
27682776
secp_ctx.seeded_randomize(&keys_manager.get_secure_random_bytes());
@@ -2840,6 +2848,7 @@ mod tests {
28402848
use ln::{PaymentPreimage, PaymentHash};
28412849
use ln::chan_utils;
28422850
use ln::chan_utils::{HTLCOutputInCommitment, ChannelPublicKeys, ChannelTransactionParameters, HolderCommitmentTransaction, CounterpartyChannelTransactionParameters};
2851+
use ln::script::ShutdownScript;
28432852
use util::test_utils::{TestLogger, TestBroadcaster, TestFeeEstimator};
28442853
use bitcoin::secp256k1::key::{SecretKey,PublicKey};
28452854
use bitcoin::secp256k1::Secp256k1;
@@ -2933,9 +2942,10 @@ mod tests {
29332942
};
29342943
// Prune with one old state and a holder commitment tx holding a few overlaps with the
29352944
// old state.
2945+
let shutdown_pubkey = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
29362946
let best_block = BestBlock::from_genesis(Network::Testnet);
29372947
let monitor = ChannelMonitor::new(Secp256k1::new(), keys,
2938-
&PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap()), 0, &Script::new(),
2948+
Some(ShutdownScript::from(shutdown_pubkey).into_inner()), 0, &Script::new(),
29392949
(OutPoint { txid: Txid::from_slice(&[43; 32]).unwrap(), index: 0 }, Script::new()),
29402950
&channel_parameters,
29412951
Script::new(), 46, 0,

lightning/src/chain/keysinterface.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ use chain::transaction::OutPoint;
3636
use ln::chan_utils;
3737
use ln::chan_utils::{HTLCOutputInCommitment, make_funding_redeemscript, ChannelPublicKeys, HolderCommitmentTransaction, ChannelTransactionParameters, CommitmentTransaction};
3838
use ln::msgs::UnsignedChannelAnnouncement;
39+
use ln::script::ShutdownScript;
3940

4041
use prelude::*;
4142
use core::sync::atomic::{AtomicUsize, Ordering};
@@ -118,8 +119,8 @@ impl_writeable_tlv_based!(StaticPaymentOutputDescriptor, {
118119
#[derive(Clone, Debug, PartialEq)]
119120
pub enum SpendableOutputDescriptor {
120121
/// An output to a script which was provided via KeysInterface directly, either from
121-
/// `get_destination_script()` or `get_shutdown_pubkey()`, thus you should already know how to
122-
/// spend it. No secret keys are provided as rust-lightning was never given any key.
122+
/// `get_destination_script()` or `get_shutdown_scriptpubkey()`, thus you should already know
123+
/// how to spend it. No secret keys are provided as rust-lightning was never given any key.
123124
/// These may include outputs from a transaction punishing our counterparty or claiming an HTLC
124125
/// on-chain using the payment preimage or after it has timed out.
125126
StaticOutput {
@@ -351,12 +352,11 @@ pub trait KeysInterface {
351352
/// This method should return a different value each time it is called, to avoid linking
352353
/// on-chain funds across channels as controlled to the same user.
353354
fn get_destination_script(&self) -> Script;
354-
/// Get a public key which we will send funds to (in the form of a P2WPKH output) when closing
355-
/// a channel.
355+
/// Get a script pubkey which we will send funds to when closing a channel.
356356
///
357357
/// This method should return a different value each time it is called, to avoid linking
358358
/// on-chain funds across channels as controlled to the same user.
359-
fn get_shutdown_pubkey(&self) -> PublicKey;
359+
fn get_shutdown_scriptpubkey(&self) -> ShutdownScript;
360360
/// Get a new set of Sign for per-channel secrets. These MUST be unique even if you
361361
/// restarted with some stale data!
362362
///
@@ -1013,8 +1013,8 @@ impl KeysInterface for KeysManager {
10131013
self.destination_script.clone()
10141014
}
10151015

1016-
fn get_shutdown_pubkey(&self) -> PublicKey {
1017-
self.shutdown_pubkey.clone()
1016+
fn get_shutdown_scriptpubkey(&self) -> ShutdownScript {
1017+
ShutdownScript::from(self.shutdown_pubkey.clone())
10181018
}
10191019

10201020
fn get_channel_signer(&self, _inbound: bool, channel_value_satoshis: u64) -> Self::Signer {

lightning/src/ln/channel.rs

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@
99

1010
use bitcoin::blockdata::script::{Script,Builder};
1111
use bitcoin::blockdata::transaction::{TxIn, TxOut, Transaction, SigHashType};
12-
use bitcoin::blockdata::opcodes;
1312
use bitcoin::util::bip143;
1413
use bitcoin::consensus::encode;
1514

1615
use bitcoin::hashes::Hash;
1716
use bitcoin::hashes::sha256::Hash as Sha256;
1817
use bitcoin::hashes::sha256d::Hash as Sha256d;
19-
use bitcoin::hash_types::{Txid, BlockHash, WPubkeyHash};
18+
use bitcoin::hash_types::{Txid, BlockHash};
2019

20+
use bitcoin::secp256k1::constants::PUBLIC_KEY_SIZE;
2121
use bitcoin::secp256k1::key::{PublicKey,SecretKey};
2222
use bitcoin::secp256k1::{Secp256k1,Signature};
2323
use bitcoin::secp256k1;
@@ -322,7 +322,7 @@ pub(super) struct Channel<Signer: Sign> {
322322
latest_monitor_update_id: u64,
323323

324324
holder_signer: Signer,
325-
shutdown_pubkey: PublicKey,
325+
shutdown_scriptpubkey: Option<ShutdownScript>,
326326
destination_script: Script,
327327

328328
// Our commitment numbers start at 2^48-1 and count down, whereas the ones used in transaction
@@ -571,7 +571,7 @@ impl<Signer: Sign> Channel<Signer> {
571571
latest_monitor_update_id: 0,
572572

573573
holder_signer,
574-
shutdown_pubkey: keys_provider.get_shutdown_pubkey(),
574+
shutdown_scriptpubkey: Some(keys_provider.get_shutdown_scriptpubkey()),
575575
destination_script: keys_provider.get_destination_script(),
576576

577577
cur_holder_commitment_transaction_number: INITIAL_COMMITMENT_NUMBER,
@@ -812,7 +812,7 @@ impl<Signer: Sign> Channel<Signer> {
812812
latest_monitor_update_id: 0,
813813

814814
holder_signer,
815-
shutdown_pubkey: keys_provider.get_shutdown_pubkey(),
815+
shutdown_scriptpubkey: Some(keys_provider.get_shutdown_scriptpubkey()),
816816
destination_script: keys_provider.get_destination_script(),
817817

818818
cur_holder_commitment_transaction_number: INITIAL_COMMITMENT_NUMBER,
@@ -1088,8 +1088,7 @@ impl<Signer: Sign> Channel<Signer> {
10881088

10891089
#[inline]
10901090
fn get_closing_scriptpubkey(&self) -> Script {
1091-
let channel_close_key_hash = WPubkeyHash::hash(&self.shutdown_pubkey.serialize());
1092-
Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0).push_slice(&channel_close_key_hash[..]).into_script()
1091+
self.shutdown_scriptpubkey.clone().unwrap().into_inner()
10931092
}
10941093

10951094
#[inline]
@@ -1621,8 +1620,9 @@ impl<Signer: Sign> Channel<Signer> {
16211620
let funding_redeemscript = self.get_funding_redeemscript();
16221621
let funding_txo_script = funding_redeemscript.to_v0_p2wsh();
16231622
let obscure_factor = get_commitment_transaction_number_obscure_factor(&self.get_holder_pubkeys().payment_point, &self.get_counterparty_pubkeys().payment_point, self.is_outbound());
1623+
let shutdown_script = self.shutdown_scriptpubkey.clone().map(|script| script.into_inner());
16241624
let channel_monitor = ChannelMonitor::new(self.secp_ctx.clone(), self.holder_signer.clone(),
1625-
&self.shutdown_pubkey, self.get_holder_selected_contest_delay(),
1625+
shutdown_script, self.get_holder_selected_contest_delay(),
16261626
&self.destination_script, (funding_txo, funding_txo_script.clone()),
16271627
&self.channel_transaction_parameters,
16281628
funding_redeemscript.clone(), self.channel_value_satoshis,
@@ -1694,8 +1694,9 @@ impl<Signer: Sign> Channel<Signer> {
16941694
let funding_txo = self.get_funding_txo().unwrap();
16951695
let funding_txo_script = funding_redeemscript.to_v0_p2wsh();
16961696
let obscure_factor = get_commitment_transaction_number_obscure_factor(&self.get_holder_pubkeys().payment_point, &self.get_counterparty_pubkeys().payment_point, self.is_outbound());
1697+
let shutdown_script = self.shutdown_scriptpubkey.clone().map(|script| script.into_inner());
16971698
let channel_monitor = ChannelMonitor::new(self.secp_ctx.clone(), self.holder_signer.clone(),
1698-
&self.shutdown_pubkey, self.get_holder_selected_contest_delay(),
1699+
shutdown_script, self.get_holder_selected_contest_delay(),
16991700
&self.destination_script, (funding_txo, funding_txo_script),
17001701
&self.channel_transaction_parameters,
17011702
funding_redeemscript.clone(), self.channel_value_satoshis,
@@ -4490,7 +4491,12 @@ impl<Signer: Sign> Writeable for Channel<Signer> {
44904491
(key_data.0.len() as u32).write(writer)?;
44914492
writer.write_all(&key_data.0[..])?;
44924493

4493-
self.shutdown_pubkey.write(writer)?;
4494+
// Write out the old serialization for shutdown_pubkey for backwards compatibility, if
4495+
// deserialized from that format.
4496+
match self.shutdown_scriptpubkey.as_ref().and_then(|script| script.as_legacy_pubkey()) {
4497+
Some(shutdown_pubkey) => shutdown_pubkey.write(writer)?,
4498+
None => [0u8; PUBLIC_KEY_SIZE].write(writer)?,
4499+
}
44944500
self.destination_script.write(writer)?;
44954501

44964502
self.cur_holder_commitment_transaction_number.write(writer)?;
@@ -4679,6 +4685,7 @@ impl<Signer: Sign> Writeable for Channel<Signer> {
46794685
(1, self.minimum_depth, option),
46804686
(3, self.counterparty_selected_channel_reserve_satoshis, option),
46814687
(5, self.config, required),
4688+
(7, self.shutdown_scriptpubkey, option),
46824689
});
46834690

46844691
Ok(())
@@ -4722,7 +4729,12 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<&'a K> for Channel<Signer>
47224729
}
47234730
let holder_signer = keys_source.read_chan_signer(&keys_data)?;
47244731

4725-
let shutdown_pubkey = Readable::read(reader)?;
4732+
// Read the old serialization for shutdown_pubkey, preferring it for shutdown_scriptpubkey
4733+
// over the TLV if valid.
4734+
let mut shutdown_scriptpubkey = match <PublicKey as Readable>::read(reader) {
4735+
Ok(pubkey) => Some(ShutdownScript::from(pubkey)),
4736+
Err(_) => None,
4737+
};
47264738
let destination_script = Readable::read(reader)?;
47274739

47284740
let cur_holder_commitment_transaction_number = Readable::read(reader)?;
@@ -4883,6 +4895,7 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<&'a K> for Channel<Signer>
48834895
(1, minimum_depth, option),
48844896
(3, counterparty_selected_channel_reserve_satoshis, option),
48854897
(5, config, option), // Note that if none is provided we will *not* overwrite the existing one.
4898+
(7, shutdown_scriptpubkey, option),
48864899
});
48874900

48884901
let mut secp_ctx = Secp256k1::new();
@@ -4900,7 +4913,7 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<&'a K> for Channel<Signer>
49004913
latest_monitor_update_id,
49014914

49024915
holder_signer,
4903-
shutdown_pubkey,
4916+
shutdown_scriptpubkey,
49044917
destination_script,
49054918

49064919
cur_holder_commitment_transaction_number,
@@ -4990,6 +5003,7 @@ mod tests {
49905003
use ln::channel::MAX_FUNDING_SATOSHIS;
49915004
use ln::features::InitFeatures;
49925005
use ln::msgs::{ChannelUpdate, DataLossProtect, DecodeError, OptionalField, UnsignedChannelUpdate};
5006+
use ln::script::ShutdownScript;
49935007
use ln::chan_utils;
49945008
use ln::chan_utils::{ChannelPublicKeys, HolderCommitmentTransaction, CounterpartyChannelTransactionParameters, HTLC_SUCCESS_TX_WEIGHT, HTLC_TIMEOUT_TX_WEIGHT};
49955009
use chain::BestBlock;
@@ -5039,10 +5053,10 @@ mod tests {
50395053
Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0).push_slice(&channel_monitor_claim_key_hash[..]).into_script()
50405054
}
50415055

5042-
fn get_shutdown_pubkey(&self) -> PublicKey {
5056+
fn get_shutdown_scriptpubkey(&self) -> ShutdownScript {
50435057
let secp_ctx = Secp256k1::signing_only();
50445058
let channel_close_key = SecretKey::from_slice(&hex::decode("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()[..]).unwrap();
5045-
PublicKey::from_secret_key(&secp_ctx, &channel_close_key)
5059+
ShutdownScript::from(PublicKey::from_secret_key(&secp_ctx, &channel_close_key))
50465060
}
50475061

50485062
fn get_channel_signer(&self, _inbound: bool, _channel_value_satoshis: u64) -> InMemorySigner {

0 commit comments

Comments
 (0)