1#![allow(unexpected_cfgs)]
8
9use async_trait::async_trait;
10use cosmrs::tendermint::{self, abci, block::Height, evidence::Evidence, Genesis, Hash};
11use serde::{de::DeserializeOwned, Serialize};
12use std::fmt;
13use tendermint_rpc::{
14 endpoint::{validators::DEFAULT_VALIDATORS_PER_PAGE, *},
15 query::Query,
16 Error, Order, Paging, SimpleRequest,
17};
18
19#[cfg(feature = "http-client")]
20use crate::error::TendermintRpcError;
21#[cfg(feature = "http-client")]
22use crate::HttpRpcClient;
23#[cfg(feature = "http-client")]
24use tendermint_rpc::client::CompatMode;
25#[cfg(feature = "http-client")]
26use tendermint_rpc::HttpClientUrl;
27
28pub mod reqwest;
29
30#[cfg(feature = "http-client")]
31pub fn http_client<U>(url: U) -> Result<HttpRpcClient, TendermintRpcError>
32where
33 U: TryInto<HttpClientUrl, Error = Error>,
34{
35 HttpRpcClient::builder(url.try_into()?)
36 .compat_mode(CompatMode::V0_37)
37 .build()
38}
39
40#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
43#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
44pub trait TendermintRpcClient {
45 async fn abci_info(&self) -> Result<abci::response::Info, Error> {
47 Ok(self.perform(abci_info::Request).await?.response)
48 }
49
50 async fn abci_query<V>(
52 &self,
53 path: Option<String>,
54 data: V,
55 height: Option<Height>,
56 prove: bool,
57 ) -> Result<abci_query::AbciQuery, Error>
58 where
59 V: Into<Vec<u8>> + Send,
60 {
61 Ok(self
62 .perform(abci_query::Request::new(path, data, height, prove))
63 .await?
64 .response)
65 }
66
67 async fn block<H>(&self, height: H) -> Result<block::Response, Error>
69 where
70 H: Into<Height> + Send,
71 {
72 self.perform(block::Request::new(height.into())).await
73 }
74
75 async fn block_by_hash(
77 &self,
78 hash: tendermint::Hash,
79 ) -> Result<block_by_hash::Response, Error> {
80 self.perform(block_by_hash::Request::new(hash)).await
81 }
82
83 async fn latest_block(&self) -> Result<block::Response, Error> {
85 self.perform(block::Request::default()).await
86 }
87
88 async fn header<H>(&self, height: H) -> Result<header::Response, Error>
90 where
91 H: Into<Height> + Send,
92 {
93 self.perform(header::Request::new(height.into())).await
94 }
95
96 async fn header_by_hash(
98 &self,
99 hash: tendermint::Hash,
100 ) -> Result<header_by_hash::Response, Error> {
101 self.perform(header_by_hash::Request::new(hash)).await
102 }
103
104 async fn block_results<H>(&self, height: H) -> Result<block_results::Response, Error>
106 where
107 H: Into<Height> + Send,
108 {
109 self.perform(block_results::Request::new(height.into()))
110 .await
111 }
112
113 async fn latest_block_results(&self) -> Result<block_results::Response, Error> {
115 self.perform(block_results::Request::default()).await
116 }
117
118 async fn block_search(
120 &self,
121 query: Query,
122 page: u32,
123 per_page: u8,
124 order: Order,
125 ) -> Result<block_search::Response, Error> {
126 self.perform(block_search::Request::new(query, page, per_page, order))
127 .await
128 }
129
130 async fn blockchain<H>(&self, min: H, max: H) -> Result<blockchain::Response, Error>
136 where
137 H: Into<Height> + Send,
138 {
139 self.perform(blockchain::Request::new(min.into(), max.into()))
141 .await
142 }
143
144 async fn broadcast_tx_async<T>(&self, tx: T) -> Result<broadcast::tx_async::Response, Error>
146 where
147 T: Into<Vec<u8>> + Send,
148 {
149 self.perform(broadcast::tx_async::Request::new(tx)).await
150 }
151
152 async fn broadcast_tx_sync<T>(&self, tx: T) -> Result<broadcast::tx_sync::Response, Error>
155 where
156 T: Into<Vec<u8>> + Send,
157 {
158 self.perform(broadcast::tx_sync::Request::new(tx)).await
159 }
160
161 async fn broadcast_tx_commit<T>(&self, tx: T) -> Result<broadcast::tx_commit::Response, Error>
164 where
165 T: Into<Vec<u8>> + Send,
166 {
167 self.perform(broadcast::tx_commit::Request::new(tx)).await
168 }
169
170 async fn commit<H>(&self, height: H) -> Result<commit::Response, Error>
172 where
173 H: Into<Height> + Send,
174 {
175 self.perform(commit::Request::new(height.into())).await
176 }
177
178 async fn consensus_params<H>(&self, height: H) -> Result<consensus_params::Response, Error>
181 where
182 H: Into<Height> + Send,
183 {
184 self.perform(consensus_params::Request::new(Some(height.into())))
185 .await
186 }
187
188 async fn consensus_state(&self) -> Result<consensus_state::Response, Error> {
190 self.perform(consensus_state::Request::new()).await
191 }
192
193 async fn validators<H>(&self, height: H, paging: Paging) -> Result<validators::Response, Error>
196 where
197 H: Into<Height> + Send,
198 {
199 let height = height.into();
200 match paging {
201 Paging::Default => {
202 self.perform(validators::Request::new(Some(height), None, None))
203 .await
204 }
205 Paging::Specific {
206 page_number,
207 per_page,
208 } => {
209 self.perform(validators::Request::new(
210 Some(height),
211 Some(page_number),
212 Some(per_page),
213 ))
214 .await
215 }
216 Paging::All => {
217 let mut page_num = 1_usize;
218 let mut validators = Vec::new();
219 let per_page = DEFAULT_VALIDATORS_PER_PAGE.into();
220 loop {
221 let response = self
222 .perform(validators::Request::new(
223 Some(height),
224 Some(page_num.into()),
225 Some(per_page),
226 ))
227 .await?;
228 validators.extend(response.validators);
229 if validators.len() as i32 == response.total {
230 return Ok(validators::Response::new(
231 response.block_height,
232 validators,
233 response.total,
234 ));
235 }
236 page_num += 1;
237 }
238 }
239 }
240 }
241
242 async fn latest_consensus_params(&self) -> Result<consensus_params::Response, Error> {
244 self.perform(consensus_params::Request::new(None)).await
245 }
246
247 async fn latest_commit(&self) -> Result<commit::Response, Error> {
249 self.perform(commit::Request::default()).await
250 }
251
252 async fn health(&self) -> Result<(), Error> {
256 self.perform(health::Request).await?;
257 Ok(())
258 }
259
260 async fn genesis<AppState>(&self) -> Result<Genesis<AppState>, Error>
262 where
263 AppState: fmt::Debug + Serialize + DeserializeOwned + Send,
264 {
265 Ok(self.perform(genesis::Request::default()).await?.genesis)
266 }
267
268 async fn net_info(&self) -> Result<net_info::Response, Error> {
270 self.perform(net_info::Request).await
271 }
272
273 async fn status(&self) -> Result<status::Response, Error> {
276 self.perform(status::Request).await
277 }
278
279 async fn broadcast_evidence(&self, e: Evidence) -> Result<evidence::Response, Error> {
281 self.perform(evidence::Request::new(e)).await
282 }
283
284 async fn tx(&self, hash: Hash, prove: bool) -> Result<tx::Response, Error> {
286 self.perform(tx::Request::new(hash, prove)).await
287 }
288
289 async fn tx_search(
291 &self,
292 query: Query,
293 prove: bool,
294 page: u32,
295 per_page: u8,
296 order: Order,
297 ) -> Result<tx_search::Response, Error> {
298 self.perform(tx_search::Request::new(query, prove, page, per_page, order))
299 .await
300 }
301
302 #[cfg(any(
303 feature = "tendermint-rpc-http-client",
304 feature = "tendermint-rpc-websocket-client"
305 ))]
306 async fn wait_until_healthy<T>(&self, timeout: T) -> Result<(), Error>
309 where
310 T: Into<core::time::Duration> + Send,
311 {
312 let timeout = timeout.into();
313 let poll_interval = core::time::Duration::from_millis(200);
314 let mut attempts_remaining = timeout.as_millis() / poll_interval.as_millis();
315
316 while self.health().await.is_err() {
317 if attempts_remaining == 0 {
318 return Err(Error::timeout(timeout));
319 }
320
321 attempts_remaining -= 1;
322 tokio::time::sleep(poll_interval).await;
323 }
324
325 Ok(())
326 }
327
328 async fn perform<R>(&self, request: R) -> Result<R::Output, Error>
333 where
334 R: SimpleRequest;
335}
336
337#[cfg(not(target_arch = "wasm32"))]
338mod non_wasm {
339 use super::*;
340 use cosmrs::tendermint::abci::response::Info;
341 use std::fmt::Debug;
342 use tendermint_rpc::endpoint::abci_query::AbciQuery;
343 use tendermint_rpc::endpoint::block::Response;
344
345 #[async_trait]
346 impl<C> TendermintRpcClient for C
347 where
348 C: tendermint_rpc::client::Client + Sync,
349 {
350 async fn abci_info(&self) -> Result<Info, Error> {
351 self.abci_info().await
352 }
353
354 async fn abci_query<V>(
355 &self,
356 path: Option<String>,
357 data: V,
358 height: Option<Height>,
359 prove: bool,
360 ) -> Result<AbciQuery, Error>
361 where
362 V: Into<Vec<u8>> + Send,
363 {
364 self.abci_query(path, data, height, prove).await
365 }
366
367 async fn block<H>(&self, height: H) -> Result<Response, Error>
368 where
369 H: Into<Height> + Send,
370 {
371 self.block(height).await
372 }
373
374 async fn block_by_hash(&self, hash: Hash) -> Result<block_by_hash::Response, Error> {
375 self.block_by_hash(hash).await
376 }
377
378 async fn latest_block(&self) -> Result<Response, Error> {
379 self.latest_block().await
380 }
381
382 async fn header<H>(&self, height: H) -> Result<header::Response, Error>
383 where
384 H: Into<Height> + Send,
385 {
386 self.header(height).await
387 }
388
389 async fn header_by_hash(&self, hash: Hash) -> Result<header_by_hash::Response, Error> {
390 self.header_by_hash(hash).await
391 }
392
393 async fn block_results<H>(&self, height: H) -> Result<block_results::Response, Error>
394 where
395 H: Into<Height> + Send,
396 {
397 self.block_results(height).await
398 }
399
400 async fn latest_block_results(&self) -> Result<block_results::Response, Error> {
401 self.latest_block_results().await
402 }
403
404 async fn block_search(
405 &self,
406 query: Query,
407 page: u32,
408 per_page: u8,
409 order: Order,
410 ) -> Result<block_search::Response, Error> {
411 self.block_search(query, page, per_page, order).await
412 }
413
414 async fn blockchain<H>(&self, min: H, max: H) -> Result<blockchain::Response, Error>
415 where
416 H: Into<Height> + Send,
417 {
418 self.blockchain(min, max).await
419 }
420
421 async fn broadcast_tx_async<T>(&self, tx: T) -> Result<broadcast::tx_async::Response, Error>
422 where
423 T: Into<Vec<u8>> + Send,
424 {
425 self.broadcast_tx_async(tx).await
426 }
427
428 async fn broadcast_tx_sync<T>(&self, tx: T) -> Result<broadcast::tx_sync::Response, Error>
429 where
430 T: Into<Vec<u8>> + Send,
431 {
432 self.broadcast_tx_sync(tx).await
433 }
434
435 async fn broadcast_tx_commit<T>(
436 &self,
437 tx: T,
438 ) -> Result<broadcast::tx_commit::Response, Error>
439 where
440 T: Into<Vec<u8>> + Send,
441 {
442 self.broadcast_tx_commit(tx).await
443 }
444
445 async fn commit<H>(&self, height: H) -> Result<commit::Response, Error>
446 where
447 H: Into<Height> + Send,
448 {
449 self.commit(height).await
450 }
451
452 async fn consensus_params<H>(&self, height: H) -> Result<consensus_params::Response, Error>
453 where
454 H: Into<Height> + Send,
455 {
456 self.consensus_params(height).await
457 }
458
459 async fn consensus_state(&self) -> Result<consensus_state::Response, Error> {
460 self.consensus_state().await
461 }
462
463 async fn validators<H>(
464 &self,
465 height: H,
466 paging: Paging,
467 ) -> Result<validators::Response, Error>
468 where
469 H: Into<Height> + Send,
470 {
471 self.validators(height, paging).await
472 }
473
474 async fn latest_consensus_params(&self) -> Result<consensus_params::Response, Error> {
475 self.latest_consensus_params().await
476 }
477
478 async fn latest_commit(&self) -> Result<commit::Response, Error> {
479 self.latest_commit().await
480 }
481
482 async fn health(&self) -> Result<(), Error> {
483 self.health().await
484 }
485
486 async fn genesis<AppState>(&self) -> Result<Genesis<AppState>, Error>
487 where
488 AppState: Debug + Serialize + DeserializeOwned + Send,
489 {
490 self.genesis().await
491 }
492
493 async fn net_info(&self) -> Result<net_info::Response, Error> {
494 self.net_info().await
495 }
496
497 async fn status(&self) -> Result<status::Response, Error> {
498 self.status().await
499 }
500
501 async fn broadcast_evidence(&self, e: Evidence) -> Result<evidence::Response, Error> {
502 self.broadcast_evidence(e).await
503 }
504
505 async fn tx(&self, hash: Hash, prove: bool) -> Result<tx::Response, Error> {
506 self.tx(hash, prove).await
507 }
508
509 async fn tx_search(
510 &self,
511 query: Query,
512 prove: bool,
513 page: u32,
514 per_page: u8,
515 order: Order,
516 ) -> Result<tx_search::Response, Error> {
517 self.tx_search(query, prove, page, per_page, order).await
518 }
519
520 #[cfg(any(
521 feature = "tendermint-rpc-http-client",
522 feature = "tendermint-rpc-websocket-client"
523 ))]
524 async fn wait_until_healthy<T>(&self, timeout: T) -> Result<(), Error>
525 where
526 T: Into<core::time::Duration> + Send,
527 {
528 self.wait_until_healthy(timeout).await
529 }
530
531 async fn perform<R>(&self, request: R) -> Result<R::Output, Error>
532 where
533 R: SimpleRequest,
534 {
535 self.perform(request).await
536 }
537 }
538}