Skip to content

Commit

Permalink
Implement avail-light-web
Browse files Browse the repository at this point in the history
  • Loading branch information
aterentic-ethernal committed Dec 3, 2024
1 parent 2832aaa commit 16ab2a2
Show file tree
Hide file tree
Showing 8 changed files with 277 additions and 2 deletions.
8 changes: 6 additions & 2 deletions .github/workflows/default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ jobs:
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
components: clippy
- run: cargo clippy --workspace -- -D warnings
# TODO: Enable avail-light-web once issue with rocksdb feature being applied
# accross the workspace is resolved
- run: cargo clippy --workspace --exclude avail-light-web -- -D warnings

test:
name: cargo test
Expand All @@ -42,7 +44,9 @@ jobs:
- uses: actions/checkout@v4
- uses: arduino/setup-protoc@v2
- uses: actions-rust-lang/setup-rust-toolchain@v1
- run: cargo test --workspace --benches --tests
# TODO: Enable avail-light-web once issue with rocksdb feature being applied
# accross the workspace is resolved
- run: cargo test --workspace --benches --tests --exclude avail-light-web
env:
RUSTFLAGS: "-C instrument-coverage"
LLVM_PROFILE_FILE: "profile-%p-%m.profraw"
Expand Down
43 changes: 43 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ members = [
"fat",
"monitor-client",
"relay",
"web",
]
default-members = ["client"]
resolver = "2"
Expand Down
30 changes: 30 additions & 0 deletions web/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
[package]
name = "avail-light-web"
version = "0.1.0"
authors.workspace = true
edition = "2021"
repository.workspace = true

[lib]
crate-type = ["cdylib", "rlib"]

[features]
default = ["console_error_panic_hook"]

[dependencies]
avail-light-core = { workspace = true }
avail-rust = { workspace = true }
clap = { workspace = true }
console_error_panic_hook = { version = "0.1.7", optional = true }
futures = { workspace = true }
libp2p = { workspace = true }
sp-io = { version = "30", features = ["disable_allocator", "disable_panic_handler"], default-features = false }
tokio = { version = "^1", default-features = false, features = ["sync", "macros", "io-util", "rt"] }
tokio_with_wasm = { version = "0.7.1", features = ["sync", "macros", "rt"] }
tracing = { workspace = true }
tracing-subscriber = { workspace = true }
tracing-wasm = "0.2.1"
wasm-bindgen = "0.2.93"
wasm-bindgen-futures = "0.4.43"
web-sys = { version = "0.3.70", features = ["console", "Window", "UrlSearchParams"] }
web-time = "1.1.0"
16 changes: 16 additions & 0 deletions web/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Avail Light Client (Web)

## Compile

`wasm-pack build --target web --dev`

## Run

`cp www/index.html pkg/`
`cd pkg`
`python3 -m http.server --directory .`

# Start LC

- Safari: http://localhost:8000/?network=hex&bootstrap=%2Fip4%2F209.38.38.158%2Fudp%2F39001%2Fwebrtc-direct%2Fcerthash%2FuEiCVz-CTCrMq4I2xwW_WznQPML3dos4GNWiXE_fJjvHiIg
- Firefox: 0.0.0.0:8000/?network=hex&bootstrap=%2Fip4%2F209.38.38.158%2Fudp%2F39001%2Fwebrtc-direct%2Fcerthash%2FuEiCVz-CTCrMq4I2xwW_WznQPML3dos4GNWiXE_fJjvHiIg
157 changes: 157 additions & 0 deletions web/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
#![cfg(target_arch = "wasm32")]

use std::sync::Arc;

use avail_light_core::data;
use avail_light_core::light_client::OutputEvent as LcEvent;
use avail_light_core::network::{self, p2p, rpc, Network};
use avail_light_core::shutdown::Controller;
use avail_light_core::types::{Delay, PeerAddress};
use avail_light_core::utils::spawn_in_span;
use avail_rust::kate_recovery::couscous;
use clap::ValueEnum;
use libp2p::Multiaddr;
use std::str::FromStr;
use tokio::sync::{broadcast, mpsc};
use tokio_with_wasm::alias as tokio;
use tracing::{error, info, warn};
use wasm_bindgen::prelude::*;
use web_time::Duration;

#[tokio::main(flavor = "current_thread")]
#[wasm_bindgen(start)]
async fn main_js() {}

#[wasm_bindgen]
pub async fn run(network_param: Option<String>, bootstrap_param: Option<String>) {
console_error_panic_hook::set_once();
tracing_wasm::set_as_global_default();

let mut network = network::Network::Local;
if let Some(value) = network_param {
network = Network::from_str(&value, true).unwrap();
};

let mut bootstrap_multiaddr = network.bootstrap_multiaddr();
if let Some(value) = bootstrap_param {
bootstrap_multiaddr = Multiaddr::from_str(&value).unwrap();
};

let version = clap::crate_version!();
let shutdown = Controller::new();
let db = data::DB::default();

// TODO: Store and read client_id from local storage
// let client_id = Uuid::new_v4();
// let execution_id = Uuid::new_v4();

let pp = Arc::new(couscous::public_params());

let cfg_rpc = rpc::configuration::RPCConfig {
full_node_ws: network.full_node_ws(),
..Default::default()
};

let cfg_libp2p = p2p::configuration::LibP2PConfig {
bootstraps: vec![PeerAddress::PeerIdAndMultiaddr((
network.bootstrap_peer_id(),
bootstrap_multiaddr,
))],
..Default::default()
};

let genesis_hash = &network.genesis_hash().to_string();
let (rpc_event_sender, rpc_event_receiver) = broadcast::channel(1000);

let (rpc_client, rpc_subscriptions) = rpc::init(
db.clone(),
genesis_hash,
&cfg_rpc,
shutdown.clone(),
rpc_event_sender.clone(),
)
.await
.unwrap();

let (id_keys, _peer_id) = p2p::identity(&cfg_libp2p, db.clone()).unwrap();

let (p2p_client, p2p_event_loop, _p2p_event_receiver) = p2p::init(
cfg_libp2p.clone(),
Default::default(),
id_keys,
version,
"DEV",
false,
shutdown.clone(),
)
.await
.unwrap();

let network_client = network::new(p2p_client.clone(), rpc_client, pp, false);

// spawn the RPC Network task for Event Loop to run in the background
// and shut it down, without delays
let _rpc_subscriptions_handle = spawn_in_span(shutdown.with_cancel(shutdown.with_trigger(
"Subscription loop failure triggered shutdown".to_string(),
async {
let result = rpc_subscriptions.run().await;
if let Err(ref err) = result {
error!(%err, "Subscription loop ended with error");
};
result
},
)));

let (lc_sender, mut lc_receiver) = mpsc::unbounded_channel::<LcEvent>();
let (block_tx, _block_rx) =
broadcast::channel::<avail_light_core::types::BlockVerified>(1 << 7);

let channels = avail_light_core::types::ClientChannels {
block_sender: block_tx,
rpc_event_receiver,
};

spawn_in_span(async move {
loop {
let Some(message) = lc_receiver.recv().await else {
info!("Exiting...");
break;
};
info!("{message:?}");
}
});

let light_client_handle = tokio::task::spawn(avail_light_core::light_client::run(
db.clone(),
network_client,
99.9,
Delay(Some(Duration::from_secs(20))),
channels,
shutdown.clone(),
lc_sender,
));

tokio::task::spawn(p2p_event_loop.run());

let bootstraps = cfg_libp2p.bootstraps.clone();
let bootstrap_p2p_client = p2p_client.clone();
spawn_in_span(shutdown.with_cancel(async move {
info!("Bootstraping the DHT with bootstrap nodes...");
let bs_result = bootstrap_p2p_client
.clone()
.bootstrap_on_startup(&bootstraps)
.await;
match bs_result {
Ok(_) => {
info!("Bootstrap done.");
},
Err(e) => {
warn!("Bootstrap process: {e:?}.");
},
}
}));

if let Err(error) = light_client_handle.await {
error!("Error running light client: {error}")
};
}
10 changes: 10 additions & 0 deletions web/www/avail-light.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import init, { run } from './avail_light_web.js';

(async () => {
try {
await init();
await run("hex", null);
} catch (error) {
console.error("Error:", error);
}
})();
14 changes: 14 additions & 0 deletions web/www/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Avail Light Client Web</title>
</head>
<body>
<h1>Avail Light Client Web</h1>
<script type="module">
const worker = new Worker('./avail-light.js', { type: 'module' });
</script>
</body>
</html>

0 comments on commit 16ab2a2

Please sign in to comment.