Skip to content

Commit 767f120

Browse files
authored
Merge pull request #1019 from jkczyz/2021-07-shutdown-pubkey
Fetch shutdown script based on `commit_upfront_shutdown_pubkey`
2 parents 03537cc + 1d3861e commit 767f120

14 files changed

+929
-185
lines changed

fuzz/src/chanmon_consistency.rs

Lines changed: 9 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,11 @@ 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+
let secret_key = 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();
171+
let pubkey_hash = WPubkeyHash::hash(&PublicKey::from_secret_key(&secp_ctx, &secret_key).serialize());
172+
ShutdownScript::new_p2wpkh(&pubkey_hash)
170173
}
171174

172175
fn get_channel_signer(&self, _inbound: bool, channel_value_satoshis: u64) -> EnforcingSigner {
@@ -250,6 +253,7 @@ fn check_api_err(api_err: APIError) {
250253
APIError::MonitorUpdateFailed => {
251254
// We can (obviously) temp-fail a monitor update
252255
},
256+
APIError::IncompatibleShutdownScript { .. } => panic!("Cannot send an incompatible shutdown script"),
253257
}
254258
}
255259
#[inline]
@@ -393,6 +397,9 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
393397
let mut channel_txn = Vec::new();
394398
macro_rules! make_channel {
395399
($source: expr, $dest: expr, $chan_id: expr) => { {
400+
$source.peer_connected(&$dest.get_our_node_id(), &Init { features: InitFeatures::known() });
401+
$dest.peer_connected(&$source.get_our_node_id(), &Init { features: InitFeatures::known() });
402+
396403
$source.create_channel($dest.get_our_node_id(), 100_000, 42, 0, None).unwrap();
397404
let open_channel = {
398405
let events = $source.get_and_clear_pending_msg_events();

fuzz/src/full_stack.rs

Lines changed: 5 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,11 @@ 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+
let secret_key = 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();
278+
let pubkey_hash = WPubkeyHash::hash(&PublicKey::from_secret_key(&secp_ctx, &secret_key).serialize());
279+
ShutdownScript::new_p2wpkh(&pubkey_hash)
277280
}
278281

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

lightning-background-processor/src/lib.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ mod tests {
243243
use lightning::get_event_msg;
244244
use lightning::ln::channelmanager::{BREAKDOWN_TIMEOUT, ChainParameters, ChannelManager, SimpleArcChannelManager};
245245
use lightning::ln::features::InitFeatures;
246-
use lightning::ln::msgs::ChannelMessageHandler;
246+
use lightning::ln::msgs::{ChannelMessageHandler, Init};
247247
use lightning::ln::peer_handler::{PeerManager, MessageHandler, SocketDescriptor};
248248
use lightning::util::config::UserConfig;
249249
use lightning::util::events::{Event, MessageSendEventsProvider, MessageSendEvent};
@@ -317,6 +317,14 @@ mod tests {
317317
let node = Node { node: manager, peer_manager, chain_monitor, persister, tx_broadcaster, logger, best_block };
318318
nodes.push(node);
319319
}
320+
321+
for i in 0..num_nodes {
322+
for j in (i+1)..num_nodes {
323+
nodes[i].node.peer_connected(&nodes[j].node.get_our_node_id(), &Init { features: InitFeatures::known() });
324+
nodes[j].node.peer_connected(&nodes[i].node.get_our_node_id(), &Init { features: InitFeatures::known() });
325+
}
326+
}
327+
320328
nodes
321329
}
322330

lightning/src/chain/channelmonitor.rs

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,9 @@ pub(crate) enum ChannelMonitorUpdateStep {
438438
/// think we've fallen behind!
439439
should_broadcast: bool,
440440
},
441+
ShutdownScript {
442+
scriptpubkey: Script,
443+
},
441444
}
442445

443446
impl_writeable_tlv_based_enum!(ChannelMonitorUpdateStep,
@@ -461,6 +464,9 @@ impl_writeable_tlv_based_enum!(ChannelMonitorUpdateStep,
461464
(4, ChannelForceClosed) => {
462465
(0, should_broadcast, required),
463466
},
467+
(5, ShutdownScript) => {
468+
(0, scriptpubkey, required),
469+
},
464470
;);
465471

466472
/// A ChannelMonitor handles chain events (blocks connected and disconnected) and generates
@@ -493,7 +499,7 @@ pub(crate) struct ChannelMonitorImpl<Signer: Sign> {
493499
destination_script: Script,
494500
broadcasted_holder_revokable_script: Option<(Script, PublicKey, PublicKey)>,
495501
counterparty_payment_script: Script,
496-
shutdown_script: Script,
502+
shutdown_script: Option<Script>,
497503

498504
channel_keys_id: [u8; 32],
499505
holder_revocation_basepoint: PublicKey,
@@ -669,7 +675,10 @@ impl<Signer: Sign> Writeable for ChannelMonitorImpl<Signer> {
669675
}
670676

671677
self.counterparty_payment_script.write(writer)?;
672-
self.shutdown_script.write(writer)?;
678+
match &self.shutdown_script {
679+
Some(script) => script.write(writer)?,
680+
None => Script::new().write(writer)?,
681+
}
673682

674683
self.channel_keys_id.write(writer)?;
675684
self.holder_revocation_basepoint.write(writer)?;
@@ -799,7 +808,7 @@ impl<Signer: Sign> Writeable for ChannelMonitorImpl<Signer> {
799808
}
800809

801810
impl<Signer: Sign> ChannelMonitor<Signer> {
802-
pub(crate) fn new(secp_ctx: Secp256k1<secp256k1::All>, keys: Signer, shutdown_pubkey: &PublicKey,
811+
pub(crate) fn new(secp_ctx: Secp256k1<secp256k1::All>, keys: Signer, shutdown_script: Option<Script>,
803812
on_counterparty_tx_csv: u16, destination_script: &Script, funding_info: (OutPoint, Script),
804813
channel_parameters: &ChannelTransactionParameters,
805814
funding_redeemscript: Script, channel_value_satoshis: u64,
@@ -808,8 +817,6 @@ impl<Signer: Sign> ChannelMonitor<Signer> {
808817
best_block: BestBlock) -> ChannelMonitor<Signer> {
809818

810819
assert!(commitment_transaction_number_obscure_factor <= (1 << 48));
811-
let our_channel_close_key_hash = WPubkeyHash::hash(&shutdown_pubkey.serialize());
812-
let shutdown_script = Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0).push_slice(&our_channel_close_key_hash[..]).into_script();
813820
let payment_key_hash = WPubkeyHash::hash(&keys.pubkeys().payment_point.serialize());
814821
let counterparty_payment_script = Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0).push_slice(&payment_key_hash[..]).into_script();
815822

@@ -1436,7 +1443,13 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
14361443
// shouldn't print the scary warning above.
14371444
log_info!(logger, "Channel off-chain state closed after we broadcasted our latest commitment transaction.");
14381445
}
1439-
}
1446+
},
1447+
ChannelMonitorUpdateStep::ShutdownScript { scriptpubkey } => {
1448+
log_trace!(logger, "Updating ChannelMonitor with shutdown script");
1449+
if let Some(shutdown_script) = self.shutdown_script.replace(scriptpubkey.clone()) {
1450+
panic!("Attempted to replace shutdown script {} with {}", shutdown_script, scriptpubkey);
1451+
}
1452+
},
14401453
}
14411454
}
14421455
self.latest_update_id = updates.update_id;
@@ -2485,7 +2498,7 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
24852498
}));
24862499
break;
24872500
}
2488-
if outp.script_pubkey == self.shutdown_script {
2501+
if self.shutdown_script.as_ref() == Some(&outp.script_pubkey) {
24892502
spendable_output = Some(SpendableOutputDescriptor::StaticOutput {
24902503
outpoint: OutPoint { txid: tx.txid(), index: i as u16 },
24912504
output: outp.clone(),
@@ -2622,7 +2635,10 @@ impl<'a, Signer: Sign, K: KeysInterface<Signer = Signer>> ReadableArgs<&'a K>
26222635
_ => return Err(DecodeError::InvalidValue),
26232636
};
26242637
let counterparty_payment_script = Readable::read(reader)?;
2625-
let shutdown_script = Readable::read(reader)?;
2638+
let shutdown_script = {
2639+
let script = <Script as Readable>::read(reader)?;
2640+
if script.is_empty() { None } else { Some(script) }
2641+
};
26262642

26272643
let channel_keys_id = Readable::read(reader)?;
26282644
let holder_revocation_basepoint = Readable::read(reader)?;
@@ -2854,6 +2870,7 @@ mod tests {
28542870
use ln::{PaymentPreimage, PaymentHash};
28552871
use ln::chan_utils;
28562872
use ln::chan_utils::{HTLCOutputInCommitment, ChannelPublicKeys, ChannelTransactionParameters, HolderCommitmentTransaction, CounterpartyChannelTransactionParameters};
2873+
use ln::script::ShutdownScript;
28572874
use util::test_utils::{TestLogger, TestBroadcaster, TestFeeEstimator};
28582875
use bitcoin::secp256k1::key::{SecretKey,PublicKey};
28592876
use bitcoin::secp256k1::Secp256k1;
@@ -2947,9 +2964,10 @@ mod tests {
29472964
};
29482965
// Prune with one old state and a holder commitment tx holding a few overlaps with the
29492966
// old state.
2967+
let shutdown_pubkey = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
29502968
let best_block = BestBlock::from_genesis(Network::Testnet);
29512969
let monitor = ChannelMonitor::new(Secp256k1::new(), keys,
2952-
&PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap()), 0, &Script::new(),
2970+
Some(ShutdownScript::new_p2wpkh_from_pubkey(shutdown_pubkey).into_inner()), 0, &Script::new(),
29532971
(OutPoint { txid: Txid::from_slice(&[43; 32]).unwrap(), index: 0 }, Script::new()),
29542972
&channel_parameters,
29552973
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::new_p2wpkh_from_pubkey(self.shutdown_pubkey.clone())
10181018
}
10191019

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

lightning/src/ln/chanmon_update_fail_tests.rs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2369,3 +2369,66 @@ fn test_reconnect_dup_htlc_claims() {
23692369
do_test_reconnect_dup_htlc_claims(HTLCStatusAtDupClaim::HoldingCell, true);
23702370
do_test_reconnect_dup_htlc_claims(HTLCStatusAtDupClaim::Cleared, true);
23712371
}
2372+
2373+
#[test]
2374+
fn test_temporary_error_during_shutdown() {
2375+
// Test that temporary failures when updating the monitor's shutdown script do not prevent
2376+
// cooperative close.
2377+
let mut config = test_default_channel_config();
2378+
config.channel_options.commit_upfront_shutdown_pubkey = false;
2379+
2380+
let chanmon_cfgs = create_chanmon_cfgs(2);
2381+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
2382+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[Some(config), Some(config)]);
2383+
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
2384+
2385+
let (_, _, channel_id, funding_tx) = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
2386+
2387+
*nodes[0].chain_monitor.update_ret.lock().unwrap() = Some(Err(ChannelMonitorUpdateErr::TemporaryFailure));
2388+
*nodes[1].chain_monitor.update_ret.lock().unwrap() = Some(Err(ChannelMonitorUpdateErr::TemporaryFailure));
2389+
close_channel(&nodes[0], &nodes[1], &channel_id, funding_tx, false);
2390+
check_added_monitors!(nodes[0], 1);
2391+
check_added_monitors!(nodes[1], 1);
2392+
}
2393+
2394+
#[test]
2395+
fn test_permanent_error_during_sending_shutdown() {
2396+
// Test that permanent failures when updating the monitor's shutdown script result in a force
2397+
// close when initiating a cooperative close.
2398+
let mut config = test_default_channel_config();
2399+
config.channel_options.commit_upfront_shutdown_pubkey = false;
2400+
2401+
let chanmon_cfgs = create_chanmon_cfgs(2);
2402+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
2403+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[Some(config), None]);
2404+
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
2405+
2406+
let channel_id = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known()).2;
2407+
*nodes[0].chain_monitor.update_ret.lock().unwrap() = Some(Err(ChannelMonitorUpdateErr::PermanentFailure));
2408+
2409+
assert!(nodes[0].node.close_channel(&channel_id).is_ok());
2410+
check_closed_broadcast!(nodes[0], true);
2411+
check_added_monitors!(nodes[0], 2);
2412+
}
2413+
2414+
#[test]
2415+
fn test_permanent_error_during_handling_shutdown() {
2416+
// Test that permanent failures when updating the monitor's shutdown script result in a force
2417+
// close when handling a cooperative close.
2418+
let mut config = test_default_channel_config();
2419+
config.channel_options.commit_upfront_shutdown_pubkey = false;
2420+
2421+
let chanmon_cfgs = create_chanmon_cfgs(2);
2422+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
2423+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, Some(config)]);
2424+
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
2425+
2426+
let channel_id = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known()).2;
2427+
*nodes[1].chain_monitor.update_ret.lock().unwrap() = Some(Err(ChannelMonitorUpdateErr::PermanentFailure));
2428+
2429+
assert!(nodes[0].node.close_channel(&channel_id).is_ok());
2430+
let shutdown = get_event_msg!(nodes[0], MessageSendEvent::SendShutdown, nodes[1].node.get_our_node_id());
2431+
nodes[1].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &InitFeatures::known(), &shutdown);
2432+
check_closed_broadcast!(nodes[1], true);
2433+
check_added_monitors!(nodes[1], 2);
2434+
}

0 commit comments

Comments
 (0)