1use std::sync::Arc;
5
6use async_trait::async_trait;
7
8use bitcoin::blockdata::block::Header as BlockHeader;
9use bitcoin::consensus::serialize;
10use bitcoin::secp256k1::PublicKey;
11use bitcoin::{BlockHash, Network, OutPoint, Txid};
12
13use crate::persist::ExternalPersistWithHelper;
14use lightning_signer::bitcoin;
15use lightning_signer::chain::tracker::{ChainTracker, Headers};
16use lightning_signer::monitor::ChainMonitor;
17use lightning_signer::node::{Node, SignedHeartbeat};
18use lightning_signer::persist::Persist;
19use lightning_signer::signer::multi_signer::MultiSigner;
20use lightning_signer::txoo::proof::TxoProof;
21use lightning_signer::wallet::Wallet;
22use vls_frontend::{ChainTrack, ChainTrackDirectory};
23
24pub struct SignerFront {
26 pub signer: Arc<MultiSigner>,
28 pub external_persist: Option<ExternalPersistWithHelper>,
30}
31
32#[async_trait]
33impl ChainTrackDirectory for SignerFront {
34 fn tracker(&self, node_id: &PublicKey) -> Arc<dyn ChainTrack> {
35 let node = self.signer.get_node(node_id).unwrap();
36 Arc::new(NodeFront::new(node, self.external_persist.clone()))
37 }
38 async fn trackers(&self) -> Vec<Arc<dyn ChainTrack>> {
39 self.signer.get_node_ids().iter().map(|node_id| self.tracker(node_id)).collect()
40 }
41}
42
43pub struct SingleFront {
45 pub node: Arc<Node>,
46 pub external_persist: Option<ExternalPersistWithHelper>,
47}
48
49#[async_trait]
50impl ChainTrackDirectory for SingleFront {
51 fn tracker(&self, _node_id: &PublicKey) -> Arc<dyn ChainTrack> {
52 unimplemented!();
54 }
55 async fn trackers(&self) -> Vec<Arc<dyn ChainTrack>> {
56 vec![Arc::new(NodeFront::new(Arc::clone(&self.node), self.external_persist.clone()))]
57 }
58}
59
60pub(crate) struct NodeFront {
62 node: Arc<Node>,
63 heartbeat_pubkey: PublicKey,
64 external_persist: Option<ExternalPersistWithHelper>,
65}
66
67impl NodeFront {
68 pub fn new(node: Arc<Node>, external_persist: Option<ExternalPersistWithHelper>) -> Self {
69 let heartbeat_pubkey = node.get_account_extended_pubkey().public_key.clone();
70 Self { node, heartbeat_pubkey, external_persist }
71 }
72
73 fn do_add_block(&self, header: BlockHeader, proof: TxoProof, persister: Arc<dyn Persist>) {
74 let mut tracker = self.node.get_tracker();
75 let proof = self.maybe_stream_block(&mut *tracker, proof);
76 tracker
77 .add_block(header, proof)
78 .unwrap_or_else(|e| panic!("{}: add_block failed: {:?}", self.node.log_prefix(), e));
79 persister.update_tracker(&self.node.get_id(), &tracker).unwrap_or_else(|e| {
80 panic!("{}: persist tracker failed: {:?}", self.node.log_prefix(), e)
81 });
82 }
83
84 fn do_remove_block(&self, proof: TxoProof, persister: Arc<dyn Persist>, prev_headers: Headers) {
85 let mut tracker = self.node.get_tracker();
86 let proof = self.maybe_stream_block(&mut *tracker, proof);
87 tracker
88 .remove_block(proof, prev_headers)
89 .unwrap_or_else(|e| panic!("{}: remove_block failed: {:?}", self.node.log_prefix(), e));
90 persister.update_tracker(&self.node.get_id(), &tracker).unwrap_or_else(|e| {
91 panic!("{}: persist tracker failed: {:?}", self.node.log_prefix(), e)
92 });
93 }
94
95 fn maybe_stream_block(
96 &self,
97 tracker: &mut ChainTracker<ChainMonitor>,
98 proof: TxoProof,
99 ) -> TxoProof {
100 let (proof, block_opt) = proof.take_block();
102 if let Some(block) = block_opt {
103 let block_hash = block.block_hash();
104 let bytes = serialize(&block);
105 let mut offset = 0;
106 for chunk in bytes.chunks(23) {
108 tracker.block_chunk(block_hash, offset, chunk).expect("block_chunk");
109 offset += chunk.len() as u32;
110 }
111 }
112 proof
113 }
114
115 fn do_beat(&self, _persister: Arc<dyn Persist>) -> SignedHeartbeat {
116 self.node.get_heartbeat()
117 }
118
119 async fn with_persist_context<F>(
120 external_persist: &ExternalPersistWithHelper,
121 persister: Arc<dyn Persist>,
122 f: F,
123 ) where
124 F: FnOnce(Arc<dyn Persist>),
125 {
126 let client = external_persist.persist_client.lock().await;
128
129 persister.enter().expect("persister enter");
130 f(persister.clone());
131 let muts = persister.prepare();
132
133 let helper = &external_persist.helper;
134 let client_hmac = helper.client_hmac(&muts);
135 let server_hmac = helper.server_hmac(&muts);
136 let received_server_hmac =
137 client.put(muts.clone(), &client_hmac).await.expect("persist failed");
138 assert_eq!(received_server_hmac, server_hmac, "server hmac mismatch");
139
140 persister.commit().expect("persister commit")
141 }
142}
143
144#[async_trait]
145impl ChainTrack for NodeFront {
146 fn log_prefix(&self) -> String {
147 format!("tracker {}", self.node.log_prefix())
148 }
149
150 async fn id(&self) -> Vec<u8> {
151 self.node.get_id().serialize().to_vec()
152 }
153
154 async fn heartbeat_pubkey(&self) -> PublicKey {
155 self.heartbeat_pubkey.clone()
156 }
157
158 fn network(&self) -> Network {
159 self.node.network()
160 }
161
162 async fn tip_info(&self) -> (u32, BlockHash) {
163 let tracker = self.node.get_tracker();
164 (tracker.height(), tracker.tip().0.block_hash())
165 }
166
167 async fn forward_watches(&self) -> (Vec<Txid>, Vec<OutPoint>) {
168 self.node.get_tracker().get_all_forward_watches()
169 }
170
171 async fn reverse_watches(&self) -> (Vec<Txid>, Vec<OutPoint>) {
172 self.node.get_tracker().get_all_reverse_watches()
173 }
174
175 async fn add_block(&self, header: BlockHeader, proof: TxoProof) {
176 let persister = self.node.get_persister();
177 if let Some(external_persist) = &self.external_persist {
178 Self::with_persist_context(external_persist, persister, |persister| {
179 self.do_add_block(header, proof, persister);
180 })
181 .await;
182 } else {
183 self.do_add_block(header, proof, persister);
184 }
185 }
186
187 async fn remove_block(&self, proof: TxoProof, prev_headers: Headers) {
188 let persister = self.node.get_persister();
189 if let Some(external_persist) = &self.external_persist {
190 Self::with_persist_context(external_persist, persister, |persister| {
191 self.do_remove_block(proof, persister, prev_headers);
192 })
193 .await;
194 } else {
195 self.do_remove_block(proof, persister, prev_headers);
196 }
197 }
198
199 async fn beat(&self) -> SignedHeartbeat {
200 let persister = self.node.get_persister();
201 let mut beat: Option<SignedHeartbeat> = None;
202 if let Some(external_persist) = &self.external_persist {
203 Self::with_persist_context(external_persist, persister, |persister| {
204 beat = Some(self.do_beat(persister));
205 })
206 .await
207 } else {
208 beat = Some(self.do_beat(persister));
209 }
210 beat.unwrap()
211 }
212}