lumina_node_uniffi/
lib.rs1#![cfg(not(target_arch = "wasm32"))]
6
7use std::str::FromStr;
8
9use blockstore::EitherBlockstore;
10use celestia_types::ExtendedHeader;
11use lumina_node::Node;
12use lumina_node::blockstore::{InMemoryBlockstore, RedbBlockstore};
13use lumina_node::events::EventSubscriber;
14use lumina_node::node::PeerTrackerInfo;
15use lumina_node::store::{EitherStore, InMemoryStore, RedbStore};
16use tendermint::hash::Hash;
17use tokio::sync::{Mutex, RwLock};
18use uniffi::Object;
19
20use crate::error::{LuminaError, Result};
21use crate::types::{NetworkInfo, NodeConfig, NodeEvent, PeerId, SyncingInfo};
22
23mod error;
24mod types;
25
26uniffi::setup_scaffolding!();
27
28lumina_node::uniffi_reexport_scaffolding!();
29celestia_types::uniffi_reexport_scaffolding!();
30celestia_grpc::uniffi_reexport_scaffolding!();
31celestia_proto::uniffi_reexport_scaffolding!();
32
33pub(crate) type Blockstore = EitherBlockstore<InMemoryBlockstore, RedbBlockstore>;
34pub(crate) type Store = EitherStore<InMemoryStore, RedbStore>;
35
36#[derive(Object)]
38pub struct LuminaNode {
39 node: RwLock<Option<Node<Blockstore, Store>>>,
40 events_subscriber: Mutex<Option<EventSubscriber>>,
41 config: NodeConfig,
42}
43
44#[uniffi::export(async_runtime = "tokio")]
45impl LuminaNode {
46 #[uniffi::constructor]
48 pub fn new(config: NodeConfig) -> Result<Self> {
49 Ok(Self {
50 node: RwLock::new(None),
51 events_subscriber: Mutex::new(None),
52 config,
53 })
54 }
55
56 pub async fn start(&self) -> Result<bool> {
58 let mut node_lock = self.node.write().await;
59 if node_lock.is_some() {
60 return Err(LuminaError::AlreadyRunning);
61 }
62
63 let builder = self.config.clone().into_node_builder().await?;
64 let (new_node, subscriber) = builder.start_subscribed().await?;
65
66 *self.events_subscriber.lock().await = Some(subscriber);
67 *node_lock = Some(new_node);
68
69 Ok(true)
70 }
71
72 pub async fn stop(&self) -> Result<()> {
74 let mut node = self.node.write().await;
75 match node.take() {
76 Some(node) => {
77 node.stop().await;
78 Ok(())
79 }
80 _ => Err(LuminaError::NodeNotRunning),
81 }
82 }
83
84 pub async fn is_running(&self) -> bool {
86 self.node.read().await.is_some()
87 }
88
89 pub async fn local_peer_id(&self) -> Result<String> {
91 let node = self.node.read().await;
92 let node = node.as_ref().ok_or(LuminaError::NodeNotRunning)?;
93 Ok(node.local_peer_id().to_base58())
94 }
95
96 pub async fn peer_tracker_info(&self) -> Result<PeerTrackerInfo> {
98 let node = self.node.read().await;
99 let node = node.as_ref().ok_or(LuminaError::NodeNotRunning)?;
100 Ok(node.peer_tracker_info())
101 }
102
103 pub async fn wait_connected(&self) -> Result<()> {
105 let node = self.node.read().await;
106 let node = node.as_ref().ok_or(LuminaError::NodeNotRunning)?;
107 Ok(node.wait_connected().await?)
108 }
109
110 pub async fn wait_connected_trusted(&self) -> Result<()> {
112 let node = self.node.read().await;
113 let node = node.as_ref().ok_or(LuminaError::NodeNotRunning)?;
114 Ok(node.wait_connected_trusted().await?)
115 }
116
117 pub async fn network_info(&self) -> Result<NetworkInfo> {
119 let node = self.node.read().await;
120 let node = node.as_ref().ok_or(LuminaError::NodeNotRunning)?;
121 let info = node.network_info().await?;
122 Ok(info.into())
123 }
124
125 pub async fn listeners(&self) -> Result<Vec<String>> {
127 let node = self.node.read().await;
128 let node = node.as_ref().ok_or(LuminaError::NodeNotRunning)?;
129 let listeners = node.listeners().await?;
130 Ok(listeners.into_iter().map(|l| l.to_string()).collect())
131 }
132
133 pub async fn connected_peers(&self) -> Result<Vec<PeerId>> {
135 let node = self.node.read().await;
136 let node = node.as_ref().ok_or(LuminaError::NodeNotRunning)?;
137 let peers = node.connected_peers().await?;
138 Ok(peers.into_iter().map(PeerId::from).collect())
139 }
140
141 pub async fn set_peer_trust(&self, peer_id: PeerId, is_trusted: bool) -> Result<()> {
143 let node = self.node.read().await;
144 let node = node.as_ref().ok_or(LuminaError::NodeNotRunning)?;
145 let peer_id = peer_id.to_libp2p().map_err(LuminaError::network)?;
146 Ok(node.set_peer_trust(peer_id, is_trusted).await?)
147 }
148
149 pub async fn request_head_header(&self) -> Result<String> {
153 let node = self.node.read().await;
154 let node = node.as_ref().ok_or(LuminaError::NodeNotRunning)?;
155 let header = node.request_head_header().await?;
156 Ok(serde_json::to_string(&header).unwrap()) }
158
159 pub async fn request_header_by_hash(&self, hash: String) -> Result<String> {
161 let node = self.node.read().await;
162 let node = node.as_ref().ok_or(LuminaError::NodeNotRunning)?;
163 let hash = Hash::from_str(&hash).map_err(|e| LuminaError::invalid_hash(e.to_string()))?;
164 let header = node.request_header_by_hash(&hash).await?;
165 Ok(serde_json::to_string(&header).unwrap())
166 }
167
168 pub async fn request_header_by_height(&self, height: u64) -> Result<String> {
170 let node = self.node.read().await;
171 let node = node.as_ref().ok_or(LuminaError::NodeNotRunning)?;
172 let header = node.request_header_by_height(height).await?;
173 Ok(serde_json::to_string(&header).unwrap())
174 }
175
176 pub async fn request_verified_headers(
181 &self,
182 from: String, amount: u64,
184 ) -> Result<Vec<String>> {
185 let node = self.node.read().await;
186 let node = node.as_ref().ok_or(LuminaError::NodeNotRunning)?;
187 let from: ExtendedHeader = serde_json::from_str(&from)
188 .map_err(|e| LuminaError::invalid_header(format!("Invalid header JSON: {e}")))?;
189 let headers = node.request_verified_headers(&from, amount).await?;
190 Ok(headers
191 .into_iter()
192 .map(|h| serde_json::to_string(&h).unwrap())
193 .collect())
194 }
195
196 pub async fn syncer_info(&self) -> Result<SyncingInfo> {
198 let node = self.node.read().await;
199 let node = node.as_ref().ok_or(LuminaError::NodeNotRunning)?;
200 let info = node.syncer_info().await?;
201 Ok(info.into())
202 }
203
204 pub async fn get_network_head_header(&self) -> Result<String> {
206 let node = self.node.read().await;
207 let node = node.as_ref().ok_or(LuminaError::NodeNotRunning)?;
208 let header = node.get_network_head_header().await?;
209 header.map_or(
210 Err(LuminaError::network("No network head header available")),
211 |h| Ok(serde_json::to_string(&h).unwrap()),
212 )
213 }
214
215 pub async fn get_local_head_header(&self) -> Result<String> {
217 let node = self.node.read().await;
218 let node = node.as_ref().ok_or(LuminaError::NodeNotRunning)?;
219 let header = node.get_local_head_header().await?;
220 Ok(serde_json::to_string(&header).unwrap())
221 }
222
223 pub async fn get_header_by_hash(&self, hash: String) -> Result<String> {
225 let node = self.node.read().await;
226 let node = node.as_ref().ok_or(LuminaError::NodeNotRunning)?;
227 let hash = Hash::from_str(&hash).map_err(|e| LuminaError::invalid_hash(e.to_string()))?;
228 let header = node.get_header_by_hash(&hash).await?;
229 Ok(serde_json::to_string(&header).unwrap())
230 }
231
232 pub async fn get_header_by_height(&self, height: u64) -> Result<String> {
234 let node = self.node.read().await;
235 let node = node.as_ref().ok_or(LuminaError::NodeNotRunning)?;
236 let header = node.get_header_by_height(height).await?;
237 Ok(serde_json::to_string(&header).unwrap())
238 }
239
240 pub async fn get_headers(
248 &self,
249 start_height: Option<u64>,
250 end_height: Option<u64>,
251 ) -> Result<Vec<String>> {
252 let node = self.node.read().await;
253 let node = node.as_ref().ok_or(LuminaError::NodeNotRunning)?;
254
255 let headers = match (start_height, end_height) {
256 (None, None) => node.get_headers(..).await,
257 (Some(start), None) => node.get_headers(start..).await,
258 (None, Some(end)) => node.get_headers(..=end).await,
259 (Some(start), Some(end)) => node.get_headers(start..=end).await,
260 }?;
261
262 Ok(headers
263 .into_iter()
264 .map(|h| serde_json::to_string(&h).unwrap())
265 .collect())
266 }
267
268 pub async fn get_sampling_metadata(&self, height: u64) -> Result<Option<String>> {
272 let node = self.node.read().await;
273 let node = node.as_ref().ok_or(LuminaError::NodeNotRunning)?;
274
275 let metadata = node.get_sampling_metadata(height).await?;
276 Ok(metadata.map(|m| serde_json::to_string(&m).unwrap()))
277 }
278
279 pub async fn next_event(&self) -> Result<NodeEvent> {
281 let mut events_subscriber = self.events_subscriber.lock().await;
282 match events_subscriber.as_mut() {
283 Some(subscriber) => {
284 let event = subscriber
285 .recv()
286 .await
287 .map_err(|_| LuminaError::NodeNotRunning)?;
288 Ok(event.event.into())
289 }
290 None => Err(LuminaError::NodeNotRunning),
291 }
292 }
293}