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