From 7745dd23616f70c5501fefeff2a02ef82bd42dd4 Mon Sep 17 00:00:00 2001 From: driftluo Date: Tue, 22 Oct 2024 15:50:56 +0800 Subject: [PATCH] feat: small wasm support --- Cargo.lock | 153 +++++++++++++---- db/Cargo.toml | 4 +- error/Cargo.toml | 4 +- error/src/lib.rs | 2 +- network/Cargo.toml | 16 +- network/src/lib.rs | 4 +- network/src/network.rs | 112 +++++++----- network/src/peer.rs | 3 + network/src/peer_registry.rs | 6 +- network/src/peer_store/peer_store_impl.rs | 97 ++++++++--- network/src/protocols/discovery/mod.rs | 11 +- network/src/protocols/discovery/state.rs | 3 + network/src/protocols/identify/mod.rs | 3 + network/src/protocols/mod.rs | 21 +-- network/src/protocols/ping.rs | 6 +- network/src/services/dump_peer_store.rs | 18 +- network/src/services/outbound_peer.rs | 14 +- network/src/services/protocol_type_checker.rs | 19 ++- resource/src/lib.rs | 17 +- script/Cargo.toml | 6 + script/src/verify.rs | 4 + spec/Cargo.toml | 12 +- spec/src/versionbits/mod.rs | 16 ++ util/app-config/src/configs/network.rs | 7 + util/fixed-hash/core/Cargo.toml | 1 - util/hash/Cargo.toml | 8 +- util/hash/src/lib.rs | 4 +- util/jsonrpc-types/src/blockchain.rs | 2 +- util/runtime/Cargo.toml | 11 +- util/runtime/src/brower.rs | 27 +++ util/runtime/src/lib.rs | 160 +----------------- util/runtime/src/native.rs | 153 +++++++++++++++++ util/spawn/src/lib.rs | 9 + util/stop-handler/Cargo.toml | 2 +- util/systemtime/Cargo.toml | 3 + util/systemtime/src/lib.rs | 9 +- util/types/Cargo.toml | 2 +- verification/Cargo.toml | 10 +- verification/src/transaction_verifier.rs | 5 +- 39 files changed, 643 insertions(+), 321 deletions(-) create mode 100644 util/runtime/src/brower.rs create mode 100644 util/runtime/src/native.rs diff --git a/Cargo.lock b/Cargo.lock index bd09682ce5..77920964c2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -203,7 +203,7 @@ version = "0.16.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb8867f378f33f78a811a8eb9bf108ad99430d7aad43315dd9319c827ef6247" dependencies = [ - "http", + "http 0.2.12", "log", "url", "wildmatch", @@ -227,7 +227,7 @@ dependencies = [ "bitflags 1.3.2", "bytes", "futures-util", - "http", + "http 0.2.12", "http-body", "hyper", "itoa", @@ -244,7 +244,7 @@ dependencies = [ "sha1", "sync_wrapper", "tokio", - "tokio-tungstenite", + "tokio-tungstenite 0.20.1", "tower", "tower-layer", "tower-service", @@ -259,7 +259,7 @@ dependencies = [ "async-trait", "bytes", "futures-util", - "http", + "http 0.2.12", "http-body", "mime", "rustversion", @@ -387,12 +387,6 @@ dependencies = [ "rand 0.8.5", ] -[[package]] -name = "bs58" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" - [[package]] name = "bs58" version = "0.5.1" @@ -435,13 +429,12 @@ dependencies = [ [[package]] name = "cacache" -version = "12.0.0" +version = "13.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "142316461ed3a3dfcba10417317472da5bfd0461e4d276bf7c07b330766d9490" +checksum = "a61ff12b19d89c752c213316b87fdb4a587f073d219b893cc56974b8c9f39bf7" dependencies = [ "digest", "either", - "futures", "hex", "libc", "memmap2", @@ -455,8 +448,6 @@ dependencies = [ "ssri", "tempfile", "thiserror", - "tokio", - "tokio-stream", "walkdir", ] @@ -638,6 +629,7 @@ dependencies = [ "ckb-logger", "ckb-spawn", "tokio", + "wasm-bindgen-futures", ] [[package]] @@ -795,6 +787,7 @@ dependencies = [ "ckb-resource", "ckb-traits", "ckb-types", + "getrandom 0.2.15", "serde", "tempfile", "toml", @@ -887,7 +880,7 @@ version = "0.119.0-pre" dependencies = [ "anyhow", "ckb-occupied-capacity", - "derive_more", + "derive_more 1.0.0", "thiserror", ] @@ -1241,7 +1234,7 @@ version = "0.119.0-pre" dependencies = [ "bitflags 1.3.2", "bloom-filters", - "bs58 0.4.0", + "bs58", "ckb-app-config", "ckb-hash", "ckb-logger", @@ -1271,6 +1264,7 @@ dependencies = [ "tokio", "tokio-util", "trust-dns-resolver", + "web-time", ] [[package]] @@ -1514,6 +1508,7 @@ dependencies = [ "ckb-vm", "daggy", "faster-hex", + "getrandom 0.2.15", "molecule", "proptest", "rand 0.8.5", @@ -1670,6 +1665,9 @@ dependencies = [ [[package]] name = "ckb-systemtime" version = "0.119.0-pre" +dependencies = [ + "web-time", +] [[package]] name = "ckb-test-chain-utils" @@ -1752,7 +1750,7 @@ dependencies = [ "ckb-merkle-mountain-range", "ckb-occupied-capacity", "ckb-rational", - "derive_more", + "derive_more 1.0.0", "golomb-coded-set", "merkle-cbt", "molecule", @@ -1789,7 +1787,7 @@ dependencies = [ "ckb-traits", "ckb-types", "ckb-verification-traits", - "derive_more", + "derive_more 1.0.0", "lru", "tokio", ] @@ -1838,7 +1836,7 @@ dependencies = [ "bytes", "cc", "ckb-vm-definitions", - "derive_more", + "derive_more 0.99.18", "goblin 0.2.3", "goblin 0.4.0", "rand 0.7.3", @@ -2356,6 +2354,27 @@ dependencies = [ "syn 2.0.79", ] +[[package]] +name = "derive_more" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", + "unicode-xid", +] + [[package]] name = "deunicode" version = "1.6.0" @@ -2709,6 +2728,10 @@ name = "futures-timer" version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" +dependencies = [ + "gloo-timers", + "send_wrapper", +] [[package]] name = "futures-util" @@ -2807,6 +2830,18 @@ dependencies = [ "walkdir", ] +[[package]] +name = "gloo-timers" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + [[package]] name = "goblin" version = "0.2.3" @@ -2866,7 +2901,7 @@ dependencies = [ "futures-core", "futures-sink", "futures-util", - "http", + "http 0.2.12", "indexmap 2.6.0", "slab", "tokio", @@ -3035,6 +3070,17 @@ dependencies = [ "itoa", ] +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + [[package]] name = "http-body" version = "0.4.6" @@ -3042,7 +3088,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", - "http", + "http 0.2.12", "pin-project-lite", ] @@ -3090,7 +3136,7 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http", + "http 0.2.12", "http-body", "httparse", "httpdate", @@ -4715,7 +4761,7 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http", + "http 0.2.12", "http-body", "hyper", "hyper-tls", @@ -5012,6 +5058,12 @@ version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +[[package]] +name = "send_wrapper" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f638d531eccd6e23b980caf34876660d38e265409d8e99b397ab71eb3612fad0" + [[package]] name = "sentry" version = "0.26.0" @@ -5670,6 +5722,7 @@ dependencies = [ "async-trait", "bytes", "futures", + "futures-timer", "igd", "js-sys", "libc", @@ -5684,6 +5737,7 @@ dependencies = [ "tentacle-secio", "thiserror", "tokio", + "tokio-tungstenite 0.21.0", "tokio-util", "tokio-yamux", "wasm-bindgen", @@ -5697,7 +5751,7 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9e71b28bf0bbf274b92f47cb2c5b42755d84a11e2246cf7bcb7b65c89483b9" dependencies = [ - "bs58 0.5.1", + "bs58", "bytes", "serde", "sha2", @@ -5710,7 +5764,7 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cac8b23a7879426a4961acea6ae66287f7fe9a934d131a722cbb88f145e97fea" dependencies = [ - "bs58 0.5.1", + "bs58", "bytes", "chacha20poly1305", "futures", @@ -5924,7 +5978,6 @@ dependencies = [ "bytes", "libc", "mio", - "parking_lot 0.12.3", "pin-project-lite", "signal-hook-registry", "socket2 0.5.7", @@ -5984,7 +6037,19 @@ dependencies = [ "futures-util", "log", "tokio", - "tungstenite", + "tungstenite 0.20.1", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c83b561d025642014097b66e6c1bb422783339e0909e4429cde4749d1990bc38" +dependencies = [ + "futures-util", + "log", + "tokio", + "tungstenite 0.21.0", ] [[package]] @@ -6008,6 +6073,7 @@ checksum = "f2ed88a04bfbf9e70343a5748a423200ee0591c55e7e487d784a55ee8af17db9" dependencies = [ "bytes", "futures", + "futures-timer", "log", "nohash-hasher", "tokio", @@ -6035,7 +6101,7 @@ dependencies = [ "base64 0.21.7", "bytes", "h2", - "http", + "http 0.2.12", "http-body", "hyper", "hyper-timeout", @@ -6080,7 +6146,7 @@ dependencies = [ "bytes", "futures-core", "futures-util", - "http", + "http 0.2.12", "http-body", "http-range-header", "pin-project-lite", @@ -6209,7 +6275,26 @@ dependencies = [ "byteorder", "bytes", "data-encoding", - "http", + "http 0.2.12", + "httparse", + "log", + "rand 0.8.5", + "sha1", + "thiserror", + "url", + "utf-8", +] + +[[package]] +name = "tungstenite" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http 1.1.0", "httparse", "log", "rand 0.8.5", @@ -6344,6 +6429,12 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + [[package]] name = "unicode_categories" version = "0.1.1" diff --git a/db/Cargo.toml b/db/Cargo.toml index 13ead9bea4..28a53c54f5 100644 --- a/db/Cargo.toml +++ b/db/Cargo.toml @@ -13,7 +13,9 @@ ckb-app-config = { path = "../util/app-config", version = "= 0.119.0-pre" } ckb-logger = { path = "../util/logger", version = "= 0.119.0-pre" } ckb-error = { path = "../error", version = "= 0.119.0-pre" } libc = "0.2" -rocksdb = { package = "ckb-rocksdb", version ="=0.21.1", features = ["snappy"], default-features = false } +rocksdb = { package = "ckb-rocksdb", version = "=0.21.1", features = [ + "snappy", +], default-features = false } ckb-db-schema = { path = "../db-schema", version = "= 0.119.0-pre" } [dev-dependencies] diff --git a/error/Cargo.toml b/error/Cargo.toml index b9b90d8faa..03fb94d9a7 100644 --- a/error/Cargo.toml +++ b/error/Cargo.toml @@ -12,4 +12,6 @@ repository = "https://github.com/nervosnetwork/ckb" thiserror = "1.0.22" anyhow = "1.0.34" ckb-occupied-capacity = { path = "../util/occupied-capacity", version = "= 0.119.0-pre" } -derive_more = { version = "0.99.0", default-features = false, features = ["display"] } +derive_more = { version = "1", default-features = false, features = [ + "display", +] } diff --git a/error/src/lib.rs b/error/src/lib.rs index 2c2dfa575e..750bd0eb59 100644 --- a/error/src/lib.rs +++ b/error/src/lib.rs @@ -89,7 +89,7 @@ impl fmt::Display for AnyError { impl fmt::Debug for AnyError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.fmt(f) + Display::fmt(&self.0, f) } } /// Return whether the error's kind is `InternalErrorKind::Database` diff --git a/network/Cargo.toml b/network/Cargo.toml index 8818bd3fd2..7211831f43 100644 --- a/network/Cargo.toml +++ b/network/Cargo.toml @@ -22,7 +22,7 @@ tokio-util = { version = "0.7", features = ["codec"] } futures = "0.3" ckb-systemtime = { path = "../util/systemtime", version = "= 0.119.0-pre" } lazy_static = { version = "1.3.0", optional = true } -bs58 = { version = "0.4.0", optional = true } +bs58 = { version = "0.5.0", optional = true } sentry = { version = "0.26.0", optional = true } faster-hex = { version = "0.6", optional = true } ckb-hash = { path = "../util/hash", version = "= 0.119.0-pre" } @@ -34,15 +34,26 @@ ipnetwork = "0.18" serde_json = "1.0" bloom-filters = "0.1" ckb-spawn = { path = "../util/spawn", version = "= 0.119.0-pre" } -socket2 = "0.5" bitflags = "1.0" +p2p = { version = "0.6.1", package = "tentacle", default-features = false } +[target.'cfg(not(target_family = "wasm"))'.dependencies] p2p = { version = "0.6.1", package = "tentacle", features = [ "upnp", "parking_lot", "openssl-vendored", + "ws", +] } +socket2 = "0.5" + +[target.'cfg(target_family = "wasm")'.dependencies] +p2p = { version = "0.6.1", package = "tentacle", default-features = false, features = [ + "wasm-timer", ] } +[target.'cfg(all(target_family = "wasm", target_os = "unknown"))'.dependencies] +web-time = "1.1.0" + [features] with_sentry = ["sentry"] with_dns_seeding = [ @@ -63,6 +74,7 @@ once_cell = "1.8.0" ckb-systemtime = { path = "../util/systemtime", version = "= 0.119.0-pre", features = [ "enable_faketime", ] } +ckb-app-config = { path = "../util/app-config", version = "= 0.119.0-pre" } [[bench]] name = "peer_store" diff --git a/network/src/lib.rs b/network/src/lib.rs index 5a524198e6..9a24bd6d69 100644 --- a/network/src/lib.rs +++ b/network/src/lib.rs @@ -32,8 +32,8 @@ pub use crate::{ peer_registry::PeerRegistry, peer_store::Score, protocols::{ - identify::Flags, support_protocols::SupportProtocols, CKBProtocol, CKBProtocolContext, - CKBProtocolHandler, PeerIndex, + identify::Flags, support_protocols::SupportProtocols, BoxedCKBProtocolContext, CKBProtocol, + CKBProtocolContext, CKBProtocolHandler, PeerIndex, }, }; pub use p2p::{ diff --git a/network/src/network.rs b/network/src/network.rs index 734c8815ae..c5cb234002 100644 --- a/network/src/network.rs +++ b/network/src/network.rs @@ -46,6 +46,8 @@ use rand::prelude::IteratorRandom; #[cfg(feature = "with_sentry")] use sentry::{capture_message, with_scope, Level}; use std::sync::mpsc; +#[cfg(not(target_family = "wasm"))] +use std::time::{Duration, Instant}; use std::{ borrow::Cow, cmp::max, @@ -55,10 +57,11 @@ use std::{ atomic::{AtomicBool, Ordering}, Arc, }, - thread, - time::{Duration, Instant}, + thread, usize, }; use tokio::{self, sync::oneshot}; +#[cfg(all(target_family = "wasm", target_os = "unknown"))] +use web_time::{Duration, Instant}; const P2P_SEND_TIMEOUT: Duration = Duration::from_secs(6); const P2P_TRY_SEND_INTERVAL: Duration = Duration::from_millis(100); @@ -92,6 +95,7 @@ pub struct NetworkState { impl NetworkState { /// Init from config pub fn from_config(config: NetworkConfig) -> Result { + #[cfg(not(target_family = "wasm"))] config.create_dir_if_not_exists()?; let local_private_key = config.fetch_private_key()?; let local_peer_id = local_private_key.peer_id(); @@ -890,7 +894,6 @@ impl NetworkService { }; service_builder = service_builder .handshake_type(network_state.local_private_key.clone().into()) - .upnp(config.upnp) .yamux_config(yamux_config) .forever(true) .max_connection_number(1024) @@ -898,30 +901,16 @@ impl NetworkService { .set_channel_size(config.channel_size()) .timeout(Duration::from_secs(5)); + #[cfg(not(target_family = "wasm"))] + { + service_builder = service_builder.upnp(config.upnp); + } + #[cfg(target_os = "linux")] let p2p_service = { if config.reuse_port_on_linux { let iter = config.listen_addresses.iter(); - #[derive(Clone, Copy, Debug, Eq, PartialEq)] - enum TransportType { - Ws, - Tcp, - } - - fn find_type(addr: &Multiaddr) -> TransportType { - let mut iter = addr.iter(); - - iter.find_map(|proto| { - if let p2p::multiaddr::Protocol::Ws = proto { - Some(TransportType::Ws) - } else { - None - } - }) - .unwrap_or(TransportType::Tcp) - } - #[derive(Clone, Copy, Debug, Eq, PartialEq)] enum BindType { None, @@ -947,38 +936,45 @@ impl NetworkService { } let mut init = BindType::None; - for addr in iter { + for multi_addr in iter { if init.is_ready() { break; } - match find_type(addr) { + match find_type(multi_addr) { // wait ckb enable ws support - TransportType::Ws => (), - TransportType::Tcp => { + TransportType::Tcp | TransportType::Ws => { // only bind once - if matches!(init, BindType::Tcp) { + if matches!(init, BindType::Tcp) || matches!(init, BindType::Ws) { continue; } - if let Some(addr) = multiaddr_to_socketaddr(addr) { + if let Some(addr) = multiaddr_to_socketaddr(multi_addr) { use p2p::service::TcpSocket; let domain = socket2::Domain::for_address(addr); - service_builder = - service_builder.tcp_config(move |socket: TcpSocket| { - let socket_ref = socket2::SockRef::from(&socket); - #[cfg(all( - unix, - not(target_os = "solaris"), - not(target_os = "illumos") - ))] - socket_ref.set_reuse_port(true)?; - - socket_ref.set_reuse_address(true)?; - if socket_ref.domain()? == domain { - socket_ref.bind(&addr.into())?; - } - Ok(socket) - }); - init.transform(TransportType::Tcp) + let bind_fn = move |socket: TcpSocket| { + let socket_ref = socket2::SockRef::from(&socket); + #[cfg(all( + unix, + not(target_os = "solaris"), + not(target_os = "illumos") + ))] + socket_ref.set_reuse_port(true)?; + + socket_ref.set_reuse_address(true)?; + if socket_ref.domain()? == domain { + socket_ref.bind(&addr.into())?; + } + Ok(socket) + }; + service_builder = match find_type(multi_addr) { + TransportType::Tcp => { + init.transform(TransportType::Tcp); + service_builder.tcp_config(bind_fn) + } + TransportType::Ws => { + init.transform(TransportType::Ws); + service_builder.tcp_config_on_ws(bind_fn) + } + }; } } } @@ -1094,11 +1090,13 @@ impl NetworkService { .unzip(); let receiver: CancellationToken = new_tokio_exit_rx(); + #[cfg(not(target_family = "wasm"))] let (start_sender, start_receiver) = mpsc::channel(); { let network_state = Arc::clone(&network_state); let p2p_control: ServiceAsyncControl = p2p_control.clone().into(); handle.spawn_task(async move { + #[cfg(not(target_family = "wasm"))] for addr in &config.listen_addresses { match p2p_service.listen(addr.to_owned()).await { Ok(listen_address) => { @@ -1121,8 +1119,9 @@ impl NetworkService { } }; } + #[cfg(not(target_family = "wasm"))] start_sender.send(Ok(())).unwrap(); - tokio::spawn(async move { p2p_service.run().await }); + p2p::runtime::spawn(async move { p2p_service.run().await }); tokio::select! { _ = receiver.cancelled() => { info!("NetworkService receive exit signal, start shutdown..."); @@ -1150,7 +1149,7 @@ impl NetworkService { } }); } - + #[cfg(not(target_family = "wasm"))] if let Ok(Err(e)) = start_receiver.recv() { return Err(e); } @@ -1419,3 +1418,22 @@ pub(crate) async fn async_disconnect_with_message( } control.disconnect(peer_index).await } + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum TransportType { + Ws, + Tcp, +} + +pub fn find_type(addr: &Multiaddr) -> TransportType { + let mut iter = addr.iter(); + + iter.find_map(|proto| { + if let p2p::multiaddr::Protocol::Ws = proto { + Some(TransportType::Ws) + } else { + None + } + }) + .unwrap_or(TransportType::Tcp) +} diff --git a/network/src/peer.rs b/network/src/peer.rs index 48ae7196eb..6b2d04499b 100644 --- a/network/src/peer.rs +++ b/network/src/peer.rs @@ -4,7 +4,10 @@ use crate::{ }; use p2p::SessionId; use std::collections::HashMap; +#[cfg(not(target_family = "wasm"))] use std::time::{Duration, Instant}; +#[cfg(all(target_family = "wasm", target_os = "unknown"))] +use web_time::{Duration, Instant}; /// Peer info from identify protocol message #[derive(Clone, Debug)] diff --git a/network/src/peer_registry.rs b/network/src/peer_registry.rs index 9f3e55536b..ff67ee5ca7 100644 --- a/network/src/peer_registry.rs +++ b/network/src/peer_registry.rs @@ -10,6 +10,10 @@ use p2p::{multiaddr::Multiaddr, SessionId}; use rand::seq::SliceRandom; use rand::thread_rng; use std::collections::{HashMap, HashSet}; +#[cfg(not(target_family = "wasm"))] +use std::time::Instant; +#[cfg(all(target_family = "wasm", target_os = "unknown"))] +use web_time::Instant; pub(crate) const EVICTION_PROTECT_PEERS: usize = 8; @@ -146,7 +150,7 @@ impl PeerRegistry { &mut candidate_peers, EVICTION_PROTECT_PEERS, |peer1, peer2| { - let now = std::time::Instant::now(); + let now = Instant::now(); let peer1_last_message = peer1 .last_ping_protocol_message_received_at .map(|t| now.saturating_duration_since(t).as_secs()) diff --git a/network/src/peer_store/peer_store_impl.rs b/network/src/peer_store/peer_store_impl.rs index 4c076066a2..180d268ef8 100644 --- a/network/src/peer_store/peer_store_impl.rs +++ b/network/src/peer_store/peer_store_impl.rs @@ -1,3 +1,4 @@ +use crate::network::{find_type, TransportType}; use crate::{ errors::{PeerStoreError, Result}, extract_peer_id, multiaddr_to_socketaddr, @@ -64,6 +65,10 @@ impl PeerStore { if self.ban_list.is_addr_banned(&addr) { return Ok(()); } + #[cfg(target_family = "wasm")] + if !matches!(find_type(&addr), TransportType::Ws) { + return Ok(()); + } self.check_purge()?; let score = self.score_config.default_score; self.addr_manager @@ -165,20 +170,33 @@ impl PeerStore { let now_ms = ckb_systemtime::unix_time_as_millis(); let peers = &self.connected_peers; let addr_expired_ms = now_ms.saturating_sub(ADDR_TRY_TIMEOUT_MS); + + // Any protocol expect websocket + #[cfg(not(target_family = "wasm"))] + let filter = |peer_addr: &AddrInfo| { + extract_peer_id(&peer_addr.addr) + .map(|peer_id| !peers.contains_key(&peer_id)) + .unwrap_or_default() + && peer_addr + .connected(|t| t > addr_expired_ms && t <= now_ms.saturating_sub(DIAL_INTERVAL)) + && required_flags_filter(required_flags, Flags::from_bits_truncate(peer_addr.flags)) + && !matches!(find_type(&peer_addr.addr), TransportType::Ws) + }; + + // Only websocket on browser + #[cfg(target_family = "wasm")] + let filter = |peer_addr: &AddrInfo| { + extract_peer_id(&peer_addr.addr) + .map(|peer_id| !peers.contains_key(&peer_id)) + .unwrap_or_default() + && peer_addr + .connected(|t| t > addr_expired_ms && t <= now_ms.saturating_sub(DIAL_INTERVAL)) + && required_flags_filter(required_flags, Flags::from_bits_truncate(peer_addr.flags)) + && matches!(find_type(&peer_addr.addr), TransportType::Ws) + }; + // get addrs that can attempt. - self.addr_manager - .fetch_random(count, |peer_addr: &AddrInfo| { - extract_peer_id(&peer_addr.addr) - .map(|peer_id| !peers.contains_key(&peer_id)) - .unwrap_or_default() - && peer_addr.connected(|t| { - t > addr_expired_ms && t <= now_ms.saturating_sub(DIAL_INTERVAL) - }) - && required_flags_filter( - required_flags, - Flags::from_bits_truncate(peer_addr.flags), - ) - }) + self.addr_manager.fetch_random(count, filter) } /// Get peers for feeler connection, this method randomly return peer addrs that we never @@ -192,14 +210,29 @@ impl PeerStore { let now_ms = ckb_systemtime::unix_time_as_millis(); let addr_expired_ms = now_ms.saturating_sub(ADDR_TRY_TIMEOUT_MS); let peers = &self.connected_peers; - self.addr_manager - .fetch_random(count, |peer_addr: &AddrInfo| { - extract_peer_id(&peer_addr.addr) - .map(|peer_id| !peers.contains_key(&peer_id)) - .unwrap_or_default() - && !peer_addr.tried_in_last_minute(now_ms) - && !peer_addr.connected(|t| t > addr_expired_ms) - }) + + // Any protocol needs to be verified + #[cfg(not(target_family = "wasm"))] + let filter = |peer_addr: &AddrInfo| { + extract_peer_id(&peer_addr.addr) + .map(|peer_id| !peers.contains_key(&peer_id)) + .unwrap_or_default() + && !peer_addr.tried_in_last_minute(now_ms) + && !peer_addr.connected(|t| t > addr_expired_ms) + }; + + // Only websocket on browser + #[cfg(target_family = "wasm")] + let filter = |peer_addr: &AddrInfo| { + extract_peer_id(&peer_addr.addr) + .map(|peer_id| !peers.contains_key(&peer_id)) + .unwrap_or_default() + && !peer_addr.tried_in_last_minute(now_ms) + && !peer_addr.connected(|t| t > addr_expired_ms) + && matches!(find_type(&peer_addr.addr), TransportType::Ws) + }; + + self.addr_manager.fetch_random(count, filter) } /// Return valid addrs that success connected, used for discovery. @@ -209,12 +242,24 @@ impl PeerStore { let now_ms = ckb_systemtime::unix_time_as_millis(); let addr_expired_ms = now_ms.saturating_sub(ADDR_TIMEOUT_MS); + + // Any protocol + #[cfg(not(target_family = "wasm"))] + let filter = |peer_addr: &AddrInfo| { + required_flags_filter(required_flags, Flags::from_bits_truncate(peer_addr.flags)) + && peer_addr.connected(|t| t > addr_expired_ms) + }; + + // Only websocket on browser + #[cfg(target_family = "wasm")] + let filter = |peer_addr: &AddrInfo| { + required_flags_filter(required_flags, Flags::from_bits_truncate(peer_addr.flags)) + && peer_addr.connected(|t| t > addr_expired_ms) + && matches!(find_type(&peer_addr.addr), TransportType::Ws) + }; + // get success connected addrs. - self.addr_manager - .fetch_random(count, |peer_addr: &AddrInfo| { - required_flags_filter(required_flags, Flags::from_bits_truncate(peer_addr.flags)) - && peer_addr.connected(|t| t > addr_expired_ms) - }) + self.addr_manager.fetch_random(count, filter) } /// Ban an addr diff --git a/network/src/protocols/discovery/mod.rs b/network/src/protocols/discovery/mod.rs index c08012ba1b..6cb19d73cc 100644 --- a/network/src/protocols/discovery/mod.rs +++ b/network/src/protocols/discovery/mod.rs @@ -1,8 +1,9 @@ -use std::{ - collections::HashMap, - sync::Arc, - time::{Duration, Instant}, -}; +use std::{collections::HashMap, sync::Arc}; + +#[cfg(not(target_family = "wasm"))] +use std::time::{Duration, Instant}; +#[cfg(all(target_family = "wasm", target_os = "unknown"))] +use web_time::{Duration, Instant}; use ckb_logger::{debug, error, trace, warn}; use p2p::{ diff --git a/network/src/protocols/discovery/state.rs b/network/src/protocols/discovery/state.rs index cba4d41d14..3a45b1b2c1 100644 --- a/network/src/protocols/discovery/state.rs +++ b/network/src/protocols/discovery/state.rs @@ -1,4 +1,7 @@ +#[cfg(not(target_family = "wasm"))] use std::time::{Duration, Instant}; +#[cfg(all(target_family = "wasm", target_os = "unknown"))] +use web_time::{Duration, Instant}; use ckb_logger::debug; use p2p::{ diff --git a/network/src/protocols/identify/mod.rs b/network/src/protocols/identify/mod.rs index d2fefde131..dfb743a348 100644 --- a/network/src/protocols/identify/mod.rs +++ b/network/src/protocols/identify/mod.rs @@ -1,7 +1,10 @@ use std::borrow::Cow; use std::collections::HashMap; use std::sync::{atomic::Ordering, Arc}; +#[cfg(not(target_family = "wasm"))] use std::time::{Duration, Instant}; +#[cfg(all(target_family = "wasm", target_os = "unknown"))] +use web_time::{Duration, Instant}; use ckb_logger::{debug, error, trace, warn}; use p2p::{ diff --git a/network/src/protocols/mod.rs b/network/src/protocols/mod.rs index f2da17e4a0..fd75cec6ae 100644 --- a/network/src/protocols/mod.rs +++ b/network/src/protocols/mod.rs @@ -128,38 +128,35 @@ pub trait CKBProtocolContext: Send { } } +pub type BoxedCKBProtocolContext = Arc; + /// Abstract protocol handle base on tentacle service handle #[async_trait] pub trait CKBProtocolHandler: Sync + Send { /// Init action on service run - async fn init(&mut self, nc: Arc); + async fn init(&mut self, nc: BoxedCKBProtocolContext); /// Called when opening protocol async fn connected( &mut self, - _nc: Arc, + _nc: BoxedCKBProtocolContext, _peer_index: PeerIndex, _version: &str, ) { } /// Called when closing protocol - async fn disconnected( - &mut self, - _nc: Arc, - _peer_index: PeerIndex, - ) { - } + async fn disconnected(&mut self, _nc: BoxedCKBProtocolContext, _peer_index: PeerIndex) {} /// Called when the corresponding protocol message is received async fn received( &mut self, - _nc: Arc, + _nc: BoxedCKBProtocolContext, _peer_index: PeerIndex, _data: Bytes, ) { } /// Called when the Service receives the notify task - async fn notify(&mut self, _nc: Arc, _token: u64) {} + async fn notify(&mut self, _nc: BoxedCKBProtocolContext, _token: u64) {} /// Behave like `Stream::poll` - async fn poll(&mut self, _nc: Arc) -> Option<()> { + async fn poll(&mut self, _nc: BoxedCKBProtocolContext) -> Option<()> { None } } @@ -648,6 +645,6 @@ impl Future for BlockingFutureTask { type Output = (); fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - tokio::task::block_in_place(|| self.task.poll_unpin(cx)) + p2p::runtime::block_in_place(|| self.task.poll_unpin(cx)) } } diff --git a/network/src/protocols/ping.rs b/network/src/protocols/ping.rs index 984dbf2a15..3f06e246e8 100644 --- a/network/src/protocols/ping.rs +++ b/network/src/protocols/ping.rs @@ -18,9 +18,13 @@ use std::{ collections::{HashMap, HashSet}, str, sync::Arc, - time::{Duration, Instant}, }; +#[cfg(not(target_family = "wasm"))] +use std::time::{Duration, Instant}; +#[cfg(all(target_family = "wasm", target_os = "unknown"))] +use web_time::{Duration, Instant}; + const SEND_PING_TOKEN: u64 = 0; const CHECK_TIMEOUT_TOKEN: u64 = 1; const CONTROL_CHANNEL_BUFFER_SIZE: usize = 2; diff --git a/network/src/services/dump_peer_store.rs b/network/src/services/dump_peer_store.rs index 735ace3a71..12e3fd5d36 100644 --- a/network/src/services/dump_peer_store.rs +++ b/network/src/services/dump_peer_store.rs @@ -1,13 +1,13 @@ use crate::NetworkState; use ckb_logger::{debug, warn}; -use futures::Future; +use futures::{Future, StreamExt}; +use p2p::runtime::{Interval, MissedTickBehavior}; use std::{ pin::Pin, sync::Arc, task::{Context, Poll}, time::Duration, }; -use tokio::time::{Instant, Interval, MissedTickBehavior}; const DEFAULT_DUMP_INTERVAL: Duration = Duration::from_secs(3600); // 1 hour @@ -27,6 +27,7 @@ impl DumpPeerStoreService { fn dump_peer_store(&self) { let path = self.network_state.config.peer_store_path(); + #[cfg(not(target_family = "wasm"))] self.network_state.with_peer_store_mut(|peer_store| { if let Err(err) = peer_store.dump_to_dir(&path) { warn!("Dump peer store error, path: {:?} error: {}", path, err); @@ -50,17 +51,20 @@ impl Future for DumpPeerStoreService { fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { if self.interval.is_none() { self.interval = { - let mut interval = tokio::time::interval_at( - Instant::now() + DEFAULT_DUMP_INTERVAL, - DEFAULT_DUMP_INTERVAL, - ); + let mut interval = Interval::new(DEFAULT_DUMP_INTERVAL); // The dump peer store service does not need to urgently compensate for the missed wake, // just delay behavior is enough interval.set_missed_tick_behavior(MissedTickBehavior::Delay); Some(interval) } } - while self.interval.as_mut().unwrap().poll_tick(cx).is_ready() { + while self + .interval + .as_mut() + .unwrap() + .poll_next_unpin(cx) + .is_ready() + { self.dump_peer_store() } Poll::Pending diff --git a/network/src/services/outbound_peer.rs b/network/src/services/outbound_peer.rs index 6498ec6894..10dca1c33c 100644 --- a/network/src/services/outbound_peer.rs +++ b/network/src/services/outbound_peer.rs @@ -4,7 +4,8 @@ use crate::{ }; use ckb_logger::trace; use ckb_systemtime::unix_time_as_millis; -use futures::Future; +use futures::{Future, StreamExt}; +use p2p::runtime::{Interval, MissedTickBehavior}; use p2p::{multiaddr::MultiAddr, service::ServiceControl}; use rand::prelude::IteratorRandom; use std::{ @@ -13,7 +14,6 @@ use std::{ task::{Context, Poll}, time::Duration, }; -use tokio::time::{Interval, MissedTickBehavior}; const FEELER_CONNECTION_COUNT: usize = 10; @@ -155,14 +155,20 @@ impl Future for OutboundPeerService { fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { if self.interval.is_none() { self.interval = { - let mut interval = tokio::time::interval(self.try_connect_interval); + let mut interval = Interval::new(self.try_connect_interval); // The outbound service does not need to urgently compensate for the missed wake, // just skip behavior is enough interval.set_missed_tick_behavior(MissedTickBehavior::Skip); Some(interval) } } - while self.interval.as_mut().unwrap().poll_tick(cx).is_ready() { + while self + .interval + .as_mut() + .unwrap() + .poll_next_unpin(cx) + .is_ready() + { // keep whitelist peer on connected self.try_dial_whitelist(); // ensure feeler work at any time diff --git a/network/src/services/protocol_type_checker.rs b/network/src/services/protocol_type_checker.rs index 9a469a7d92..8a43853743 100644 --- a/network/src/services/protocol_type_checker.rs +++ b/network/src/services/protocol_type_checker.rs @@ -10,15 +10,18 @@ /// Other protocols will be closed after a timeout. use crate::{network::disconnect_with_message, NetworkState, Peer, ProtocolId, SupportProtocols}; use ckb_logger::debug; -use futures::Future; +use futures::{Future, StreamExt}; +use p2p::runtime::{Interval, MissedTickBehavior}; use p2p::service::ServiceControl; +#[cfg(not(target_family = "wasm"))] +use std::time::{Duration, Instant}; use std::{ pin::Pin, sync::Arc, task::{Context, Poll}, - time::{Duration, Instant}, }; -use tokio::time::{Interval, MissedTickBehavior}; +#[cfg(all(target_family = "wasm", target_os = "unknown"))] +use web_time::{Duration, Instant}; const TIMEOUT: Duration = Duration::from_secs(10); const CHECK_INTERVAL: Duration = Duration::from_secs(30); @@ -129,14 +132,20 @@ impl Future for ProtocolTypeCheckerService { fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { if self.interval.is_none() { self.interval = { - let mut interval = tokio::time::interval(CHECK_INTERVAL); + let mut interval = Interval::new(CHECK_INTERVAL); // The protocol type checker service does not need to urgently compensate for the missed wake, // just skip behavior is enough interval.set_missed_tick_behavior(MissedTickBehavior::Skip); Some(interval) } } - while self.interval.as_mut().unwrap().poll_tick(cx).is_ready() { + while self + .interval + .as_mut() + .unwrap() + .poll_next_unpin(cx) + .is_ready() + { self.check_protocol_type(); } Poll::Pending diff --git a/resource/src/lib.rs b/resource/src/lib.rs index 188b060381..b9ec148e88 100644 --- a/resource/src/lib.rs +++ b/resource/src/lib.rs @@ -33,7 +33,7 @@ use serde::{Deserialize, Serialize}; use std::borrow::Cow; use std::fmt; use std::fs; -use std::io::{self, BufReader, Read}; +use std::io::{self, BufReader, Cursor, Read}; use std::path::{Path, PathBuf}; use ckb_system_scripts::BUNDLED_CELL; @@ -71,6 +71,11 @@ pub enum Resource { /// The file path to the resource. file: PathBuf, }, + /// A resource that init by user custom + Raw { + /// raw data + raw: String, + }, } impl fmt::Display for Resource { @@ -78,6 +83,7 @@ impl fmt::Display for Resource { match self { Resource::Bundled { bundled } => write!(f, "Bundled({bundled})"), Resource::FileSystem { file } => write!(f, "FileSystem({})", file.display()), + Resource::Raw { raw } => write!(f, "Raw({})", raw), } } } @@ -93,6 +99,10 @@ impl Resource { Resource::FileSystem { file } } + pub fn raw(raw: String) -> Resource { + Resource::Raw { raw } + } + /// Creates the CKB config file resource from the file system. /// /// It searches the file name `CKB_CONFIG_FILE_NAME` in the directory `root_dir`. @@ -156,6 +166,7 @@ impl Resource { SourceFiles::new(&BUNDLED_CELL, &BUNDLED).is_available(bundled) } Resource::FileSystem { file } => file.exists(), + Resource::Raw { .. } => true, } } @@ -185,6 +196,7 @@ impl Resource { match self { Resource::Bundled { bundled } => SourceFiles::new(&BUNDLED_CELL, &BUNDLED).get(bundled), Resource::FileSystem { file } => Ok(Cow::Owned(fs::read(file)?)), + Resource::Raw { raw } => Ok(Cow::Owned(raw.to_owned().into_bytes())), } } @@ -195,6 +207,9 @@ impl Resource { SourceFiles::new(&BUNDLED_CELL, &BUNDLED).read(bundled) } Resource::FileSystem { file } => Ok(Box::new(BufReader::new(fs::File::open(file)?))), + Resource::Raw { raw } => Ok(Box::new(BufReader::new(Cursor::new( + raw.to_owned().into_bytes(), + )))), } } diff --git a/script/Cargo.toml b/script/Cargo.toml index 5c63d38216..1043fc1f79 100644 --- a/script/Cargo.toml +++ b/script/Cargo.toml @@ -28,6 +28,12 @@ ckb-logger = { path = "../util/logger", version = "= 0.119.0-pre", optional = tr serde = { version = "1.0", features = ["derive"] } ckb-error = { path = "../error", version = "= 0.119.0-pre" } ckb-chain-spec = { path = "../spec", version = "= 0.119.0-pre" } +tokio = { version = "1.35.0", features = [] } + +[target.'cfg(target_family = "wasm")'.dependencies] +getrandom = { version = "0.2", features = ["js"] } + +[target.'cfg(not(target_family = "wasm"))'.dependencies] tokio = { version = "1.35.0", features = ["rt-multi-thread"] } [dev-dependencies] diff --git a/script/src/verify.rs b/script/src/verify.rs index d20afd5ceb..09c674f76c 100644 --- a/script/src/verify.rs +++ b/script/src/verify.rs @@ -39,6 +39,7 @@ use std::{ collections::{BTreeMap, HashMap}, sync::RwLock, }; +#[cfg(not(target_family = "wasm"))] use tokio::sync::{ oneshot, watch::{self, Receiver}, @@ -689,6 +690,7 @@ where /// Performing a resumable verification on the transaction scripts with signal channel, /// if `Suspend` comes from `command_rx`, the process will be hang up until `Resume` comes, /// otherwise, it will return until the verification is completed. + #[cfg(not(target_family = "wasm"))] pub async fn resumable_verify_with_signal( &self, limit_cycles: Cycle, @@ -1072,6 +1074,7 @@ where } } + #[cfg(not(target_family = "wasm"))] async fn verify_group_with_signal( &self, group: &ScriptGroup, @@ -1163,6 +1166,7 @@ where } } + #[cfg(not(target_family = "wasm"))] async fn chunk_run_with_signal( &self, script_group: &ScriptGroup, diff --git a/spec/Cargo.toml b/spec/Cargo.toml index d25714b549..5dd24e906d 100644 --- a/spec/Cargo.toml +++ b/spec/Cargo.toml @@ -11,7 +11,6 @@ repository = "https://github.com/nervosnetwork/ckb" [dependencies] serde = { version = "1.0", features = ["derive"] } toml = "0.5" -cacache = { version = "12.0.0", default-features = false, features = ["tokio-runtime", "mmap"] } ckb-constant = { path = "../util/constant", version = "= 0.119.0-pre" } ckb-types = { path = "../util/types", version = "= 0.119.0-pre" } ckb-pow = { path = "../pow", version = "= 0.119.0-pre" } @@ -19,12 +18,17 @@ ckb-resource = { path = "../resource", version = "= 0.119.0-pre" } ckb-jsonrpc-types = { path = "../util/jsonrpc-types", version = "= 0.119.0-pre" } ckb-dao-utils = { path = "../util/dao/utils", version = "= 0.119.0-pre" } ckb-rational = { path = "../util/rational", version = "= 0.119.0-pre" } -ckb-crypto = { path = "../util/crypto", version = "= 0.119.0-pre"} -ckb-hash = { path = "../util/hash", version = "= 0.119.0-pre"} +ckb-crypto = { path = "../util/crypto", version = "= 0.119.0-pre" } +ckb-hash = { path = "../util/hash", version = "= 0.119.0-pre" } ckb-error = { path = "../error", version = "= 0.119.0-pre" } ckb-traits = { path = "../traits", version = "= 0.119.0-pre" } -ckb-logger = {path = "../util/logger", version = "= 0.119.0-pre"} +ckb-logger = { path = "../util/logger", version = "= 0.119.0-pre" } +[target.'cfg(target_family = "wasm")'.dependencies] +getrandom = { version = "0.2", features = ["js"] } + +[target.'cfg(not(target_family = "wasm"))'.dependencies] +cacache = { version = "13.0.0", default-features = false, features = ["mmap"] } [dev-dependencies] tempfile.workspace = true diff --git a/spec/src/versionbits/mod.rs b/spec/src/versionbits/mod.rs index 5c62a9834a..f9cb5af1fe 100644 --- a/spec/src/versionbits/mod.rs +++ b/spec/src/versionbits/mod.rs @@ -149,6 +149,7 @@ pub struct Cache { impl Cache { /// Reads the entire contents of a cache file synchronously into a bytes vector, /// looking the data up by key. + #[cfg(not(target_family = "wasm"))] pub fn get(&self, key: &Byte32) -> Option { match cacache::read_sync(&self.path, Self::encode_key(key)) { Ok(bytes) => Some(Self::decode_value(bytes)), @@ -160,7 +161,15 @@ impl Cache { } } + /// Soft Versionbit only work on tx-pool/block_assembler, it will not work on wasm, + /// so it can unimplemented + #[cfg(target_family = "wasm")] + pub fn get(&self, key: &Byte32) -> Option { + unimplemented!() + } + /// Writes data to the cache synchronously + #[cfg(not(target_family = "wasm"))] pub fn insert(&self, key: &Byte32, value: ThresholdState) { if let Err(e) = cacache::write_sync(&self.path, Self::encode_key(key), Self::encode_value(value)) @@ -169,6 +178,13 @@ impl Cache { } } + /// Soft Versionbit only work on tx-pool/block_assembler, it will not work on wasm, + /// so it can unimplemented + #[cfg(target_family = "wasm")] + pub fn insert(&self, key: &Byte32, value: ThresholdState) { + unimplemented!() + } + fn decode_value(value: Vec) -> ThresholdState { ThresholdState::from_u8(value[0]) } diff --git a/util/app-config/src/configs/network.rs b/util/app-config/src/configs/network.rs index b30ff1689f..82ca7d4e75 100644 --- a/util/app-config/src/configs/network.rs +++ b/util/app-config/src/configs/network.rs @@ -297,6 +297,7 @@ impl Config { } /// Reads the private key from file or generates one if the file does not exist. + #[cfg(not(target_family = "wasm"))] pub fn fetch_private_key(&self) -> Result { match self.read_secret_key()? { Some(key) => Ok(key), @@ -307,6 +308,12 @@ impl Config { } } + #[cfg(target_family = "wasm")] + pub fn fetch_private_key(&self) -> Result { + let random_key_pair = generate_random_key(); + secio::SecioKeyPair::secp256k1_raw_key(&random_key_pair).map_err(Into::into) + } + /// Gets the list of whitelist peers. pub fn whitelist_peers(&self) -> Vec { self.whitelist_peers.clone() diff --git a/util/fixed-hash/core/Cargo.toml b/util/fixed-hash/core/Cargo.toml index b08197f184..69af156315 100644 --- a/util/fixed-hash/core/Cargo.toml +++ b/util/fixed-hash/core/Cargo.toml @@ -15,6 +15,5 @@ faster-hex = "0.6" schemars = { version = "0.8.19", package = "ckb_schemars" } - [dev-dependencies] serde_json = "1.0" diff --git a/util/hash/Cargo.toml b/util/hash/Cargo.toml index 021a3cd9ee..d930f110c6 100644 --- a/util/hash/Cargo.toml +++ b/util/hash/Cargo.toml @@ -10,12 +10,14 @@ repository = "https://github.com/nervosnetwork/ckb" [features] default = ["blake2b-ref", "blake2b-rs"] -ckb-contract = ["blake2b-ref"] # This feature is used for CKB contract development +ckb-contract = [ + "blake2b-ref", +] # This feature is used for CKB contract development -[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +[target.'cfg(not(target_family = "wasm"))'.dependencies] blake2b-rs = { version = "0.2", optional = true } -[target.'cfg(target_arch = "wasm32")'.dependencies] +[target.'cfg(target_family = "wasm")'.dependencies] blake2b-ref = { version = "0.3", optional = true } [dependencies] diff --git a/util/hash/src/lib.rs b/util/hash/src/lib.rs index b988f041f5..530794e0c5 100644 --- a/util/hash/src/lib.rs +++ b/util/hash/src/lib.rs @@ -12,10 +12,10 @@ #[cfg(feature = "ckb-contract")] pub use blake2b_ref::{Blake2b, Blake2bBuilder}; -#[cfg(all(not(feature = "ckb-contract"), target_arch = "wasm32"))] +#[cfg(all(not(feature = "ckb-contract"), target_family = "wasm"))] pub use blake2b_ref::{Blake2b, Blake2bBuilder}; -#[cfg(all(not(feature = "ckb-contract"), not(target_arch = "wasm32")))] +#[cfg(all(not(feature = "ckb-contract"), not(target_family = "wasm")))] pub use blake2b_rs::{Blake2b, Blake2bBuilder}; #[doc(hidden)] diff --git a/util/jsonrpc-types/src/blockchain.rs b/util/jsonrpc-types/src/blockchain.rs index e5812d1d9e..abdf5ce939 100644 --- a/util/jsonrpc-types/src/blockchain.rs +++ b/util/jsonrpc-types/src/blockchain.rs @@ -25,7 +25,7 @@ use std::fmt; /// when the low 1 bit is 0, it indicates the data, /// and then it relies on the high 7 bits to indicate /// that the data actually corresponds to the version. -#[derive(Default, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, Debug, JsonSchema)] +#[derive(Default, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash, Debug, JsonSchema)] #[serde(rename_all = "snake_case")] pub enum ScriptHashType { /// Type "data" matches script code via cell data hash, and run the script code in v0 CKB VM. diff --git a/util/runtime/Cargo.toml b/util/runtime/Cargo.toml index fbf1d7539b..be589d9e94 100644 --- a/util/runtime/Cargo.toml +++ b/util/runtime/Cargo.toml @@ -9,6 +9,13 @@ homepage = "https://github.com/nervosnetwork/ckb" repository = "https://github.com/nervosnetwork/ckb" [dependencies] -tokio = { version = "1", features = ["full"] } +tokio = { version = "1", features = ["rt", "sync"] } ckb-logger = { path = "../logger", version = "= 0.119.0-pre" } -ckb-spawn = { path = "../spawn", version = "= 0.119.0-pre" } +ckb-spawn = { path = "../spawn", version = "= 0.119.0-pre" } + +[target.'cfg(not(target_family = "wasm"))'.dependencies] +tokio = { version = "1", features = ["rt-multi-thread"] } + + +[target.'cfg(target_family = "wasm")'.dependencies] +wasm-bindgen-futures = "0.4" diff --git a/util/runtime/src/brower.rs b/util/runtime/src/brower.rs new file mode 100644 index 0000000000..18c88678b9 --- /dev/null +++ b/util/runtime/src/brower.rs @@ -0,0 +1,27 @@ +use ckb_spawn::Spawn; +use std::future::Future; +use wasm_bindgen_futures::spawn_local; + +#[derive(Debug, Clone)] +pub struct Handle {} + +impl Handle { + /// Spawns a future onto the runtime. + /// + /// This spawns the given future onto the runtime's executor + pub fn spawn(&self, future: F) + where + F: Future + 'static, + { + spawn_local(async move { future.await }) + } +} + +impl Spawn for Handle { + fn spawn_task(&self, future: F) + where + F: Future + 'static, + { + self.spawn(future); + } +} diff --git a/util/runtime/src/lib.rs b/util/runtime/src/lib.rs index 5b9809bea0..89ca13d117 100644 --- a/util/runtime/src/lib.rs +++ b/util/runtime/src/lib.rs @@ -1,159 +1,15 @@ //! Utilities for tokio runtime. -use ckb_spawn::Spawn; -use core::future::Future; -use std::sync::atomic::{AtomicU32, Ordering}; -use std::thread::available_parallelism; -use tokio::runtime::Builder; -use tokio::runtime::Handle as TokioHandle; - -use tokio::task::JoinHandle; - pub use tokio; pub use tokio::runtime::Runtime; -use tokio::sync::mpsc::{Receiver, Sender}; - -// Handle is a newtype wrap and unwrap tokio::Handle, it is workaround with Rust Orphan Rules. -// We need `Handle` impl ckb spawn trait decouple tokio dependence - -/// Handle to the runtime. -#[derive(Debug, Clone)] -pub struct Handle { - pub(crate) inner: TokioHandle, - guard: Option>, -} - -impl Handle { - /// Create a new Handle - pub fn new(inner: TokioHandle, guard: Option>) -> Self { - Self { inner, guard } - } - - /// Drop the guard - pub fn drop_guard(&mut self) { - let _ = self.guard.take(); - } -} - -impl Handle { - /// Enter the runtime context. This allows you to construct types that must - /// have an executor available on creation such as [`tokio::time::Sleep`] or [`tokio::net::TcpStream`]. - /// It will also allow you to call methods such as [`tokio::spawn`]. - pub fn enter(&self, f: F) -> R - where - F: FnOnce() -> R, - { - let _enter = self.inner.enter(); - f() - } - - /// Spawns a future onto the runtime. - /// - /// This spawns the given future onto the runtime's executor - pub fn spawn(&self, future: F) -> JoinHandle - where - F: Future + Send + 'static, - F::Output: Send + 'static, - { - let tokio_task_guard = self.guard.clone(); - - self.inner.spawn(async move { - // move tokio_task_guard into the spawned future - // so that it will be dropped when the future is finished - let _guard = tokio_task_guard; - future.await - }) - } - - /// Run a future to completion on the Tokio runtime from a synchronous context. - pub fn block_on(&self, future: F) -> F::Output { - self.inner.block_on(future) - } - - /// Spawns a future onto the runtime blocking pool. - /// - /// This spawns the given future onto the runtime's blocking executor - pub fn spawn_blocking(&self, f: F) -> JoinHandle - where - F: FnOnce() -> R + Send + 'static, - R: Send + 'static, - { - self.inner.spawn_blocking(f) - } - - /// Transform to inner tokio handler - pub fn into_inner(self) -> TokioHandle { - self.inner - } -} - -/// Create a new runtime with unique name. -fn new_runtime(worker_num: Option) -> Runtime { - Builder::new_multi_thread() - .enable_all() - .worker_threads(worker_num.unwrap_or_else(|| available_parallelism().unwrap().into())) - .thread_name_fn(|| { - static ATOMIC_ID: AtomicU32 = AtomicU32::new(0); - let id = ATOMIC_ID - .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |n| { - // A long thread name will cut to 15 characters in debug tools. - // Such as "top", "htop", "gdb" and so on. - // It's a kernel limit. - // - // So if we want to see the whole name in debug tools, - // this number should have 6 digits at most, - // since the prefix uses 9 characters in below code. - // - // There still has a issue: - // When id wraps around, we couldn't know whether the old id - // is released or not. - // But we can ignore this, because it's almost impossible. - if n >= 999_999 { - Some(0) - } else { - Some(n + 1) - } - }) - .expect("impossible since the above closure must return Some(number)"); - format!("GlobalRt-{id}") - }) - .build() - .expect("ckb runtime initialized") -} - -/// Create new threaded_scheduler tokio Runtime, return `Runtime` -pub fn new_global_runtime(worker_num: Option) -> (Handle, Receiver<()>, Runtime) { - let runtime = new_runtime(worker_num); - let handle = runtime.handle().clone(); - let (guard, handle_stop_rx): (Sender<()>, Receiver<()>) = tokio::sync::mpsc::channel::<()>(1); - - (Handle::new(handle, Some(guard)), handle_stop_rx, runtime) -} - -/// Create new threaded_scheduler tokio Runtime, return `Handle` and background thread join handle, -/// NOTICE: This is only used in testing -pub fn new_background_runtime() -> Handle { - let runtime = new_runtime(None); - let handle = runtime.handle().clone(); - let (guard, mut handle_stop_rx): (Sender<()>, Receiver<()>) = - tokio::sync::mpsc::channel::<()>(1); - let _thread = std::thread::Builder::new() - .name("GlobalRtBuilder".to_string()) - .spawn(move || { - let ret = runtime.block_on(async move { handle_stop_rx.recv().await }); - ckb_logger::debug!("Global runtime finished {:?}", ret); - }) - .expect("tokio runtime started"); +#[cfg(not(target_family = "wasm"))] +pub use native::*; - Handle::new(handle, Some(guard)) -} +#[cfg(target_family = "wasm")] +pub use brower::*; -impl Spawn for Handle { - fn spawn_task(&self, future: F) - where - F: Future + Send + 'static, - { - self.spawn(future); - } -} +#[cfg(target_family = "wasm")] +mod brower; +#[cfg(not(target_family = "wasm"))] +mod native; diff --git a/util/runtime/src/native.rs b/util/runtime/src/native.rs new file mode 100644 index 0000000000..7c7a728f78 --- /dev/null +++ b/util/runtime/src/native.rs @@ -0,0 +1,153 @@ +use ckb_spawn::Spawn; +use core::future::Future; +use std::sync::atomic::{AtomicU32, Ordering}; +use std::thread::available_parallelism; +use tokio::runtime::{Builder, Handle as TokioHandle, Runtime}; + +use tokio::sync::mpsc::{Receiver, Sender}; +use tokio::task::JoinHandle; + +// Handle is a newtype wrap and unwrap tokio::Handle, it is workaround with Rust Orphan Rules. +// We need `Handle` impl ckb spawn trait decouple tokio dependence + +/// Handle to the runtime. +#[derive(Debug, Clone)] +pub struct Handle { + pub(crate) inner: TokioHandle, + guard: Option>, +} + +impl Handle { + /// Create a new Handle + pub fn new(inner: TokioHandle, guard: Option>) -> Self { + Self { inner, guard } + } + + /// Drop the guard + pub fn drop_guard(&mut self) { + let _ = self.guard.take(); + } +} + +impl Handle { + /// Enter the runtime context. This allows you to construct types that must + /// have an executor available on creation such as [`tokio::time::Sleep`] or [`tokio::net::TcpStream`]. + /// It will also allow you to call methods such as [`tokio::spawn`]. + pub fn enter(&self, f: F) -> R + where + F: FnOnce() -> R, + { + let _enter = self.inner.enter(); + f() + } + + /// Spawns a future onto the runtime. + /// + /// This spawns the given future onto the runtime's executor + pub fn spawn(&self, future: F) -> JoinHandle + where + F: Future + Send + 'static, + F::Output: Send + 'static, + { + let tokio_task_guard = self.guard.clone(); + + self.inner.spawn(async move { + // move tokio_task_guard into the spawned future + // so that it will be dropped when the future is finished + let _guard = tokio_task_guard; + future.await + }) + } + + /// Run a future to completion on the Tokio runtime from a synchronous context. + pub fn block_on(&self, future: F) -> F::Output { + self.inner.block_on(future) + } + + /// Spawns a future onto the runtime blocking pool. + /// + /// This spawns the given future onto the runtime's blocking executor + pub fn spawn_blocking(&self, f: F) -> JoinHandle + where + F: FnOnce() -> R + Send + 'static, + R: Send + 'static, + { + self.inner.spawn_blocking(f) + } + + /// Transform to inner tokio handler + pub fn into_inner(self) -> TokioHandle { + self.inner + } +} + +/// Create a new runtime with unique name. +fn new_runtime(worker_num: Option) -> Runtime { + Builder::new_multi_thread() + .enable_all() + .worker_threads(worker_num.unwrap_or_else(|| available_parallelism().unwrap().into())) + .thread_name_fn(|| { + static ATOMIC_ID: AtomicU32 = AtomicU32::new(0); + let id = ATOMIC_ID + .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |n| { + // A long thread name will cut to 15 characters in debug tools. + // Such as "top", "htop", "gdb" and so on. + // It's a kernel limit. + // + // So if we want to see the whole name in debug tools, + // this number should have 6 digits at most, + // since the prefix uses 9 characters in below code. + // + // There still has a issue: + // When id wraps around, we couldn't know whether the old id + // is released or not. + // But we can ignore this, because it's almost impossible. + if n >= 999_999 { + Some(0) + } else { + Some(n + 1) + } + }) + .expect("impossible since the above closure must return Some(number)"); + format!("GlobalRt-{id}") + }) + .build() + .expect("ckb runtime initialized") +} + +/// Create new threaded_scheduler tokio Runtime, return `Runtime` +pub fn new_global_runtime(worker_num: Option) -> (Handle, Receiver<()>, Runtime) { + let runtime = new_runtime(worker_num); + let handle = runtime.handle().clone(); + let (guard, handle_stop_rx): (Sender<()>, Receiver<()>) = tokio::sync::mpsc::channel::<()>(1); + + (Handle::new(handle, Some(guard)), handle_stop_rx, runtime) +} + +/// Create new threaded_scheduler tokio Runtime, return `Handle` and background thread join handle, +/// NOTICE: This is only used in testing +pub fn new_background_runtime() -> Handle { + let runtime = new_runtime(None); + let handle = runtime.handle().clone(); + + let (guard, mut handle_stop_rx): (Sender<()>, Receiver<()>) = + tokio::sync::mpsc::channel::<()>(1); + let _thread = std::thread::Builder::new() + .name("GlobalRtBuilder".to_string()) + .spawn(move || { + let ret = runtime.block_on(async move { handle_stop_rx.recv().await }); + ckb_logger::debug!("Global runtime finished {:?}", ret); + }) + .expect("tokio runtime started"); + + Handle::new(handle, Some(guard)) +} + +impl Spawn for Handle { + fn spawn_task(&self, future: F) + where + F: Future + Send + 'static, + { + self.spawn(future); + } +} diff --git a/util/spawn/src/lib.rs b/util/spawn/src/lib.rs index 83864084bb..8d5bcabf23 100644 --- a/util/spawn/src/lib.rs +++ b/util/spawn/src/lib.rs @@ -5,9 +5,18 @@ use core::future::Future; /// `Spawn` abstract async runtime, spawns a future onto the runtime +#[cfg(not(target_family = "wasm"))] pub trait Spawn { /// This spawns the given future onto the runtime's executor fn spawn_task(&self, task: F) where F: Future + Send + 'static; } + +#[cfg(target_family = "wasm")] +pub trait Spawn { + /// This spawns the given future onto the runtime's executor + fn spawn_task(&self, task: F) + where + F: Future + 'static; +} diff --git a/util/stop-handler/Cargo.toml b/util/stop-handler/Cargo.toml index 6d8e34936b..93edb2c596 100644 --- a/util/stop-handler/Cargo.toml +++ b/util/stop-handler/Cargo.toml @@ -10,7 +10,7 @@ repository = "https://github.com/nervosnetwork/ckb" [dependencies] ckb-logger = { path = "../logger", version = "= 0.119.0-pre" } -tokio = { version = "1", features = ["sync", "rt-multi-thread"] } +tokio = { version = "1", features = ["sync"] } ckb-channel = { path = "../channel", version = "= 0.119.0-pre" } ckb-util = { path = "..", version = "= 0.119.0-pre" } once_cell = "1.8.0" diff --git a/util/systemtime/Cargo.toml b/util/systemtime/Cargo.toml index 90cb7f31a3..44d7d46f45 100644 --- a/util/systemtime/Cargo.toml +++ b/util/systemtime/Cargo.toml @@ -10,6 +10,9 @@ repository = "https://github.com/nervosnetwork/ckb" [dependencies] +[target.'cfg(all(target_family = "wasm", target_os = "unknown"))'.dependencies] +web-time = "1.1.0" + [dev-dependencies] [features] diff --git a/util/systemtime/src/lib.rs b/util/systemtime/src/lib.rs index aed840fa23..5e6321acc9 100644 --- a/util/systemtime/src/lib.rs +++ b/util/systemtime/src/lib.rs @@ -4,7 +4,10 @@ mod test_realtime; #[cfg(feature = "enable_faketime")] use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; -use std::time::Duration; +#[cfg(not(target_family = "wasm"))] +use std::time::{Duration, SystemTime}; +#[cfg(all(target_family = "wasm", target_os = "unknown"))] +use web_time::{Duration, SystemTime}; // Store faketime timestamp here #[cfg(feature = "enable_faketime")] @@ -16,8 +19,8 @@ static FAKETIME_ENABLED: AtomicBool = AtomicBool::new(false); // Get real system's timestamp in millis fn system_time_as_millis() -> u64 { - let duration = std::time::SystemTime::now() - .duration_since(std::time::SystemTime::UNIX_EPOCH) + let duration = SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH) .expect("SystemTime before UNIX EPOCH!"); duration.as_secs() * 1000 + u64::from(duration.subsec_millis()) } diff --git a/util/types/Cargo.toml b/util/types/Cargo.toml index f73489ec43..39fd9848c9 100644 --- a/util/types/Cargo.toml +++ b/util/types/Cargo.toml @@ -27,7 +27,7 @@ bit-vec = "0.6.3" ckb-error = { path = "../../error", version = "= 0.119.0-pre" } ckb-rational = { path = "../rational", version = "= 0.119.0-pre" } once_cell = "1.8.0" -derive_more = { version = "0.99.0", default-features = false, features = [ +derive_more = { version = "1", default-features = false, features = [ "display", ] } ckb-merkle-mountain-range = "0.5.2" diff --git a/verification/Cargo.toml b/verification/Cargo.toml index c60cb91800..3c0fd6e390 100644 --- a/verification/Cargo.toml +++ b/verification/Cargo.toml @@ -19,11 +19,15 @@ ckb-chain-spec = { path = "../spec", version = "= 0.119.0-pre" } ckb-dao = { path = "../util/dao", version = "= 0.119.0-pre" } ckb-dao-utils = { path = "../util/dao/utils", version = "= 0.119.0-pre" } ckb-error = { path = "../error", version = "= 0.119.0-pre" } -derive_more = { version = "0.99.0", default-features=false, features = ["display"] } +derive_more = { version = "1", default-features = false, features = [ + "display", +] } ckb-verification-traits = { path = "./traits", version = "= 0.119.0-pre" } -tokio = { version = "1", features = ["sync", "process"] } +tokio = { version = "1", features = ["sync", "macros"] } [dev-dependencies] ckb-test-chain-utils = { path = "../util/test-chain-utils", version = "= 0.119.0-pre" } ckb-resource = { path = "../resource", version = "= 0.119.0-pre" } -ckb-systemtime = {path = "../util/systemtime", version = "= 0.119.0-pre", features=["enable_faketime"]} +ckb-systemtime = { path = "../util/systemtime", version = "= 0.119.0-pre", features = [ + "enable_faketime", +] } diff --git a/verification/src/transaction_verifier.rs b/verification/src/transaction_verifier.rs index b6317cebaa..62be30fcfb 100644 --- a/verification/src/transaction_verifier.rs +++ b/verification/src/transaction_verifier.rs @@ -5,7 +5,9 @@ use ckb_chain_spec::consensus::Consensus; use ckb_dao::DaoCalculator; use ckb_dao_utils::DaoError; use ckb_error::Error; -use ckb_script::{ChunkCommand, TransactionScriptsVerifier, TransactionSnapshot}; +#[cfg(not(target_family = "wasm"))] +use ckb_script::ChunkCommand; +use ckb_script::{TransactionScriptsVerifier, TransactionSnapshot}; use ckb_traits::{ CellDataProvider, EpochProvider, ExtensionProvider, HeaderFieldsProvider, HeaderProvider, }; @@ -175,6 +177,7 @@ where /// Perform context-dependent verification with command /// The verification will be interrupted when receiving a Suspend command + #[cfg(not(target_family = "wasm"))] pub async fn verify_with_pause( &self, max_cycles: Cycle,