X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fchain%2Fkeysinterface.rs;h=7063a38c4af33b862c810f710c5a3ee19abc3e1c;hb=acf9292d585fe558a33a2192e2e5e025f0c1edb2;hp=0a464193d0d6ba1765bc584514b1661b9164c4f3;hpb=34de734194f88a63a9507aeeafb14ef6e8775eb2;p=rust-lightning diff --git a/lightning/src/chain/keysinterface.rs b/lightning/src/chain/keysinterface.rs index 0a464193..7063a38c 100644 --- a/lightning/src/chain/keysinterface.rs +++ b/lightning/src/chain/keysinterface.rs @@ -34,14 +34,14 @@ use bitcoin::{PackedLockTime, secp256k1, Sequence, Witness}; use crate::util::transaction_utils; use crate::util::crypto::{hkdf_extract_expand_twice, sign}; -use crate::util::ser::{Writeable, Writer, Readable, ReadableArgs}; +use crate::util::ser::{Writeable, Writer, Readable}; #[cfg(anchors)] use crate::util::events::HTLCDescriptor; use crate::chain::transaction::OutPoint; use crate::ln::channel::ANCHOR_OUTPUT_VALUE_SATOSHI; use crate::ln::{chan_utils, PaymentPreimage}; use crate::ln::chan_utils::{HTLCOutputInCommitment, make_funding_redeemscript, ChannelPublicKeys, HolderCommitmentTransaction, ChannelTransactionParameters, CommitmentTransaction, ClosingTransaction}; -use crate::ln::msgs::UnsignedChannelAnnouncement; +use crate::ln::msgs::{UnsignedChannelAnnouncement, UnsignedGossipMessage}; use crate::ln::script::ShutdownScript; use crate::prelude::*; @@ -137,14 +137,14 @@ impl_writeable_tlv_based!(StaticPaymentOutputDescriptor, { /// [`SpendableOutputs`]: crate::util::events::Event::SpendableOutputs #[derive(Clone, Debug, PartialEq, Eq)] pub enum SpendableOutputDescriptor { - /// An output to a script which was provided via [`KeysInterface`] directly, either from + /// An output to a script which was provided via [`SignerProvider`] directly, either from /// [`get_destination_script`] or [`get_shutdown_scriptpubkey`], thus you should already /// know how to spend it. No secret keys are provided as LDK was never given any key. /// These may include outputs from a transaction punishing our counterparty or claiming an HTLC /// on-chain using the payment preimage or after it has timed out. /// - /// [`get_shutdown_scriptpubkey`]: KeysInterface::get_shutdown_scriptpubkey - /// [`get_destination_script`]: KeysInterface::get_shutdown_scriptpubkey + /// [`get_shutdown_scriptpubkey`]: SignerProvider::get_shutdown_scriptpubkey + /// [`get_destination_script`]: SignerProvider::get_shutdown_scriptpubkey StaticOutput { /// The outpoint which is spendable. outpoint: OutPoint, @@ -383,21 +383,25 @@ pub trait BaseSign { fn sign_holder_anchor_input( &self, anchor_tx: &Transaction, input: usize, secp_ctx: &Secp256k1, ) -> Result; - /// Signs a channel announcement message with our funding key and our node secret key (aka - /// node_id or network_key), proving it comes from one of the channel participants. + /// Signs a channel announcement message with our funding key proving it comes from one of the + /// channel participants. /// - /// The first returned signature should be from our node secret key, the second from our - /// funding key. + /// Channel announcements also require a signature from each node's network key. Our node + /// signature is computed through [`NodeSigner::sign_gossip_message`]. /// /// Note that if this fails or is rejected, the channel will not be publicly announced and /// our counterparty may (though likely will not) close the channel on us for violating the /// protocol. - fn sign_channel_announcement(&self, msg: &UnsignedChannelAnnouncement, secp_ctx: &Secp256k1) - -> Result<(Signature, Signature), ()>; + fn sign_channel_announcement_with_funding_key( + &self, msg: &UnsignedChannelAnnouncement, secp_ctx: &Secp256k1 + ) -> Result; /// Set the counterparty static channel data, including basepoints, - /// `counterparty_selected`/`holder_selected_contest_delay` and funding outpoint. Since these - /// are static channel data, they MUST NOT be allowed to change to different values once set, - /// as LDK may call this method more than once. + /// `counterparty_selected`/`holder_selected_contest_delay` and funding outpoint. + /// + /// This data is static, and will never change for a channel once set. For a given [`BaseSign`] + /// instance, LDK will call this method exactly once - either immediately after construction + /// (not including if done via [`SignerProvider::read_chan_signer`]) or when the funding + /// information has been generated. /// /// channel_parameters.is_populated() MUST be true. fn provide_channel_parameters(&mut self, channel_parameters: &ChannelTransactionParameters); @@ -414,7 +418,7 @@ pub trait Sign: BaseSign + Writeable {} /// Specifies the recipient of an invoice. /// -/// This indicates to [`KeysInterface::sign_invoice`] what node secret key should be used to sign +/// This indicates to [`NodeSigner::sign_invoice`] what node secret key should be used to sign /// the invoice. pub enum Recipient { /// The invoice should be signed with the local node secret key. @@ -426,69 +430,91 @@ pub enum Recipient { PhantomNode, } -/// A trait to describe an object which can get user secrets and key material. -pub trait KeysInterface { - /// A type which implements [`Sign`] which will be returned by [`Self::derive_channel_signer`]. - type Signer : Sign; - /// Get node secret key based on the provided [`Recipient`]. +/// A trait that describes a source of entropy. +pub trait EntropySource { + /// Gets a unique, cryptographically-secure, random 32-byte value. This method must return a + /// different value each time it is called. + fn get_secure_random_bytes(&self) -> [u8; 32]; +} + +/// A trait that can handle cryptographic operations at the scope level of a node. +pub trait NodeSigner { + /// Get secret key material as bytes for use in encrypting and decrypting inbound payment data. /// - /// The `node_id`/`network_key` is the public key that corresponds to this secret key. + /// If the implementor of this trait supports [phantom node payments], then every node that is + /// intended to be included in the phantom invoice route hints must return the same value from + /// this method. + // This is because LDK avoids storing inbound payment data by encrypting payment data in the + // payment hash and/or payment secret, therefore for a payment to be receivable by multiple + // nodes, they must share the key that encrypts this payment data. /// - /// This method must return the same value each time it is called with a given [`Recipient`] - /// parameter. + /// This method must return the same value each time it is called. /// - /// Errors if the [`Recipient`] variant is not supported by the implementation. - fn get_node_secret(&self, recipient: Recipient) -> Result; - /// Get node id based on the provided [`Recipient`]. This public key corresponds to the secret in - /// [`get_node_secret`]. + /// [phantom node payments]: PhantomKeysManager + fn get_inbound_payment_key_material(&self) -> KeyMaterial; + + /// Get node id based on the provided [`Recipient`]. /// /// This method must return the same value each time it is called with a given [`Recipient`] /// parameter. /// /// Errors if the [`Recipient`] variant is not supported by the implementation. - /// - /// [`get_node_secret`]: Self::get_node_secret - fn get_node_id(&self, recipient: Recipient) -> Result { - let secp_ctx = Secp256k1::signing_only(); - Ok(PublicKey::from_secret_key(&secp_ctx, &self.get_node_secret(recipient)?)) - } - /// Gets the ECDH shared secret of our [`node secret`] and `other_key`, multiplying by `tweak` if + fn get_node_id(&self, recipient: Recipient) -> Result; + + /// Gets the ECDH shared secret of our node secret and `other_key`, multiplying by `tweak` if /// one is provided. Note that this tweak can be applied to `other_key` instead of our node /// secret, though this is less efficient. /// - /// Errors if the [`Recipient`] variant is not supported by the implementation. + /// Note that if this fails while attempting to forward an HTLC, LDK will panic. The error + /// should be resolved to allow LDK to resume forwarding HTLCs. /// - /// [`node secret`]: Self::get_node_secret + /// Errors if the [`Recipient`] variant is not supported by the implementation. fn ecdh(&self, recipient: Recipient, other_key: &PublicKey, tweak: Option<&Scalar>) -> Result; - /// Get a script pubkey which we send funds to when claiming on-chain contestable outputs. + + /// Sign an invoice. /// - /// This method should return a different value each time it is called, to avoid linking - /// on-chain funds across channels as controlled to the same user. - fn get_destination_script(&self) -> Script; - /// Get a script pubkey which we will send funds to when closing a channel. + /// By parameterizing by the raw invoice bytes instead of the hash, we allow implementors of + /// this trait to parse the invoice and make sure they're signing what they expect, rather than + /// blindly signing the hash. /// - /// This method should return a different value each time it is called, to avoid linking - /// on-chain funds across channels as controlled to the same user. - fn get_shutdown_scriptpubkey(&self) -> ShutdownScript; - /// Get a new set of [`Sign`] for per-channel secrets. These MUST be unique even if you - /// restarted with some stale data! + /// The `hrp_bytes` are ASCII bytes, while the `invoice_data` is base32. + /// + /// The secret key used to sign the invoice is dependent on the [`Recipient`]. + /// + /// Errors if the [`Recipient`] variant is not supported by the implementation. + fn sign_invoice(&self, hrp_bytes: &[u8], invoice_data: &[u5], recipient: Recipient) -> Result; + + /// Sign a gossip message. + /// + /// Note that if this fails, LDK may panic and the message will not be broadcast to the network + /// or a possible channel counterparty. If LDK panics, the error should be resolved to allow the + /// message to be broadcast, as otherwise it may prevent one from receiving funds over the + /// corresponding channel. + fn sign_gossip_message(&self, msg: UnsignedGossipMessage) -> Result; +} + +/// A trait that can return signer instances for individual channels. +pub trait SignerProvider { + /// A type which implements [`Sign`] which will be returned by [`Self::derive_channel_signer`]. + type Signer : Sign; + + /// Generates a unique `channel_keys_id` that can be used to obtain a [`Self::Signer`] through + /// [`SignerProvider::derive_channel_signer`]. The `user_channel_id` is provided to allow + /// implementations of [`SignerProvider`] to maintain a mapping between itself and the generated + /// `channel_keys_id`. /// /// This method must return a different value each time it is called. fn generate_channel_keys_id(&self, inbound: bool, channel_value_satoshis: u64, user_channel_id: u128) -> [u8; 32]; + /// Derives the private key material backing a `Signer`. /// /// To derive a new `Signer`, a fresh `channel_keys_id` should be obtained through - /// [`KeysInterface::generate_channel_keys_id`]. Otherwise, an existing `Signer` can be + /// [`SignerProvider::generate_channel_keys_id`]. Otherwise, an existing `Signer` can be /// re-derived from its `channel_keys_id`, which can be obtained through its trait method /// [`BaseSign::channel_keys_id`]. fn derive_channel_signer(&self, channel_value_satoshis: u64, channel_keys_id: [u8; 32]) -> Self::Signer; - /// Gets a unique, cryptographically-secure, random 32 byte value. This is used for encrypting - /// onion packets and for temporary channel IDs. There is no requirement that these be - /// persisted anywhere, though they must be unique across restarts. - /// - /// This method must return a different value each time it is called. - fn get_secure_random_bytes(&self) -> [u8; 32]; - /// Reads a [`Signer`] for this [`KeysInterface`] from the given input stream. + + /// Reads a [`Signer`] for this [`SignerProvider`] from the given input stream. /// This is only called during deserialization of other objects which contain /// [`Sign`]-implementing objects (i.e., [`ChannelMonitor`]s and [`ChannelManager`]s). /// The bytes are exactly those which `::write()` writes, and @@ -502,29 +528,18 @@ pub trait KeysInterface { /// [`ChannelMonitor`]: crate::chain::channelmonitor::ChannelMonitor /// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager fn read_chan_signer(&self, reader: &[u8]) -> Result; - /// Sign an invoice. - /// By parameterizing by the raw invoice bytes instead of the hash, we allow implementors of - /// this trait to parse the invoice and make sure they're signing what they expect, rather than - /// blindly signing the hash. - /// The `hrp` is ASCII bytes, while the invoice data is base32-encoded. - /// - /// The secret key used to sign the invoice is dependent on the [`Recipient`]. - /// - /// Errors if the [`Recipient`] variant is not supported by the implementation. - fn sign_invoice(&self, hrp_bytes: &[u8], invoice_data: &[u5], receipient: Recipient) -> Result; - /// Get secret key material as bytes for use in encrypting and decrypting inbound payment data. - /// - /// If the implementor of this trait supports [phantom node payments], then every node that is - /// intended to be included in the phantom invoice route hints must return the same value from - /// this method. - // This is because LDK avoids storing inbound payment data by encrypting payment data in the - // payment hash and/or payment secret, therefore for a payment to be receivable by multiple - // nodes, they must share the key that encrypts this payment data. + + /// Get a script pubkey which we send funds to when claiming on-chain contestable outputs. /// - /// This method must return the same value each time it is called. + /// This method should return a different value each time it is called, to avoid linking + /// on-chain funds across channels as controlled to the same user. + fn get_destination_script(&self) -> Script; + + /// Get a script pubkey which we will send funds to when closing a channel. /// - /// [phantom node payments]: PhantomKeysManager - fn get_inbound_payment_key_material(&self) -> KeyMaterial; + /// This method should return a different value each time it is called, to avoid linking + /// on-chain funds across channels as controlled to the same user. + fn get_shutdown_scriptpubkey(&self) -> ShutdownScript; } #[derive(Clone)] @@ -548,8 +563,6 @@ pub struct InMemorySigner { pub commitment_seed: [u8; 32], /// Holder public keys and basepoints. pub(crate) holder_channel_pubkeys: ChannelPublicKeys, - /// Private key of our node secret, used for signing channel announcements. - node_secret: SecretKey, /// Counterparty public keys and counterparty/holder `selected_contest_delay`, populated on channel acceptance. channel_parameters: Option, /// The total value of this channel. @@ -562,7 +575,6 @@ impl InMemorySigner { /// Creates a new [`InMemorySigner`]. pub fn new( secp_ctx: &Secp256k1, - node_secret: SecretKey, funding_key: SecretKey, revocation_base_key: SecretKey, payment_key: SecretKey, @@ -583,7 +595,6 @@ impl InMemorySigner { delayed_payment_base_key, htlc_base_key, commitment_seed, - node_secret, channel_value_satoshis, holder_channel_pubkeys, channel_parameters: None, @@ -854,10 +865,11 @@ impl BaseSign for InMemorySigner { Ok(sign(secp_ctx, &hash_to_message!(&sighash[..]), &self.funding_key)) } - fn sign_channel_announcement(&self, msg: &UnsignedChannelAnnouncement, secp_ctx: &Secp256k1) - -> Result<(Signature, Signature), ()> { + fn sign_channel_announcement_with_funding_key( + &self, msg: &UnsignedChannelAnnouncement, secp_ctx: &Secp256k1 + ) -> Result { let msghash = hash_to_message!(&Sha256dHash::hash(&msg.encode()[..])[..]); - Ok((sign(secp_ctx, &msghash, &self.node_secret), sign(secp_ctx, &msghash, &self.funding_key))) + Ok(sign(secp_ctx, &msghash, &self.funding_key)) } fn provide_channel_parameters(&mut self, channel_parameters: &ChannelTransactionParameters) { @@ -897,8 +909,8 @@ impl Writeable for InMemorySigner { } } -impl ReadableArgs for InMemorySigner { - fn read(reader: &mut R, node_secret: SecretKey) -> Result { +impl Readable for InMemorySigner { + fn read(reader: &mut R) -> Result { let _ver = read_ver_prefix!(reader, SERIALIZATION_VERSION); let funding_key = Readable::read(reader)?; @@ -923,7 +935,6 @@ impl ReadableArgs for InMemorySigner { payment_key, delayed_payment_base_key, htlc_base_key, - node_secret, commitment_seed, channel_value_satoshis, holder_channel_pubkeys, @@ -933,8 +944,8 @@ impl ReadableArgs for InMemorySigner { } } -/// Simple [`KeysInterface`] implementation that takes a 32-byte seed for use as a BIP 32 extended -/// key and derives keys from that. +/// Simple implementation of [`EntropySource`], [`NodeSigner`], and [`SignerProvider`] that takes a +/// 32-byte seed for use as a BIP 32 extended key and derives keys from that. /// /// Your `node_id` is seed/0'. /// Unilateral closes may use seed/1'. @@ -1081,7 +1092,6 @@ impl KeysManager { InMemorySigner::new( &self.secp_ctx, - self.node_secret, funding_key, revocation_base_key, payment_key, @@ -1224,16 +1234,20 @@ impl KeysManager { } } -impl KeysInterface for KeysManager { - type Signer = InMemorySigner; +impl EntropySource for KeysManager { + fn get_secure_random_bytes(&self) -> [u8; 32] { + let mut sha = self.rand_bytes_unique_start.clone(); - fn get_node_secret(&self, recipient: Recipient) -> Result { - match recipient { - Recipient::Node => Ok(self.node_secret.clone()), - Recipient::PhantomNode => Err(()) - } + let child_ix = self.rand_bytes_child_index.fetch_add(1, Ordering::AcqRel); + let child_privkey = self.rand_bytes_master_key.ckd_priv(&self.secp_ctx, ChildNumber::from_hardened_idx(child_ix as u32).expect("key space exhausted")).expect("Your RNG is busted"); + sha.input(&child_privkey.private_key[..]); + + sha.input(b"Unique Secure Random Bytes Salt"); + Sha256::from_engine(sha).into_inner() } +} +impl NodeSigner for KeysManager { fn get_node_id(&self, recipient: Recipient) -> Result { match recipient { Recipient::Node => Ok(self.node_id.clone()), @@ -1242,7 +1256,10 @@ impl KeysInterface for KeysManager { } fn ecdh(&self, recipient: Recipient, other_key: &PublicKey, tweak: Option<&Scalar>) -> Result { - let mut node_secret = self.get_node_secret(recipient)?; + let mut node_secret = match recipient { + Recipient::Node => Ok(self.node_secret.clone()), + Recipient::PhantomNode => Err(()) + }?; if let Some(tweak) = tweak { node_secret = node_secret.mul_tweak(tweak).map_err(|_| ())?; } @@ -1253,17 +1270,32 @@ impl KeysInterface for KeysManager { self.inbound_payment_key.clone() } - fn get_destination_script(&self) -> Script { - self.destination_script.clone() + fn sign_invoice(&self, hrp_bytes: &[u8], invoice_data: &[u5], recipient: Recipient) -> Result { + let preimage = construct_invoice_preimage(&hrp_bytes, &invoice_data); + let secret = match recipient { + Recipient::Node => Ok(&self.node_secret), + Recipient::PhantomNode => Err(()) + }?; + Ok(self.secp_ctx.sign_ecdsa_recoverable(&hash_to_message!(&Sha256::hash(&preimage)), secret)) } - fn get_shutdown_scriptpubkey(&self) -> ShutdownScript { - ShutdownScript::new_p2wpkh_from_pubkey(self.shutdown_pubkey.clone()) + fn sign_gossip_message(&self, msg: UnsignedGossipMessage) -> Result { + let msg_hash = hash_to_message!(&Sha256dHash::hash(&msg.encode()[..])[..]); + Ok(sign(&self.secp_ctx, &msg_hash, &self.node_secret)) } +} + +impl SignerProvider for KeysManager { + type Signer = InMemorySigner; fn generate_channel_keys_id(&self, _inbound: bool, _channel_value_satoshis: u64, user_channel_id: u128) -> [u8; 32] { let child_idx = self.channel_child_index.fetch_add(1, Ordering::AcqRel); - assert!(child_idx <= core::u32::MAX as usize); + // `child_idx` is the only thing guaranteed to make each channel unique without a restart + // (though `user_channel_id` should help, depending on user behavior). If it manages to + // roll over, we may generate duplicate keys for two different channels, which could result + // in loss of funds. Because we only support 32-bit+ systems, assert that our `AtomicUsize` + // doesn't reach `u32::MAX`. + assert!(child_idx < core::u32::MAX as usize, "2^32 channels opened without restart"); let mut id = [0; 32]; id[0..4].copy_from_slice(&(child_idx as u32).to_be_bytes()); id[4..8].copy_from_slice(&self.starting_time_nanos.to_be_bytes()); @@ -1276,28 +1308,16 @@ impl KeysInterface for KeysManager { self.derive_channel_keys(channel_value_satoshis, &channel_keys_id) } - fn get_secure_random_bytes(&self) -> [u8; 32] { - let mut sha = self.rand_bytes_unique_start.clone(); - - let child_ix = self.rand_bytes_child_index.fetch_add(1, Ordering::AcqRel); - let child_privkey = self.rand_bytes_master_key.ckd_priv(&self.secp_ctx, ChildNumber::from_hardened_idx(child_ix as u32).expect("key space exhausted")).expect("Your RNG is busted"); - sha.input(&child_privkey.private_key[..]); - - sha.input(b"Unique Secure Random Bytes Salt"); - Sha256::from_engine(sha).into_inner() + fn read_chan_signer(&self, reader: &[u8]) -> Result { + InMemorySigner::read(&mut io::Cursor::new(reader)) } - fn read_chan_signer(&self, reader: &[u8]) -> Result { - InMemorySigner::read(&mut io::Cursor::new(reader), self.node_secret.clone()) + fn get_destination_script(&self) -> Script { + self.destination_script.clone() } - fn sign_invoice(&self, hrp_bytes: &[u8], invoice_data: &[u5], recipient: Recipient) -> Result { - let preimage = construct_invoice_preimage(&hrp_bytes, &invoice_data); - let secret = match recipient { - Recipient::Node => self.get_node_secret(Recipient::Node)?, - Recipient::PhantomNode => return Err(()), - }; - Ok(self.secp_ctx.sign_ecdsa_recoverable(&hash_to_message!(&Sha256::hash(&preimage)), &secret)) + fn get_shutdown_scriptpubkey(&self) -> ShutdownScript { + ShutdownScript::new_p2wpkh_from_pubkey(self.shutdown_pubkey.clone()) } } @@ -1329,16 +1349,13 @@ pub struct PhantomKeysManager { phantom_node_id: PublicKey, } -impl KeysInterface for PhantomKeysManager { - type Signer = InMemorySigner; - - fn get_node_secret(&self, recipient: Recipient) -> Result { - match recipient { - Recipient::Node => self.inner.get_node_secret(Recipient::Node), - Recipient::PhantomNode => Ok(self.phantom_secret.clone()), - } +impl EntropySource for PhantomKeysManager { + fn get_secure_random_bytes(&self) -> [u8; 32] { + self.inner.get_secure_random_bytes() } +} +impl NodeSigner for PhantomKeysManager { fn get_node_id(&self, recipient: Recipient) -> Result { match recipient { Recipient::Node => self.inner.get_node_id(Recipient::Node), @@ -1347,7 +1364,10 @@ impl KeysInterface for PhantomKeysManager { } fn ecdh(&self, recipient: Recipient, other_key: &PublicKey, tweak: Option<&Scalar>) -> Result { - let mut node_secret = self.get_node_secret(recipient)?; + let mut node_secret = match recipient { + Recipient::Node => self.inner.node_secret.clone(), + Recipient::PhantomNode => self.phantom_secret.clone(), + }; if let Some(tweak) = tweak { node_secret = node_secret.mul_tweak(tweak).map_err(|_| ())?; } @@ -1358,13 +1378,22 @@ impl KeysInterface for PhantomKeysManager { self.inbound_payment_key.clone() } - fn get_destination_script(&self) -> Script { - self.inner.get_destination_script() + fn sign_invoice(&self, hrp_bytes: &[u8], invoice_data: &[u5], recipient: Recipient) -> Result { + let preimage = construct_invoice_preimage(&hrp_bytes, &invoice_data); + let secret = match recipient { + Recipient::Node => &self.inner.node_secret, + Recipient::PhantomNode => &self.phantom_secret, + }; + Ok(self.inner.secp_ctx.sign_ecdsa_recoverable(&hash_to_message!(&Sha256::hash(&preimage)), secret)) } - fn get_shutdown_scriptpubkey(&self) -> ShutdownScript { - self.inner.get_shutdown_scriptpubkey() + fn sign_gossip_message(&self, msg: UnsignedGossipMessage) -> Result { + self.inner.sign_gossip_message(msg) } +} + +impl SignerProvider for PhantomKeysManager { + type Signer = InMemorySigner; fn generate_channel_keys_id(&self, inbound: bool, channel_value_satoshis: u64, user_channel_id: u128) -> [u8; 32] { self.inner.generate_channel_keys_id(inbound, channel_value_satoshis, user_channel_id) @@ -1374,18 +1403,16 @@ impl KeysInterface for PhantomKeysManager { self.inner.derive_channel_signer(channel_value_satoshis, channel_keys_id) } - fn get_secure_random_bytes(&self) -> [u8; 32] { - self.inner.get_secure_random_bytes() - } - fn read_chan_signer(&self, reader: &[u8]) -> Result { self.inner.read_chan_signer(reader) } - fn sign_invoice(&self, hrp_bytes: &[u8], invoice_data: &[u5], recipient: Recipient) -> Result { - let preimage = construct_invoice_preimage(&hrp_bytes, &invoice_data); - let secret = self.get_node_secret(recipient)?; - Ok(self.inner.secp_ctx.sign_ecdsa_recoverable(&hash_to_message!(&Sha256::hash(&preimage)), &secret)) + fn get_destination_script(&self) -> Script { + self.inner.get_destination_script() + } + + fn get_shutdown_scriptpubkey(&self) -> ShutdownScript { + self.inner.get_shutdown_scriptpubkey() } }