Skip to main content

vls_protocol_client/
dyn_signer.rs

1use std::any::Any;
2
3use delegate::delegate;
4
5use crate::bitcoin::Address;
6use crate::HTLCDescriptor;
7use bitcoin::{secp256k1, Transaction, TxOut, Txid};
8use lightning::ln::chan_utils::{
9    ChannelPublicKeys, ChannelTransactionParameters, ClosingTransaction, CommitmentTransaction,
10    HTLCOutputInCommitment, HolderCommitmentTransaction,
11};
12use lightning::ln::msgs::{DecodeError, UnsignedChannelAnnouncement, UnsignedGossipMessage};
13use lightning::ln::script::ShutdownScript;
14use lightning::sign::ecdsa::EcdsaChannelSigner;
15use lightning::sign::ChannelSigner;
16use lightning::sign::InMemorySigner;
17use lightning::sign::{
18    NodeSigner, PeerStorageKey, ReceiveAuthKey, Recipient, SignerProvider,
19    SpendableOutputDescriptor,
20};
21use lightning::types::payment::PaymentPreimage;
22use lightning::util::ser::Readable;
23use lightning::util::ser::{Writeable, Writer};
24use lightning_invoice::RawBolt11Invoice;
25use lightning_signer::bitcoin::secp256k1::All;
26use lightning_signer::bitcoin::{self, ScriptBuf};
27use lightning_signer::lightning;
28use lightning_signer::lightning::ln::inbound_payment::ExpandedKey;
29use lightning_signer::lightning_invoice;
30use lightning_signer::util::loopback::LoopbackChannelSigner;
31use secp256k1::ecdsa::RecoverableSignature;
32use secp256k1::{ecdh::SharedSecret, ecdsa::Signature, PublicKey, Scalar, Secp256k1, SecretKey};
33
34/// Helper to allow DynSigner to clone itself
35pub trait InnerSign: EcdsaChannelSigner + Send + Sync {
36    fn box_clone(&self) -> Box<dyn InnerSign>;
37    fn as_any(&self) -> &dyn Any;
38    fn vwrite(&self, writer: &mut Vec<u8>) -> Result<(), bitcoin::io::Error>;
39}
40
41/// A ChannelSigner derived struct allowing run-time selection of a signer
42pub struct DynSigner {
43    pub inner: Box<dyn InnerSign>,
44}
45
46impl DynSigner {
47    pub fn new<S: InnerSign + 'static>(inner: S) -> Self {
48        DynSigner { inner: Box::new(inner) }
49    }
50}
51
52impl Clone for DynSigner {
53    fn clone(&self) -> Self {
54        DynSigner { inner: self.inner.box_clone() }
55    }
56}
57
58// This is taken care of by KeysInterface
59impl Readable for DynSigner {
60    fn read<R: bitcoin::io::Read>(_reader: &mut R) -> Result<Self, DecodeError> {
61        unimplemented!()
62    }
63}
64
65impl EcdsaChannelSigner for DynSigner {
66    delegate! {
67        to self.inner {
68            fn sign_counterparty_commitment(
69                &self,
70                channel_parameters: &ChannelTransactionParameters,
71                commitment_tx: &CommitmentTransaction,
72                inbound_htlc_preimages: Vec<PaymentPreimage>,
73                outbound_htlc_preimages: Vec<PaymentPreimage>,
74                secp_ctx: &Secp256k1<secp256k1::All>,
75            ) -> Result<(Signature, Vec<Signature>), ()>;
76
77            fn sign_holder_commitment(
78                &self,
79                channel_parameters: &ChannelTransactionParameters,
80                commitment_tx: &HolderCommitmentTransaction,
81                secp_ctx: &Secp256k1<secp256k1::All>,
82            ) -> Result<Signature, ()>;
83
84            fn unsafe_sign_holder_commitment(
85                &self,
86                channel_parameters: &ChannelTransactionParameters,
87                commitment_tx: &HolderCommitmentTransaction,
88                secp_ctx: &Secp256k1<secp256k1::All>,
89            ) -> Result<Signature, ()>;
90
91            fn sign_justice_revoked_output(
92                &self,
93                channel_parameters: &ChannelTransactionParameters,
94                justice_tx: &Transaction,
95                input: usize,
96                amount: u64,
97                per_commitment_key: &SecretKey,
98                secp_ctx: &Secp256k1<secp256k1::All>,
99            ) -> Result<Signature, ()>;
100
101            fn sign_justice_revoked_htlc(
102                &self,
103                channel_parameters: &ChannelTransactionParameters,
104                justice_tx: &Transaction,
105                input: usize,
106                amount: u64,
107                per_commitment_key: &SecretKey,
108                htlc: &HTLCOutputInCommitment,
109                secp_ctx: &Secp256k1<secp256k1::All>,
110            ) -> Result<Signature, ()>;
111
112            fn sign_counterparty_htlc_transaction(
113                &self,
114                channel_parameters: &ChannelTransactionParameters,
115                htlc_tx: &Transaction,
116                input: usize,
117                amount: u64,
118                per_commitment_point: &PublicKey,
119                htlc: &HTLCOutputInCommitment,
120                secp_ctx: &Secp256k1<secp256k1::All>,
121            ) -> Result<Signature, ()>;
122
123            fn sign_closing_transaction(
124                &self,
125                channel_parameters: &ChannelTransactionParameters,
126                closing_tx: &ClosingTransaction,
127                secp_ctx: &Secp256k1<secp256k1::All>,
128            ) -> Result<Signature, ()>;
129
130            fn sign_channel_announcement_with_funding_key(
131                &self,
132                channel_parameters: &ChannelTransactionParameters,
133                msg: &UnsignedChannelAnnouncement,
134                secp_ctx: &Secp256k1<secp256k1::All>,
135            ) -> Result<Signature, ()>;
136
137            fn sign_holder_keyed_anchor_input(
138                &self,
139                channel_parameters: &ChannelTransactionParameters,
140                anchor_tx: &Transaction,
141                input: usize,
142                secp_ctx: &Secp256k1<secp256k1::All>,
143            ) -> Result<Signature, ()>;
144
145            fn sign_holder_htlc_transaction(&self, htlc_tx: &Transaction, input: usize, htlc_descriptor: &HTLCDescriptor, secp_ctx: &Secp256k1<All>) -> Result<Signature, ()>;
146
147            fn sign_splice_shared_input(
148                &self,
149                channel_parameters: &ChannelTransactionParameters,
150                tx: &Transaction,
151                input_index: usize,
152                secp_ctx: &Secp256k1<secp256k1::All>,
153            ) -> Signature;
154        }
155    }
156}
157
158impl ChannelSigner for DynSigner {
159    delegate! {
160        to self.inner {
161            fn validate_counterparty_revocation(&self, idx: u64, sk: &SecretKey) -> Result<(), ()>;
162
163            fn get_per_commitment_point(
164                &self,
165                idx: u64,
166                secp_ctx: &Secp256k1<secp256k1::All>,
167            ) -> Result<PublicKey, ()>;
168
169            fn release_commitment_secret(&self, idx: u64) -> Result<[u8; 32], ()>;
170
171            fn validate_holder_commitment(
172                &self,
173                holder_tx: &HolderCommitmentTransaction,
174                outbound_htlc_preimages: Vec<PaymentPreimage>,
175            ) -> Result<(), ()>;
176
177            fn pubkeys(&self, secp_ctx: &Secp256k1<secp256k1::All>) -> ChannelPublicKeys;
178
179            fn new_funding_pubkey(&self, splice_parent_funding_txid: Txid, secp_ctx: &Secp256k1<secp256k1::All>) -> PublicKey;
180
181            fn channel_keys_id(&self) -> [u8; 32];
182        }
183    }
184}
185
186impl Writeable for DynSigner {
187    fn write<W: Writer>(&self, writer: &mut W) -> Result<(), bitcoin::io::Error> {
188        let inner = self.inner.as_ref();
189        let mut buf = Vec::new();
190        inner.vwrite(&mut buf)?;
191        writer.write_all(&buf)
192    }
193}
194
195impl InnerSign for InMemorySigner {
196    fn box_clone(&self) -> Box<dyn InnerSign> {
197        Box::new(self.clone())
198    }
199
200    fn as_any(&self) -> &dyn Any {
201        self
202    }
203
204    fn vwrite(&self, _writer: &mut Vec<u8>) -> Result<(), bitcoin::io::Error> {
205        // LDK 0.2 dropped the `Writeable` impl on `InMemorySigner` and the
206        // matching `read_chan_signer` from `SignerProvider`, so this never
207        // round-trips. The `Writeable for DynSigner` impl is required for
208        // trait bounds only.
209        Ok(())
210    }
211}
212
213impl InnerSign for LoopbackChannelSigner {
214    fn box_clone(&self) -> Box<dyn InnerSign> {
215        Box::new(self.clone())
216    }
217
218    fn as_any(&self) -> &dyn Any {
219        self
220    }
221
222    fn vwrite(&self, writer: &mut Vec<u8>) -> Result<(), bitcoin::io::Error> {
223        self.write(writer)
224    }
225}
226
227pub struct DynKeysInterface {
228    pub inner: Box<dyn SpendableKeysInterface<EcdsaSigner = DynSigner>>,
229}
230
231impl DynKeysInterface {
232    pub fn new(inner: Box<dyn SpendableKeysInterface<EcdsaSigner = DynSigner>>) -> Self {
233        DynKeysInterface { inner }
234    }
235}
236
237impl NodeSigner for DynKeysInterface {
238    delegate! {
239        to self.inner {
240            fn get_node_id(&self, recipient: Recipient) -> Result<PublicKey, ()>;
241            fn sign_gossip_message(&self, msg: UnsignedGossipMessage) -> Result<Signature, ()>;
242            fn ecdh(&self, recipient: Recipient, other_key: &PublicKey, tweak: Option<&Scalar>) -> Result<SharedSecret, ()>;
243
244            fn sign_invoice(
245                &self,
246                invoice: &RawBolt11Invoice,
247                recipient: Recipient,
248            ) -> Result<RecoverableSignature, ()>;
249
250            fn sign_bolt12_invoice(
251                &self, invoice: &lightning::offers::invoice::UnsignedBolt12Invoice
252            ) -> Result<bitcoin::secp256k1::schnorr::Signature, ()>;
253
254            fn get_expanded_key(&self) -> ExpandedKey;
255
256            fn get_peer_storage_key(&self) -> PeerStorageKey;
257
258            fn get_receive_auth_key(&self) -> ReceiveAuthKey;
259
260            fn sign_message(&self, msg: &[u8]) -> Result<String, ()>;
261        }
262    }
263}
264
265impl SignerProvider for DynKeysInterface {
266    type EcdsaSigner = DynSigner;
267
268    delegate! {
269        to self.inner {
270            fn get_destination_script(&self, buf: [u8; 32]) -> Result<ScriptBuf, ()>;
271
272            fn get_shutdown_scriptpubkey(&self) -> Result<ShutdownScript, ()>;
273
274            fn generate_channel_keys_id(&self, _inbound: bool, _user_channel_id: u128) -> [u8; 32];
275
276            fn derive_channel_signer(&self, _channel_keys_id: [u8; 32]) -> Self::EcdsaSigner;
277        }
278    }
279}
280
281// TODO(devrandom) why is spend_spendable_outputs not in KeysInterface?
282pub trait SpendableKeysInterface: NodeSigner + SignerProvider + Send + Sync {
283    fn spend_spendable_outputs(
284        &self,
285        descriptors: &[&SpendableOutputDescriptor],
286        outputs: Vec<TxOut>,
287        change_destination_script: ScriptBuf,
288        feerate_sat_per_1000_weight: u32,
289        secp_ctx: &Secp256k1<All>,
290    ) -> anyhow::Result<Transaction>;
291
292    /// Swept funds from closed channels are sent here
293    /// This is implemented by setting the change destination to spend_spendable_outputs to this address.
294    fn get_sweep_address(&self) -> Address;
295}
296
297impl SpendableKeysInterface for DynKeysInterface {
298    delegate! {
299        to self.inner {
300            fn spend_spendable_outputs(
301                &self,
302                descriptors: &[&SpendableOutputDescriptor],
303                outputs: Vec<TxOut>,
304                change_destination_script: ScriptBuf,
305                feerate_sat_per_1000_weight: u32,
306                secp_ctx: &Secp256k1<All>,
307            ) -> anyhow::Result<Transaction>;
308
309            fn get_sweep_address(&self) -> Address;
310        }
311    }
312}