Skip to content

Commit 1b70d9e

Browse files
committed
Require user cooperative close payout scripts to be Segwit
There is little reason for users to be paying out to non-Segwit scripts when closing channels at this point. Given we will soon, in rare cases, force-close during shutdown when a counterparty closes to a non-Segwit script, we should also require it of our own users.
1 parent c43db96 commit 1b70d9e

File tree

2 files changed

+22
-52
lines changed

2 files changed

+22
-52
lines changed

lightning/src/ln/channel.rs

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use ln::{PaymentPreimage, PaymentHash};
2626
use ln::features::{ChannelFeatures, InitFeatures};
2727
use ln::msgs;
2828
use ln::msgs::{DecodeError, OptionalField, DataLossProtect};
29-
use ln::script::ShutdownScript;
29+
use ln::script::{self, ShutdownScript};
3030
use ln::channelmanager::{CounterpartyForwardingInfo, PendingHTLCStatus, HTLCSource, HTLCFailReason, HTLCFailureMsg, PendingHTLCInfo, RAACommitmentOrder, BREAKDOWN_TIMEOUT, MIN_CLTV_EXPIRY_DELTA, MAX_LOCAL_BREAKDOWN_TIMEOUT};
3131
use ln::chan_utils::{CounterpartyCommitmentSecrets, TxCreationKeys, HTLCOutputInCommitment, HTLC_SUCCESS_TX_WEIGHT, HTLC_TIMEOUT_TX_WEIGHT, make_funding_redeemscript, ChannelPublicKeys, CommitmentTransaction, HolderCommitmentTransaction, ChannelTransactionParameters, CounterpartyChannelTransactionParameters, MAX_HTLCS, get_commitment_transaction_number_obscure_factor, ClosingTransaction};
3232
use ln::chan_utils;
@@ -44,7 +44,6 @@ use util::scid_utils::scid_from_parts;
4444
use io;
4545
use prelude::*;
4646
use core::{cmp,mem,fmt};
47-
use core::convert::TryFrom;
4847
use core::ops::Deref;
4948
#[cfg(any(test, feature = "fuzztarget", debug_assertions))]
5049
use sync::Mutex;
@@ -896,10 +895,10 @@ impl<Signer: Sign> Channel<Signer> {
896895
if script.len() == 0 {
897896
None
898897
} else {
899-
match ShutdownScript::try_from((script.clone(), their_features)) {
900-
Ok(shutdown_script) => Some(shutdown_script.into_inner()),
901-
Err(_) => return Err(ChannelError::Close(format!("Peer is signaling upfront_shutdown but has provided an unacceptable scriptpubkey format: {}", script))),
898+
if !script::is_bolt2_compliant(&script, their_features) {
899+
return Err(ChannelError::Close(format!("Peer is signaling upfront_shutdown but has provided an unacceptable scriptpubkey format: {}", script)))
902900
}
901+
Some(script.clone())
903902
}
904903
},
905904
// Peer is signaling upfront shutdown but don't opt-out with correct mechanism (a.k.a 0-length script). Peer looks buggy, we fail the channel
@@ -1641,10 +1640,10 @@ impl<Signer: Sign> Channel<Signer> {
16411640
if script.len() == 0 {
16421641
None
16431642
} else {
1644-
match ShutdownScript::try_from((script.clone(), their_features)) {
1645-
Ok(shutdown_script) => Some(shutdown_script.into_inner()),
1646-
Err(_) => return Err(ChannelError::Close(format!("Peer is signaling upfront_shutdown but has provided an unacceptable scriptpubkey format: {}", script))),
1643+
if !script::is_bolt2_compliant(&script, their_features) {
1644+
return Err(ChannelError::Close(format!("Peer is signaling upfront_shutdown but has provided an unacceptable scriptpubkey format: {}", script)));
16471645
}
1646+
Some(script.clone())
16481647
}
16491648
},
16501649
// Peer is signaling upfront shutdown but don't opt-out with correct mechanism (a.k.a 0-length script). Peer looks buggy, we fail the channel
@@ -3494,17 +3493,16 @@ impl<Signer: Sign> Channel<Signer> {
34943493
}
34953494
assert_eq!(self.channel_state & ChannelState::ShutdownComplete as u32, 0);
34963495

3497-
let shutdown_scriptpubkey = match ShutdownScript::try_from((msg.scriptpubkey.clone(), their_features)) {
3498-
Ok(script) => script.into_inner(),
3499-
Err(_) => return Err(ChannelError::Close(format!("Got a nonstandard scriptpubkey ({}) from remote peer", msg.scriptpubkey.to_bytes().to_hex()))),
3500-
};
3496+
if !script::is_bolt2_compliant(&msg.scriptpubkey, their_features) {
3497+
return Err(ChannelError::Close(format!("Got a nonstandard scriptpubkey ({}) from remote peer", msg.scriptpubkey.to_bytes().to_hex())));
3498+
}
35013499

35023500
if self.counterparty_shutdown_scriptpubkey.is_some() {
3503-
if Some(&shutdown_scriptpubkey) != self.counterparty_shutdown_scriptpubkey.as_ref() {
3504-
return Err(ChannelError::Close(format!("Got shutdown request with a scriptpubkey ({}) which did not match their previous scriptpubkey.", shutdown_scriptpubkey.to_bytes().to_hex())));
3501+
if Some(&msg.scriptpubkey) != self.counterparty_shutdown_scriptpubkey.as_ref() {
3502+
return Err(ChannelError::Close(format!("Got shutdown request with a scriptpubkey ({}) which did not match their previous scriptpubkey.", msg.scriptpubkey.to_bytes().to_hex())));
35053503
}
35063504
} else {
3507-
self.counterparty_shutdown_scriptpubkey = Some(shutdown_scriptpubkey);
3505+
self.counterparty_shutdown_scriptpubkey = Some(msg.scriptpubkey.clone());
35083506
}
35093507

35103508
// If we have any LocalAnnounced updates we'll probably just get back an update_fail_htlc

lightning/src/ln/script.rs

Lines changed: 9 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use bitcoin::blockdata::opcodes::all::OP_PUSHBYTES_0 as SEGWIT_V0;
44
use bitcoin::blockdata::script::{Builder, Script};
55
use bitcoin::hashes::Hash;
6-
use bitcoin::hash_types::{PubkeyHash, ScriptHash, WPubkeyHash, WScriptHash};
6+
use bitcoin::hash_types::{WPubkeyHash, WScriptHash};
77
use bitcoin::secp256k1::key::PublicKey;
88

99
use ln::features::InitFeatures;
@@ -66,16 +66,6 @@ impl ShutdownScript {
6666
Self(ShutdownScriptImpl::Legacy(pubkey))
6767
}
6868

69-
/// Generates a P2PKH script pubkey from the given [`PubkeyHash`].
70-
pub fn new_p2pkh(pubkey_hash: &PubkeyHash) -> Self {
71-
Self(ShutdownScriptImpl::Bolt2(Script::new_p2pkh(pubkey_hash)))
72-
}
73-
74-
/// Generates a P2SH script pubkey from the given [`ScriptHash`].
75-
pub fn new_p2sh(script_hash: &ScriptHash) -> Self {
76-
Self(ShutdownScriptImpl::Bolt2(Script::new_p2sh(script_hash)))
77-
}
78-
7969
/// Generates a P2WPKH script pubkey from the given [`WPubkeyHash`].
8070
pub fn new_p2wpkh(pubkey_hash: &WPubkeyHash) -> Self {
8171
Self(ShutdownScriptImpl::Bolt2(Script::new_v0_wpkh(pubkey_hash)))
@@ -126,7 +116,9 @@ impl ShutdownScript {
126116
}
127117
}
128118

129-
fn is_bolt2_compliant(script: &Script, features: &InitFeatures) -> bool {
119+
/// Check if a given script is compliant with BOLT 2's shutdown script requirements for the given
120+
/// counterparty features.
121+
pub(crate) fn is_bolt2_compliant(script: &Script, features: &InitFeatures) -> bool {
130122
if script.is_p2pkh() || script.is_p2sh() || script.is_v0_p2wpkh() || script.is_v0_p2wsh() {
131123
true
132124
} else if features.supports_shutdown_anysegwit() {
@@ -136,6 +128,8 @@ fn is_bolt2_compliant(script: &Script, features: &InitFeatures) -> bool {
136128
}
137129
}
138130

131+
// Note that this is only for our own shutdown scripts. Counterparties are still allowed to send us
132+
// non-witness shutdown scripts which this rejects.
139133
impl TryFrom<Script> for ShutdownScript {
140134
type Error = InvalidShutdownScript;
141135

@@ -144,11 +138,13 @@ impl TryFrom<Script> for ShutdownScript {
144138
}
145139
}
146140

141+
// Note that this is only for our own shutdown scripts. Counterparties are still allowed to send us
142+
// non-witness shutdown scripts which this rejects.
147143
impl TryFrom<(Script, &InitFeatures)> for ShutdownScript {
148144
type Error = InvalidShutdownScript;
149145

150146
fn try_from((script, features): (Script, &InitFeatures)) -> Result<Self, Self::Error> {
151-
if is_bolt2_compliant(&script, features) {
147+
if is_bolt2_compliant(&script, features) && script.is_witness_program() {
152148
Ok(Self(ShutdownScriptImpl::Bolt2(script)))
153149
} else {
154150
Err(InvalidShutdownScript { script })
@@ -216,30 +212,6 @@ mod shutdown_script_tests {
216212
assert_eq!(shutdown_script.into_inner(), p2wpkh_script);
217213
}
218214

219-
#[test]
220-
fn generates_p2pkh_from_pubkey_hash() {
221-
let pubkey_hash = pubkey().pubkey_hash();
222-
let p2pkh_script = Script::new_p2pkh(&pubkey_hash);
223-
224-
let shutdown_script = ShutdownScript::new_p2pkh(&pubkey_hash);
225-
assert!(shutdown_script.is_compatible(&InitFeatures::known()));
226-
assert!(shutdown_script.is_compatible(&InitFeatures::known().clear_shutdown_anysegwit()));
227-
assert_eq!(shutdown_script.into_inner(), p2pkh_script);
228-
assert!(ShutdownScript::try_from(p2pkh_script).is_ok());
229-
}
230-
231-
#[test]
232-
fn generates_p2sh_from_script_hash() {
233-
let script_hash = redeem_script().script_hash();
234-
let p2sh_script = Script::new_p2sh(&script_hash);
235-
236-
let shutdown_script = ShutdownScript::new_p2sh(&script_hash);
237-
assert!(shutdown_script.is_compatible(&InitFeatures::known()));
238-
assert!(shutdown_script.is_compatible(&InitFeatures::known().clear_shutdown_anysegwit()));
239-
assert_eq!(shutdown_script.into_inner(), p2sh_script);
240-
assert!(ShutdownScript::try_from(p2sh_script).is_ok());
241-
}
242-
243215
#[test]
244216
fn generates_p2wpkh_from_pubkey_hash() {
245217
let pubkey_hash = pubkey().wpubkey_hash().unwrap();

0 commit comments

Comments
 (0)