Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
e73aac3
Squash
expenses Dec 15, 2019
7d32a2e
Merge remote-tracking branch 'parity/master' into ashley-browser-utils
expenses Dec 15, 2019
2299645
Fix keystore on wasm
expenses Dec 15, 2019
a42413b
Update utils/browser/Cargo.toml
expenses Dec 16, 2019
ec53ba6
Merge remote-tracking branch 'parity/master' into ashley-browser-utils
expenses Dec 16, 2019
808e01a
export console functions
expenses Dec 17, 2019
2d8f94f
Merge branch 'ashley-browser-utils' of github.com:paritytech/substrat…
expenses Dec 17, 2019
243b9a1
Merge remote-tracking branch 'parity/master' into ashley-browser-utils
expenses Dec 22, 2019
e40d8a2
Merge remote-tracking branch 'parity/master' into ashley-browser-utils
expenses Jan 2, 2020
3406be5
Use an Option<PathBuf> in keystore instead of cfg flags
expenses Jan 2, 2020
182d402
Merge branch 'ashley-browser-utils' of github.com:paritytech/substrat…
expenses Jan 2, 2020
2b292f0
Add a KeystoreConfig
expenses Jan 3, 2020
a4c2e3c
Merge remote-tracking branch 'parity/master' into ashley-browser-utils
expenses Jan 3, 2020
7fe5701
Update libp2p
expenses Jan 3, 2020
72fffb4
Merge remote-tracking branch 'parity/master' into ashley-browser-utils
expenses Jan 6, 2020
3c9c6a8
Merge remote-tracking branch 'parity/master' into ashley-browser-utils
expenses Jan 6, 2020
48ac10f
Bump kvdb-web version
expenses Jan 6, 2020
ee17a06
Fix cli
expenses Jan 6, 2020
6c9e3df
Merge remote-tracking branch 'parity/master' into ashley-browser-utils
expenses Jan 6, 2020
02083d0
Upgrade versions
expenses Jan 7, 2020
29855d2
Merge remote-tracking branch 'parity/master' into ashley-browser-utils
expenses Jan 7, 2020
66d2f09
Update wasm-bindgen stuff
expenses Jan 7, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
158 changes: 104 additions & 54 deletions Cargo.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ members = [
"test-utils/client",
"test-utils/runtime",
"test-utils/runtime/client",
"utils/browser",
"utils/build-script-utils",
"utils/fork-tree",
"utils/frame/rpc/support",
Expand Down
21 changes: 4 additions & 17 deletions bin/node/cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -87,15 +87,9 @@ ctrlc = { version = "3.1.3", features = ["termination"], optional = true }
node-transaction-factory = { version = "2.0.0", optional = true, path = "../transaction-factory" }

# WASM-specific dependencies
libp2p = { version = "0.13.2", default-features = false, optional = true }
clear_on_drop = { version = "0.2.3", features = ["no_cc"], optional = true } # Imported just for the `no_cc` feature
console_error_panic_hook = { version = "0.1.1", optional = true }
console_log = { version = "0.1.2", optional = true }
js-sys = { version = "0.3.22", optional = true }
wasm-bindgen = { version = "0.2.45", optional = true }
wasm-bindgen-futures = { version = "0.3.22", optional = true }
kvdb-memorydb = { version = "0.2.0", optional = true }
rand6 = { package = "rand", version = "0.6", features = ["wasm-bindgen"], optional = true } # Imported just for the `wasm-bindgen` feature
wasm-bindgen = { version = "0.2.57", optional = true }
wasm-bindgen-futures = { version = "0.4.7", optional = true }
browser-utils = { path = "../../../utils/browser", optional = true }

[dev-dependencies]
sc-keystore = { version = "2.0.0", path = "../../../client/keystore" }
Expand All @@ -113,16 +107,9 @@ vergen = "3.0.4"
[features]
default = ["cli"]
browser = [
"clear_on_drop",
"console_error_panic_hook",
"console_log",
"js-sys",
"libp2p",
"browser-utils",
"wasm-bindgen",
"wasm-bindgen-futures",
"kvdb-memorydb",
"rand/wasm-bindgen",
"rand6"
]
cli = [
"sc-cli",
Expand Down
2 changes: 1 addition & 1 deletion bin/node/cli/browser-demo/build.sh
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
#!/usr/bin/env sh
wasm-pack build --target web --out-dir ./browser-demo/pkg --no-typescript --release ./.. -- --no-default-features --features "browser"
python -m SimpleHTTPServer 8000
python -m http.server 8000
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 Python2 is now deprecated 😅

4 changes: 2 additions & 2 deletions bin/node/cli/browser-demo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

// Build our client.
log('Starting client');
let client = start_client(ws());
let client = await start_client(ws());
log('Client started');

client.rpcSubscribe('{"method":"chain_subscribeNewHead","params":[],"id":1,"jsonrpc":"2.0"}',
Expand All @@ -29,7 +29,7 @@
client
.rpcSend('{"method":"system_networkState","params":[],"id":1,"jsonrpc":"2.0"}')
.then((r) => log("Network state: " + r));
}, 1000);
}, 20000);
}

start();
Expand Down
142 changes: 19 additions & 123 deletions bin/node/cli/src/browser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,45 +15,31 @@
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.

use crate::ChainSpec;
use futures01::{prelude::*, sync::oneshot, sync::mpsc};
use libp2p::wasm_ext;
use log::{debug, info};
use std::sync::Arc;
use sc_service::{AbstractService, RpcSession, Roles as ServiceRoles, Configuration, config::DatabaseConfig};
use log::info;
use wasm_bindgen::prelude::*;
use sc_service::Configuration;
use browser_utils::{
Transport, Client,
browser_configuration, set_console_error_panic_hook, init_console_log,
};

/// Starts the client.
///
/// You must pass a libp2p transport that supports .
#[wasm_bindgen]
pub fn start_client(wasm_ext: wasm_ext::ffi::Transport) -> Result<Client, JsValue> {
pub async fn start_client(wasm_ext: Transport) -> Result<Client, JsValue> {
start_inner(wasm_ext)
.await
.map_err(|err| JsValue::from_str(&err.to_string()))
}

fn start_inner(wasm_ext: wasm_ext::ffi::Transport) -> Result<Client, Box<dyn std::error::Error>> {
console_error_panic_hook::set_once();
console_log::init_with_level(log::Level::Info);
async fn start_inner(wasm_ext: Transport) -> Result<Client, Box<dyn std::error::Error>> {
set_console_error_panic_hook();
init_console_log(log::Level::Info)?;

// Build the configuration to pass to the service.
let config = {
let wasm_ext = wasm_ext::ExtTransport::new(wasm_ext);
let chain_spec = ChainSpec::FlamingFir.load().map_err(|e| format!("{:?}", e))?;
let mut config = Configuration::<(), _, _>::default_with_spec_and_base_path(chain_spec, None);
config.network.transport = sc_network::config::TransportConfig::Normal {
wasm_external_transport: Some(wasm_ext.clone()),
allow_private_ipv4: true,
enable_mdns: false,
};
config.telemetry_external_transport = Some(wasm_ext);
config.roles = ServiceRoles::LIGHT;
config.name = "Browser node".to_string();
config.database = {
let db = Arc::new(kvdb_memorydb::create(10));
DatabaseConfig::Custom(db)
};
config
};
let chain_spec = ChainSpec::FlamingFir.load()
.map_err(|e| format!("{:?}", e))?;

let config: Configuration<(), _, _> = browser_configuration(wasm_ext, chain_spec)
.await?;

info!("Substrate browser node");
info!(" version {}", config.full_version());
Expand All @@ -63,98 +49,8 @@ fn start_inner(wasm_ext: wasm_ext::ffi::Transport) -> Result<Client, Box<dyn std
info!("Roles: {:?}", config.roles);

// Create the service. This is the most heavy initialization step.
let mut service = crate::service::new_light(config).map_err(|e| format!("{:?}", e))?;

// We now dispatch a background task responsible for processing the service.
//
// The main action performed by the code below consists in polling the service with
// `service.poll()`.
// The rest consists in handling RPC requests.
let (rpc_send_tx, mut rpc_send_rx) = mpsc::unbounded::<RpcMessage>();
wasm_bindgen_futures::spawn_local(futures01::future::poll_fn(move || {
loop {
match rpc_send_rx.poll() {
Ok(Async::Ready(Some(message))) => {
let fut = service.rpc_query(&message.session, &message.rpc_json);
let _ = message.send_back.send(Box::new(fut));
},
Ok(Async::NotReady) => break,
Err(_) | Ok(Async::Ready(None)) => return Ok(Async::Ready(())),
}
}

loop {
match service.poll().map_err(|_| ())? {
Async::Ready(()) => return Ok(Async::Ready(())),
Async::NotReady => break
}
}

Ok(Async::NotReady)
}));

Ok(Client {
rpc_send_tx,
})
}

/// A running client.
#[wasm_bindgen]
pub struct Client {
rpc_send_tx: mpsc::UnboundedSender<RpcMessage>,
}

struct RpcMessage {
rpc_json: String,
session: RpcSession,
send_back: oneshot::Sender<Box<dyn Future<Item = Option<String>, Error = ()>>>,
}

#[wasm_bindgen]
impl Client {
/// Allows starting an RPC request. Returns a `Promise` containing the result of that request.
#[wasm_bindgen(js_name = "rpcSend")]
pub fn rpc_send(&mut self, rpc: &str) -> js_sys::Promise {
let rpc_session = RpcSession::new(mpsc::channel(1).0);
let (tx, rx) = oneshot::channel();
let _ = self.rpc_send_tx.unbounded_send(RpcMessage {
rpc_json: rpc.to_owned(),
session: rpc_session,
send_back: tx,
});
let fut = rx
.map_err(|_| ())
.and_then(|fut| fut)
.map(|s| JsValue::from_str(&s.unwrap_or(String::new())))
.map_err(|_| JsValue::NULL);
wasm_bindgen_futures::future_to_promise(fut)
}
let service = crate::service::new_light(config)
.map_err(|e| format!("{:?}", e))?;

/// Subscribes to an RPC pubsub endpoint.
#[wasm_bindgen(js_name = "rpcSubscribe")]
pub fn rpc_subscribe(&mut self, rpc: &str, callback: js_sys::Function) {
let (tx, rx) = mpsc::channel(4);
let rpc_session = RpcSession::new(tx);
let (fut_tx, fut_rx) = oneshot::channel();
let _ = self.rpc_send_tx.unbounded_send(RpcMessage {
rpc_json: rpc.to_owned(),
session: rpc_session.clone(),
send_back: fut_tx,
});
let fut_rx = fut_rx
.map_err(|_| ())
.and_then(|fut| fut);
wasm_bindgen_futures::spawn_local(fut_rx.then(|_| Ok(())));
wasm_bindgen_futures::spawn_local(rx.for_each(move |s| {
match callback.call1(&callback, &JsValue::from_str(&s)) {
Ok(_) => Ok(()),
Err(_) => Err(()),
}
}).then(move |v| {
// We need to keep `rpc_session` alive.
debug!("RPC subscription has ended");
drop(rpc_session);
v
}));
}
Ok(browser_utils::start_client(service))
}
38 changes: 22 additions & 16 deletions client/cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ pub mod informant;

use sc_client_api::execution_extensions::ExecutionStrategies;
use sc_service::{
config::{Configuration, DatabaseConfig},
config::{Configuration, DatabaseConfig, KeystoreConfig},
ServiceBuilderCommand,
RuntimeGenesis, ChainSpecExtension, PruningMode, ChainSpec,
};
Expand Down Expand Up @@ -754,20 +754,22 @@ fn fill_config_keystore_password<C, G, E>(
config: &mut sc_service::Configuration<C, G, E>,
cli: &RunCmd,
) -> Result<(), String> {
config.keystore_password = if cli.password_interactive {
#[cfg(not(target_os = "unknown"))]
{
Some(input_keystore_password()?.into())
}
#[cfg(target_os = "unknown")]
None
} else if let Some(ref file) = cli.password_filename {
Some(fs::read_to_string(file).map_err(|e| format!("{}", e))?.into())
} else if let Some(ref password) = cli.password {
Some(password.clone().into())
} else {
None
};
if let KeystoreConfig::Path { password, .. } = &mut config.keystore {
*password = if cli.password_interactive {
#[cfg(not(target_os = "unknown"))]
{
Some(input_keystore_password()?.into())
}
#[cfg(target_os = "unknown")]
None
} else if let Some(ref file) = cli.password_filename {
Some(fs::read_to_string(file).map_err(|e| format!("{}", e))?.into())
} else if let Some(ref password) = cli.password {
Some(password.clone().into())
} else {
None
};
}

Ok(())
}
Expand Down Expand Up @@ -873,7 +875,11 @@ where
)?
}

config.keystore_path = cli.keystore_path.or_else(|| config.in_chain_config_dir(DEFAULT_KEYSTORE_CONFIG_PATH));
let default_keystore_path = config.in_chain_config_dir(DEFAULT_KEYSTORE_CONFIG_PATH);

if let KeystoreConfig::Path { path, ..} = &mut config.keystore {
*path = path.clone().or(default_keystore_path);
}

// set sentry mode (i.e. act as an authority but **never** actively participate)
config.sentry_mode = cli.sentry;
Expand Down
Loading