From 25a6a77468b3108555cc6ab3b716cd8934584646 Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Wed, 21 Jul 2021 20:12:14 -0500 Subject: [PATCH] Add ShutdownScript for BOLT 2 acceptable scripts BOLT 2 enumerates the script formats that may be used for a shutdown script. KeysInterface::get_shutdown_pubkey returns a PublicKey used to form one of the acceptable formats (P2WPKH). Add a ShutdownScript abstraction to encapsulate all accept formats and be backwards compatible with P2WPKH scripts serialized as the corresponding PublicKey. --- lightning/src/ln/mod.rs | 1 + lightning/src/ln/script.rs | 196 +++++++++++++++++++++++++++++++++++++ 2 files changed, 197 insertions(+) create mode 100644 lightning/src/ln/script.rs diff --git a/lightning/src/ln/mod.rs b/lightning/src/ln/mod.rs index 7500b93c..5f928eea 100644 --- a/lightning/src/ln/mod.rs +++ b/lightning/src/ln/mod.rs @@ -27,6 +27,7 @@ pub mod msgs; pub mod peer_handler; pub mod chan_utils; pub mod features; +pub mod script; #[cfg(feature = "fuzztarget")] pub mod peer_channel_encryptor; diff --git a/lightning/src/ln/script.rs b/lightning/src/ln/script.rs new file mode 100644 index 00000000..69b09e95 --- /dev/null +++ b/lightning/src/ln/script.rs @@ -0,0 +1,196 @@ +//! Abstractions for scripts used in the Lightning Network. + +use bitcoin::bech32::u5; +use bitcoin::blockdata::opcodes::all::OP_PUSHBYTES_0 as SEGWIT_V0; +use bitcoin::blockdata::script::Script; +use bitcoin::hashes::Hash; +use bitcoin::hash_types::{PubkeyHash, ScriptHash, WPubkeyHash, WScriptHash}; +use bitcoin::secp256k1::key::PublicKey; + +use ln::features::InitFeatures; + +use std::convert::From; +use std::convert::TryFrom; + +/// A script pubkey for shutting down a channel as defined by [BOLT #2]. +/// +/// [BOLT #2]: https://github.com/lightningnetwork/lightning-rfc/blob/master/02-peer-protocol.md +pub struct ShutdownScript(ShutdownScriptImpl); + +/// An error occurring when converting from [`Script`] to [`ShutdownScript`]. +#[derive(Debug)] +pub struct InvalidShutdownScript(Script); + +enum ShutdownScriptImpl { + /// [`PublicKey`] used to form a P2WPKH script pubkey. Used to support backward-compatible + /// serialization. + Legacy(PublicKey), + + /// [`Script`] adhering to a script pubkey format specified in BOLT #2. + Bolt2(Script), +} + +impl ShutdownScript { + /// Generates a P2PKH script pubkey from the given [`PubkeyHash`]. + pub fn new_p2pkh(pubkey_hash: &PubkeyHash) -> Self { + Self(ShutdownScriptImpl::Bolt2(Script::new_p2pkh(pubkey_hash))) + } + + /// Generates a P2SH script pubkey from the given [`ScriptHash`]. + pub fn new_p2sh(script_hash: &ScriptHash) -> Self { + Self(ShutdownScriptImpl::Bolt2(Script::new_p2sh(script_hash))) + } + + /// Generates a P2WPKH script pubkey from the given [`WPubkeyHash`]. + pub fn new_p2wpkh(pubkey_hash: &WPubkeyHash) -> Self { + Self(ShutdownScriptImpl::Bolt2(Script::new_v0_wpkh(pubkey_hash))) + } + + /// Generates a P2WSH script pubkey from the given [`WScriptHash`]. + pub fn new_p2wsh(script_hash: &WScriptHash) -> Self { + Self(ShutdownScriptImpl::Bolt2(Script::new_v0_wsh(script_hash))) + } + + /// Generates a P2WSH script pubkey from the given segwit version and program. + /// + /// # Panics + /// + /// This function may panic if given a segwit program with an invalid length. + pub fn new_witness_program(version: u5, program: &[u8]) -> Self { + let script = Script::new_witness_program(version, program); + Self::try_from(script).expect("Invalid segwit program") + } + + /// Converts the shutdown script into the underlying [`Script`]. + pub fn into_inner(self) -> Script { + self.into() + } +} + +impl From for ShutdownScript { + fn from(pubkey: PublicKey) -> Self { + Self(ShutdownScriptImpl::Legacy(pubkey)) + } +} + +impl TryFrom