cometbft_light_client_js/
lib.rs

1//! CometBFT Light Client JavaScript/WASM interface.
2//!
3//! This crate exposes some of the [`cometbft-light-client-verifier`] crate's
4//! functionality to be used from the JavaScript ecosystem.
5//!
6//! For a detailed example, please see the [`verifier-web` example] in the
7//! repository.
8//!
9//! [`cometbft-light-client-verifier`]: https://github.com/cometbft/cometbft-rs/tree/main/light-client-verifier
10//! [`verifier-web` example]: https://github.com/cometbft/cometbft-rs/tree/main/light-client-js/examples/verifier-web
11
12mod utils;
13
14use std::time::Duration;
15
16use cometbft::Time;
17use cometbft_light_client_verifier::{
18    options::Options,
19    types::{LightBlock, TrustThreshold},
20    Verifier,
21};
22use serde::{Deserialize, Serialize};
23use wasm_bindgen::{prelude::*, JsValue};
24
25// TODO: Use Web Crypto API for cryptographic routines.
26// https://github.com/cometbft/cometbft-rs/issues/1241
27use cometbft_light_client_verifier::ProdVerifier;
28
29/// Check whether a given untrusted block can be trusted.
30#[wasm_bindgen]
31pub fn verify(untrusted: JsValue, trusted: JsValue, options: JsValue, now: JsValue) -> JsValue {
32    let result = deserialize_params(untrusted, trusted, options, now).map(
33        |(untrusted, trusted, options, now)| {
34            let verifier = ProdVerifier::default();
35            verifier.verify_update_header(
36                untrusted.as_untrusted_state(),
37                trusted.as_trusted_state(),
38                &options,
39                now,
40            )
41        },
42    );
43    serde_wasm_bindgen::to_value(&result).unwrap()
44}
45
46fn deserialize_params(
47    untrusted: JsValue,
48    trusted: JsValue,
49    options: JsValue,
50    now: JsValue,
51) -> Result<(LightBlock, LightBlock, Options, Time), Error> {
52    let untrusted =
53        serde_wasm_bindgen::from_value(untrusted).map_err(|e| Error::Serialization {
54            param: "untrusted".into(),
55            msg: e.to_string(),
56        })?;
57
58    let trusted = serde_wasm_bindgen::from_value(trusted).map_err(|e| Error::Serialization {
59        param: "trusted".into(),
60        msg: e.to_string(),
61    })?;
62
63    let options = serde_wasm_bindgen::from_value::<JsOptions>(options)
64        .map(Into::into)
65        .map_err(|e| Error::Serialization {
66            param: "options".into(),
67            msg: e.to_string(),
68        })?;
69
70    let now = serde_wasm_bindgen::from_value(now).map_err(|e| Error::Serialization {
71        param: "now".into(),
72        msg: e.to_string(),
73    })?;
74
75    Ok((untrusted, trusted, options, now))
76}
77
78/// Errors produced by this crate.
79#[derive(Serialize, Deserialize, Debug)]
80#[serde(tag = "type")]
81pub enum Error {
82    /// A serialization/deserialization error occurred.
83    #[serde(rename = "serialization")]
84    Serialization { param: String, msg: String },
85}
86
87// Simplified options supplied from JavaScript.
88#[derive(Debug, Serialize, Deserialize)]
89pub struct JsOptions {
90    pub trust_threshold: (u64, u64),
91    pub trusting_period: u64,
92    pub clock_drift: u64,
93}
94
95impl From<JsOptions> for Options {
96    fn from(o: JsOptions) -> Self {
97        let (num, den) = o.trust_threshold;
98        Self {
99            trust_threshold: TrustThreshold::new(num, den).unwrap(),
100            trusting_period: Duration::from_secs(o.trusting_period),
101            clock_drift: Duration::from_secs(o.clock_drift),
102        }
103    }
104}