Merge branch 'master' into ui-2
# Conflicts: # js/src/shell/Connection/connection.js # js/src/ui/Icons/index.js # js/src/views/Accounts/CreateAccount/RecoveryPhrase/recoveryPhrase.js
This commit is contained in:
commit
602115d81e
@ -593,6 +593,19 @@ js-test:
|
|||||||
tags:
|
tags:
|
||||||
- rust
|
- rust
|
||||||
- rust-stable
|
- rust-stable
|
||||||
|
js-test-node_7:
|
||||||
|
stage: test
|
||||||
|
image: parity/rust-debian-node_7:gitlab-ci
|
||||||
|
before_script:
|
||||||
|
- git submodule update --init --recursive
|
||||||
|
- export JS_FILES_MODIFIED=$(git --no-pager diff --name-only $CI_BUILD_REF^ $CI_BUILD_REF | grep ^js/ | wc -l)
|
||||||
|
- if [ $JS_FILES_MODIFIED -eq 0 ]; then echo "Skipping JS deps install since no JS files modified."; else ./js/scripts/install-deps.sh;fi
|
||||||
|
script:
|
||||||
|
- if [ $JS_FILES_MODIFIED -eq 0 ]; then echo "Skipping JS lint since no JS files modified."; else ./js/scripts/lint.sh && ./js/scripts/test.sh && ./js/scripts/build.sh; fi
|
||||||
|
tags:
|
||||||
|
- rust
|
||||||
|
- rust-stable
|
||||||
|
allow_failure: true
|
||||||
test-rust-beta:
|
test-rust-beta:
|
||||||
stage: test
|
stage: test
|
||||||
only:
|
only:
|
||||||
|
4
Cargo.lock
generated
4
Cargo.lock
generated
@ -1640,6 +1640,7 @@ dependencies = [
|
|||||||
"log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"mime 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"mime 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"mime_guess 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"mime_guess 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"native-contracts 0.1.0",
|
||||||
"parity-reactor 0.1.0",
|
"parity-reactor 0.1.0",
|
||||||
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -1783,7 +1784,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "parity-ui-precompiled"
|
name = "parity-ui-precompiled"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
source = "git+https://github.com/paritytech/js-precompiled.git#bc28cda725b0bfe655b807611091389e9fcdaac8"
|
source = "git+https://github.com/paritytech/js-precompiled.git#69ff5bc9fa4c64a0657308a64a45a95b3d984950"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"parity-dapps-glue 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"parity-dapps-glue 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
@ -1798,6 +1799,7 @@ dependencies = [
|
|||||||
"ethcore-ipc-codegen 1.7.0",
|
"ethcore-ipc-codegen 1.7.0",
|
||||||
"ethcore-util 1.7.0",
|
"ethcore-util 1.7.0",
|
||||||
"ethsync 1.7.0",
|
"ethsync 1.7.0",
|
||||||
|
"futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"ipc-common-types 1.7.0",
|
"ipc-common-types 1.7.0",
|
||||||
"log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"parity-hash-fetch 1.7.0",
|
"parity-hash-fetch 1.7.0",
|
||||||
|
@ -95,6 +95,16 @@ impl<R: URLHint + 'static, F: Fetch> ContentFetcher<F, R> {
|
|||||||
fn set_status(&self, content_id: &str, status: ContentStatus) {
|
fn set_status(&self, content_id: &str, status: ContentStatus) {
|
||||||
self.cache.lock().insert(content_id.to_owned(), status);
|
self.cache.lock().insert(content_id.to_owned(), status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// resolve contract call synchronously.
|
||||||
|
// TODO: port to futures-based hyper and make it all async.
|
||||||
|
fn resolve(&self, content_id: Vec<u8>) -> Option<URLHintResult> {
|
||||||
|
use futures::Future;
|
||||||
|
|
||||||
|
self.resolver.resolve(content_id)
|
||||||
|
.wait()
|
||||||
|
.unwrap_or_else(|e| { warn!("Error resolving content-id: {}", e); None })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: URLHint + 'static, F: Fetch> Fetcher for ContentFetcher<F, R> {
|
impl<R: URLHint + 'static, F: Fetch> Fetcher for ContentFetcher<F, R> {
|
||||||
@ -108,10 +118,8 @@ impl<R: URLHint + 'static, F: Fetch> Fetcher for ContentFetcher<F, R> {
|
|||||||
}
|
}
|
||||||
// fallback to resolver
|
// fallback to resolver
|
||||||
if let Ok(content_id) = content_id.from_hex() {
|
if let Ok(content_id) = content_id.from_hex() {
|
||||||
// else try to resolve the app_id
|
|
||||||
let has_content = self.resolver.resolve(content_id).is_some();
|
|
||||||
// if there is content or we are syncing return true
|
// if there is content or we are syncing return true
|
||||||
has_content || self.sync.is_major_importing()
|
self.sync.is_major_importing() || self.resolve(content_id).is_some()
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
@ -137,7 +145,7 @@ impl<R: URLHint + 'static, F: Fetch> Fetcher for ContentFetcher<F, R> {
|
|||||||
_ => {
|
_ => {
|
||||||
trace!(target: "dapps", "Content unavailable. Fetching... {:?}", content_id);
|
trace!(target: "dapps", "Content unavailable. Fetching... {:?}", content_id);
|
||||||
let content_hex = content_id.from_hex().expect("to_handler is called only when `contains` returns true.");
|
let content_hex = content_id.from_hex().expect("to_handler is called only when `contains` returns true.");
|
||||||
let content = self.resolver.resolve(content_hex);
|
let content = self.resolve(content_hex);
|
||||||
|
|
||||||
let cache = self.cache.clone();
|
let cache = self.cache.clone();
|
||||||
let id = content_id.clone();
|
let id = content_id.clone();
|
||||||
@ -225,6 +233,7 @@ mod tests {
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use util::Bytes;
|
use util::Bytes;
|
||||||
use fetch::{Fetch, Client};
|
use fetch::{Fetch, Client};
|
||||||
|
use futures::{future, Future, BoxFuture};
|
||||||
use hash_fetch::urlhint::{URLHint, URLHintResult};
|
use hash_fetch::urlhint::{URLHint, URLHintResult};
|
||||||
use parity_reactor::Remote;
|
use parity_reactor::Remote;
|
||||||
|
|
||||||
@ -236,8 +245,8 @@ mod tests {
|
|||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct FakeResolver;
|
struct FakeResolver;
|
||||||
impl URLHint for FakeResolver {
|
impl URLHint for FakeResolver {
|
||||||
fn resolve(&self, _id: Bytes) -> Option<URLHintResult> {
|
fn resolve(&self, _id: Bytes) -> BoxFuture<Option<URLHintResult>, String> {
|
||||||
None
|
future::ok(None).boxed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ fn should_return_503_when_syncing_but_should_make_the_calls() {
|
|||||||
|
|
||||||
// then
|
// then
|
||||||
response.assert_status("HTTP/1.1 503 Service Unavailable");
|
response.assert_status("HTTP/1.1 503 Service Unavailable");
|
||||||
assert_eq!(registrar.calls.lock().len(), 4);
|
assert_eq!(registrar.calls.lock().len(), 2);
|
||||||
assert_security_headers_for_embed(&response.headers);
|
assert_security_headers_for_embed(&response.headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,9 +64,10 @@ impl ContractClient for FakeRegistrar {
|
|||||||
Ok(REGISTRAR.parse().unwrap())
|
Ok(REGISTRAR.parse().unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call(&self, address: Address, data: Bytes) -> Result<Bytes, String> {
|
fn call(&self, address: Address, data: Bytes) -> ::futures::BoxFuture<Bytes, String> {
|
||||||
let call = (address.to_hex(), data.to_hex());
|
let call = (address.to_hex(), data.to_hex());
|
||||||
self.calls.lock().push(call.clone());
|
self.calls.lock().push(call.clone());
|
||||||
self.responses.lock().get(&call).cloned().expect(&format!("No response for call: {:?}", call))
|
let res = self.responses.lock().get(&call).cloned().expect(&format!("No response for call: {:?}", call));
|
||||||
|
Box::new(::futures::future::done(res))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,18 +20,13 @@ use std::path::Path;
|
|||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
// TODO: `include!` these from files where they're pretty-printed?
|
// TODO: just walk the "res" directory and generate whole crate automatically.
|
||||||
const REGISTRY_ABI: &'static str = r#"[{"constant":true,"inputs":[{"name":"_data","type":"address"}],"name":"canReverse","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_new","type":"address"}],"name":"setOwner","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_key","type":"string"},{"name":"_value","type":"bytes32"}],"name":"setData","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"string"}],"name":"confirmReverse","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"bytes32"}],"name":"reserve","outputs":[{"name":"success","type":"bool"}],"payable":true,"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"bytes32"}],"name":"drop","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_key","type":"string"}],"name":"getAddress","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_amount","type":"uint256"}],"name":"setFee","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_to","type":"address"}],"name":"transfer","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_key","type":"string"}],"name":"getData","outputs":[{"name":"","type":"bytes32"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"reserved","outputs":[{"name":"reserved","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"drain","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"string"},{"name":"_who","type":"address"}],"name":"proposeReverse","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"hasReverse","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_key","type":"string"}],"name":"getUint","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"fee","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"getOwner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"getReverse","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_data","type":"address"}],"name":"reverse","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_key","type":"string"},{"name":"_value","type":"uint256"}],"name":"setUint","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"string"},{"name":"_who","type":"address"}],"name":"confirmReverseAs","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"removeReverse","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_key","type":"string"},{"name":"_value","type":"address"}],"name":"setAddress","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"}]"#;
|
const REGISTRY_ABI: &'static str = include_str!("res/registrar.json");
|
||||||
|
const URLHINT_ABI: &'static str = include_str!("res/urlhint.json");
|
||||||
const SERVICE_TRANSACTION_ABI: &'static str = r#"[{"constant":false,"inputs":[{"name":"_new","type":"address"}],"name":"setOwner","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_who","type":"address"}],"name":"certify","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"getAddress","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_who","type":"address"}],"name":"revoke","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"delegate","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"getUint","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_new","type":"address"}],"name":"setDelegate","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"}],"name":"certified","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"get","outputs":[{"name":"","type":"bytes32"}],"payable":false,"type":"function"}]"#;
|
const SERVICE_TRANSACTION_ABI: &'static str = include_str!("res/service_transaction.json");
|
||||||
|
const SECRETSTORE_ACL_STORAGE_ABI: &'static str = include_str!("res/secretstore_acl_storage.json");
|
||||||
const SECRETSTORE_ACL_STORAGE_ABI: &'static str = r#"[{"constant":true,"inputs":[{"name":"user","type":"address"},{"name":"document","type":"bytes32"}],"name":"checkPermissions","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"}]"#;
|
const VALIDATOR_SET_ABI: &'static str = include_str!("res/validator_set.json");
|
||||||
|
const VALIDATOR_REPORT_ABI: &'static str = include_str!("res/validator_report.json");
|
||||||
// be very careful changing these: ensure `ethcore/engines` validator sets have corresponding
|
|
||||||
// changes.
|
|
||||||
const VALIDATOR_SET_ABI: &'static str = r#"[{"constant":true,"inputs":[],"name":"transitionNonce","outputs":[{"name":"nonce","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"getValidators","outputs":[{"name":"validators","type":"address[]"}],"payable":false,"type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_parent_hash","type":"bytes32"},{"indexed":true,"name":"_nonce","type":"uint256"},{"indexed":false,"name":"_new_set","type":"address[]"}],"name":"ValidatorsChanged","type":"event"}]"#;
|
|
||||||
|
|
||||||
const VALIDATOR_REPORT_ABI: &'static str = r#"[{"constant":false,"inputs":[{"name":"validator","type":"address"},{"name":"blockNumber","type":"uint256"},{"name":"proof","type":"bytes"}],"name":"reportMalicious","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"validator","type":"address"},{"name":"blockNumber","type":"uint256"}],"name":"reportBenign","outputs":[],"payable":false,"type":"function"}]"#;
|
|
||||||
|
|
||||||
const TEST_VALIDATOR_SET_ABI: &'static str = r#"[{"constant":true,"inputs":[],"name":"transitionNonce","outputs":[{"name":"n","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"newValidators","type":"address[]"}],"name":"setValidators","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"getValidators","outputs":[{"name":"vals","type":"address[]"}],"payable":false,"type":"function"},{"inputs":[],"payable":false,"type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_parent_hash","type":"bytes32"},{"indexed":true,"name":"_nonce","type":"uint256"},{"indexed":false,"name":"_new_set","type":"address[]"}],"name":"ValidatorsChanged","type":"event"}]"#;
|
const TEST_VALIDATOR_SET_ABI: &'static str = r#"[{"constant":true,"inputs":[],"name":"transitionNonce","outputs":[{"name":"n","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"newValidators","type":"address[]"}],"name":"setValidators","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"getValidators","outputs":[{"name":"vals","type":"address[]"}],"payable":false,"type":"function"},{"inputs":[],"payable":false,"type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_parent_hash","type":"bytes32"},{"indexed":true,"name":"_nonce","type":"uint256"},{"indexed":false,"name":"_new_set","type":"address[]"}],"name":"ValidatorsChanged","type":"event"}]"#;
|
||||||
|
|
||||||
@ -51,6 +46,7 @@ fn build_test_contracts() {
|
|||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
build_file("Registry", REGISTRY_ABI, "registry.rs");
|
build_file("Registry", REGISTRY_ABI, "registry.rs");
|
||||||
|
build_file("Urlhint", URLHINT_ABI, "urlhint.rs");
|
||||||
build_file("ServiceTransactionChecker", SERVICE_TRANSACTION_ABI, "service_transaction.rs");
|
build_file("ServiceTransactionChecker", SERVICE_TRANSACTION_ABI, "service_transaction.rs");
|
||||||
build_file("SecretStoreAclStorage", SECRETSTORE_ACL_STORAGE_ABI, "secretstore_acl_storage.rs");
|
build_file("SecretStoreAclStorage", SECRETSTORE_ACL_STORAGE_ABI, "secretstore_acl_storage.rs");
|
||||||
build_file("ValidatorSet", VALIDATOR_SET_ABI, "validator_set.rs");
|
build_file("ValidatorSet", VALIDATOR_SET_ABI, "validator_set.rs");
|
||||||
|
@ -50,6 +50,8 @@ use futures::{{future, Future, IntoFuture, BoxFuture}};
|
|||||||
use ethabi::{{Contract, Interface, Token, Event}};
|
use ethabi::{{Contract, Interface, Token, Event}};
|
||||||
use util::{{self, Uint}};
|
use util::{{self, Uint}};
|
||||||
|
|
||||||
|
/// Generated Rust bindings to an Ethereum contract.
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
pub struct {name} {{
|
pub struct {name} {{
|
||||||
contract: Contract,
|
contract: Contract,
|
||||||
/// Address to make calls to.
|
/// Address to make calls to.
|
||||||
@ -101,6 +103,7 @@ fn generate_functions(contract: &Contract) -> Result<String, Error> {
|
|||||||
|
|
||||||
functions.push_str(&format!(r##"
|
functions.push_str(&format!(r##"
|
||||||
/// Call the function "{abi_name}" on the contract.
|
/// Call the function "{abi_name}" on the contract.
|
||||||
|
///
|
||||||
/// Inputs: {abi_inputs:?}
|
/// Inputs: {abi_inputs:?}
|
||||||
/// Outputs: {abi_outputs:?}
|
/// Outputs: {abi_outputs:?}
|
||||||
pub fn {snake_name}<F, U>(&self, call: F, {params}) -> BoxFuture<{output_type}, String>
|
pub fn {snake_name}<F, U>(&self, call: F, {params}) -> BoxFuture<{output_type}, String>
|
||||||
@ -121,7 +124,7 @@ pub fn {snake_name}<F, U>(&self, call: F, {params}) -> BoxFuture<{output_type},
|
|||||||
call_future
|
call_future
|
||||||
.into_future()
|
.into_future()
|
||||||
.and_then(move |out| function.decode_output(out).map_err(|e| format!("{{:?}}", e)))
|
.and_then(move |out| function.decode_output(out).map_err(|e| format!("{{:?}}", e)))
|
||||||
.map(::std::collections::VecDeque::from)
|
.map(Vec::into_iter)
|
||||||
.and_then(|mut outputs| {decode_outputs})
|
.and_then(|mut outputs| {decode_outputs})
|
||||||
.boxed()
|
.boxed()
|
||||||
}}
|
}}
|
||||||
@ -174,7 +177,7 @@ fn input_params_codegen(inputs: &[ParamType]) -> Result<(String, String), ParamT
|
|||||||
// as a tuple, and the second gives code to get that tuple from a deque of tokens.
|
// as a tuple, and the second gives code to get that tuple from a deque of tokens.
|
||||||
//
|
//
|
||||||
// produce output type of the form (type_1, type_2, ...) without trailing comma.
|
// produce output type of the form (type_1, type_2, ...) without trailing comma.
|
||||||
// produce code for getting this output type from `outputs: VecDeque<Token>`, where
|
// produce code for getting this output type from `outputs: Vec<Token>::IntoIter`, where
|
||||||
// an `Err(String)` can be returned.
|
// an `Err(String)` can be returned.
|
||||||
//
|
//
|
||||||
// returns any unsupported param type encountered.
|
// returns any unsupported param type encountered.
|
||||||
@ -190,7 +193,7 @@ fn output_params_codegen(outputs: &[ParamType]) -> Result<(String, String), Para
|
|||||||
decode_outputs.push_str(&format!(
|
decode_outputs.push_str(&format!(
|
||||||
r#"
|
r#"
|
||||||
outputs
|
outputs
|
||||||
.pop_front()
|
.next()
|
||||||
.and_then(|output| {{ {} }})
|
.and_then(|output| {{ {} }})
|
||||||
.ok_or_else(|| "Wrong output type".to_string())?
|
.ok_or_else(|| "Wrong output type".to_string())?
|
||||||
"#,
|
"#,
|
||||||
|
21
ethcore/native_contracts/res/registrar.json
Normal file
21
ethcore/native_contracts/res/registrar.json
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
[
|
||||||
|
{"constant":false,"inputs":[{"name":"_new","type":"address"}],"name":"setOwner","outputs":[],"type":"function"},
|
||||||
|
{"constant":false,"inputs":[{"name":"_name","type":"string"}],"name":"confirmReverse","outputs":[{"name":"success","type":"bool"}],"type":"function"},
|
||||||
|
{"constant":false,"inputs":[{"name":"_name","type":"bytes32"}],"name":"reserve","outputs":[{"name":"success","type":"bool"}],"type":"function"},
|
||||||
|
{"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_key","type":"string"},{"name":"_value","type":"bytes32"}],"name":"set","outputs":[{"name":"success","type":"bool"}],"type":"function"},
|
||||||
|
{"constant":false,"inputs":[{"name":"_name","type":"bytes32"}],"name":"drop","outputs":[{"name":"success","type":"bool"}],"type":"function"},
|
||||||
|
{"constant":true,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_key","type":"string"}],"name":"getAddress","outputs":[{"name":"","type":"address"}],"type":"function"},
|
||||||
|
{"constant":false,"inputs":[{"name":"_amount","type":"uint256"}],"name":"setFee","outputs":[],"type":"function"},
|
||||||
|
{"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_to","type":"address"}],"name":"transfer","outputs":[{"name":"success","type":"bool"}],"type":"function"},
|
||||||
|
{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"type":"function"},
|
||||||
|
{"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"reserved","outputs":[{"name":"reserved","type":"bool"}],"type":"function"},
|
||||||
|
{"constant":false,"inputs":[],"name":"drain","outputs":[],"type":"function"},
|
||||||
|
{"constant":false,"inputs":[{"name":"_name","type":"string"},{"name":"_who","type":"address"}],"name":"proposeReverse","outputs":[{"name":"success","type":"bool"}],"type":"function"},
|
||||||
|
{"constant":true,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_key","type":"string"}],"name":"getUint","outputs":[{"name":"","type":"uint256"}],"type":"function"},
|
||||||
|
{"constant":true,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_key","type":"string"}],"name":"get","outputs":[{"name":"","type":"bytes32"}],"type":"function"},
|
||||||
|
{"constant":true,"inputs":[],"name":"fee","outputs":[{"name":"","type":"uint256"}],"type":"function"},
|
||||||
|
{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"reverse","outputs":[{"name":"","type":"string"}],"type":"function"},
|
||||||
|
{"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_key","type":"string"},{"name":"_value","type":"uint256"}],"name":"setUint","outputs":[{"name":"success","type":"bool"}],"type":"function"},
|
||||||
|
{"constant":false,"inputs":[],"name":"removeReverse","outputs":[],"type":"function"},
|
||||||
|
{"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_key","type":"string"},{"name":"_value","type":"address"}],"name":"setAddress","outputs":[{"name":"success","type":"bool"}],"type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"Drained","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"FeeChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"name","type":"bytes32"},{"indexed":true,"name":"owner","type":"address"}],"name":"Reserved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"name","type":"bytes32"},{"indexed":true,"name":"oldOwner","type":"address"},{"indexed":true,"name":"newOwner","type":"address"}],"name":"Transferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"name","type":"bytes32"},{"indexed":true,"name":"owner","type":"address"}],"name":"Dropped","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"name","type":"bytes32"},{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"key","type":"string"}],"name":"DataChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"name","type":"string"},{"indexed":true,"name":"reverse","type":"address"}],"name":"ReverseProposed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"name","type":"string"},{"indexed":true,"name":"reverse","type":"address"}],"name":"ReverseConfirmed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"name","type":"string"},{"indexed":true,"name":"reverse","type":"address"}],"name":"ReverseRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"old","type":"address"},{"indexed":true,"name":"current","type":"address"}],"name":"NewOwner","type":"event"}
|
||||||
|
]
|
@ -0,0 +1,3 @@
|
|||||||
|
[
|
||||||
|
{"constant":true,"inputs":[{"name":"user","type":"address"},{"name":"document","type":"bytes32"}],"name":"checkPermissions","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"}
|
||||||
|
]
|
12
ethcore/native_contracts/res/service_transaction.json
Normal file
12
ethcore/native_contracts/res/service_transaction.json
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
[
|
||||||
|
{"constant":false,"inputs":[{"name":"_new","type":"address"}],"name":"setOwner","outputs":[],"payable":false,"type":"function"},
|
||||||
|
{"constant":false,"inputs":[{"name":"_who","type":"address"}],"name":"certify","outputs":[],"payable":false,"type":"function"},
|
||||||
|
{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"getAddress","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},
|
||||||
|
{"constant":false,"inputs":[{"name":"_who","type":"address"}],"name":"revoke","outputs":[],"payable":false,"type":"function"},
|
||||||
|
{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},
|
||||||
|
{"constant":true,"inputs":[],"name":"delegate","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},
|
||||||
|
{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"getUint","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},
|
||||||
|
{"constant":false,"inputs":[{"name":"_new","type":"address"}],"name":"setDelegate","outputs":[],"payable":false,"type":"function"},
|
||||||
|
{"constant":true,"inputs":[{"name":"_who","type":"address"}],"name":"certified","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},
|
||||||
|
{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"get","outputs":[{"name":"","type":"bytes32"}],"payable":false,"type":"function"}
|
||||||
|
]
|
6
ethcore/native_contracts/res/urlhint.json
Normal file
6
ethcore/native_contracts/res/urlhint.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
[
|
||||||
|
{"constant":false,"inputs":[{"name":"_content","type":"bytes32"},{"name":"_url","type":"string"}],"name":"hintURL","outputs":[],"type":"function"},
|
||||||
|
{"constant":false,"inputs":[{"name":"_content","type":"bytes32"},{"name":"_accountSlashRepo","type":"string"},{"name":"_commit","type":"bytes20"}],"name":"hint","outputs":[],"type":"function"},
|
||||||
|
{"constant":true,"inputs":[{"name":"","type":"bytes32"}],"name":"entries","outputs":[{"name":"accountSlashRepo","type":"string"},{"name":"commit","type":"bytes20"},{"name":"owner","type":"address"}],"type":"function"},
|
||||||
|
{"constant":false,"inputs":[{"name":"_content","type":"bytes32"}],"name":"unhint","outputs":[],"type":"function"}
|
||||||
|
]
|
4
ethcore/native_contracts/res/validator_report.json
Normal file
4
ethcore/native_contracts/res/validator_report.json
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
[
|
||||||
|
{"constant":false,"inputs":[{"name":"validator","type":"address"},{"name":"blockNumber","type":"uint256"},{"name":"proof","type":"bytes"}],"name":"reportMalicious","outputs":[],"payable":false,"type":"function"},
|
||||||
|
{"constant":false,"inputs":[{"name":"validator","type":"address"},{"name":"blockNumber","type":"uint256"}],"name":"reportBenign","outputs":[],"payable":false,"type":"function"}
|
||||||
|
]
|
5
ethcore/native_contracts/res/validator_set.json
Normal file
5
ethcore/native_contracts/res/validator_set.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
[
|
||||||
|
{"constant":true,"inputs":[],"name":"transitionNonce","outputs":[{"name":"nonce","type":"uint256"}],"payable":false,"type":"function"},
|
||||||
|
{"constant":true,"inputs":[],"name":"getValidators","outputs":[{"name":"validators","type":"address[]"}],"payable":false,"type":"function"},
|
||||||
|
{"anonymous":false,"inputs":[{"indexed":true,"name":"_parent_hash","type":"bytes32"},{"indexed":true,"name":"_nonce","type":"uint256"},{"indexed":false,"name":"_new_set","type":"address[]"}],"name":"ValidatorsChanged","type":"event"}
|
||||||
|
]
|
@ -24,6 +24,7 @@ extern crate ethabi;
|
|||||||
extern crate ethcore_util as util;
|
extern crate ethcore_util as util;
|
||||||
|
|
||||||
mod registry;
|
mod registry;
|
||||||
|
mod urlhint;
|
||||||
mod service_transaction;
|
mod service_transaction;
|
||||||
mod secretstore_acl_storage;
|
mod secretstore_acl_storage;
|
||||||
mod validator_set;
|
mod validator_set;
|
||||||
@ -32,6 +33,7 @@ mod validator_report;
|
|||||||
pub mod test_contracts;
|
pub mod test_contracts;
|
||||||
|
|
||||||
pub use self::registry::Registry;
|
pub use self::registry::Registry;
|
||||||
|
pub use self::urlhint::Urlhint;
|
||||||
pub use self::service_transaction::ServiceTransactionChecker;
|
pub use self::service_transaction::ServiceTransactionChecker;
|
||||||
pub use self::secretstore_acl_storage::SecretStoreAclStorage;
|
pub use self::secretstore_acl_storage::SecretStoreAclStorage;
|
||||||
pub use self::validator_set::ValidatorSet;
|
pub use self::validator_set::ValidatorSet;
|
||||||
|
22
ethcore/native_contracts/src/urlhint.rs
Normal file
22
ethcore/native_contracts/src/urlhint.rs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#![allow(unused_mut, unused_variables, unused_imports)]
|
||||||
|
|
||||||
|
//! Registrar contract: maps names to arbitrary URL.
|
||||||
|
// TODO: testing.
|
||||||
|
|
||||||
|
include!(concat!(env!("OUT_DIR"), "/urlhint.rs"));
|
@ -86,10 +86,7 @@ impl Memory for Vec<u8> {
|
|||||||
fn write_slice(&mut self, offset: U256, slice: &[u8]) {
|
fn write_slice(&mut self, offset: U256, slice: &[u8]) {
|
||||||
let off = offset.low_u64() as usize;
|
let off = offset.low_u64() as usize;
|
||||||
|
|
||||||
// TODO [todr] Optimize?
|
self[off..off+slice.len()].copy_from_slice(slice);
|
||||||
for pos in off..off+slice.len() {
|
|
||||||
self[pos] = slice[pos - off];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write(&mut self, offset: U256, value: U256) {
|
fn write(&mut self, offset: U256, value: U256) {
|
||||||
@ -114,9 +111,13 @@ impl Memory for Vec<u8> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use util::U256;
|
||||||
|
use super::Memory;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_memory_read_and_write() {
|
fn test_memory_read_and_write() {
|
||||||
// given
|
// given
|
||||||
let mem: &mut Memory = &mut vec![];
|
let mem: &mut Memory = &mut vec![];
|
||||||
mem.resize(0x80 + 32);
|
mem.resize(0x80 + 32);
|
||||||
@ -126,10 +127,10 @@ fn test_memory_read_and_write() {
|
|||||||
|
|
||||||
// then
|
// then
|
||||||
assert_eq!(mem.read(U256::from(0x80)), U256::from(0xabcdef));
|
assert_eq!(mem.read(U256::from(0x80)), U256::from(0xabcdef));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_memory_read_and_write_byte() {
|
fn test_memory_read_and_write_byte() {
|
||||||
// given
|
// given
|
||||||
let mem: &mut Memory = &mut vec![];
|
let mem: &mut Memory = &mut vec![];
|
||||||
mem.resize(32);
|
mem.resize(32);
|
||||||
@ -141,4 +142,26 @@ fn test_memory_read_and_write_byte() {
|
|||||||
|
|
||||||
// then
|
// then
|
||||||
assert_eq!(mem.read(U256::from(0x00)), U256::from(0xabcdef));
|
assert_eq!(mem.read(U256::from(0x00)), U256::from(0xabcdef));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_memory_read_slice_and_write_slice() {
|
||||||
|
let mem: &mut Memory = &mut vec![];
|
||||||
|
mem.resize(32);
|
||||||
|
|
||||||
|
{
|
||||||
|
let slice = "abcdefghijklmnopqrstuvwxyz012345".as_bytes();
|
||||||
|
mem.write_slice(U256::from(0), slice);
|
||||||
|
|
||||||
|
assert_eq!(mem.read_slice(U256::from(0), U256::from(32)), slice);
|
||||||
|
}
|
||||||
|
|
||||||
|
// write again
|
||||||
|
{
|
||||||
|
let slice = "67890".as_bytes();
|
||||||
|
mem.write_slice(U256::from(0x1), slice);
|
||||||
|
|
||||||
|
assert_eq!(mem.read_slice(U256::from(0), U256::from(7)), "a67890g".as_bytes());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -7,7 +7,7 @@ version = "1.7.0"
|
|||||||
authors = ["Parity Technologies <admin@parity.io>"]
|
authors = ["Parity Technologies <admin@parity.io>"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ethabi = "1.0.0"
|
ethabi = "1.0.4"
|
||||||
futures = "0.1"
|
futures = "0.1"
|
||||||
log = "0.3"
|
log = "0.3"
|
||||||
mime = "0.2"
|
mime = "0.2"
|
||||||
@ -17,3 +17,4 @@ rustc-serialize = "0.3"
|
|||||||
fetch = { path = "../util/fetch" }
|
fetch = { path = "../util/fetch" }
|
||||||
ethcore-util = { path = "../util" }
|
ethcore-util = { path = "../util" }
|
||||||
parity-reactor = { path = "../util/reactor" }
|
parity-reactor = { path = "../util/reactor" }
|
||||||
|
native-contracts = { path = "../ethcore/native_contracts" }
|
||||||
|
@ -87,55 +87,7 @@ impl From<io::Error> for Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Default Hash-fetching client using on-chain contract to resolve hashes to URLs.
|
fn validate_hash(path: PathBuf, hash: H256, result: Result<Response, FetchError>) -> Result<PathBuf, Error> {
|
||||||
pub struct Client<F: Fetch + 'static = FetchClient> {
|
|
||||||
contract: URLHintContract,
|
|
||||||
fetch: F,
|
|
||||||
remote: Remote,
|
|
||||||
random_path: Arc<Fn() -> PathBuf + Sync + Send>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Client {
|
|
||||||
/// Creates new instance of the `Client` given on-chain contract client and task runner.
|
|
||||||
pub fn new(contract: Arc<ContractClient>, remote: Remote) -> Self {
|
|
||||||
Client::with_fetch(contract, FetchClient::new().unwrap(), remote)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<F: Fetch + 'static> Client<F> {
|
|
||||||
|
|
||||||
/// Creates new instance of the `Client` given on-chain contract client, fetch service and task runner.
|
|
||||||
pub fn with_fetch(contract: Arc<ContractClient>, fetch: F, remote: Remote) -> Self {
|
|
||||||
Client {
|
|
||||||
contract: URLHintContract::new(contract),
|
|
||||||
fetch: fetch,
|
|
||||||
remote: remote,
|
|
||||||
random_path: Arc::new(random_temp_path),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<F: Fetch + 'static> HashFetch for Client<F> {
|
|
||||||
fn fetch(&self, hash: H256, on_done: Box<Fn(Result<PathBuf, Error>) + Send>) {
|
|
||||||
debug!(target: "fetch", "Fetching: {:?}", hash);
|
|
||||||
|
|
||||||
let url = self.contract.resolve(hash.to_vec()).map(|content| match content {
|
|
||||||
URLHintResult::Dapp(dapp) => {
|
|
||||||
dapp.url()
|
|
||||||
},
|
|
||||||
URLHintResult::Content(content) => {
|
|
||||||
content.url
|
|
||||||
},
|
|
||||||
}).ok_or_else(|| Error::NoResolution);
|
|
||||||
|
|
||||||
debug!(target: "fetch", "Resolved {:?} to {:?}. Fetching...", hash, url);
|
|
||||||
|
|
||||||
match url {
|
|
||||||
Err(err) => on_done(Err(err)),
|
|
||||||
Ok(url) => {
|
|
||||||
let random_path = self.random_path.clone();
|
|
||||||
let future = self.fetch.fetch(&url).then(move |result| {
|
|
||||||
fn validate_hash(path: PathBuf, hash: H256, result: Result<Response, FetchError>) -> Result<PathBuf, Error> {
|
|
||||||
let response = result?;
|
let response = result?;
|
||||||
if !response.is_success() {
|
if !response.is_success() {
|
||||||
return Err(Error::InvalidStatus);
|
return Err(Error::InvalidStatus);
|
||||||
@ -155,8 +107,55 @@ impl<F: Fetch + 'static> HashFetch for Client<F> {
|
|||||||
} else {
|
} else {
|
||||||
Ok(path)
|
Ok(path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Default Hash-fetching client using on-chain contract to resolve hashes to URLs.
|
||||||
|
pub struct Client<F: Fetch + 'static = FetchClient> {
|
||||||
|
contract: URLHintContract,
|
||||||
|
fetch: F,
|
||||||
|
remote: Remote,
|
||||||
|
random_path: Arc<Fn() -> PathBuf + Sync + Send>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Client {
|
||||||
|
/// Creates new instance of the `Client` given on-chain contract client and task runner.
|
||||||
|
pub fn new(contract: Arc<ContractClient>, remote: Remote) -> Self {
|
||||||
|
Client::with_fetch(contract, FetchClient::new().unwrap(), remote)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F: Fetch + 'static> Client<F> {
|
||||||
|
/// Creates new instance of the `Client` given on-chain contract client, fetch service and task runner.
|
||||||
|
pub fn with_fetch(contract: Arc<ContractClient>, fetch: F, remote: Remote) -> Self {
|
||||||
|
Client {
|
||||||
|
contract: URLHintContract::new(contract),
|
||||||
|
fetch: fetch,
|
||||||
|
remote: remote,
|
||||||
|
random_path: Arc::new(random_temp_path),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F: Fetch + 'static> HashFetch for Client<F> {
|
||||||
|
fn fetch(&self, hash: H256, on_done: Box<Fn(Result<PathBuf, Error>) + Send>) {
|
||||||
|
debug!(target: "fetch", "Fetching: {:?}", hash);
|
||||||
|
|
||||||
|
let random_path = self.random_path.clone();
|
||||||
|
let remote_fetch = self.fetch.clone();
|
||||||
|
let future = self.contract.resolve(hash.to_vec())
|
||||||
|
.map_err(|e| { warn!("Error resolving URL: {}", e); Error::NoResolution })
|
||||||
|
.and_then(|maybe_url| maybe_url.ok_or(Error::NoResolution))
|
||||||
|
.map(|content| match content {
|
||||||
|
URLHintResult::Dapp(dapp) => {
|
||||||
|
dapp.url()
|
||||||
|
},
|
||||||
|
URLHintResult::Content(content) => {
|
||||||
|
content.url
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.and_then(move |url| {
|
||||||
|
debug!(target: "fetch", "Resolved {:?} to {:?}. Fetching...", hash, url);
|
||||||
|
let future = remote_fetch.fetch(&url).then(move |result| {
|
||||||
debug!(target: "fetch", "Content fetched, validating hash ({:?})", hash);
|
debug!(target: "fetch", "Content fetched, validating hash ({:?})", hash);
|
||||||
let path = random_path();
|
let path = random_path();
|
||||||
let res = validate_hash(path.clone(), hash, result);
|
let res = validate_hash(path.clone(), hash, result);
|
||||||
@ -165,13 +164,13 @@ impl<F: Fetch + 'static> HashFetch for Client<F> {
|
|||||||
// Remove temporary file in case of error
|
// Remove temporary file in case of error
|
||||||
let _ = fs::remove_file(&path);
|
let _ = fs::remove_file(&path);
|
||||||
}
|
}
|
||||||
on_done(res);
|
res
|
||||||
|
|
||||||
Ok(()) as Result<(), ()>
|
|
||||||
});
|
});
|
||||||
self.remote.spawn(self.fetch.process(future));
|
remote_fetch.process(future)
|
||||||
},
|
})
|
||||||
}
|
.then(move |res| { on_done(res); Ok(()) as Result<(), ()> });
|
||||||
|
|
||||||
|
self.remote.spawn(future);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -225,7 +224,7 @@ mod tests {
|
|||||||
let mut registrar = FakeRegistrar::new();
|
let mut registrar = FakeRegistrar::new();
|
||||||
registrar.responses = Mutex::new(vec![
|
registrar.responses = Mutex::new(vec![
|
||||||
Ok(format!("000000000000000000000000{}", URLHINT).from_hex().unwrap()),
|
Ok(format!("000000000000000000000000{}", URLHINT).from_hex().unwrap()),
|
||||||
Ok("00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000deadcafebeefbeefcafedeaddeedfeedffffffff000000000000000000000000000000000000000000000000000000000000003d68747470733a2f2f657468636f72652e696f2f6173736574732f696d616765732f657468636f72652d626c61636b2d686f72697a6f6e74616c2e706e67000000".from_hex().unwrap()),
|
Ok("00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000deadcafebeefbeefcafedeaddeedfeedffffffff000000000000000000000000000000000000000000000000000000000000003c68747470733a2f2f7061726974792e696f2f6173736574732f696d616765732f657468636f72652d626c61636b2d686f72697a6f6e74616c2e706e6700000000".from_hex().unwrap()),
|
||||||
]);
|
]);
|
||||||
registrar
|
registrar
|
||||||
}
|
}
|
||||||
|
@ -25,12 +25,14 @@ extern crate mime;
|
|||||||
|
|
||||||
extern crate ethabi;
|
extern crate ethabi;
|
||||||
extern crate ethcore_util as util;
|
extern crate ethcore_util as util;
|
||||||
pub extern crate fetch;
|
|
||||||
extern crate futures;
|
extern crate futures;
|
||||||
extern crate mime_guess;
|
extern crate mime_guess;
|
||||||
|
extern crate native_contracts;
|
||||||
|
extern crate parity_reactor;
|
||||||
extern crate rand;
|
extern crate rand;
|
||||||
extern crate rustc_serialize;
|
extern crate rustc_serialize;
|
||||||
extern crate parity_reactor;
|
|
||||||
|
pub extern crate fetch;
|
||||||
|
|
||||||
mod client;
|
mod client;
|
||||||
|
|
||||||
|
@ -16,13 +16,13 @@
|
|||||||
|
|
||||||
//! URLHint Contract
|
//! URLHint Contract
|
||||||
|
|
||||||
use std::fmt;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use rustc_serialize::hex::ToHex;
|
use rustc_serialize::hex::ToHex;
|
||||||
use mime::Mime;
|
use mime::Mime;
|
||||||
use mime_guess;
|
use mime_guess;
|
||||||
|
|
||||||
use ethabi::{Interface, Contract, Token};
|
use futures::{future, BoxFuture, Future};
|
||||||
|
use native_contracts::{Registry, Urlhint};
|
||||||
use util::{Address, Bytes, Hashable};
|
use util::{Address, Bytes, Hashable};
|
||||||
|
|
||||||
const COMMIT_LEN: usize = 20;
|
const COMMIT_LEN: usize = 20;
|
||||||
@ -33,7 +33,7 @@ pub trait ContractClient: Send + Sync {
|
|||||||
/// Get registrar address
|
/// Get registrar address
|
||||||
fn registrar(&self) -> Result<Address, String>;
|
fn registrar(&self) -> Result<Address, String>;
|
||||||
/// Call Contract
|
/// Call Contract
|
||||||
fn call(&self, address: Address, data: Bytes) -> Result<Bytes, String>;
|
fn call(&self, address: Address, data: Bytes) -> BoxFuture<Bytes, String>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Github-hosted dapp.
|
/// Github-hosted dapp.
|
||||||
@ -44,7 +44,7 @@ pub struct GithubApp {
|
|||||||
/// Github Repository
|
/// Github Repository
|
||||||
pub repo: String,
|
pub repo: String,
|
||||||
/// Commit on Github
|
/// Commit on Github
|
||||||
pub commit: [u8;COMMIT_LEN],
|
pub commit: [u8; COMMIT_LEN],
|
||||||
/// Dapp owner address
|
/// Dapp owner address
|
||||||
pub owner: Address,
|
pub owner: Address,
|
||||||
}
|
}
|
||||||
@ -94,91 +94,31 @@ pub enum URLHintResult {
|
|||||||
/// URLHint Contract interface
|
/// URLHint Contract interface
|
||||||
pub trait URLHint: Send + Sync {
|
pub trait URLHint: Send + Sync {
|
||||||
/// Resolves given id to registrar entry.
|
/// Resolves given id to registrar entry.
|
||||||
fn resolve(&self, id: Bytes) -> Option<URLHintResult>;
|
fn resolve(&self, id: Bytes) -> BoxFuture<Option<URLHintResult>, String>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `URLHintContract` API
|
/// `URLHintContract` API
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct URLHintContract {
|
pub struct URLHintContract {
|
||||||
urlhint: Contract,
|
urlhint: Arc<Urlhint>,
|
||||||
registrar: Contract,
|
registrar: Registry,
|
||||||
client: Arc<ContractClient>,
|
client: Arc<ContractClient>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl URLHintContract {
|
impl URLHintContract {
|
||||||
/// Creates new `URLHintContract`
|
/// Creates new `URLHintContract`
|
||||||
pub fn new(client: Arc<ContractClient>) -> Self {
|
pub fn new(client: Arc<ContractClient>) -> Self {
|
||||||
let urlhint = Interface::load(include_bytes!("../res/urlhint.json")).expect("urlhint.json is valid ABI");
|
|
||||||
let registrar = Interface::load(include_bytes!("../res/registrar.json")).expect("registrar.json is valid ABI");
|
|
||||||
|
|
||||||
URLHintContract {
|
URLHintContract {
|
||||||
urlhint: Contract::new(urlhint),
|
urlhint: Arc::new(Urlhint::new(Default::default())),
|
||||||
registrar: Contract::new(registrar),
|
registrar: Registry::new(Default::default()),
|
||||||
client: client,
|
client: client,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn urlhint_address(&self) -> Option<Address> {
|
fn decode_urlhint_output(output: (String, ::util::H160, Address)) -> Option<URLHintResult> {
|
||||||
let res = || {
|
let (account_slash_repo, commit, owner) = output;
|
||||||
let get_address = self.registrar.function("getAddress".into()).map_err(as_string)?;
|
|
||||||
let params = get_address.encode_call(
|
|
||||||
vec![Token::FixedBytes((*"githubhint".sha3()).to_vec()), Token::String("A".into())]
|
|
||||||
).map_err(as_string)?;
|
|
||||||
let output = self.client.call(self.client.registrar()?, params)?;
|
|
||||||
let result = get_address.decode_output(output).map_err(as_string)?;
|
|
||||||
|
|
||||||
match result.get(0) {
|
|
||||||
Some(&Token::Address(address)) if address != *Address::default() => Ok(address.into()),
|
|
||||||
Some(&Token::Address(_)) => Err(format!("Contract not found.")),
|
|
||||||
e => Err(format!("Invalid result: {:?}", e)),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
match res() {
|
|
||||||
Ok(res) => Some(res),
|
|
||||||
Err(e) => {
|
|
||||||
warn!(target: "dapps", "Error while calling registrar: {:?}", e);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn encode_urlhint_call(&self, id: Bytes) -> Option<Bytes> {
|
|
||||||
let call = self.urlhint
|
|
||||||
.function("entries".into())
|
|
||||||
.and_then(|f| f.encode_call(vec![Token::FixedBytes(id)]));
|
|
||||||
|
|
||||||
match call {
|
|
||||||
Ok(res) => {
|
|
||||||
Some(res)
|
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
warn!(target: "dapps", "Error while encoding urlhint call: {:?}", e);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn decode_urlhint_output(&self, output: Bytes) -> Option<URLHintResult> {
|
|
||||||
trace!(target: "dapps", "Output: {:?}", output.to_hex());
|
|
||||||
let output = self.urlhint
|
|
||||||
.function("entries".into())
|
|
||||||
.and_then(|f| f.decode_output(output));
|
|
||||||
|
|
||||||
if let Ok(vec) = output {
|
|
||||||
if vec.len() != 3 {
|
|
||||||
warn!(target: "dapps", "Invalid contract output: {:?}", vec);
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut it = vec.into_iter();
|
|
||||||
let account_slash_repo = it.next().expect("element 0 of 3-len vector known to exist; qed");
|
|
||||||
let commit = it.next().expect("element 1 of 3-len vector known to exist; qed");
|
|
||||||
let owner = it.next().expect("element 2 of 3-len vector known to exist qed");
|
|
||||||
|
|
||||||
match (account_slash_repo, commit, owner) {
|
|
||||||
(Token::String(account_slash_repo), Token::FixedBytes(commit), Token::Address(owner)) => {
|
|
||||||
let owner = owner.into();
|
|
||||||
if owner == Address::default() {
|
if owner == Address::default() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
@ -207,33 +147,38 @@ impl URLHintContract {
|
|||||||
commit: commit,
|
commit: commit,
|
||||||
owner: owner,
|
owner: owner,
|
||||||
}))
|
}))
|
||||||
},
|
|
||||||
e => {
|
|
||||||
warn!(target: "dapps", "Invalid contract output parameters: {:?}", e);
|
|
||||||
None
|
|
||||||
},
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
warn!(target: "dapps", "Invalid contract output: {:?}", output);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl URLHint for URLHintContract {
|
impl URLHint for URLHintContract {
|
||||||
fn resolve(&self, id: Bytes) -> Option<URLHintResult> {
|
fn resolve(&self, id: Bytes) -> BoxFuture<Option<URLHintResult>, String> {
|
||||||
self.urlhint_address().and_then(|address| {
|
use futures::future::Either;
|
||||||
// Prepare contract call
|
|
||||||
self.encode_urlhint_call(id)
|
let do_call = |_, data| {
|
||||||
.and_then(|data| {
|
let addr = match self.client.registrar() {
|
||||||
let call = self.client.call(address, data);
|
Ok(addr) => addr,
|
||||||
if let Err(ref e) = call {
|
Err(e) => return future::err(e).boxed(),
|
||||||
warn!(target: "dapps", "Error while calling urlhint: {:?}", e);
|
};
|
||||||
|
|
||||||
|
self.client.call(addr, data)
|
||||||
|
};
|
||||||
|
|
||||||
|
let urlhint = self.urlhint.clone();
|
||||||
|
let client = self.client.clone();
|
||||||
|
self.registrar.get_address(do_call, "githubhint".sha3(), "A".into())
|
||||||
|
.map(|addr| if addr == Address::default() { None } else { Some(addr) })
|
||||||
|
.and_then(move |address| {
|
||||||
|
let mut fixed_id = [0; 32];
|
||||||
|
let len = ::std::cmp::min(32, id.len());
|
||||||
|
fixed_id[..len].copy_from_slice(&id[..len]);
|
||||||
|
|
||||||
|
match address {
|
||||||
|
None => Either::A(future::ok(None)),
|
||||||
|
Some(address) => {
|
||||||
|
let do_call = move |_, data| client.call(address, data);
|
||||||
|
Either::B(urlhint.entries(do_call, ::util::H256(fixed_id)).map(decode_urlhint_output))
|
||||||
}
|
}
|
||||||
call.ok()
|
}
|
||||||
})
|
}).boxed()
|
||||||
.and_then(|output| self.decode_urlhint_output(output))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,16 +205,14 @@ fn guess_mime_type(url: &str) -> Option<Mime> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_string<T: fmt::Debug>(e: T) -> String {
|
|
||||||
format!("{:?}", e)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub mod tests {
|
pub mod tests {
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use rustc_serialize::hex::FromHex;
|
use rustc_serialize::hex::FromHex;
|
||||||
|
|
||||||
|
use futures::{BoxFuture, Future, IntoFuture};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use super::guess_mime_type;
|
use super::guess_mime_type;
|
||||||
use util::{Bytes, Address, Mutex, ToPretty};
|
use util::{Bytes, Address, Mutex, ToPretty};
|
||||||
@ -297,14 +240,14 @@ pub mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ContractClient for FakeRegistrar {
|
impl ContractClient for FakeRegistrar {
|
||||||
|
|
||||||
fn registrar(&self) -> Result<Address, String> {
|
fn registrar(&self) -> Result<Address, String> {
|
||||||
Ok(REGISTRAR.parse().unwrap())
|
Ok(REGISTRAR.parse().unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call(&self, address: Address, data: Bytes) -> Result<Bytes, String> {
|
fn call(&self, address: Address, data: Bytes) -> BoxFuture<Bytes, String> {
|
||||||
self.calls.lock().push((address.to_hex(), data.to_hex()));
|
self.calls.lock().push((address.to_hex(), data.to_hex()));
|
||||||
self.responses.lock().remove(0)
|
let res = self.responses.lock().remove(0);
|
||||||
|
res.into_future().boxed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -312,11 +255,19 @@ pub mod tests {
|
|||||||
fn should_call_registrar_and_urlhint_contracts() {
|
fn should_call_registrar_and_urlhint_contracts() {
|
||||||
// given
|
// given
|
||||||
let registrar = FakeRegistrar::new();
|
let registrar = FakeRegistrar::new();
|
||||||
|
let resolve_result = {
|
||||||
|
use ethabi::{Encoder, Token};
|
||||||
|
Encoder::encode(vec![Token::String(String::new()), Token::FixedBytes(vec![0; 20]), Token::Address([0; 20])])
|
||||||
|
};
|
||||||
|
registrar.responses.lock()[1] = Ok(resolve_result);
|
||||||
|
|
||||||
let calls = registrar.calls.clone();
|
let calls = registrar.calls.clone();
|
||||||
let urlhint = URLHintContract::new(Arc::new(registrar));
|
let urlhint = URLHintContract::new(Arc::new(registrar));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// when
|
// when
|
||||||
let res = urlhint.resolve("test".bytes().collect());
|
let res = urlhint.resolve("test".bytes().collect()).wait().unwrap();
|
||||||
let calls = calls.lock();
|
let calls = calls.lock();
|
||||||
let call0 = calls.get(0).expect("Registrar resolve called");
|
let call0 = calls.get(0).expect("Registrar resolve called");
|
||||||
let call1 = calls.get(1).expect("URLHint Resolve called");
|
let call1 = calls.get(1).expect("URLHint Resolve called");
|
||||||
@ -344,7 +295,7 @@ pub mod tests {
|
|||||||
let urlhint = URLHintContract::new(Arc::new(registrar));
|
let urlhint = URLHintContract::new(Arc::new(registrar));
|
||||||
|
|
||||||
// when
|
// when
|
||||||
let res = urlhint.resolve("test".bytes().collect());
|
let res = urlhint.resolve("test".bytes().collect()).wait().unwrap();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assert_eq!(res, Some(URLHintResult::Dapp(GithubApp {
|
assert_eq!(res, Some(URLHintResult::Dapp(GithubApp {
|
||||||
@ -361,12 +312,12 @@ pub mod tests {
|
|||||||
let mut registrar = FakeRegistrar::new();
|
let mut registrar = FakeRegistrar::new();
|
||||||
registrar.responses = Mutex::new(vec![
|
registrar.responses = Mutex::new(vec![
|
||||||
Ok(format!("000000000000000000000000{}", URLHINT).from_hex().unwrap()),
|
Ok(format!("000000000000000000000000{}", URLHINT).from_hex().unwrap()),
|
||||||
Ok("00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000deadcafebeefbeefcafedeaddeedfeedffffffff000000000000000000000000000000000000000000000000000000000000003d68747470733a2f2f657468636f72652e696f2f6173736574732f696d616765732f657468636f72652d626c61636b2d686f72697a6f6e74616c2e706e67000000".from_hex().unwrap()),
|
Ok("00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000deadcafebeefbeefcafedeaddeedfeedffffffff000000000000000000000000000000000000000000000000000000000000003c68747470733a2f2f7061726974792e696f2f6173736574732f696d616765732f657468636f72652d626c61636b2d686f72697a6f6e74616c2e706e6700000000".from_hex().unwrap()),
|
||||||
]);
|
]);
|
||||||
let urlhint = URLHintContract::new(Arc::new(registrar));
|
let urlhint = URLHintContract::new(Arc::new(registrar));
|
||||||
|
|
||||||
// when
|
// when
|
||||||
let res = urlhint.resolve("test".bytes().collect());
|
let res = urlhint.resolve("test".bytes().collect()).wait().unwrap();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assert_eq!(res, Some(URLHintResult::Content(Content {
|
assert_eq!(res, Some(URLHintResult::Content(Content {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "parity.js",
|
"name": "parity.js",
|
||||||
"version": "1.7.78",
|
"version": "1.7.80",
|
||||||
"main": "release/index.js",
|
"main": "release/index.js",
|
||||||
"jsnext:main": "src/index.js",
|
"jsnext:main": "src/index.js",
|
||||||
"author": "Parity Team <admin@parity.io>",
|
"author": "Parity Team <admin@parity.io>",
|
||||||
|
@ -49,7 +49,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.info {
|
.info {
|
||||||
margin-top: 2em;
|
margin-top: 1em;
|
||||||
line-height: 1.618em
|
line-height: 1.618em
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,6 +59,13 @@
|
|||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.timestamp {
|
||||||
|
background: rgba(255, 255, 255, 0.1);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||||
|
margin: 0.75em 0;
|
||||||
|
padding: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
.btnrow {
|
.btnrow {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
padding: 0 4em;
|
padding: 0 4em;
|
||||||
|
@ -94,9 +94,16 @@ class Connection extends Component {
|
|||||||
} }
|
} }
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div className={ styles.timestamp }>
|
||||||
|
<FormattedMessage
|
||||||
|
id='connection.timestamp'
|
||||||
|
defaultMessage='Ensure that both the Parity node and this machine connecting have computer clocks in-sync with each other and with a timestamp server, ensuring both successful token validation and block operations.'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div className={ styles.form }>
|
<div className={ styles.form }>
|
||||||
<Input
|
<Input
|
||||||
className={ styles.formInput }
|
className={ styles.formInput }
|
||||||
|
autoFocus
|
||||||
disabled={ loading }
|
disabled={ loading }
|
||||||
error={
|
error={
|
||||||
validToken || (!token || !token.length)
|
validToken || (!token || !token.length)
|
||||||
|
@ -79,7 +79,7 @@ class FirstRun extends Component {
|
|||||||
visible: PropTypes.bool.isRequired
|
visible: PropTypes.bool.isRequired
|
||||||
}
|
}
|
||||||
|
|
||||||
createStore = new CreateStore(this.context.api, {}, false);
|
createStore = new CreateStore(this.context.api, {}, true, false);
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
stage: 0,
|
stage: 0,
|
||||||
|
@ -39,21 +39,6 @@ const TYPES = [
|
|||||||
),
|
),
|
||||||
key: 'fromNew'
|
key: 'fromNew'
|
||||||
},
|
},
|
||||||
{
|
|
||||||
description: (
|
|
||||||
<FormattedMessage
|
|
||||||
id='createAccount.creationType.fromPhrase.description'
|
|
||||||
defaultMessage='Recover using a previously stored recovery phrase and new password'
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
label: (
|
|
||||||
<FormattedMessage
|
|
||||||
id='createAccount.creationType.fromPhrase.label'
|
|
||||||
defaultMessage='Recovery phrase'
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
key: 'fromPhrase'
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
description: (
|
description: (
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
|
@ -18,7 +18,7 @@ import { observer } from 'mobx-react';
|
|||||||
import React, { Component, PropTypes } from 'react';
|
import React, { Component, PropTypes } from 'react';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
import { Checkbox, Form, Input } from '@parity/ui';
|
import { Checkbox, Form, Input, Warning } from '@parity/ui';
|
||||||
import PasswordStrength from '@parity/ui/Form/PasswordStrength';
|
import PasswordStrength from '@parity/ui/Form/PasswordStrength';
|
||||||
|
|
||||||
import ChangeVault from '../ChangeVault';
|
import ChangeVault from '../ChangeVault';
|
||||||
@ -32,12 +32,24 @@ export default class RecoveryPhrase extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { isWindowsPhrase, name, nameError, password, passwordRepeat, passwordRepeatError, passwordHint, phrase } = this.props.createStore;
|
const { isWindowsPhrase, name, nameError, passPhraseError, password, passwordRepeat, passwordRepeatError, passwordHint, phrase } = this.props.createStore;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<div className={ styles.details }>
|
||||||
|
{ this.renderWarning() }
|
||||||
<Form>
|
<Form>
|
||||||
<Input
|
<Input
|
||||||
autoFocus
|
autoFocus
|
||||||
|
error={
|
||||||
|
passPhraseError
|
||||||
|
? (
|
||||||
|
<FormattedMessage
|
||||||
|
id='createAccount.recoveryPhrase.passPhrase.error'
|
||||||
|
defaultMessage='enter a recovery phrase'
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
: null
|
||||||
|
}
|
||||||
hint={
|
hint={
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='createAccount.recoveryPhrase.phrase.hint'
|
id='createAccount.recoveryPhrase.phrase.hint'
|
||||||
@ -141,12 +153,68 @@ export default class RecoveryPhrase extends Component {
|
|||||||
defaultMessage='Key was created with Parity <1.4.5 on Windows'
|
defaultMessage='Key was created with Parity <1.4.5 on Windows'
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
onClick={ this.onToggleWindowsPhrase }
|
onCheck={ this.onToggleWindowsPhrase }
|
||||||
/>
|
/>
|
||||||
</Form>
|
</Form>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderWarning () {
|
||||||
|
const { isTest, phrase } = this.props.createStore;
|
||||||
|
|
||||||
|
if (!isTest && phrase.length === 0) {
|
||||||
|
return (
|
||||||
|
<Warning
|
||||||
|
warning={
|
||||||
|
<FormattedMessage
|
||||||
|
id='createAccount.recoveryPhrase.warning.emptyPhrase'
|
||||||
|
defaultMessage={ `The recovery phrase is empty.
|
||||||
|
This account can be recovered by anyone.
|
||||||
|
` }
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (phrase.length === 0) {
|
||||||
|
return (
|
||||||
|
<Warning
|
||||||
|
warning={
|
||||||
|
<FormattedMessage
|
||||||
|
id='createAccount.recoveryPhrase.warning.testnetEmptyPhrase'
|
||||||
|
defaultMessage={ `The recovery phrase is empty.
|
||||||
|
This account can be recovered by anyone.
|
||||||
|
Proceed with caution.
|
||||||
|
` }
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const words = phrase.split(' ');
|
||||||
|
|
||||||
|
if (words.length < 11) {
|
||||||
|
return (
|
||||||
|
<Warning
|
||||||
|
warning={
|
||||||
|
<FormattedMessage
|
||||||
|
id='createAccount.recoveryPhrase.warning.shortPhrase'
|
||||||
|
defaultMessage={ `The recovery phrase is less than 11 words.
|
||||||
|
This account has not been generated by Parity and might be insecure.
|
||||||
|
Proceed with caution.
|
||||||
|
` }
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
onToggleWindowsPhrase = (event) => {
|
onToggleWindowsPhrase = (event) => {
|
||||||
const { createStore } = this.props;
|
const { createStore } = this.props;
|
||||||
|
|
||||||
|
@ -63,8 +63,14 @@ const TITLES = {
|
|||||||
),
|
),
|
||||||
import: (
|
import: (
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='createAccount.title.importWallet'
|
id='createAccount.title.importAccount'
|
||||||
defaultMessage='import wallet'
|
defaultMessage='import account'
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
restore: (
|
||||||
|
<FormattedMessage
|
||||||
|
id='createAccount.title.restoreAccount'
|
||||||
|
defaultMessage='restore account'
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
qr: (
|
qr: (
|
||||||
@ -76,25 +82,37 @@ const TITLES = {
|
|||||||
};
|
};
|
||||||
const STAGE_NAMES = [TITLES.type, TITLES.create, TITLES.info];
|
const STAGE_NAMES = [TITLES.type, TITLES.create, TITLES.info];
|
||||||
const STAGE_IMPORT = [TITLES.type, TITLES.import, TITLES.info];
|
const STAGE_IMPORT = [TITLES.type, TITLES.import, TITLES.info];
|
||||||
|
const STAGE_RESTORE = [TITLES.restore, TITLES.info];
|
||||||
const STAGE_QR = [TITLES.type, TITLES.qr, TITLES.info];
|
const STAGE_QR = [TITLES.type, TITLES.qr, TITLES.info];
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
class CreateAccount extends Component {
|
class CreateAccount extends Component {
|
||||||
static contextTypes = {
|
static contextTypes = {
|
||||||
api: PropTypes.object.isRequired
|
api: PropTypes.object.isRequired
|
||||||
}
|
};
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
accounts: PropTypes.object.isRequired,
|
accounts: PropTypes.object.isRequired,
|
||||||
|
isTest: PropTypes.bool.isRequired,
|
||||||
newError: PropTypes.func.isRequired,
|
newError: PropTypes.func.isRequired,
|
||||||
onClose: PropTypes.func,
|
onClose: PropTypes.func,
|
||||||
onUpdate: PropTypes.func
|
onUpdate: PropTypes.func,
|
||||||
}
|
restore: PropTypes.bool
|
||||||
|
};
|
||||||
|
|
||||||
createStore = new Store(this.context.api, this.props.accounts);
|
static defaultProps = {
|
||||||
|
restore: false
|
||||||
|
};
|
||||||
|
|
||||||
|
createStore = new Store(this.context.api, this.props.accounts, this.props.isTest);
|
||||||
vaultStore = VaultStore.get(this.context.api);
|
vaultStore = VaultStore.get(this.context.api);
|
||||||
|
|
||||||
componentWillMount () {
|
componentWillMount () {
|
||||||
|
if (this.props.restore) {
|
||||||
|
this.createStore.setCreateType('fromPhrase');
|
||||||
|
this.createStore.nextStage();
|
||||||
|
}
|
||||||
|
|
||||||
return this.vaultStore.loadVaults();
|
return this.vaultStore.loadVaults();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,6 +125,8 @@ class CreateAccount extends Component {
|
|||||||
steps = STAGE_NAMES;
|
steps = STAGE_NAMES;
|
||||||
} else if (createType === 'fromQr') {
|
} else if (createType === 'fromQr') {
|
||||||
steps = STAGE_QR;
|
steps = STAGE_QR;
|
||||||
|
} else if (createType === 'fromPhrase') {
|
||||||
|
steps = STAGE_RESTORE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -199,6 +219,7 @@ class CreateAccount extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderDialogActions () {
|
renderDialogActions () {
|
||||||
|
const { restore } = this.props;
|
||||||
const { createType, canCreate, isBusy, stage } = this.createStore;
|
const { createType, canCreate, isBusy, stage } = this.createStore;
|
||||||
|
|
||||||
const cancelBtn = (
|
const cancelBtn = (
|
||||||
@ -215,6 +236,22 @@ class CreateAccount extends Component {
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const backBtn = restore
|
||||||
|
? null
|
||||||
|
: (
|
||||||
|
<Button
|
||||||
|
icon={ <PrevIcon /> }
|
||||||
|
key='back'
|
||||||
|
label={
|
||||||
|
<FormattedMessage
|
||||||
|
id='createAccount.button.back'
|
||||||
|
defaultMessage='Back'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
onClick={ this.createStore.prevStage }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
switch (stage) {
|
switch (stage) {
|
||||||
case STAGE_SELECT_TYPE:
|
case STAGE_SELECT_TYPE:
|
||||||
return [
|
return [
|
||||||
@ -235,17 +272,7 @@ class CreateAccount extends Component {
|
|||||||
case STAGE_CREATE:
|
case STAGE_CREATE:
|
||||||
return [
|
return [
|
||||||
cancelBtn,
|
cancelBtn,
|
||||||
<Button
|
backBtn,
|
||||||
icon={ <PrevIcon /> }
|
|
||||||
key='back'
|
|
||||||
label={
|
|
||||||
<FormattedMessage
|
|
||||||
id='createAccount.button.back'
|
|
||||||
defaultMessage='Back'
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
onClick={ this.createStore.prevStage }
|
|
||||||
/>,
|
|
||||||
<Button
|
<Button
|
||||||
disabled={ !canCreate || isBusy }
|
disabled={ !canCreate || isBusy }
|
||||||
icon={ <CheckIcon /> }
|
icon={ <CheckIcon /> }
|
||||||
@ -335,6 +362,12 @@ class CreateAccount extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function mapStateToProps (state) {
|
||||||
|
const { isTest } = state.nodeStatus;
|
||||||
|
|
||||||
|
return { isTest };
|
||||||
|
}
|
||||||
|
|
||||||
function mapDispatchToProps (dispatch) {
|
function mapDispatchToProps (dispatch) {
|
||||||
return bindActionCreators({
|
return bindActionCreators({
|
||||||
newError
|
newError
|
||||||
@ -342,6 +375,6 @@ function mapDispatchToProps (dispatch) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default connect(
|
export default connect(
|
||||||
null,
|
mapStateToProps,
|
||||||
mapDispatchToProps
|
mapDispatchToProps
|
||||||
)(CreateAccount);
|
)(CreateAccount);
|
||||||
|
@ -54,7 +54,11 @@ function createRedux () {
|
|||||||
dispatch: sinon.stub(),
|
dispatch: sinon.stub(),
|
||||||
subscribe: sinon.stub(),
|
subscribe: sinon.stub(),
|
||||||
getState: () => {
|
getState: () => {
|
||||||
return {};
|
return {
|
||||||
|
nodeStatus: {
|
||||||
|
isTest: true
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -50,9 +50,10 @@ export default class Store {
|
|||||||
@observable walletFileError = ERRORS.noFile;
|
@observable walletFileError = ERRORS.noFile;
|
||||||
@observable walletJson = '';
|
@observable walletJson = '';
|
||||||
|
|
||||||
constructor (api, accounts, loadGeth = true) {
|
constructor (api, accounts, isTest, loadGeth = true) {
|
||||||
this._api = api;
|
this._api = api;
|
||||||
this.accounts = Object.assign({}, accounts);
|
this.accounts = Object.assign({}, accounts);
|
||||||
|
this.isTest = isTest;
|
||||||
|
|
||||||
if (loadGeth) {
|
if (loadGeth) {
|
||||||
this.loadAvailableGethAccounts();
|
this.loadAvailableGethAccounts();
|
||||||
@ -72,7 +73,7 @@ export default class Store {
|
|||||||
return !(this.nameError || this.passwordRepeatError) && this.hasAddress;
|
return !(this.nameError || this.passwordRepeatError) && this.hasAddress;
|
||||||
|
|
||||||
case 'fromPhrase':
|
case 'fromPhrase':
|
||||||
return !(this.nameError || this.passwordRepeatError);
|
return !(this.nameError || this.passwordRepeatError || this.passPhraseError);
|
||||||
|
|
||||||
case 'fromQr':
|
case 'fromQr':
|
||||||
return this.qrAddressValid && !this.nameError;
|
return this.qrAddressValid && !this.nameError;
|
||||||
@ -85,6 +86,10 @@ export default class Store {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@computed get passPhraseError () {
|
||||||
|
return !this.isTest && this.phrase.length === 0;
|
||||||
|
}
|
||||||
|
|
||||||
@computed get hasAddress () {
|
@computed get hasAddress () {
|
||||||
return !!(this.address);
|
return !!(this.address);
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ function createStore (loadGeth) {
|
|||||||
createVaultStore();
|
createVaultStore();
|
||||||
|
|
||||||
api = createApi();
|
api = createApi();
|
||||||
store = new Store(api, ACCOUNTS, loadGeth);
|
store = new Store(api, ACCOUNTS, true, loadGeth);
|
||||||
|
|
||||||
return store;
|
return store;
|
||||||
}
|
}
|
||||||
|
@ -54,6 +54,7 @@ class Accounts extends Component {
|
|||||||
newDialog: false,
|
newDialog: false,
|
||||||
newWalletDialog: false,
|
newWalletDialog: false,
|
||||||
newExportDialog: false,
|
newExportDialog: false,
|
||||||
|
restoreDialog: false,
|
||||||
sortOrder: '',
|
sortOrder: '',
|
||||||
searchValues: [],
|
searchValues: [],
|
||||||
searchTokens: [],
|
searchTokens: [],
|
||||||
@ -97,6 +98,7 @@ class Accounts extends Component {
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{ this.renderNewDialog() }
|
{ this.renderNewDialog() }
|
||||||
|
{ this.renderRestoreDialog() }
|
||||||
{ this.renderNewWalletDialog() }
|
{ this.renderNewWalletDialog() }
|
||||||
{ this.renderNewExportDialog() }
|
{ this.renderNewExportDialog() }
|
||||||
{ this.renderActionbar() }
|
{ this.renderActionbar() }
|
||||||
@ -260,6 +262,17 @@ class Accounts extends Component {
|
|||||||
}
|
}
|
||||||
onClick={ this.onNewWalletClick }
|
onClick={ this.onNewWalletClick }
|
||||||
/>,
|
/>,
|
||||||
|
<Button
|
||||||
|
key='restoreAccount'
|
||||||
|
icon={ <AddIcon /> }
|
||||||
|
label={
|
||||||
|
<FormattedMessage
|
||||||
|
id='accounts.button.restoreAccount'
|
||||||
|
defaultMessage='restore'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
onClick={ this.onRestoreAccountClick }
|
||||||
|
/>,
|
||||||
<Button
|
<Button
|
||||||
key='newExport'
|
key='newExport'
|
||||||
icon={ <FileDownloadIcon /> }
|
icon={ <FileDownloadIcon /> }
|
||||||
@ -301,7 +314,23 @@ class Accounts extends Component {
|
|||||||
<CreateAccount
|
<CreateAccount
|
||||||
accounts={ accounts }
|
accounts={ accounts }
|
||||||
onClose={ this.onNewAccountClose }
|
onClose={ this.onNewAccountClose }
|
||||||
onUpdate={ this.onNewAccountUpdate }
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderRestoreDialog () {
|
||||||
|
const { accounts } = this.props;
|
||||||
|
const { restoreDialog } = this.state;
|
||||||
|
|
||||||
|
if (!restoreDialog) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<CreateAccount
|
||||||
|
accounts={ accounts }
|
||||||
|
onClose={ this.onRestoreAccountClose }
|
||||||
|
restore
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -349,6 +378,12 @@ class Accounts extends Component {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onRestoreAccountClick = () => {
|
||||||
|
this.setState({
|
||||||
|
restoreDialog: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
onNewWalletClick = () => {
|
onNewWalletClick = () => {
|
||||||
this.setState({
|
this.setState({
|
||||||
newWalletDialog: true
|
newWalletDialog: true
|
||||||
@ -367,6 +402,12 @@ class Accounts extends Component {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onRestoreAccountClose = () => {
|
||||||
|
this.setState({
|
||||||
|
restoreDialog: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
onNewWalletClose = () => {
|
onNewWalletClose = () => {
|
||||||
this.setState({
|
this.setState({
|
||||||
newWalletDialog: false
|
newWalletDialog: false
|
||||||
@ -379,9 +420,6 @@ class Accounts extends Component {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onNewAccountUpdate = () => {
|
|
||||||
}
|
|
||||||
|
|
||||||
onHardwareChange = () => {
|
onHardwareChange = () => {
|
||||||
const { accountsInfo } = this.props;
|
const { accountsInfo } = this.props;
|
||||||
const { wallets } = this.hwstore;
|
const { wallets } = this.hwstore;
|
||||||
|
@ -20,12 +20,16 @@ use std::sync::Arc;
|
|||||||
use dir::default_data_path;
|
use dir::default_data_path;
|
||||||
use ethcore::client::{Client, BlockChainClient, BlockId};
|
use ethcore::client::{Client, BlockChainClient, BlockId};
|
||||||
use ethcore::transaction::{Transaction, Action};
|
use ethcore::transaction::{Transaction, Action};
|
||||||
|
use ethsync::LightSync;
|
||||||
|
use futures::{future, IntoFuture, Future, BoxFuture};
|
||||||
use hash_fetch::fetch::Client as FetchClient;
|
use hash_fetch::fetch::Client as FetchClient;
|
||||||
use hash_fetch::urlhint::ContractClient;
|
use hash_fetch::urlhint::ContractClient;
|
||||||
use helpers::replace_home;
|
use helpers::replace_home;
|
||||||
|
use light::client::Client as LightClient;
|
||||||
|
use light::on_demand::{self, OnDemand};
|
||||||
use rpc_apis::SignerService;
|
use rpc_apis::SignerService;
|
||||||
use parity_reactor;
|
use parity_reactor;
|
||||||
use util::{Bytes, Address, U256};
|
use util::{Bytes, Address};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct Configuration {
|
pub struct Configuration {
|
||||||
@ -60,23 +64,62 @@ impl ContractClient for FullRegistrar {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call(&self, address: Address, data: Bytes) -> Result<Bytes, String> {
|
fn call(&self, address: Address, data: Bytes) -> BoxFuture<Bytes, String> {
|
||||||
let from = Address::default();
|
self.client.call_contract(BlockId::Latest, address, data)
|
||||||
let transaction = Transaction {
|
.into_future()
|
||||||
nonce: self.client.latest_nonce(&from),
|
.boxed()
|
||||||
action: Action::Call(address),
|
}
|
||||||
gas: U256::from(50_000_000),
|
}
|
||||||
gas_price: U256::default(),
|
|
||||||
value: U256::default(),
|
|
||||||
data: data,
|
|
||||||
}.fake_sign(from);
|
|
||||||
|
|
||||||
self.client.call(&transaction, BlockId::Latest, Default::default())
|
/// Registrar implementation for the light client.
|
||||||
.map_err(|e| format!("{:?}", e))
|
pub struct LightRegistrar {
|
||||||
.map(|executed| {
|
/// The light client.
|
||||||
executed.output
|
pub client: Arc<LightClient>,
|
||||||
|
/// Handle to the on-demand service.
|
||||||
|
pub on_demand: Arc<OnDemand>,
|
||||||
|
/// Handle to the light network service.
|
||||||
|
pub sync: Arc<LightSync>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ContractClient for LightRegistrar {
|
||||||
|
fn registrar(&self) -> Result<Address, String> {
|
||||||
|
self.client.engine().additional_params().get("registrar")
|
||||||
|
.ok_or_else(|| "Registrar not defined.".into())
|
||||||
|
.and_then(|registrar| {
|
||||||
|
registrar.parse().map_err(|e| format!("Invalid registrar address: {:?}", e))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn call(&self, address: Address, data: Bytes) -> BoxFuture<Bytes, String> {
|
||||||
|
let (header, env_info) = (self.client.best_block_header(), self.client.latest_env_info());
|
||||||
|
|
||||||
|
let maybe_future = self.sync.with_context(move |ctx| {
|
||||||
|
self.on_demand
|
||||||
|
.transaction_proof(ctx, on_demand::request::TransactionProof {
|
||||||
|
tx: Transaction {
|
||||||
|
nonce: self.client.engine().account_start_nonce(),
|
||||||
|
action: Action::Call(address),
|
||||||
|
gas: 50_000_000.into(),
|
||||||
|
gas_price: 0.into(),
|
||||||
|
value: 0.into(),
|
||||||
|
data: data,
|
||||||
|
}.fake_sign(Address::default()),
|
||||||
|
header: header,
|
||||||
|
env_info: env_info,
|
||||||
|
engine: self.client.engine().clone(),
|
||||||
|
})
|
||||||
|
.then(|res| match res {
|
||||||
|
Ok(Ok(executed)) => Ok(executed.output),
|
||||||
|
Ok(Err(e)) => Err(format!("Failed to execute transaction: {}", e)),
|
||||||
|
Err(_) => Err(format!("On-demand service dropped request unexpectedly.")),
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
match maybe_future {
|
||||||
|
Some(fut) => fut.boxed(),
|
||||||
|
None => future::err("cannot query registry: network disabled".into()).boxed(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: light client implementation forwarding to OnDemand and waiting for future
|
// TODO: light client implementation forwarding to OnDemand and waiting for future
|
||||||
|
@ -279,7 +279,7 @@ fn execute_light(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) ->
|
|||||||
secret_store: account_provider,
|
secret_store: account_provider,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
settings: Arc::new(cmd.net_settings),
|
settings: Arc::new(cmd.net_settings),
|
||||||
on_demand: on_demand,
|
on_demand: on_demand.clone(),
|
||||||
cache: cache,
|
cache: cache,
|
||||||
transaction_queue: txq,
|
transaction_queue: txq,
|
||||||
dapps_interface: match cmd.dapps_conf.enabled {
|
dapps_interface: match cmd.dapps_conf.enabled {
|
||||||
@ -290,7 +290,7 @@ fn execute_light(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) ->
|
|||||||
true => Some(cmd.http_conf.port),
|
true => Some(cmd.http_conf.port),
|
||||||
false => None,
|
false => None,
|
||||||
},
|
},
|
||||||
fetch: fetch,
|
fetch: fetch.clone(),
|
||||||
geth_compatibility: cmd.geth_compatibility,
|
geth_compatibility: cmd.geth_compatibility,
|
||||||
remote: event_loop.remote(),
|
remote: event_loop.remote(),
|
||||||
});
|
});
|
||||||
@ -301,9 +301,29 @@ fn execute_light(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) ->
|
|||||||
stats: rpc_stats.clone(),
|
stats: rpc_stats.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// the dapps server
|
||||||
|
let dapps_deps = {
|
||||||
|
let contract_client = Arc::new(::dapps::LightRegistrar {
|
||||||
|
client: service.client().clone(),
|
||||||
|
sync: light_sync.clone(),
|
||||||
|
on_demand: on_demand,
|
||||||
|
});
|
||||||
|
|
||||||
|
let sync = light_sync.clone();
|
||||||
|
dapps::Dependencies {
|
||||||
|
sync_status: Arc::new(move || sync.is_major_importing()),
|
||||||
|
contract_client: contract_client,
|
||||||
|
remote: event_loop.raw_remote(),
|
||||||
|
fetch: fetch,
|
||||||
|
signer: deps_for_rpc_apis.signer_service.clone(),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let dapps_middleware = dapps::new(cmd.dapps_conf.clone(), dapps_deps)?;
|
||||||
|
|
||||||
// start rpc servers
|
// start rpc servers
|
||||||
let _ws_server = rpc::new_ws(cmd.ws_conf, &dependencies)?;
|
let _ws_server = rpc::new_ws(cmd.ws_conf, &dependencies)?;
|
||||||
let _http_server = rpc::new_http(cmd.http_conf.clone(), &dependencies, None)?;
|
let _http_server = rpc::new_http(cmd.http_conf.clone(), &dependencies, dapps_middleware)?;
|
||||||
let _ipc_server = rpc::new_ipc(cmd.ipc_conf, &dependencies)?;
|
let _ipc_server = rpc::new_ipc(cmd.ipc_conf, &dependencies)?;
|
||||||
|
|
||||||
// the signer server
|
// the signer server
|
||||||
@ -315,8 +335,6 @@ fn execute_light(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) ->
|
|||||||
let signing_queue = deps_for_rpc_apis.signer_service.queue();
|
let signing_queue = deps_for_rpc_apis.signer_service.queue();
|
||||||
let _signer_server = signer::start(cmd.signer_conf.clone(), signing_queue, signer_deps)?;
|
let _signer_server = signer::start(cmd.signer_conf.clone(), signing_queue, signer_deps)?;
|
||||||
|
|
||||||
// TODO: Dapps
|
|
||||||
|
|
||||||
// minimal informant thread. Just prints block number every 5 seconds.
|
// minimal informant thread. Just prints block number every 5 seconds.
|
||||||
// TODO: integrate with informant.rs
|
// TODO: integrate with informant.rs
|
||||||
let informant_client = service.client().clone();
|
let informant_client = service.client().clone();
|
||||||
|
@ -16,6 +16,7 @@ target_info = "0.1"
|
|||||||
ethcore = { path = "../ethcore" }
|
ethcore = { path = "../ethcore" }
|
||||||
ethsync = { path = "../sync" }
|
ethsync = { path = "../sync" }
|
||||||
ethcore-util = { path = "../util" }
|
ethcore-util = { path = "../util" }
|
||||||
|
futures = "0.1"
|
||||||
parity-hash-fetch = { path = "../hash-fetch" }
|
parity-hash-fetch = { path = "../hash-fetch" }
|
||||||
ipc-common-types = { path = "../ipc-common-types" }
|
ipc-common-types = { path = "../ipc-common-types" }
|
||||||
ethcore-ipc = { path = "../ipc/rpc" }
|
ethcore-ipc = { path = "../ipc/rpc" }
|
||||||
|
@ -24,6 +24,7 @@ extern crate ethcore;
|
|||||||
extern crate ethabi;
|
extern crate ethabi;
|
||||||
extern crate ethsync;
|
extern crate ethsync;
|
||||||
extern crate ethcore_ipc as ipc;
|
extern crate ethcore_ipc as ipc;
|
||||||
|
extern crate futures;
|
||||||
extern crate target_info;
|
extern crate target_info;
|
||||||
extern crate parity_reactor;
|
extern crate parity_reactor;
|
||||||
extern crate path;
|
extern crate path;
|
||||||
|
@ -14,23 +14,25 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use std::sync::{Arc, Weak};
|
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::path::{PathBuf};
|
use std::path::{PathBuf};
|
||||||
use target_info::Target;
|
use std::sync::{Arc, Weak};
|
||||||
use util::misc;
|
|
||||||
use ipc_common_types::{VersionInfo, ReleaseTrack};
|
|
||||||
use path::restrict_permissions_owner;
|
|
||||||
use util::{Address, H160, H256, Mutex, Bytes};
|
|
||||||
use ethsync::{SyncProvider};
|
|
||||||
use ethcore::client::{BlockId, BlockChainClient, ChainNotify};
|
use ethcore::client::{BlockId, BlockChainClient, ChainNotify};
|
||||||
|
use ethsync::{SyncProvider};
|
||||||
|
use futures::{future, Future, BoxFuture};
|
||||||
use hash_fetch::{self as fetch, HashFetch};
|
use hash_fetch::{self as fetch, HashFetch};
|
||||||
use hash_fetch::fetch::Client as FetchService;
|
use hash_fetch::fetch::Client as FetchService;
|
||||||
|
use ipc_common_types::{VersionInfo, ReleaseTrack};
|
||||||
use operations::Operations;
|
use operations::Operations;
|
||||||
use parity_reactor::Remote;
|
use parity_reactor::Remote;
|
||||||
|
use path::restrict_permissions_owner;
|
||||||
use service::{Service};
|
use service::{Service};
|
||||||
|
use target_info::Target;
|
||||||
use types::all::{ReleaseInfo, OperationsInfo, CapState};
|
use types::all::{ReleaseInfo, OperationsInfo, CapState};
|
||||||
|
use util::{Address, H160, H256, Mutex, Bytes};
|
||||||
|
use util::misc;
|
||||||
|
|
||||||
/// Filter for releases.
|
/// Filter for releases.
|
||||||
#[derive(Debug, Eq, PartialEq, Clone)]
|
#[derive(Debug, Eq, PartialEq, Clone)]
|
||||||
@ -338,9 +340,12 @@ impl fetch::urlhint::ContractClient for Updater {
|
|||||||
.ok_or_else(|| "Registrar not available".into())
|
.ok_or_else(|| "Registrar not available".into())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call(&self, address: Address, data: Bytes) -> Result<Bytes, String> {
|
fn call(&self, address: Address, data: Bytes) -> BoxFuture<Bytes, String> {
|
||||||
self.client.upgrade().ok_or_else(|| "Client not available".to_owned())?
|
future::done(
|
||||||
.call_contract(BlockId::Latest, address, data)
|
self.client.upgrade()
|
||||||
|
.ok_or_else(|| "Client not available".into())
|
||||||
|
.and_then(move |c| c.call_contract(BlockId::Latest, address, data))
|
||||||
|
).boxed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user