Skip to main content

hashiverse_client_wasm/
lib.rs

1#![feature(try_blocks)]
2pub mod wasm_transport;
3pub mod wasm_bootstrap_provider;
4pub mod wasm_local_settings;
5pub mod wasm_client_storage;
6pub mod wasm_key_locker;
7pub mod wasm_parallel_pow_generator;
8pub mod with_js_context;
9pub mod hashiverse_client_wasm;
10pub mod wasm_try;
11
12use hashiverse_lib::tools::pow::pow_measure_from_data_hash;
13use hashiverse_lib::tools::types::{Hash, Pow, Salt};
14use log::{info, trace};
15use std::sync::Arc;
16use wasm_bindgen::prelude::*;
17
18/// Initialise logging and panic hook. Must be called manually before using the WASM module.
19/// Pass `verbose = true` for the main worker (logs confirmation), `false` for PoW sub-workers (silent).
20#[wasm_bindgen]
21pub fn wasm_init(verbose: bool) {
22
23    // Set up logging
24    {
25        fern::Dispatch::new()
26            .level(log::LevelFilter::Trace) // Default level
27            .level_for("wasm_bindgen", log::LevelFilter::Warn)
28            .level_for("scraper", log::LevelFilter::Warn)
29            .level_for("html5ever", log::LevelFilter::Warn)
30            .level_for("selectors", log::LevelFilter::Warn)
31            .chain(fern::Output::call(console_log::log))
32            .apply()
33            .expect("Failed to initialize logging")
34        ;
35
36        if verbose {
37            info!("Logging initialized");
38        }
39    }
40
41    console_error_panic_hook::set_once();
42    if verbose {
43        trace!("WASM module panic hook set");
44    }
45}
46
47/// Sync PoW batch computation for sub-workers. Each sub-worker calls this function
48/// with a portion of the total iteration budget.
49///
50/// Returns a colon-separated string: `salt_hex:pow_u8:hash_hex`
51#[wasm_bindgen]
52pub fn pow_compute_batch(iteration_limit: u32, pow_min: u8, data_hash_hex: String) -> String {
53    let data_hash = match hex::decode(&data_hash_hex).ok().and_then(|b| Hash::from_slice(&b).ok()) {
54        Some(h) => h,
55        None => return format!("{}:0:{}", hex::encode(Salt::zero()), hex::encode(Hash::zero())),
56    };
57
58    let pow_min = Pow(pow_min);
59    let mut best = (Salt::zero(), Pow(0), Hash::zero());
60
61    for _ in 0..iteration_limit {
62        let salt = Salt::random();
63        if let Ok((pow, hash)) = pow_measure_from_data_hash(&data_hash, &salt) {
64            if pow > best.1 {
65                best = (salt, pow, hash);
66                if pow >= pow_min {
67                    break;
68                }
69            }
70        }
71    }
72    format!("{}:{}:{}", hex::encode(best.0), best.1 .0, hex::encode(best.2))
73}
74
75/// Global storage for the WasmParallelPowGenerator singleton.
76static WASM_PARALLEL_POW_GENERATOR: std::sync::OnceLock<Arc<wasm_parallel_pow_generator::WasmParallelPowGenerator>> = std::sync::OnceLock::new();
77
78/// Initialize the parallel PoW worker pool. Call from TypeScript, passing an
79/// array of ready `Worker` handles that each run `HashiversePowWorker.ts`.
80#[wasm_bindgen]
81pub fn init_pow_workers(workers_js: JsValue) {
82    let workers_array: js_sys::Array = match workers_js.dyn_into() {
83        Ok(a) => a,
84        Err(_) => {
85            log::warn!("init_pow_workers: expected an Array of Workers");
86            return;
87        }
88    };
89
90    let mut workers = Vec::new();
91    for i in 0..workers_array.length() {
92        let val = workers_array.get(i);
93        match val.dyn_into::<web_sys::Worker>() {
94            Ok(w) => workers.push(w),
95            Err(_) => log::warn!("init_pow_workers: element {} is not a Worker", i),
96        }
97    }
98
99    if workers.is_empty() {
100        log::warn!("init_pow_workers: no valid Workers provided");
101        return;
102    }
103
104    let generator = wasm_parallel_pow_generator::WasmParallelPowGenerator::from_workers(workers);
105    let _ = WASM_PARALLEL_POW_GENERATOR.set(Arc::new(generator));
106}
107
108/// Get the global WasmParallelPowGenerator if initialized.
109pub fn get_wasm_parallel_pow_generator() -> Option<Arc<wasm_parallel_pow_generator::WasmParallelPowGenerator>> {
110    WASM_PARALLEL_POW_GENERATOR.get().cloned()
111}