Merge branch 'master' into block_header_rpc

This commit is contained in:
Robert Habermeier 2017-04-10 18:06:28 +02:00
commit 5b65f10828
74 changed files with 2105 additions and 875 deletions

View File

@ -14,13 +14,14 @@ cache:
untracked: true untracked: true
linux-stable: linux-stable:
stage: build stage: build
image: ethcore/rust:stable image: parity/rust:gitlab-ci
only: only:
- beta - beta
- tags - tags
- stable - stable
- triggers - triggers
script: script:
- rustup default stable
- cargo build -j $(nproc) --release --features final $CARGOFLAGS - cargo build -j $(nproc) --release --features final $CARGOFLAGS
- cargo build -j $(nproc) --release -p evmbin - cargo build -j $(nproc) --release -p evmbin
- cargo build -j $(nproc) --release -p ethstore - cargo build -j $(nproc) --release -p ethstore
@ -105,13 +106,14 @@ linux-stable-debian:
name: "stable-x86_64-unknown-debian-gnu_parity" name: "stable-x86_64-unknown-debian-gnu_parity"
linux-beta: linux-beta:
stage: build stage: build
image: ethcore/rust:beta image: parity/rust:gitlab-ci
only: only:
- beta - beta
- tags - tags
- stable - stable
- triggers - triggers
script: script:
- rustup default beta
- cargo build -j $(nproc) --release $CARGOFLAGS - cargo build -j $(nproc) --release $CARGOFLAGS
- strip target/release/parity - strip target/release/parity
tags: tags:
@ -124,13 +126,14 @@ linux-beta:
allow_failure: true allow_failure: true
linux-nightly: linux-nightly:
stage: build stage: build
image: ethcore/rust:nightly image: parity/rust:gitlab-ci
only: only:
- beta - beta
- tags - tags
- stable - stable
- triggers - triggers
script: script:
- rustup default nightly
- cargo build -j $(nproc) --release $CARGOFLAGS - cargo build -j $(nproc) --release $CARGOFLAGS
- strip target/release/parity - strip target/release/parity
tags: tags:
@ -544,11 +547,12 @@ test-windows:
allow_failure: true allow_failure: true
test-rust-stable: test-rust-stable:
stage: test stage: test
image: ethcore/rust:stable image: parity/rust:gitlab-ci
before_script: before_script:
- git submodule update --init --recursive - git submodule update --init --recursive
- export RUST_FILES_MODIFIED=$(git --no-pager diff --name-only $CI_BUILD_REF^ $CI_BUILD_REF | grep -v -e ^js -e ^\\. -e ^LICENSE -e ^README.md -e ^appveyor.yml -e ^test.sh -e ^windows/ -e ^scripts/ -e^mac/ -e ^nsis/ | wc -l) - export RUST_FILES_MODIFIED=$(git --no-pager diff --name-only $CI_BUILD_REF^ $CI_BUILD_REF | grep -v -e ^js -e ^\\. -e ^LICENSE -e ^README.md -e ^appveyor.yml -e ^test.sh -e ^windows/ -e ^scripts/ -e^mac/ -e ^nsis/ | wc -l)
script: script:
- rustup show
- export RUST_BACKTRACE=1 - export RUST_BACKTRACE=1
- if [ $RUST_FILES_MODIFIED -eq 0 ]; then echo "Skipping Rust tests since no Rust files modified."; else ./test.sh $CARGOFLAGS; fi - if [ $RUST_FILES_MODIFIED -eq 0 ]; then echo "Skipping Rust tests since no Rust files modified."; else ./test.sh $CARGOFLAGS; fi
tags: tags:

173
Cargo.lock generated
View File

@ -30,7 +30,7 @@ dependencies = [
"futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
"isatty 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "isatty 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", "jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"number_prefix 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "number_prefix 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-dapps 1.7.0", "parity-dapps 1.7.0",
@ -350,7 +350,7 @@ name = "env_logger"
version = "0.4.2" version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -382,7 +382,7 @@ dependencies = [
name = "ethash" name = "ethash"
version = "1.7.0" version = "1.7.0"
dependencies = [ dependencies = [
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"primal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "primal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"sha3 0.1.0", "sha3 0.1.0",
@ -420,7 +420,7 @@ dependencies = [
"itertools 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"linked-hash-map 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "linked-hash-map 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"lru-cache 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "lru-cache 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"native-contracts 0.1.0", "native-contracts 0.1.0",
"num 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", "num 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
@ -465,7 +465,7 @@ name = "ethcore-io"
version = "1.7.0" version = "1.7.0"
dependencies = [ dependencies = [
"crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.1 (git+https://github.com/paritytech/mio)", "mio 0.6.1 (git+https://github.com/paritytech/mio)",
"parking_lot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -499,7 +499,7 @@ dependencies = [
"ethcore-ipc 1.7.0", "ethcore-ipc 1.7.0",
"ethcore-ipc-codegen 1.7.0", "ethcore-ipc-codegen 1.7.0",
"ethcore-ipc-nano 1.7.0", "ethcore-ipc-nano 1.7.0",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"nanomsg 0.5.1 (git+https://github.com/paritytech/nanomsg.rs.git?branch=parity-1.7)", "nanomsg 0.5.1 (git+https://github.com/paritytech/nanomsg.rs.git?branch=parity-1.7)",
"semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
@ -511,7 +511,7 @@ version = "1.7.0"
dependencies = [ dependencies = [
"ethcore-ipc 1.7.0", "ethcore-ipc 1.7.0",
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"nanomsg 0.5.1 (git+https://github.com/paritytech/nanomsg.rs.git?branch=parity-1.7)", "nanomsg 0.5.1 (git+https://github.com/paritytech/nanomsg.rs.git?branch=parity-1.7)",
] ]
@ -524,7 +524,7 @@ dependencies = [
"ethcore-ipc-codegen 1.7.0", "ethcore-ipc-codegen 1.7.0",
"ethcore-ipc-nano 1.7.0", "ethcore-ipc-nano 1.7.0",
"ethcore-util 1.7.0", "ethcore-util 1.7.0",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"nanomsg 0.5.1 (git+https://github.com/paritytech/nanomsg.rs.git?branch=parity-1.7)", "nanomsg 0.5.1 (git+https://github.com/paritytech/nanomsg.rs.git?branch=parity-1.7)",
"semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -542,7 +542,7 @@ dependencies = [
"ethcore-util 1.7.0", "ethcore-util 1.7.0",
"futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
"itertools 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"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)",
"rlp 0.1.0", "rlp 0.1.0",
"smallvec 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -559,7 +559,7 @@ dependencies = [
"env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"isatty 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "isatty 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
@ -579,7 +579,7 @@ dependencies = [
"ethkey 0.2.0", "ethkey 0.2.0",
"igd 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "igd 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.1 (git+https://github.com/paritytech/mio)", "mio 0.6.1 (git+https://github.com/paritytech/mio)",
"parking_lot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"path 0.1.0", "path 0.1.0",
@ -596,6 +596,7 @@ dependencies = [
name = "ethcore-rpc" name = "ethcore-rpc"
version = "1.7.0" version = "1.7.0"
dependencies = [ dependencies = [
"cid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"clippy 0.0.103 (registry+https://github.com/rust-lang/crates.io-index)", "clippy 0.0.103 (registry+https://github.com/rust-lang/crates.io-index)",
"ethash 1.7.0", "ethash 1.7.0",
"ethcore 1.7.0", "ethcore 1.7.0",
@ -617,11 +618,13 @@ dependencies = [
"jsonrpc-ipc-server 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", "jsonrpc-ipc-server 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
"jsonrpc-macros 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", "jsonrpc-macros 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
"jsonrpc-minihttp-server 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", "jsonrpc-minihttp-server 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"multihash 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"order-stat 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "order-stat 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-reactor 0.1.0", "parity-reactor 0.1.0",
"parity-updater 1.7.0", "parity-updater 1.7.0",
"rlp 0.1.0", "rlp 0.1.0",
"rust-crypto 0.2.36 (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)",
"semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)",
@ -649,14 +652,15 @@ dependencies = [
"futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-cpupool 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"hyper 0.10.5 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.10.5 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"native-contracts 0.1.0", "native-contracts 0.1.0",
"parking_lot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.4.0 (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)",
"serde 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-core 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-proto 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-proto 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -674,7 +678,7 @@ dependencies = [
"ethcore-util 1.7.0", "ethcore-util 1.7.0",
"jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", "jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
"jsonrpc-server-utils 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", "jsonrpc-server-utils 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"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)",
"parity-ui 1.7.0", "parity-ui 1.7.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)",
@ -698,9 +702,9 @@ dependencies = [
"jsonrpc-macros 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", "jsonrpc-macros 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
"jsonrpc-tcp-server 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", "jsonrpc-tcp-server 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-core 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -719,7 +723,7 @@ dependencies = [
"heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"itertools 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"lru-cache 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "lru-cache 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"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)",
@ -786,7 +790,7 @@ dependencies = [
"ethkey 0.2.0", "ethkey 0.2.0",
"itertools 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-wordlist 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-wordlist 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"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)",
@ -817,7 +821,7 @@ dependencies = [
"ethcore-util 1.7.0", "ethcore-util 1.7.0",
"ethkey 0.2.0", "ethkey 0.2.0",
"heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"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)",
"rlp 0.1.0", "rlp 0.1.0",
@ -857,7 +861,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-cpupool 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (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)",
"parking_lot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"reqwest 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "reqwest 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -922,7 +926,7 @@ dependencies = [
"ethkey 0.2.0", "ethkey 0.2.0",
"hidapi 0.3.1 (git+https://github.com/paritytech/hidapi-rs)", "hidapi 0.3.1 (git+https://github.com/paritytech/hidapi-rs)",
"libusb 0.3.0 (git+https://github.com/paritytech/libusb-rs)", "libusb 0.3.0 (git+https://github.com/paritytech/libusb-rs)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -964,7 +968,7 @@ dependencies = [
"cookie 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "cookie 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"httparse 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "httparse 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (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)",
"rotor 0.6.3 (git+https://github.com/paritytech/rotor)", "rotor 0.6.3 (git+https://github.com/paritytech/rotor)",
"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)",
@ -982,7 +986,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"httparse 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "httparse 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (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)",
"num_cpus 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.2.0 (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)",
@ -1079,7 +1083,7 @@ version = "7.0.0"
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#32c1c083139db50db6a5d532ccfc2004236dbfc3" source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#32c1c083139db50db6a5d532ccfc2004236dbfc3"
dependencies = [ dependencies = [
"futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1093,7 +1097,7 @@ dependencies = [
"hyper 0.10.0-a.0 (git+https://github.com/paritytech/hyper)", "hyper 0.10.0-a.0 (git+https://github.com/paritytech/hyper)",
"jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", "jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
"jsonrpc-server-utils 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", "jsonrpc-server-utils 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -1105,7 +1109,7 @@ source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#32c1c0
dependencies = [ dependencies = [
"jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", "jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
"jsonrpc-server-utils 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", "jsonrpc-server-utils 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-tokio-ipc 0.1.0 (git+https://github.com/nikvolf/parity-tokio-ipc)", "parity-tokio-ipc 0.1.0 (git+https://github.com/nikvolf/parity-tokio-ipc)",
"tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -1127,7 +1131,7 @@ source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#32c1c0
dependencies = [ dependencies = [
"jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", "jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
"jsonrpc-server-utils 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", "jsonrpc-server-utils 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-minihttp 0.1.0 (git+https://github.com/tomusdrw/tokio-minihttp)", "tokio-minihttp 0.1.0 (git+https://github.com/tomusdrw/tokio-minihttp)",
"tokio-proto 0.1.0 (git+https://github.com/tomusdrw/tokio-proto)", "tokio-proto 0.1.0 (git+https://github.com/tomusdrw/tokio-proto)",
@ -1140,7 +1144,7 @@ version = "7.0.0"
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#32c1c083139db50db6a5d532ccfc2004236dbfc3" source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#32c1c083139db50db6a5d532ccfc2004236dbfc3"
dependencies = [ dependencies = [
"jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", "jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -1150,8 +1154,8 @@ version = "7.0.0"
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#32c1c083139db50db6a5d532ccfc2004236dbfc3" source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#32c1c083139db50db6a5d532ccfc2004236dbfc3"
dependencies = [ dependencies = [
"jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", "jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-core 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -1162,7 +1166,7 @@ source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#32c1c0
dependencies = [ dependencies = [
"jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", "jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
"jsonrpc-server-utils 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", "jsonrpc-server-utils 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1233,7 +1237,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "log" name = "log"
version = "0.3.6" version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
@ -1262,7 +1266,7 @@ name = "mime"
version = "0.2.0" version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -1293,9 +1297,9 @@ dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazycell 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazycell 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"miow 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.27 (registry+https://github.com/rust-lang/crates.io-index)",
"nix 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1303,16 +1307,16 @@ dependencies = [
[[package]] [[package]]
name = "mio" name = "mio"
version = "0.6.2" version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"iovec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazycell 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazycell 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"miow 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.27 (registry+https://github.com/rust-lang/crates.io-index)",
"nix 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -1324,8 +1328,8 @@ source = "git+https://github.com/alexcrichton/mio-named-pipes#903dc2f7eac6700c62
dependencies = [ dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazycell 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazycell 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
"miow 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -1336,7 +1340,7 @@ version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -1345,7 +1349,7 @@ version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.27 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -1356,7 +1360,7 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.27 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -1439,7 +1443,7 @@ dependencies = [
[[package]] [[package]]
name = "net2" name = "net2"
version = "0.2.23" version = "0.2.27"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1620,7 +1624,7 @@ dependencies = [
"jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", "jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
"jsonrpc-http-server 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", "jsonrpc-http-server 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
"linked-hash-map 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "linked-hash-map 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (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)",
"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)",
@ -1660,7 +1664,7 @@ dependencies = [
"ethcore-util 1.7.0", "ethcore-util 1.7.0",
"fetch 0.1.0", "fetch 0.1.0",
"futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (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)",
"parity-reactor 0.1.0", "parity-reactor 0.1.0",
@ -1689,7 +1693,7 @@ dependencies = [
"ethcore-io 1.7.0", "ethcore-io 1.7.0",
"ethcore-util 1.7.0", "ethcore-util 1.7.0",
"ethkey 0.2.0", "ethkey 0.2.0",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"rlp 0.1.0", "rlp 0.1.0",
"serde 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1701,7 +1705,7 @@ name = "parity-reactor"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-core 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -1713,7 +1717,7 @@ dependencies = [
"ethcore-util 1.7.0", "ethcore-util 1.7.0",
"futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
"jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", "jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"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)",
"serde 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1728,11 +1732,11 @@ version = "0.1.0"
source = "git+https://github.com/nikvolf/parity-tokio-ipc#3d4234de6bdc78688ef803935111003080fd5375" source = "git+https://github.com/nikvolf/parity-tokio-ipc#3d4234de6bdc78688ef803935111003080fd5375"
dependencies = [ dependencies = [
"futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"mio-named-pipes 0.1.4 (git+https://github.com/alexcrichton/mio-named-pipes)", "mio-named-pipes 0.1.4 (git+https://github.com/alexcrichton/mio-named-pipes)",
"miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"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)",
"tokio-core 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-line 0.1.0 (git+https://github.com/tokio-rs/tokio-line)", "tokio-line 0.1.0 (git+https://github.com/tokio-rs/tokio-line)",
"tokio-named-pipes 0.1.0 (git+https://github.com/alexcrichton/tokio-named-pipes)", "tokio-named-pipes 0.1.0 (git+https://github.com/alexcrichton/tokio-named-pipes)",
"tokio-uds 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-uds 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1757,7 +1761,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#9bfc6f3dfca2c337c53084bedcc65c2b526927a1" source = "git+https://github.com/paritytech/js-precompiled.git#b4c41885c6e02c64fb773546b2f135f56ea7022f"
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)",
] ]
@ -1773,7 +1777,7 @@ dependencies = [
"ethcore-util 1.7.0", "ethcore-util 1.7.0",
"ethsync 1.7.0", "ethsync 1.7.0",
"ipc-common-types 1.7.0", "ipc-common-types 1.7.0",
"log 0.3.6 (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",
"parity-reactor 0.1.0", "parity-reactor 0.1.0",
"path 0.1.0", "path 0.1.0",
@ -1992,7 +1996,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"hyper 0.10.5 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.10.5 (registry+https://github.com/rust-lang/crates.io-index)",
"hyper-native-tls 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "hyper-native-tls 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_urlencoded 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde_urlencoded 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2043,7 +2047,7 @@ name = "rotor"
version = "0.6.3" version = "0.6.3"
source = "git+https://github.com/paritytech/rotor#2a3764a830174aa94405593be550e8fc7ecea25a" source = "git+https://github.com/paritytech/rotor#2a3764a830174aa94405593be550e8fc7ecea25a"
dependencies = [ dependencies = [
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.1 (git+https://github.com/paritytech/mio)", "mio 0.6.1 (git+https://github.com/paritytech/mio)",
"quick-error 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "quick-error 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2309,7 +2313,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
name = "stats" name = "stats"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -2361,7 +2365,7 @@ version = "0.58.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (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)",
"syntex_errors 0.58.0 (registry+https://github.com/rust-lang/crates.io-index)", "syntex_errors 0.58.0 (registry+https://github.com/rust-lang/crates.io-index)",
"syntex_pos 0.58.0 (registry+https://github.com/rust-lang/crates.io-index)", "syntex_pos 0.58.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2442,14 +2446,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "tokio-core" name = "tokio-core"
version = "0.1.4" version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"bytes 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
"scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -2459,7 +2466,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"bytes 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -2468,7 +2475,7 @@ version = "0.1.0"
source = "git+https://github.com/tokio-rs/tokio-line#482614ae0c82daf584727ae65a80d854fe861f81" source = "git+https://github.com/tokio-rs/tokio-line#482614ae0c82daf584727ae65a80d854fe861f81"
dependencies = [ dependencies = [
"futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-core 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-proto 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-proto 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -2480,10 +2487,10 @@ source = "git+https://github.com/tomusdrw/tokio-minihttp#8acbafae3e77e7f7eb516b4
dependencies = [ dependencies = [
"futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
"httparse 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "httparse 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.27 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-core 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-proto 0.1.0 (git+https://github.com/tomusdrw/tokio-proto)", "tokio-proto 0.1.0 (git+https://github.com/tomusdrw/tokio-proto)",
"tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -2495,7 +2502,7 @@ source = "git+https://github.com/alexcrichton/tokio-named-pipes#3a22f8fc9a441b54
dependencies = [ dependencies = [
"futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
"mio-named-pipes 0.1.4 (git+https://github.com/alexcrichton/mio-named-pipes)", "mio-named-pipes 0.1.4 (git+https://github.com/alexcrichton/mio-named-pipes)",
"tokio-core 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -2504,13 +2511,13 @@ version = "0.1.0"
source = "git+https://github.com/tomusdrw/tokio-proto#f6ee08cb594fa2fc1b4178eaaca0855d66e68fd3" source = "git+https://github.com/tomusdrw/tokio-proto#f6ee08cb594fa2fc1b4178eaaca0855d66e68fd3"
dependencies = [ dependencies = [
"futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.27 (registry+https://github.com/rust-lang/crates.io-index)",
"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)",
"slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"take 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "take 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-core 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -2520,13 +2527,13 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.27 (registry+https://github.com/rust-lang/crates.io-index)",
"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)",
"slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"take 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "take 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-core 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -2544,10 +2551,10 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
"mio-uds 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "mio-uds 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-core 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -2695,7 +2702,7 @@ source = "git+https://github.com/paritytech/ws-rs.git?branch=parity-1.7#30415c17
dependencies = [ dependencies = [
"bytes 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"httparse 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "httparse 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.1 (git+https://github.com/paritytech/mio)", "mio 0.6.1 (git+https://github.com/paritytech/mio)",
"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)",
"sha1 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "sha1 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2827,7 +2834,7 @@ dependencies = [
"checksum libusb-sys 0.2.3 (git+https://github.com/paritytech/libusb-sys)" = "<none>" "checksum libusb-sys 0.2.3 (git+https://github.com/paritytech/libusb-sys)" = "<none>"
"checksum linked-hash-map 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bda158e0dabeb97ee8a401f4d17e479d6b891a14de0bba79d5cc2d4d325b5e48" "checksum linked-hash-map 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bda158e0dabeb97ee8a401f4d17e479d6b891a14de0bba79d5cc2d4d325b5e48"
"checksum linked-hash-map 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6d262045c5b87c0861b3f004610afd0e2c851e2908d08b6c870cbb9d5f494ecd" "checksum linked-hash-map 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6d262045c5b87c0861b3f004610afd0e2c851e2908d08b6c870cbb9d5f494ecd"
"checksum log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ab83497bf8bf4ed2a74259c1c802351fcd67a65baa86394b6ba73c36f4838054" "checksum log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "5141eca02775a762cc6cd564d8d2c50f67c0ea3a372cbf1c51592b3e029e10ad"
"checksum lru-cache 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "656fa4dfcb02bcf1063c592ba3ff6a5303ee1f2afe98c8a889e8b1a77c6dfdb7" "checksum lru-cache 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "656fa4dfcb02bcf1063c592ba3ff6a5303ee1f2afe98c8a889e8b1a77c6dfdb7"
"checksum matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "15305656809ce5a4805b1ff2946892810992197ce1270ff79baded852187942e" "checksum matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "15305656809ce5a4805b1ff2946892810992197ce1270ff79baded852187942e"
"checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4" "checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4"
@ -2835,7 +2842,7 @@ dependencies = [
"checksum mime_guess 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5e50bf542f81754ef69e5cea856946a3819f7c09ea97b4903c8bc8a89f74e7b6" "checksum mime_guess 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5e50bf542f81754ef69e5cea856946a3819f7c09ea97b4903c8bc8a89f74e7b6"
"checksum miniz-sys 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d1f4d337a01c32e1f2122510fed46393d53ca35a7f429cb0450abaedfa3ed54" "checksum miniz-sys 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d1f4d337a01c32e1f2122510fed46393d53ca35a7f429cb0450abaedfa3ed54"
"checksum mio 0.6.1 (git+https://github.com/paritytech/mio)" = "<none>" "checksum mio 0.6.1 (git+https://github.com/paritytech/mio)" = "<none>"
"checksum mio 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5b493dc9fd96bd2077f2117f178172b0765db4dfda3ea4d8000401e6d65d3e80" "checksum mio 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f27d38f824a0d267d55b29b171e9e99269a53812e385fa75c1fe700ae254a6a4"
"checksum mio-named-pipes 0.1.4 (git+https://github.com/alexcrichton/mio-named-pipes)" = "<none>" "checksum mio-named-pipes 0.1.4 (git+https://github.com/alexcrichton/mio-named-pipes)" = "<none>"
"checksum mio-uds 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "78437f00d9615c366932cbfe79790b5c2945706ba67cf78378ffacc0069ed9de" "checksum mio-uds 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "78437f00d9615c366932cbfe79790b5c2945706ba67cf78378ffacc0069ed9de"
"checksum miow 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3e690c5df6b2f60acd45d56378981e827ff8295562fc8d34f573deb267a59cd1" "checksum miow 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3e690c5df6b2f60acd45d56378981e827ff8295562fc8d34f573deb267a59cd1"
@ -2846,7 +2853,7 @@ dependencies = [
"checksum nanomsg 0.5.1 (git+https://github.com/paritytech/nanomsg.rs.git?branch=parity-1.7)" = "<none>" "checksum nanomsg 0.5.1 (git+https://github.com/paritytech/nanomsg.rs.git?branch=parity-1.7)" = "<none>"
"checksum nanomsg-sys 0.5.0 (git+https://github.com/paritytech/nanomsg.rs.git?branch=parity-1.7)" = "<none>" "checksum nanomsg-sys 0.5.0 (git+https://github.com/paritytech/nanomsg.rs.git?branch=parity-1.7)" = "<none>"
"checksum native-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aa4e52995154bb6f0b41e4379a279482c9387c1632e3798ba4e511ef8c54ee09" "checksum native-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aa4e52995154bb6f0b41e4379a279482c9387c1632e3798ba4e511ef8c54ee09"
"checksum net2 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)" = "6a816012ca11cb47009693c1e0c6130e26d39e4d97ee2a13c50e868ec83e3204" "checksum net2 0.2.27 (registry+https://github.com/rust-lang/crates.io-index)" = "18b9642ad6222faf5ce46f6966f59b71b9775ad5758c9e09fcf0a6c8061972b4"
"checksum nix 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a0d95c5fa8b641c10ad0b8887454ebaafa3c92b5cd5350f8fc693adafd178e7b" "checksum nix 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a0d95c5fa8b641c10ad0b8887454ebaafa3c92b5cd5350f8fc693adafd178e7b"
"checksum nodrop 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "52cd74cd09beba596430cc6e3091b74007169a56246e1262f0ba451ea95117b2" "checksum nodrop 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "52cd74cd09beba596430cc6e3091b74007169a56246e1262f0ba451ea95117b2"
"checksum nom 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6caab12c5f97aa316cb249725aa32115118e1522b445e26c257dd77cad5ffd4e" "checksum nom 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6caab12c5f97aa316cb249725aa32115118e1522b445e26c257dd77cad5ffd4e"
@ -2944,7 +2951,7 @@ dependencies = [
"checksum thread_local 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c85048c6260d17cf486ceae3282d9fb6b90be220bf5b28c400f5485ffc29f0c7" "checksum thread_local 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c85048c6260d17cf486ceae3282d9fb6b90be220bf5b28c400f5485ffc29f0c7"
"checksum time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "3c7ec6d62a20df54e07ab3b78b9a3932972f4b7981de295563686849eb3989af" "checksum time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "3c7ec6d62a20df54e07ab3b78b9a3932972f4b7981de295563686849eb3989af"
"checksum tiny-keccak 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f7aef43048292ca0bae4ab32180e85f6202cf2816c2a210c396a84b99dab9270" "checksum tiny-keccak 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f7aef43048292ca0bae4ab32180e85f6202cf2816c2a210c396a84b99dab9270"
"checksum tokio-core 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3d1be481b55126f02ef88ff86748086473cb537a949fc4a8f4be403a530ae54b" "checksum tokio-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "99e958104a67877907c1454386d5482fe8e965a55d60be834a15a44328e7dc76"
"checksum tokio-io 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6a278fde45f1be68e44995227d426aaa4841e0980bb0a21b981092f28c3c8473" "checksum tokio-io 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6a278fde45f1be68e44995227d426aaa4841e0980bb0a21b981092f28c3c8473"
"checksum tokio-line 0.1.0 (git+https://github.com/tokio-rs/tokio-line)" = "<none>" "checksum tokio-line 0.1.0 (git+https://github.com/tokio-rs/tokio-line)" = "<none>"
"checksum tokio-minihttp 0.1.0 (git+https://github.com/tomusdrw/tokio-minihttp)" = "<none>" "checksum tokio-minihttp 0.1.0 (git+https://github.com/tomusdrw/tokio-minihttp)" = "<none>"

View File

@ -14,6 +14,8 @@
// 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;
use unicase::UniCase; use unicase::UniCase;
use hyper::{server, net, Decoder, Encoder, Next, Control}; use hyper::{server, net, Decoder, Encoder, Next, Control};
use hyper::header; use hyper::header;
@ -28,16 +30,16 @@ use endpoint::{Endpoint, Endpoints, Handler, EndpointPath};
use jsonrpc_http_server::{self, AccessControlAllowOrigin}; use jsonrpc_http_server::{self, AccessControlAllowOrigin};
#[derive(Clone)] #[derive(Clone)]
pub struct RestApi<F> { pub struct RestApi {
// TODO [ToDr] cors_domains should be handled by the server to avoid duplicated logic. // TODO [ToDr] cors_domains should be handled by the server to avoid duplicated logic.
// RequestMiddleware should be able to tell that cors headers should be included. // RequestMiddleware should be able to tell that cors headers should be included.
cors_domains: Option<Vec<AccessControlAllowOrigin>>, cors_domains: Option<Vec<AccessControlAllowOrigin>>,
apps: Vec<App>, apps: Vec<App>,
fetcher: F, fetcher: Arc<Fetcher>,
} }
impl<F: Fetcher + Clone> RestApi<F> { impl RestApi {
pub fn new(cors_domains: Vec<AccessControlAllowOrigin>, endpoints: &Endpoints, fetcher: F) -> Box<Endpoint> { pub fn new(cors_domains: Vec<AccessControlAllowOrigin>, endpoints: &Endpoints, fetcher: Arc<Fetcher>) -> Box<Endpoint> {
Box::new(RestApi { Box::new(RestApi {
cors_domains: Some(cors_domains), cors_domains: Some(cors_domains),
apps: Self::list_apps(endpoints), apps: Self::list_apps(endpoints),
@ -52,22 +54,22 @@ impl<F: Fetcher + Clone> RestApi<F> {
} }
} }
impl<F: Fetcher + Clone> Endpoint for RestApi<F> { impl Endpoint for RestApi {
fn to_async_handler(&self, path: EndpointPath, control: Control) -> Box<Handler> { fn to_async_handler(&self, path: EndpointPath, control: Control) -> Box<Handler> {
Box::new(RestApiRouter::new((*self).clone(), path, control)) Box::new(RestApiRouter::new((*self).clone(), path, control))
} }
} }
struct RestApiRouter<F> { struct RestApiRouter {
api: RestApi<F>, api: RestApi,
cors_header: Option<header::AccessControlAllowOrigin>, cors_header: Option<header::AccessControlAllowOrigin>,
path: Option<EndpointPath>, path: Option<EndpointPath>,
control: Option<Control>, control: Option<Control>,
handler: Box<Handler>, handler: Box<Handler>,
} }
impl<F: Fetcher> RestApiRouter<F> { impl RestApiRouter {
fn new(api: RestApi<F>, path: EndpointPath, control: Control) -> Self { fn new(api: RestApi, path: EndpointPath, control: Control) -> Self {
RestApiRouter { RestApiRouter {
path: Some(path), path: Some(path),
cors_header: None, cors_header: None,
@ -82,6 +84,7 @@ impl<F: Fetcher> RestApiRouter<F> {
} }
fn resolve_content(&self, hash: Option<&str>, path: EndpointPath, control: Control) -> Option<Box<Handler>> { fn resolve_content(&self, hash: Option<&str>, path: EndpointPath, control: Control) -> Option<Box<Handler>> {
trace!(target: "dapps", "Resolving content: {:?} from path: {:?}", hash, path);
match hash { match hash {
Some(hash) if self.api.fetcher.contains(hash) => { Some(hash) if self.api.fetcher.contains(hash) => {
Some(self.api.fetcher.to_async_handler(path, control)) Some(self.api.fetcher.to_async_handler(path, control))
@ -114,8 +117,7 @@ impl<F: Fetcher> RestApiRouter<F> {
} }
} }
impl<F: Fetcher> server::Handler<net::HttpStream> for RestApiRouter<F> { impl server::Handler<net::HttpStream> for RestApiRouter {
fn on_request(&mut self, request: server::Request<net::HttpStream>) -> Next { fn on_request(&mut self, request: server::Request<net::HttpStream>) -> Next {
self.cors_header = jsonrpc_http_server::cors_header(&request, &self.api.cors_domains).into(); self.cors_header = jsonrpc_http_server::cors_header(&request, &self.api.cors_domains).into();
@ -168,5 +170,4 @@ impl<F: Fetcher> server::Handler<net::HttpStream> for RestApiRouter<F> {
fn on_response_writable(&mut self, encoder: &mut Encoder<net::HttpStream>) -> Next { fn on_response_writable(&mut self, encoder: &mut Encoder<net::HttpStream>) -> Next {
self.handler.on_response_writable(encoder) self.handler.on_response_writable(encoder)
} }
} }

View File

@ -47,8 +47,7 @@ pub trait Fetcher: Send + Sync + 'static {
fn to_async_handler(&self, path: EndpointPath, control: hyper::Control) -> Box<Handler>; fn to_async_handler(&self, path: EndpointPath, control: hyper::Control) -> Box<Handler>;
} }
#[derive(Clone)] pub struct ContentFetcher<F: Fetch = FetchClient, R: URLHint + 'static = URLHintContract> {
pub struct ContentFetcher<F: Fetch + Clone = FetchClient, R: URLHint + Clone + 'static = URLHintContract> {
dapps_path: PathBuf, dapps_path: PathBuf,
resolver: R, resolver: R,
cache: Arc<Mutex<ContentCache>>, cache: Arc<Mutex<ContentCache>>,
@ -58,14 +57,14 @@ pub struct ContentFetcher<F: Fetch + Clone = FetchClient, R: URLHint + Clone + '
fetch: F, fetch: F,
} }
impl<R: URLHint + Clone + 'static, F: Fetch + Clone> Drop for ContentFetcher<F, R> { impl<R: URLHint + 'static, F: Fetch> Drop for ContentFetcher<F, R> {
fn drop(&mut self) { fn drop(&mut self) {
// Clear cache path // Clear cache path
let _ = fs::remove_dir_all(&self.dapps_path); let _ = fs::remove_dir_all(&self.dapps_path);
} }
} }
impl<R: URLHint + Clone + 'static, F: Fetch + Clone> ContentFetcher<F, R> { impl<R: URLHint + 'static, F: Fetch> ContentFetcher<F, R> {
pub fn new(resolver: R, sync_status: Arc<SyncStatus>, embeddable_on: Option<(String, u16)>, remote: Remote, fetch: F) -> Self { pub fn new(resolver: R, sync_status: Arc<SyncStatus>, embeddable_on: Option<(String, u16)>, remote: Remote, fetch: F) -> Self {
let mut dapps_path = env::temp_dir(); let mut dapps_path = env::temp_dir();
@ -98,7 +97,7 @@ impl<R: URLHint + Clone + 'static, F: Fetch + Clone> ContentFetcher<F, R> {
} }
} }
impl<R: URLHint + Clone + 'static, F: Fetch + Clone> Fetcher for ContentFetcher<F, R> { impl<R: URLHint + 'static, F: Fetch> Fetcher for ContentFetcher<F, R> {
fn contains(&self, content_id: &str) -> bool { fn contains(&self, content_id: &str) -> bool {
{ {
let mut cache = self.cache.lock(); let mut cache = self.cache.lock();

View File

@ -98,13 +98,13 @@ impl<F> WebProxyTokens for F where F: Fn(String) -> bool + Send + Sync {
} }
/// Dapps server as `jsonrpc-http-server` request middleware. /// Dapps server as `jsonrpc-http-server` request middleware.
pub struct Middleware<F: Fetch + Clone> { pub struct Middleware {
router: router::Router<apps::fetcher::ContentFetcher<F>>, router: router::Router,
} }
impl<F: Fetch + Clone> Middleware<F> { impl Middleware {
/// Creates new Dapps server middleware. /// Creates new Dapps server middleware.
pub fn new( pub fn new<F: Fetch + Clone>(
remote: Remote, remote: Remote,
signer_address: Option<(String, u16)>, signer_address: Option<(String, u16)>,
dapps_path: PathBuf, dapps_path: PathBuf,
@ -114,13 +114,13 @@ impl<F: Fetch + Clone> Middleware<F> {
web_proxy_tokens: Arc<WebProxyTokens>, web_proxy_tokens: Arc<WebProxyTokens>,
fetch: F, fetch: F,
) -> Self { ) -> Self {
let content_fetcher = apps::fetcher::ContentFetcher::new( let content_fetcher = Arc::new(apps::fetcher::ContentFetcher::new(
hash_fetch::urlhint::URLHintContract::new(registrar), hash_fetch::urlhint::URLHintContract::new(registrar),
sync_status, sync_status,
signer_address.clone(), signer_address.clone(),
remote.clone(), remote.clone(),
fetch.clone(), fetch.clone(),
); ));
let endpoints = apps::all_endpoints( let endpoints = apps::all_endpoints(
dapps_path, dapps_path,
extra_dapps, extra_dapps,
@ -138,7 +138,11 @@ impl<F: Fetch + Clone> Middleware<F> {
special.insert(router::SpecialEndpoint::Utils, Some(apps::utils())); special.insert(router::SpecialEndpoint::Utils, Some(apps::utils()));
special.insert( special.insert(
router::SpecialEndpoint::Api, router::SpecialEndpoint::Api,
Some(api::RestApi::new(cors_domains.clone(), &endpoints, content_fetcher.clone())), Some(api::RestApi::new(
cors_domains.clone(),
&endpoints,
content_fetcher.clone()
)),
); );
special special
}; };
@ -156,7 +160,7 @@ impl<F: Fetch + Clone> Middleware<F> {
} }
} }
impl<F: Fetch + Clone> http::RequestMiddleware for Middleware<F> { impl http::RequestMiddleware for Middleware {
fn on_request(&self, req: &hyper::server::Request<hyper::net::HttpStream>, control: &hyper::Control) -> http::RequestMiddlewareAction { fn on_request(&self, req: &hyper::server::Request<hyper::net::HttpStream>, control: &hyper::Control) -> http::RequestMiddlewareAction {
self.router.on_request(req, control) self.router.on_request(req, control)
} }

View File

@ -19,6 +19,7 @@
use address; use address;
use std::cmp; use std::cmp;
use std::sync::Arc;
use std::collections::HashMap; use std::collections::HashMap;
use url::{Url, Host}; use url::{Url, Host};
@ -40,14 +41,14 @@ pub enum SpecialEndpoint {
None, None,
} }
pub struct Router<F> { pub struct Router {
signer_address: Option<(String, u16)>, signer_address: Option<(String, u16)>,
endpoints: Endpoints, endpoints: Endpoints,
fetch: F, fetch: Arc<Fetcher>,
special: HashMap<SpecialEndpoint, Option<Box<Endpoint>>>, special: HashMap<SpecialEndpoint, Option<Box<Endpoint>>>,
} }
impl<F: Fetcher + 'static> http::RequestMiddleware for Router<F> { impl http::RequestMiddleware for Router {
fn on_request(&self, req: &server::Request<HttpStream>, control: &Control) -> http::RequestMiddlewareAction { fn on_request(&self, req: &server::Request<HttpStream>, control: &Control) -> http::RequestMiddlewareAction {
// Choose proper handler depending on path / domain // Choose proper handler depending on path / domain
let url = handlers::extract_url(req); let url = handlers::extract_url(req);
@ -146,10 +147,10 @@ impl<F: Fetcher + 'static> http::RequestMiddleware for Router<F> {
} }
} }
impl<F> Router<F> { impl Router {
pub fn new( pub fn new(
signer_address: Option<(String, u16)>, signer_address: Option<(String, u16)>,
content_fetcher: F, content_fetcher: Arc<Fetcher>,
endpoints: Endpoints, endpoints: Endpoints,
special: HashMap<SpecialEndpoint, Option<Box<Endpoint>>>, special: HashMap<SpecialEndpoint, Option<Box<Endpoint>>>,
) -> Self { ) -> Self {

View File

@ -23,11 +23,10 @@ use snapshot::Error;
use util::{U256, H256, Bytes, HashDB, SHA3_EMPTY, SHA3_NULL_RLP}; use util::{U256, H256, Bytes, HashDB, SHA3_EMPTY, SHA3_NULL_RLP};
use util::trie::{TrieDB, Trie}; use util::trie::{TrieDB, Trie};
use rlp::{RlpStream, UntrustedRlp}; use rlp::{RlpStream, UntrustedRlp};
use itertools::Itertools;
use std::collections::HashSet; use std::collections::HashSet;
// An empty account -- these are replaced with RLP null data for a space optimization. // An empty account -- these were replaced with RLP null data for a space optimization in v1.
const ACC_EMPTY: BasicAccount = BasicAccount { const ACC_EMPTY: BasicAccount = BasicAccount {
nonce: U256([0, 0, 0, 0]), nonce: U256([0, 0, 0, 0]),
balance: U256([0, 0, 0, 0]), balance: U256([0, 0, 0, 0]),
@ -62,28 +61,19 @@ impl CodeState {
} }
// walk the account's storage trie, returning a vector of RLP items containing the // walk the account's storage trie, returning a vector of RLP items containing the
// account properties and the storage. Each item contains at most `max_storage_items` // account address hash, account properties and the storage. Each item contains at most `max_storage_items`
// storage records split according to snapshot format definition. // storage records split according to snapshot format definition.
pub fn to_fat_rlps(acc: &BasicAccount, acct_db: &AccountDB, used_code: &mut HashSet<H256>, max_storage_items: usize) -> Result<Vec<Bytes>, Error> { pub fn to_fat_rlps(account_hash: &H256, acc: &BasicAccount, acct_db: &AccountDB, used_code: &mut HashSet<H256>, first_chunk_size: usize, max_chunk_size: usize) -> Result<Vec<Bytes>, Error> {
if acc == &ACC_EMPTY {
return Ok(vec![::rlp::NULL_RLP.to_vec()]);
}
let db = TrieDB::new(acct_db, &acc.storage_root)?; let db = TrieDB::new(acct_db, &acc.storage_root)?;
let mut chunks = Vec::new();
let mut db_iter = db.iter()?;
let mut target_chunk_size = first_chunk_size;
let mut account_stream = RlpStream::new_list(2);
let mut leftover: Option<Vec<u8>> = None;
loop {
account_stream.append(account_hash);
account_stream.begin_list(5);
let chunks = db.iter()?.chunks(max_storage_items);
let pair_chunks = chunks.into_iter().map(|chunk| chunk.collect());
pair_chunks.pad_using(1, |_| Vec::new(), ).map(|pairs| {
let mut stream = RlpStream::new_list(pairs.len());
for r in pairs {
let (k, v) = r?;
stream.begin_list(2).append(&k).append(&&*v);
}
let pairs_rlp = stream.out();
let mut account_stream = RlpStream::new_list(5);
account_stream.append(&acc.nonce) account_stream.append(&acc.nonce)
.append(&acc.balance); .append(&acc.balance);
@ -105,9 +95,49 @@ pub fn to_fat_rlps(acc: &BasicAccount, acct_db: &AccountDB, used_code: &mut Hash
} }
} }
account_stream.append_raw(&pairs_rlp, 1); account_stream.begin_unbounded_list();
Ok(account_stream.out()) if account_stream.len() > target_chunk_size {
}).collect() // account does not fit, push an empty record to mark a new chunk
target_chunk_size = max_chunk_size;
chunks.push(Vec::new());
}
if let Some(pair) = leftover.take() {
if !account_stream.append_raw_checked(&pair, 1, target_chunk_size) {
return Err(Error::ChunkTooSmall);
}
}
loop {
match db_iter.next() {
Some(Ok((k, v))) => {
let pair = {
let mut stream = RlpStream::new_list(2);
stream.append(&k).append(&&*v);
stream.drain()
};
if !account_stream.append_raw_checked(&pair, 1, target_chunk_size) {
account_stream.complete_unbounded_list();
let stream = ::std::mem::replace(&mut account_stream, RlpStream::new_list(2));
chunks.push(stream.out());
target_chunk_size = max_chunk_size;
leftover = Some(pair.to_vec());
break;
}
},
Some(Err(e)) => {
return Err(e.into());
},
None => {
account_stream.complete_unbounded_list();
let stream = ::std::mem::replace(&mut account_stream, RlpStream::new_list(2));
chunks.push(stream.out());
return Ok(chunks);
}
}
}
}
} }
// decode a fat rlp, and rebuild the storage trie as we go. // decode a fat rlp, and rebuild the storage trie as we go.
@ -181,7 +211,7 @@ mod tests {
use snapshot::tests::helpers::fill_storage; use snapshot::tests::helpers::fill_storage;
use util::sha3::{SHA3_EMPTY, SHA3_NULL_RLP}; use util::sha3::{SHA3_EMPTY, SHA3_NULL_RLP};
use util::{Address, H256, HashDB, DBValue}; use util::{Address, H256, HashDB, DBValue, Hashable};
use rlp::UntrustedRlp; use rlp::UntrustedRlp;
use std::collections::HashSet; use std::collections::HashSet;
@ -203,8 +233,8 @@ mod tests {
let thin_rlp = ::rlp::encode(&account); let thin_rlp = ::rlp::encode(&account);
assert_eq!(::rlp::decode::<BasicAccount>(&thin_rlp), account); assert_eq!(::rlp::decode::<BasicAccount>(&thin_rlp), account);
let fat_rlps = to_fat_rlps(&account, &AccountDB::new(db.as_hashdb(), &addr), &mut Default::default(), usize::max_value()).unwrap(); let fat_rlps = to_fat_rlps(&addr.sha3(), &account, &AccountDB::new(db.as_hashdb(), &addr), &mut Default::default(), usize::max_value(), usize::max_value()).unwrap();
let fat_rlp = UntrustedRlp::new(&fat_rlps[0]); let fat_rlp = UntrustedRlp::new(&fat_rlps[0]).at(1).unwrap();
assert_eq!(from_fat_rlp(&mut AccountDBMut::new(db.as_hashdb_mut(), &addr), fat_rlp, H256::zero()).unwrap().0, account); assert_eq!(from_fat_rlp(&mut AccountDBMut::new(db.as_hashdb_mut(), &addr), fat_rlp, H256::zero()).unwrap().0, account);
} }
@ -228,8 +258,8 @@ mod tests {
let thin_rlp = ::rlp::encode(&account); let thin_rlp = ::rlp::encode(&account);
assert_eq!(::rlp::decode::<BasicAccount>(&thin_rlp), account); assert_eq!(::rlp::decode::<BasicAccount>(&thin_rlp), account);
let fat_rlp = to_fat_rlps(&account, &AccountDB::new(db.as_hashdb(), &addr), &mut Default::default(), usize::max_value()).unwrap(); let fat_rlp = to_fat_rlps(&addr.sha3(), &account, &AccountDB::new(db.as_hashdb(), &addr), &mut Default::default(), usize::max_value(), usize::max_value()).unwrap();
let fat_rlp = UntrustedRlp::new(&fat_rlp[0]); let fat_rlp = UntrustedRlp::new(&fat_rlp[0]).at(1).unwrap();
assert_eq!(from_fat_rlp(&mut AccountDBMut::new(db.as_hashdb_mut(), &addr), fat_rlp, H256::zero()).unwrap().0, account); assert_eq!(from_fat_rlp(&mut AccountDBMut::new(db.as_hashdb_mut(), &addr), fat_rlp, H256::zero()).unwrap().0, account);
} }
@ -253,11 +283,11 @@ mod tests {
let thin_rlp = ::rlp::encode(&account); let thin_rlp = ::rlp::encode(&account);
assert_eq!(::rlp::decode::<BasicAccount>(&thin_rlp), account); assert_eq!(::rlp::decode::<BasicAccount>(&thin_rlp), account);
let fat_rlps = to_fat_rlps(&account, &AccountDB::new(db.as_hashdb(), &addr), &mut Default::default(), 100).unwrap(); let fat_rlps = to_fat_rlps(&addr.sha3(), &account, &AccountDB::new(db.as_hashdb(), &addr), &mut Default::default(), 500, 1000).unwrap();
let mut root = SHA3_NULL_RLP; let mut root = SHA3_NULL_RLP;
let mut restored_account = None; let mut restored_account = None;
for rlp in fat_rlps { for rlp in fat_rlps {
let fat_rlp = UntrustedRlp::new(&rlp); let fat_rlp = UntrustedRlp::new(&rlp).at(1).unwrap();
restored_account = Some(from_fat_rlp(&mut AccountDBMut::new(db.as_hashdb_mut(), &addr), fat_rlp, root).unwrap().0); restored_account = Some(from_fat_rlp(&mut AccountDBMut::new(db.as_hashdb_mut(), &addr), fat_rlp, root).unwrap().0);
root = restored_account.as_ref().unwrap().storage_root.clone(); root = restored_account.as_ref().unwrap().storage_root.clone();
} }
@ -297,12 +327,12 @@ mod tests {
let mut used_code = HashSet::new(); let mut used_code = HashSet::new();
let fat_rlp1 = to_fat_rlps(&account1, &AccountDB::new(db.as_hashdb(), &addr1), &mut used_code, usize::max_value()).unwrap(); let fat_rlp1 = to_fat_rlps(&addr1.sha3(), &account1, &AccountDB::new(db.as_hashdb(), &addr1), &mut used_code, usize::max_value(), usize::max_value()).unwrap();
let fat_rlp2 = to_fat_rlps(&account2, &AccountDB::new(db.as_hashdb(), &addr2), &mut used_code, usize::max_value()).unwrap(); let fat_rlp2 = to_fat_rlps(&addr2.sha3(), &account2, &AccountDB::new(db.as_hashdb(), &addr2), &mut used_code, usize::max_value(), usize::max_value()).unwrap();
assert_eq!(used_code.len(), 1); assert_eq!(used_code.len(), 1);
let fat_rlp1 = UntrustedRlp::new(&fat_rlp1[0]); let fat_rlp1 = UntrustedRlp::new(&fat_rlp1[0]).at(1).unwrap();
let fat_rlp2 = UntrustedRlp::new(&fat_rlp2[0]); let fat_rlp2 = UntrustedRlp::new(&fat_rlp2[0]).at(1).unwrap();
let (acc, maybe_code) = from_fat_rlp(&mut AccountDBMut::new(db.as_hashdb_mut(), &addr2), fat_rlp2, H256::zero()).unwrap(); let (acc, maybe_code) = from_fat_rlp(&mut AccountDBMut::new(db.as_hashdb_mut(), &addr2), fat_rlp2, H256::zero()).unwrap();
assert!(maybe_code.is_none()); assert!(maybe_code.is_none());
@ -316,9 +346,6 @@ mod tests {
#[test] #[test]
fn encoding_empty_acc() { fn encoding_empty_acc() {
let mut db = get_temp_state_db(); let mut db = get_temp_state_db();
let mut used_code = HashSet::new();
assert_eq!(to_fat_rlps(&ACC_EMPTY, &AccountDB::new(db.as_hashdb(), &Address::default()), &mut used_code, usize::max_value()).unwrap(), vec![::rlp::NULL_RLP.to_vec()]);
assert_eq!(from_fat_rlp(&mut AccountDBMut::new(db.as_hashdb_mut(), &Address::default()), UntrustedRlp::new(&::rlp::NULL_RLP), H256::zero()).unwrap(), (ACC_EMPTY, None)); assert_eq!(from_fat_rlp(&mut AccountDBMut::new(db.as_hashdb_mut(), &Address::default()), UntrustedRlp::new(&::rlp::NULL_RLP), H256::zero()).unwrap(), (ACC_EMPTY, None));
} }
} }

View File

@ -55,6 +55,8 @@ pub enum Error {
Io(::std::io::Error), Io(::std::io::Error),
/// Snapshot version is not supported. /// Snapshot version is not supported.
VersionNotSupported(u64), VersionNotSupported(u64),
/// Max chunk size is to small to fit basic account data.
ChunkTooSmall,
} }
impl fmt::Display for Error { impl fmt::Display for Error {
@ -76,6 +78,7 @@ impl fmt::Display for Error {
Error::Decoder(ref err) => err.fmt(f), Error::Decoder(ref err) => err.fmt(f),
Error::Trie(ref err) => err.fmt(f), Error::Trie(ref err) => err.fmt(f),
Error::VersionNotSupported(ref ver) => write!(f, "Snapshot version {} is not supprted.", ver), Error::VersionNotSupported(ref ver) => write!(f, "Snapshot version {} is not supprted.", ver),
Error::ChunkTooSmall => write!(f, "Chunk size is too small."),
} }
} }
} }

View File

@ -83,9 +83,6 @@ mod traits {
// Try to have chunks be around 4MB (before compression) // Try to have chunks be around 4MB (before compression)
const PREFERRED_CHUNK_SIZE: usize = 4 * 1024 * 1024; const PREFERRED_CHUNK_SIZE: usize = 4 * 1024 * 1024;
// Try to have chunks be around 4MB (before compression)
const MAX_STORAGE_ENTRIES_PER_ACCOUNT_RECORD: usize = 80_000;
// How many blocks to include in a snapshot, starting from the head of the chain. // How many blocks to include in a snapshot, starting from the head of the chain.
const SNAPSHOT_BLOCKS: u64 = 30000; const SNAPSHOT_BLOCKS: u64 = 30000;
@ -305,20 +302,9 @@ impl<'a> StateChunker<'a> {
// //
// If the buffer is greater than the desired chunk size, // If the buffer is greater than the desired chunk size,
// this will write out the data to disk. // this will write out the data to disk.
fn push(&mut self, account_hash: Bytes, data: Bytes, force_chunk: bool) -> Result<(), Error> { fn push(&mut self, data: Bytes) -> Result<(), Error> {
let pair = { self.cur_size += data.len();
let mut stream = RlpStream::new_list(2); self.rlps.push(data);
stream.append(&account_hash).append_raw(&data, 1);
stream.out()
};
if force_chunk || self.cur_size + pair.len() >= PREFERRED_CHUNK_SIZE {
self.write_chunk()?;
}
self.cur_size += pair.len();
self.rlps.push(pair);
Ok(()) Ok(())
} }
@ -348,6 +334,11 @@ impl<'a> StateChunker<'a> {
Ok(()) Ok(())
} }
// Get current chunk size.
fn chunk_size(&self) -> usize {
self.cur_size
}
} }
/// Walk the given state database starting from the given root, /// Walk the given state database starting from the given root,
@ -377,9 +368,12 @@ pub fn chunk_state<'a>(db: &HashDB, root: &H256, writer: &Mutex<SnapshotWriter +
let account_db = AccountDB::from_hash(db, account_key_hash); let account_db = AccountDB::from_hash(db, account_key_hash);
let fat_rlps = account::to_fat_rlps(&account, &account_db, &mut used_code, MAX_STORAGE_ENTRIES_PER_ACCOUNT_RECORD)?; let fat_rlps = account::to_fat_rlps(&account_key_hash, &account, &account_db, &mut used_code, PREFERRED_CHUNK_SIZE - chunker.chunk_size(), PREFERRED_CHUNK_SIZE)?;
for (i, fat_rlp) in fat_rlps.into_iter().enumerate() { for (i, fat_rlp) in fat_rlps.into_iter().enumerate() {
chunker.push(account_key.clone(), fat_rlp, i > 0)?; if i > 0 {
chunker.write_chunk()?;
}
chunker.push(fat_rlp)?;
} }
} }

View File

@ -122,10 +122,9 @@ fn get_code_from_prev_chunk() {
let mut db = MemoryDB::new(); let mut db = MemoryDB::new();
AccountDBMut::from_hash(&mut db, hash).insert(&code[..]); AccountDBMut::from_hash(&mut db, hash).insert(&code[..]);
let fat_rlp = account::to_fat_rlps(&acc, &AccountDB::from_hash(&db, hash), &mut used_code, usize::max_value()).unwrap(); let fat_rlp = account::to_fat_rlps(&hash, &acc, &AccountDB::from_hash(&db, hash), &mut used_code, usize::max_value(), usize::max_value()).unwrap();
let mut stream = RlpStream::new_list(1); let mut stream = RlpStream::new_list(1);
stream.begin_list(2).append(&hash).append_raw(&fat_rlp[0], 1); stream.append_raw(&fat_rlp[0], 1);
stream.out() stream.out()
}; };

View File

@ -214,10 +214,10 @@ mod derivation {
use rcrypto::sha2::Sha512; use rcrypto::sha2::Sha512;
use bigint::hash::{H512, H256}; use bigint::hash::{H512, H256};
use bigint::prelude::{U256, U512, Uint}; use bigint::prelude::{U256, U512, Uint};
use secp256k1;
use secp256k1::key::{SecretKey, PublicKey}; use secp256k1::key::{SecretKey, PublicKey};
use SECP256K1; use SECP256K1;
use keccak; use keccak;
use math::curve_order;
use super::{Label, Derivation}; use super::{Label, Derivation};
#[derive(Debug)] #[derive(Debug)]
@ -233,7 +233,7 @@ mod derivation {
// For hardened derivation, pass u32 index at least 2^31 or custom Derivation::Hard(T) enum // For hardened derivation, pass u32 index at least 2^31 or custom Derivation::Hard(T) enum
// //
// Can panic if passed `private_key` is not a valid secp256k1 private key // Can panic if passed `private_key` is not a valid secp256k1 private key
// (outside of (0..curve_n()]) field // (outside of (0..curve_order()]) field
pub fn private<T>(private_key: H256, chain_code: H256, index: Derivation<T>) -> (H256, H256) where T: Label { pub fn private<T>(private_key: H256, chain_code: H256, index: Derivation<T>) -> (H256, H256) where T: Label {
match index { match index {
Derivation::Soft(index) => private_soft(private_key, chain_code, index), Derivation::Soft(index) => private_soft(private_key, chain_code, index),
@ -260,7 +260,7 @@ mod derivation {
} }
// Can panic if passed `private_key` is not a valid secp256k1 private key // Can panic if passed `private_key` is not a valid secp256k1 private key
// (outside of (0..curve_n()]) field // (outside of (0..curve_order()]) field
fn private_soft<T>(private_key: H256, chain_code: H256, index: T) -> (H256, H256) where T: Label { fn private_soft<T>(private_key: H256, chain_code: H256, index: T) -> (H256, H256) where T: Label {
let mut data = vec![0u8; 33 + T::len()]; let mut data = vec![0u8; 33 + T::len()];
@ -295,7 +295,7 @@ mod derivation {
fn private_add(k1: U256, k2: U256) -> U256 { fn private_add(k1: U256, k2: U256) -> U256 {
let sum = U512::from(k1) + U512::from(k2); let sum = U512::from(k1) + U512::from(k2);
modulo(sum, curve_n()) modulo(sum, curve_order())
} }
// todo: surely can be optimized // todo: surely can be optimized
@ -305,12 +305,6 @@ mod derivation {
md.into() md.into()
} }
// returns n (for mod(n)) for the secp256k1 elliptic curve
// todo: maybe lazy static
fn curve_n() -> U256 {
H256::from_slice(&secp256k1::constants::CURVE_ORDER).into()
}
pub fn public<T>(public_key: H512, chain_code: H256, derivation: Derivation<T>) -> Result<(H512, H256), Error> where T: Label { pub fn public<T>(public_key: H512, chain_code: H256, derivation: Derivation<T>) -> Result<(H512, H256), Error> where T: Label {
let index = match derivation { let index = match derivation {
Derivation::Soft(index) => index, Derivation::Soft(index) => index,
@ -339,7 +333,7 @@ mod derivation {
let new_chain_code = H256::from(&i_512[32..64]); let new_chain_code = H256::from(&i_512[32..64]);
// Generated private key can (extremely rarely) be out of secp256k1 key field // Generated private key can (extremely rarely) be out of secp256k1 key field
if curve_n() <= new_private.clone().into() { return Err(Error::MissingIndex); } if curve_order() <= new_private.clone().into() { return Err(Error::MissingIndex); }
let new_private_sec = SecretKey::from_slice(&SECP256K1, &*new_private) let new_private_sec = SecretKey::from_slice(&SECP256K1, &*new_private)
.expect("Private key belongs to the field [0..CURVE_ORDER) (checked above); So initializing can never fail; qed"); .expect("Private key belongs to the field [0..CURVE_ORDER) (checked above); So initializing can never fail; qed");
let mut new_public = PublicKey::from_secret_key(&SECP256K1, &new_private_sec) let mut new_public = PublicKey::from_secret_key(&SECP256K1, &new_private_sec)

View File

@ -27,7 +27,7 @@ pub fn public_to_address(public: &Public) -> Address {
result result
} }
#[derive(Clone)] #[derive(Debug, Clone, PartialEq)]
/// secp256k1 key pair /// secp256k1 key pair
pub struct KeyPair { pub struct KeyPair {
secret: Secret, secret: Secret,

View File

@ -16,7 +16,9 @@
use super::{SECP256K1, Public, Secret, Error}; use super::{SECP256K1, Public, Secret, Error};
use secp256k1::key; use secp256k1::key;
use secp256k1::constants::{GENERATOR_X, GENERATOR_Y}; use secp256k1::constants::{GENERATOR_X, GENERATOR_Y, CURVE_ORDER};
use bigint::prelude::U256;
use bigint::hash::H256;
/// Inplace multiply public key by secret key (EC point * scalar) /// Inplace multiply public key by secret key (EC point * scalar)
pub fn public_mul_secret(public: &mut Public, secret: &Secret) -> Result<(), Error> { pub fn public_mul_secret(public: &mut Public, secret: &Secret) -> Result<(), Error> {
@ -47,6 +49,14 @@ pub fn public_sub(public: &mut Public, other: &Public) -> Result<(), Error> {
Ok(()) Ok(())
} }
/// Replace public key with its negation (EC point = - EC point)
pub fn public_negate(public: &mut Public) -> Result<(), Error> {
let mut key_public = to_secp256k1_public(public)?;
key_public.mul_assign(&SECP256K1, &key::MINUS_ONE_KEY)?;
set_public(public, &key_public);
Ok(())
}
/// Return base point of secp256k1 /// Return base point of secp256k1
pub fn generation_point() -> Public { pub fn generation_point() -> Public {
let mut public_sec_raw = [0u8; 65]; let mut public_sec_raw = [0u8; 65];
@ -61,6 +71,11 @@ pub fn generation_point() -> Public {
public public
} }
/// Return secp256k1 elliptic curve order
pub fn curve_order() -> U256 {
H256::from_slice(&CURVE_ORDER).into()
}
fn to_secp256k1_public(public: &Public) -> Result<key::PublicKey, Error> { fn to_secp256k1_public(public: &Public) -> Result<key::PublicKey, Error> {
let public_data = { let public_data = {
let mut temp = [4u8; 65]; let mut temp = [4u8; 65];

View File

@ -67,6 +67,15 @@ impl Secret {
Ok(()) Ok(())
} }
/// Inplace decrease secret key (scalar - 1)
pub fn dec(&mut self) -> Result<(), Error> {
let mut key_secret = self.to_secp256k1_secret()?;
key_secret.add_assign(&SECP256K1, &key::MINUS_ONE_KEY)?;
*self = key_secret.into();
Ok(())
}
/// Inplace multiply one secret key to another (scalar * scalar) /// Inplace multiply one secret key to another (scalar * scalar)
pub fn mul(&mut self, other: &Secret) -> Result<(), Error> { pub fn mul(&mut self, other: &Secret) -> Result<(), Error> {
let mut key_secret = self.to_secp256k1_secret()?; let mut key_secret = self.to_secp256k1_secret()?;

View File

@ -1,6 +1,6 @@
{ {
"name": "parity.js", "name": "parity.js",
"version": "1.7.46", "version": "1.7.49",
"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>",

View File

@ -37,7 +37,11 @@ Object.keys(rustMethods).forEach((group) => {
}); });
}); });
function printType (type) { function printType (type, obj) {
if (!type) {
throw new Error(`Invalid type in ${JSON.stringify(obj)}`);
}
return type.print || `\`${type.name}\``; return type.print || `\`${type.name}\``;
} }
@ -45,7 +49,7 @@ function formatDescription (obj, prefix = '', indent = '') {
const optional = obj.optional ? '(optional) ' : ''; const optional = obj.optional ? '(optional) ' : '';
const defaults = obj.default ? `(default: \`${obj.default}\`) ` : ''; const defaults = obj.default ? `(default: \`${obj.default}\`) ` : '';
return `${indent}${prefix}${printType(obj.type)} - ${optional}${defaults}${obj.desc}`; return `${indent}${prefix}${printType(obj.type, obj)} - ${optional}${defaults}${obj.desc}`;
} }
function formatType (obj) { function formatType (obj) {

View File

@ -165,10 +165,6 @@ export function inOptions (_options = {}) {
options[key] = inNumber16((new BigNumber(options[key])).round()); options[key] = inNumber16((new BigNumber(options[key])).round());
break; break;
case 'minBlock':
options[key] = options[key] ? inNumber16(options[key]) : null;
break;
case 'value': case 'value':
case 'nonce': case 'nonce':
options[key] = inNumber16(options[key]); options[key] = inNumber16(options[key]);
@ -211,3 +207,36 @@ export function inTraceType (whatTrace) {
return whatTrace; return whatTrace;
} }
function inDeriveType (derive) {
return derive && derive.type === 'hard' ? 'hard' : 'soft';
}
export function inDeriveHash (derive) {
const hash = derive && derive.hash ? derive.hash : derive;
const type = inDeriveType(derive);
return {
hash: inHex(hash),
type
};
}
export function inDeriveIndex (derive) {
if (!derive) {
return [];
}
if (!isArray(derive)) {
derive = [derive];
}
return derive.map(item => {
const index = inNumber10(item && item.index ? item.index : item);
return {
index,
type: inDeriveType(item)
};
});
}

View File

@ -16,7 +16,11 @@
import BigNumber from 'bignumber.js'; import BigNumber from 'bignumber.js';
import { inAddress, inBlockNumber, inData, inFilter, inHex, inNumber10, inNumber16, inOptions, inTraceType } from './input'; import {
inAddress, inBlockNumber, inData, inFilter, inHex,
inNumber10, inNumber16, inOptions, inTraceType,
inDeriveHash, inDeriveIndex
} from './input';
import { isAddress } from '../../../test/types'; import { isAddress } from '../../../test/types';
describe('api/format/input', () => { describe('api/format/input', () => {
@ -215,7 +219,7 @@ describe('api/format/input', () => {
expect(formatted.to).to.equal(''); expect(formatted.to).to.equal('');
}); });
['gas', 'gasPrice', 'value', 'minBlock', 'nonce'].forEach((input) => { ['gas', 'gasPrice', 'value', 'nonce'].forEach((input) => {
it(`formats ${input} number as hexnumber`, () => { it(`formats ${input} number as hexnumber`, () => {
const block = {}; const block = {};
@ -226,8 +230,8 @@ describe('api/format/input', () => {
}); });
}); });
it('passes minBlock as null when specified as such', () => { it('passes condition as null when specified as such', () => {
expect(inOptions({ minBlock: null })).to.deep.equal({ minBlock: null }); expect(inOptions({ condition: null })).to.deep.equal({ condition: null });
}); });
it('ignores and passes through unknown keys', () => { it('ignores and passes through unknown keys', () => {
@ -272,4 +276,66 @@ describe('api/format/input', () => {
expect(inTraceType(type)).to.deep.equal([type]); expect(inTraceType(type)).to.deep.equal([type]);
}); });
}); });
describe('inDeriveHash', () => {
it('returns derive hash', () => {
expect(inDeriveHash(1)).to.deep.equal({
hash: '0x1',
type: 'soft'
});
expect(inDeriveHash(null)).to.deep.equal({
hash: '0x',
type: 'soft'
});
expect(inDeriveHash({
hash: 5
})).to.deep.equal({
hash: '0x5',
type: 'soft'
});
expect(inDeriveHash({
hash: 5,
type: 'hard'
})).to.deep.equal({
hash: '0x5',
type: 'hard'
});
});
});
describe('inDeriveIndex', () => {
it('returns derive hash', () => {
expect(inDeriveIndex(null)).to.deep.equal([]);
expect(inDeriveIndex([])).to.deep.equal([]);
expect(inDeriveIndex([1])).to.deep.equal([{
index: 1,
type: 'soft'
}]);
expect(inDeriveIndex({
index: 1
})).to.deep.equal([{
index: 1,
type: 'soft'
}]);
expect(inDeriveIndex([{
index: 1,
type: 'hard'
}, 5])).to.deep.equal([
{
index: 1,
type: 'hard'
},
{
index: 5,
type: 'soft'
}
]);
});
});
}); });

View File

@ -216,6 +216,8 @@ export function outSignerRequest (request) {
break; break;
case 'payload': case 'payload':
request[key].decrypt = outSigningPayload(request[key].decrypt);
request[key].sign = outSigningPayload(request[key].sign);
request[key].signTransaction = outTransaction(request[key].signTransaction); request[key].signTransaction = outTransaction(request[key].signTransaction);
request[key].sendTransaction = outTransaction(request[key].sendTransaction); request[key].sendTransaction = outTransaction(request[key].sendTransaction);
break; break;
@ -284,12 +286,6 @@ export function outTransaction (tx) {
tx[key] = outTransactionCondition(tx[key]); tx[key] = outTransactionCondition(tx[key]);
break; break;
case 'minBlock':
tx[key] = tx[key]
? outNumber(tx[key])
: null;
break;
case 'creates': case 'creates':
case 'from': case 'from':
case 'to': case 'to':
@ -302,6 +298,20 @@ export function outTransaction (tx) {
return tx; return tx;
} }
export function outSigningPayload (payload) {
if (payload) {
Object.keys(payload).forEach((key) => {
switch (key) {
case 'address':
payload[key] = outAddress(payload[key]);
break;
}
});
}
return payload;
}
export function outTrace (trace) { export function outTrace (trace) {
if (trace) { if (trace) {
if (trace.action) { if (trace.action) {

View File

@ -392,7 +392,7 @@ describe('api/format/output', () => {
}); });
}); });
['blockNumber', 'gasPrice', 'gas', 'minBlock', 'nonce', 'transactionIndex', 'value'].forEach((input) => { ['blockNumber', 'gasPrice', 'gas', 'nonce', 'transactionIndex', 'value'].forEach((input) => {
it(`formats ${input} number as hexnumber`, () => { it(`formats ${input} number as hexnumber`, () => {
const block = {}; const block = {};
@ -404,8 +404,8 @@ describe('api/format/output', () => {
}); });
}); });
it('passes minBlock as null when null', () => { it('passes condition as null when null', () => {
expect(outTransaction({ minBlock: null })).to.deep.equal({ minBlock: null }); expect(outTransaction({ condition: null })).to.deep.equal({ condition: null });
}); });
it('ignores and passes through unknown keys', () => { it('ignores and passes through unknown keys', () => {

View File

@ -14,7 +14,9 @@
// 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/>.
import { inAddress, inAddresses, inData, inHex, inNumber16, inOptions, inBlockNumber } from '../../format/input'; import {
inAddress, inAddresses, inData, inHex, inNumber16, inOptions, inBlockNumber, inDeriveHash, inDeriveIndex
} from '../../format/input';
import { outAccountInfo, outAddress, outAddresses, outChainStatus, outHistogram, outHwAccountInfo, outNodeKind, outNumber, outPeers, outRecentDapps, outTransaction, outVaultMeta } from '../../format/output'; import { outAccountInfo, outAddress, outAddresses, outChainStatus, outHistogram, outHwAccountInfo, outNodeKind, outNumber, outPeers, outRecentDapps, outTransaction, outVaultMeta } from '../../format/output';
export default class Parity { export default class Parity {
@ -117,6 +119,18 @@ export default class Parity {
.execute('parity_devLogsLevels'); .execute('parity_devLogsLevels');
} }
deriveAddressHash (address, password, hash, shouldSave) {
return this._transport
.execute('parity_deriveAddressHash', inAddress(address), password, inDeriveHash(hash), !!shouldSave)
.then(outAddress);
}
deriveAddressIndex (address, password, index, shouldSave) {
return this._transport
.execute('parity_deriveAddressIndex', inAddress(address), password, inDeriveIndex(index), !!shouldSave)
.then(outAddress);
}
dropNonReservedPeers () { dropNonReservedPeers () {
return this._transport return this._transport
.execute('parity_dropNonReservedPeers'); .execute('parity_dropNonReservedPeers');
@ -137,6 +151,11 @@ export default class Parity {
.execute('parity_executeUpgrade'); .execute('parity_executeUpgrade');
} }
exportAccount (address, password) {
return this._transport
.execute('parity_exportAccount', inAddress(address), password);
}
extraData () { extraData () {
return this._transport return this._transport
.execute('parity_extraData'); .execute('parity_extraData');
@ -401,6 +420,12 @@ export default class Parity {
.execute('parity_removeReservedPeer', encode); .execute('parity_removeReservedPeer', encode);
} }
removeTransaction (hash) {
return this._transport
.execute('parity_removeTransaction', inHex(hash))
.then(outTransaction);
}
rpcSettings () { rpcSettings () {
return this._transport return this._transport
.execute('parity_rpcSettings'); .execute('parity_rpcSettings');

View File

@ -23,7 +23,7 @@ const parityNode = (
process.env.PARITY_URL && `http://${process.env.PARITY_URL}` process.env.PARITY_URL && `http://${process.env.PARITY_URL}`
) || ( ) || (
process.env.NODE_ENV === 'production' process.env.NODE_ENV === 'production'
? 'http://127.0.0.1:8080' ? 'http://127.0.0.1:8545'
: '' : ''
); );

View File

@ -379,7 +379,9 @@ export default {
gasPrice: '0x2d20cff33', gasPrice: '0x2d20cff33',
hash: '0x09e64eb1ae32bb9ac415ce4ddb3dbad860af72d9377bb5f073c9628ab413c532', hash: '0x09e64eb1ae32bb9ac415ce4ddb3dbad860af72d9377bb5f073c9628ab413c532',
input: '0x', input: '0x',
minBlock: null, condition: {
block: 1
},
networkId: null, networkId: null,
nonce: '0x0', nonce: '0x0',
publicKey: '0x3fa8c08c65a83f6b4ea3e04e1cc70cbe3cd391499e3e05ab7dedf28aff9afc538200ff93e3f2b2cb5029f03c7ebee820d63a4c5a9541c83acebe293f54cacf0e', publicKey: '0x3fa8c08c65a83f6b4ea3e04e1cc70cbe3cd391499e3e05ab7dedf28aff9afc538200ff93e3f2b2cb5029f03c7ebee820d63a4c5a9541c83acebe293f54cacf0e',
@ -435,17 +437,17 @@ export default {
type: String, type: String,
desc: 'Capability, either `full` or `light`.' desc: 'Capability, either `full` or `light`.'
} }
},
example: {
availability: 'personal',
capability: 'light'
} }
},
example: {
availability: 'personal',
capability: 'light'
} }
}, },
netChain: { netChain: {
section: SECTION_NET, section: SECTION_NET,
desc: 'Returns the name of the connected chain.', desc: 'Returns the name of the connected chain. DEPRECATED use `parity_chain` instead.',
params: [], params: [],
returns: { returns: {
type: String, type: String,
@ -454,6 +456,17 @@ export default {
} }
}, },
chain: {
section: SECTION_NET,
desc: 'Returns the name of the connected chain. ',
params: [],
returns: {
type: String,
desc: 'chain name, one of: "foundation", "kovan", &c. of a filename.',
example: 'homestead'
}
},
netPeers: { netPeers: {
section: SECTION_NET, section: SECTION_NET,
desc: 'Returns number of peers.', desc: 'Returns number of peers.',
@ -589,7 +602,9 @@ export default {
gasPrice: '0xba43b7400', gasPrice: '0xba43b7400',
hash: '0x160b3c30ab1cf5871083f97ee1cee3901cfba3b0a2258eb337dd20a7e816b36e', hash: '0x160b3c30ab1cf5871083f97ee1cee3901cfba3b0a2258eb337dd20a7e816b36e',
input: '0x095ea7b3000000000000000000000000bf4ed7b27f1d666546e30d74d50d173d20bca75400000000000000000000000000002643c948210b4bd99244ccd64d5555555555', input: '0x095ea7b3000000000000000000000000bf4ed7b27f1d666546e30d74d50d173d20bca75400000000000000000000000000002643c948210b4bd99244ccd64d5555555555',
minBlock: null, condition: {
block: 1
},
networkId: 1, networkId: 1,
nonce: '0x5', nonce: '0x5',
publicKey: '0x96157302dade55a1178581333e57d60ffe6fdf5a99607890456a578b4e6b60e335037d61ed58aa4180f9fd747dc50d44a7924aa026acbfb988b5062b629d6c36', publicKey: '0x96157302dade55a1178581333e57d60ffe6fdf5a99607890456a578b4e6b60e335037d61ed58aa4180f9fd747dc50d44a7924aa026acbfb988b5062b629d6c36',
@ -609,6 +624,7 @@ export default {
}, },
pendingTransactionsStats: { pendingTransactionsStats: {
section: SECTION_NET,
desc: 'Returns propagation stats for transactions in the queue.', desc: 'Returns propagation stats for transactions in the queue.',
params: [], params: [],
returns: { returns: {
@ -626,6 +642,49 @@ export default {
} }
}, },
removeTransaction: {
section: SECTION_NET,
desc: 'Removes transaction from local transaction pool. Scheduled transactions and not-propagated transactions are safe to remove, removal of other transactions may have no effect though.',
params: [{
type: Hash,
desc: 'Hash of transaction to remove.',
example: '0x2547ea3382099c7c76d33dd468063b32d41016aacb02cbd51ebc14ff5d2b6a43'
}],
returns: {
type: Object,
desc: 'Removed transaction or `null`.',
details: TransactionResponse.details,
example: [
{
blockHash: null,
blockNumber: null,
creates: null,
from: '0xee3ea02840129123d5397f91be0391283a25bc7d',
gas: '0x23b58',
gasPrice: '0xba43b7400',
hash: '0x160b3c30ab1cf5871083f97ee1cee3901cfba3b0a2258eb337dd20a7e816b36e',
input: '0x095ea7b3000000000000000000000000bf4ed7b27f1d666546e30d74d50d173d20bca75400000000000000000000000000002643c948210b4bd99244ccd64d5555555555',
condition: {
block: 1
},
networkId: 1,
nonce: '0x5',
publicKey: '0x96157302dade55a1178581333e57d60ffe6fdf5a99607890456a578b4e6b60e335037d61ed58aa4180f9fd747dc50d44a7924aa026acbfb988b5062b629d6c36',
r: '0x92e8beb19af2bad0511d516a86e77fa73004c0811b2173657a55797bdf8558e1',
raw: '0xf8aa05850ba43b740083023b5894bb9bc244d798123fde783fcc1c72d3bb8c18941380b844095ea7b3000000000000000000000000bf4ed7b27f1d666546e30d74d50d173d20bca75400000000000000000000000000002643c948210b4bd99244ccd64d555555555526a092e8beb19af2bad0511d516a86e77fa73004c0811b2173657a55797bdf8558e1a062b4d4d125bbcb9c162453bc36ca156537543bb4414d59d1805d37fb63b351b8',
s: '0x62b4d4d125bbcb9c162453bc36ca156537543bb4414d59d1805d37fb63b351b8',
standardV: '0x1',
to: '0xbb9bc244d798123fde783fcc1c72d3bb8c189413',
transactionIndex: null,
v: '0x26',
value: '0x0'
},
new Dummy('{ ... }'),
new Dummy('{ ... }')
]
}
},
phraseToAddress: { phraseToAddress: {
section: SECTION_ACCOUNTS, section: SECTION_ACCOUNTS,
desc: 'Converts a secret phrase into the corresponding address.', desc: 'Converts a secret phrase into the corresponding address.',
@ -916,7 +975,9 @@ export default {
v: '0x25', v: '0x25',
r: '0xb40c6967a7e8bbdfd99a25fd306b9ef23b80e719514aeb7ddd19e2303d6fc139', r: '0xb40c6967a7e8bbdfd99a25fd306b9ef23b80e719514aeb7ddd19e2303d6fc139',
s: '0x6bf770ab08119e67dc29817e1412a0e3086f43da308c314db1b3bca9fb6d32bd', s: '0x6bf770ab08119e67dc29817e1412a0e3086f43da308c314db1b3bca9fb6d32bd',
minBlock: null condition: {
block: 1
}
}, },
new Dummy('{ ... }, { ... }, ...') new Dummy('{ ... }, { ... }, ...')
] ]
@ -1307,12 +1368,14 @@ export default {
params: [ params: [
{ {
type: Array, type: Array,
desc: 'List of the Geth addresses to import.' desc: 'List of the Geth addresses to import.',
example: ['0x407d73d8a49eeb85d32cf465507dd71d507100c1']
} }
], ],
returns: { returns: {
type: Array, type: Array,
desc: 'Array of the imported addresses.' desc: 'Array of the imported addresses.',
example: ['0x407d73d8a49eeb85d32cf465507dd71d507100c1']
} }
}, },
@ -1322,7 +1385,114 @@ export default {
params: [], params: [],
returns: { returns: {
type: Array, type: Array,
desc: '20 Bytes addresses owned by the client.' desc: '20 Bytes addresses owned by the client.',
example: ['0x407d73d8a49eeb85d32cf465507dd71d507100c1']
}
},
deriveAddressHash: {
subdoc: SUBDOC_ACCOUNTS,
desc: 'Derive new address from given account address using specific hash.',
params: [
{
type: Address,
desc: 'Account address to derive from.',
example: '0x407d73d8a49eeb85d32cf465507dd71d507100c1'
},
{
type: String,
desc: 'Password to the account.',
example: 'hunter2'
},
{
type: Object,
desc: 'Derivation hash and type (`soft` or `hard`). E.g. `{ hash: "0x123..123", type: "hard" }`.',
example: {
hash: '0x2547ea3382099c7c76d33dd468063b32d41016aacb02cbd51ebc14ff5d2b6a43',
type: 'hard'
}
},
{
type: Boolean,
desc: 'Flag indicating if the account should be saved.',
example: false
}
],
returns: {
type: Address,
desc: '20 Bytes new derived address.',
example: '0x407d73d8a49eeb85d32cf465507dd71d507100c1'
}
},
deriveAddressIndex: {
subdoc: SUBDOC_ACCOUNTS,
desc: 'Derive new address from given account address using hierarchical derivation (sequence of 32-bit integer indices).',
params: [
{
type: Address,
desc: 'Account address to export.',
example: '0x407d73d8a49eeb85d32cf465507dd71d507100c1'
},
{
type: String,
desc: 'Password to the account.',
example: 'hunter2'
},
{
type: Array,
desc: 'Hierarchical derivation sequence of index and type (`soft` or `hard`). E.g. `[{index:1,type:"hard"},{index:2,type:"soft"}]`.',
example: [
{ index: 1, type: 'hard' },
{ index: 2, type: 'soft' }
]
},
{
type: Boolean,
desc: 'Flag indicating if the account should be saved.',
example: false
}
],
returns: {
type: Address,
desc: '20 Bytes new derived address.',
example: '0x407d73d8a49eeb85d32cf465507dd71d507100c1'
}
},
exportAccount: {
subdoc: SUBDOC_ACCOUNTS,
desc: 'Returns a standard wallet file for given account if password matches.',
params: [
{
type: Address,
desc: 'Account address to export.',
example: '0x407d73d8a49eeb85d32cf465507dd71d507100c1'
},
{
type: String,
desc: 'Password to the account.',
example: 'hunter2'
}
],
returns: {
type: Object,
desc: 'Standard wallet JSON.',
example: {
'address': '0042e5d2a662eeaca8a7e828c174f98f35d8925b',
'crypto': {
'cipher': 'aes-128-ctr',
'cipherparams': { 'iv': 'a1c6ff99070f8032ca1c4e8add006373' },
'ciphertext': 'df27e3db64aa18d984b6439443f73660643c2d119a6f0fa2fa9a6456fc802d75',
'kdf': 'pbkdf2',
'kdfparams': { 'c': 10240, 'dklen': 32, 'prf': 'hmac-sha256', 'salt': 'ddc325335cda5567a1719313e73b4842511f3e4a837c9658eeb78e51ebe8c815' },
'mac': '3dc888ae79cbb226ff9c455669f6cf2d79be72120f2298f6cb0d444fddc0aa3d'
},
'id': '6a186c80-7797-cff2-bc2e-7c1d6a6cc76e',
'meta': '{"passwordHint":"parity-export-test","timestamp":1490017814987}',
'name': 'parity-export-test',
'version': 3
}
} }
}, },
@ -1529,6 +1699,23 @@ export default {
} }
}, },
setChain: {
subdoc: SUBDOC_SET,
desc: 'Sets the network spec file Parity is using.',
params: [
{
type: String,
desc: 'Chain spec name, one of: "foundation", "ropsten", "morden", "kovan", "olympic", "classic", "dev", "expanse" or a filename.',
example: 'foundation'
}
],
returns: {
type: Boolean,
desc: '`true` if the call succeeded.',
example: true
}
},
setMode: { setMode: {
subdoc: SUBDOC_SET, subdoc: SUBDOC_SET,
desc: 'Changes the operating mode of Parity.', desc: 'Changes the operating mode of Parity.',

View File

@ -14,7 +14,7 @@
// 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/>.
import { Quantity, Data, BlockNumber } from '../types'; import { Quantity, Data } from '../types';
import { fromDecimal, Dummy } from '../helpers'; import { fromDecimal, Dummy } from '../helpers';
export default { export default {
@ -71,9 +71,9 @@ export default {
desc: 'Gas provided by the sender in Wei.', desc: 'Gas provided by the sender in Wei.',
optional: true optional: true
}, },
minBlock: { condition: {
type: BlockNumber, type: Object,
desc: 'Integer block number, or the string `\'latest\'`, `\'earliest\'` or `\'pending\'`. Request will not be propagated till the given block is reached.', desc: 'Condition for scheduled transaction. Can be either an integer block number `{ block: 1 }` or UTC timestamp (in seconds) `{ timestamp: 1491290692 }`.',
optional: true optional: true
} }
}, },
@ -114,7 +114,7 @@ export default {
}, },
confirmRequestWithToken: { confirmRequestWithToken: {
desc: 'Confirm specific request with token.', desc: 'Confirm specific request with rolling token.',
params: [ params: [
{ {
type: Quantity, type: Quantity,
@ -135,9 +135,9 @@ export default {
desc: 'Gas provided by the sender in Wei.', desc: 'Gas provided by the sender in Wei.',
optional: true optional: true
}, },
minBlock: { condition: {
type: BlockNumber, type: Object,
desc: 'Integer block number, or the string `\'latest\'`, `\'earliest\'` or `\'pending\'`. Request will not be propagated till the given block is reached.', desc: 'Conditional submission of the transaction. Can be either an integer block number `{ block: 1 }` or UTC timestamp (in seconds) `{ time: 1491290692 }` or `null`.',
optional: true optional: true
} }
}, },
@ -145,7 +145,7 @@ export default {
}, },
{ {
type: String, type: String,
desc: 'Password.', desc: 'Password (initially) or a token returned by the previous call.',
example: 'hunter2' example: 'hunter2'
} }
], ],
@ -159,7 +159,7 @@ export default {
}, },
token: { token: {
type: String, type: String,
desc: 'Token used to authenticate the request.' desc: 'Token used to authenticate the next request.'
} }
}, },
example: { example: {

View File

@ -102,9 +102,9 @@ export class TransactionRequest {
desc: 'Integer of a nonce. This allows to overwrite your own pending transactions that use the same nonce.', desc: 'Integer of a nonce. This allows to overwrite your own pending transactions that use the same nonce.',
optional: true optional: true
}, },
minBlock: { condition: {
type: BlockNumber, type: Object,
desc: 'Delay until this block if specified.', desc: 'Conditional submission of the transaction. Can be either an integer block number `{ block: 1 }` or UTC timestamp (in seconds) `{ time: 1491290692 }` or `null`.',
optional: true optional: true
} }
} }

View File

@ -28,7 +28,7 @@ export default class SecureApi extends Api {
_tokens = []; _tokens = [];
_dappsInterface = null; _dappsInterface = null;
_dappsPort = 8080; _dappsPort = 8545;
_signerPort = 8180; _signerPort = 8180;
static getTransport (url, sysuiToken) { static getTransport (url, sysuiToken) {

View File

@ -0,0 +1,183 @@
// 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/>.
import { observer } from 'mobx-react';
import React, { Component, PropTypes } from 'react';
import { FormattedMessage } from 'react-intl';
import { connect } from 'react-redux';
import Account from '../Account';
import TransactionPendingForm from '../TransactionPendingForm';
import RequestOrigin from '../RequestOrigin';
import styles from '../SignRequest/signRequest.css';
@observer
class DecryptRequest extends Component {
static contextTypes = {
api: PropTypes.object
};
static propTypes = {
accounts: PropTypes.object.isRequired,
address: PropTypes.string.isRequired,
data: PropTypes.string.isRequired,
id: PropTypes.object.isRequired,
isFinished: PropTypes.bool.isRequired,
netVersion: PropTypes.string.isRequired,
signerStore: PropTypes.object.isRequired,
className: PropTypes.string,
focus: PropTypes.bool,
isSending: PropTypes.bool,
onConfirm: PropTypes.func,
onReject: PropTypes.func,
origin: PropTypes.any,
status: PropTypes.string
};
static defaultProps = {
focus: false,
origin: {
type: 'unknown',
details: ''
}
};
componentWillMount () {
const { address, signerStore } = this.props;
signerStore.fetchBalance(address);
}
render () {
const { className } = this.props;
return (
<div className={ `${styles.container} ${className}` }>
{ this.renderDetails() }
{ this.renderActions() }
</div>
);
}
renderDetails () {
const { api } = this.context;
const { address, data, netVersion, origin, signerStore } = this.props;
const { balances, externalLink } = signerStore;
const balance = balances[address];
if (!balance) {
return <div />;
}
return (
<div className={ styles.signDetails }>
<div className={ styles.address }>
<Account
address={ address }
balance={ balance }
className={ styles.account }
externalLink={ externalLink }
netVersion={ netVersion }
/>
<RequestOrigin origin={ origin } />
</div>
<div className={ styles.info } title={ api.util.sha3(data) }>
<p>
<FormattedMessage
id='signer.decryptRequest.request'
defaultMessage='A request to decrypt data using your account:'
/>
</p>
<div className={ styles.signData }>
<p>{ data }</p>
</div>
</div>
</div>
);
}
renderActions () {
const { accounts, address, focus, isFinished, status } = this.props;
const account = accounts[address];
if (isFinished) {
if (status === 'confirmed') {
return (
<div className={ styles.actions }>
<span className={ styles.isConfirmed }>
<FormattedMessage
id='signer.decryptRequest.state.confirmed'
defaultMessage='Confirmed'
/>
</span>
</div>
);
}
return (
<div className={ styles.actions }>
<span className={ styles.isRejected }>
<FormattedMessage
id='signer.decryptRequest.state.rejected'
defaultMessage='Rejected'
/>
</span>
</div>
);
}
return (
<TransactionPendingForm
account={ account }
address={ address }
focus={ focus }
isSending={ this.props.isSending }
netVersion={ this.props.netVersion }
onConfirm={ this.onConfirm }
onReject={ this.onReject }
className={ styles.actions }
/>
);
}
onConfirm = (data) => {
const { id } = this.props;
const { password } = data;
this.props.onConfirm({ id, password });
}
onReject = () => {
this.props.onReject(this.props.id);
}
}
function mapStateToProps (state) {
const { accounts } = state.personal;
return {
accounts
};
}
export default connect(
mapStateToProps,
null
)(DecryptRequest);

View File

@ -0,0 +1,17 @@
// 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/>.
export default from './decryptRequest';

View File

@ -33,7 +33,7 @@
} }
.hash { .hash {
margin-left: .2em; margin-left: .5em;
} }
.hash, .url { .hash, .url {

View File

@ -16,8 +16,9 @@
import React, { Component, PropTypes } from 'react'; import React, { Component, PropTypes } from 'react';
import TransactionPending from '../TransactionPending'; import DecryptRequest from '../DecryptRequest';
import SignRequest from '../SignRequest'; import SignRequest from '../SignRequest';
import TransactionPending from '../TransactionPending';
export default class RequestPending extends Component { export default class RequestPending extends Component {
static propTypes = { static propTypes = {
@ -32,6 +33,7 @@ export default class RequestPending extends Component {
onReject: PropTypes.func.isRequired, onReject: PropTypes.func.isRequired,
origin: PropTypes.object.isRequired, origin: PropTypes.object.isRequired,
payload: PropTypes.oneOfType([ payload: PropTypes.oneOfType([
PropTypes.shape({ decrypt: PropTypes.object.isRequired }),
PropTypes.shape({ sendTransaction: PropTypes.object.isRequired }), PropTypes.shape({ sendTransaction: PropTypes.object.isRequired }),
PropTypes.shape({ sign: PropTypes.object.isRequired }), PropTypes.shape({ sign: PropTypes.object.isRequired }),
PropTypes.shape({ signTransaction: PropTypes.object.isRequired }) PropTypes.shape({ signTransaction: PropTypes.object.isRequired })
@ -68,6 +70,27 @@ export default class RequestPending extends Component {
); );
} }
if (payload.decrypt) {
const { decrypt } = payload;
return (
<DecryptRequest
address={ decrypt.address }
className={ className }
focus={ focus }
data={ decrypt.msg }
id={ id }
isFinished={ false }
isSending={ isSending }
netVersion={ netVersion }
onConfirm={ this.onConfirm }
onReject={ onReject }
origin={ origin }
signerStore={ signerStore }
/>
);
}
const transaction = payload.sendTransaction || payload.signTransaction; const transaction = payload.sendTransaction || payload.signTransaction;
if (transaction) { if (transaction) {

View File

@ -19,7 +19,7 @@
.container { .container {
display: flex; display: flex;
padding: 1.5em 0 1em; padding: 1.5em 1em 1.5em 0;
} }
.actions, .signDetails { .actions, .signDetails {
@ -28,35 +28,43 @@
} }
.signData { .signData {
border: 0.25em solid red; border: 0.25em solid red;
padding: 0.5em; margin-left: 2em;
margin-left: -2em; padding: 0.5em;
overflow: auto; overflow: auto;
max-height: 6em; max-height: 6em;
max-width: calc(100% - 2em);
} }
.signData > p { .signData > p {
color: white; color: white;
} }
.signDetails { .signDetails {
flex: 10; flex: 1;
overflow: auto;
}
.account img {
display: inline-block;
height: 50px;
margin: 5px;
width: 50px;
} }
.address, .info { .address, .info {
box-sizing: border-box; box-sizing: border-box;
display: inline-block; display: inline-block;
width: 50%; vertical-align: top;
} }
.address { .address {
padding-right: $accountPadding; width: 40%;
} }
.info { .info {
padding: 0 30px;
color: #E53935; color: #E53935;
vertical-align: top; width: 60%;
} }
.info p:first-child { .info p:first-child {
@ -81,10 +89,3 @@
display: inline-block; display: inline-block;
min-height: $finishedHeight; min-height: $finishedHeight;
} }
.signDetails img {
display: inline-block;
width: 50px;
height: 50px;
margin: 5px;
}

View File

@ -123,6 +123,7 @@ class SignRequest extends Component {
<Account <Account
address={ address } address={ address }
balance={ balance } balance={ balance }
className={ styles.account }
externalLink={ externalLink } externalLink={ externalLink }
netVersion={ netVersion } netVersion={ netVersion }
/> />
@ -155,9 +156,7 @@ class SignRequest extends Component {
renderActions () { renderActions () {
const { accounts, address, focus, isFinished, status } = this.props; const { accounts, address, focus, isFinished, status } = this.props;
const account = Object const account = accounts[address];
.values(accounts)
.find((account) => address === account.address.toLowerCase());
if (isFinished) { if (isFinished) {
if (status === 'confirmed') { if (status === 'confirmed') {
@ -191,6 +190,7 @@ class SignRequest extends Component {
address={ address } address={ address }
focus={ focus } focus={ focus }
isSending={ this.props.isSending } isSending={ this.props.isSending }
netVersion={ this.props.netVersion }
onConfirm={ this.onConfirm } onConfirm={ this.onConfirm }
onReject={ this.onReject } onReject={ this.onReject }
className={ styles.actions } className={ styles.actions }

View File

@ -171,13 +171,13 @@ function addProxies (app) {
})); }));
app.use('/api', proxy({ app.use('/api', proxy({
target: 'http://127.0.0.1:8080', target: 'http://127.0.0.1:8545',
changeOrigin: true, changeOrigin: true,
autoRewrite: true autoRewrite: true
})); }));
app.use('/app', proxy({ app.use('/app', proxy({
target: 'http://127.0.0.1:8080', target: 'http://127.0.0.1:8545',
changeOrigin: true, changeOrigin: true,
pathRewrite: { pathRewrite: {
'^/app': '' '^/app': ''
@ -193,7 +193,7 @@ function addProxies (app) {
})); }));
app.use('/rpc', proxy({ app.use('/rpc', proxy({
target: 'http://127.0.0.1:8080', target: 'http://127.0.0.1:8545',
changeOrigin: true changeOrigin: true
})); }));
} }

View File

@ -69,8 +69,11 @@ pass = "test_pass"
[secretstore] [secretstore]
disable = false disable = false
port = 8082 nodes = []
http_interface = "local"
http_port = 8082
interface = "local" interface = "local"
port = 8083
path = "$HOME/.parity/secretstore" path = "$HOME/.parity/secretstore"
[ipfs] [ipfs]

View File

@ -38,7 +38,8 @@ user = "username"
pass = "password" pass = "password"
[secretstore] [secretstore]
port = 8082 http_port = 8082
port = 8083
[ipfs] [ipfs]
enable = false enable = false

View File

@ -187,10 +187,18 @@ usage! {
// Secret Store // Secret Store
flag_no_secretstore: bool = false, flag_no_secretstore: bool = false,
or |c: &Config| otry!(c.secretstore).disable.clone(), or |c: &Config| otry!(c.secretstore).disable.clone(),
flag_secretstore_port: u16 = 8082u16, flag_secretstore_secret: Option<String> = None,
or |c: &Config| otry!(c.secretstore).port.clone(), or |c: &Config| otry!(c.secretstore).self_secret.clone().map(Some),
flag_secretstore_nodes: String = "",
or |c: &Config| otry!(c.secretstore).nodes.as_ref().map(|vec| vec.join(",")),
flag_secretstore_interface: String = "local", flag_secretstore_interface: String = "local",
or |c: &Config| otry!(c.secretstore).interface.clone(), or |c: &Config| otry!(c.secretstore).interface.clone(),
flag_secretstore_port: u16 = 8083u16,
or |c: &Config| otry!(c.secretstore).port.clone(),
flag_secretstore_http_interface: String = "local",
or |c: &Config| otry!(c.secretstore).http_interface.clone(),
flag_secretstore_http_port: u16 = 8082u16,
or |c: &Config| otry!(c.secretstore).http_port.clone(),
flag_secretstore_path: String = "$BASE/secretstore", flag_secretstore_path: String = "$BASE/secretstore",
or |c: &Config| otry!(c.secretstore).path.clone(), or |c: &Config| otry!(c.secretstore).path.clone(),
@ -454,8 +462,12 @@ struct Dapps {
#[derive(Default, Debug, PartialEq, RustcDecodable)] #[derive(Default, Debug, PartialEq, RustcDecodable)]
struct SecretStore { struct SecretStore {
disable: Option<bool>, disable: Option<bool>,
port: Option<u16>, self_secret: Option<String>,
nodes: Option<Vec<String>>,
interface: Option<String>, interface: Option<String>,
port: Option<u16>,
http_interface: Option<String>,
http_port: Option<u16>,
path: Option<String>, path: Option<String>,
} }
@ -697,8 +709,12 @@ mod tests {
flag_no_dapps: false, flag_no_dapps: false,
flag_no_secretstore: false, flag_no_secretstore: false,
flag_secretstore_port: 8082u16, flag_secretstore_secret: None,
flag_secretstore_nodes: "".into(),
flag_secretstore_interface: "local".into(), flag_secretstore_interface: "local".into(),
flag_secretstore_port: 8083u16,
flag_secretstore_http_interface: "local".into(),
flag_secretstore_http_port: 8082u16,
flag_secretstore_path: "$HOME/.parity/secretstore".into(), flag_secretstore_path: "$HOME/.parity/secretstore".into(),
// IPFS // IPFS
@ -909,8 +925,12 @@ mod tests {
}), }),
secretstore: Some(SecretStore { secretstore: Some(SecretStore {
disable: None, disable: None,
port: Some(8082), self_secret: None,
nodes: None,
interface: None, interface: None,
port: Some(8083),
http_interface: None,
http_port: Some(8082),
path: None, path: None,
}), }),
ipfs: Some(Ipfs { ipfs: Some(Ipfs {

View File

@ -22,398 +22,408 @@ Usage:
parity db kill [options] parity db kill [options]
Operating Options: Operating Options:
--mode MODE Set the operating mode. MODE can be one of: --mode MODE Set the operating mode. MODE can be one of:
last - Uses the last-used mode, active if none. last - Uses the last-used mode, active if none.
active - Parity continuously syncs the chain. active - Parity continuously syncs the chain.
passive - Parity syncs initially, then sleeps and passive - Parity syncs initially, then sleeps and
wakes regularly to resync. wakes regularly to resync.
dark - Parity syncs only when the RPC is active. dark - Parity syncs only when the RPC is active.
offline - Parity doesn't sync. (default: {flag_mode}). offline - Parity doesn't sync. (default: {flag_mode}).
--mode-timeout SECS Specify the number of seconds before inactivity --mode-timeout SECS Specify the number of seconds before inactivity
timeout occurs when mode is dark or passive timeout occurs when mode is dark or passive
(default: {flag_mode_timeout}). (default: {flag_mode_timeout}).
--mode-alarm SECS Specify the number of seconds before auto sleep --mode-alarm SECS Specify the number of seconds before auto sleep
reawake timeout occurs when mode is passive reawake timeout occurs when mode is passive
(default: {flag_mode_alarm}). (default: {flag_mode_alarm}).
--auto-update SET Set a releases set to automatically update and --auto-update SET Set a releases set to automatically update and
install. install.
all - All updates in the our release track. all - All updates in the our release track.
critical - Only consensus/security updates. critical - Only consensus/security updates.
none - No updates will be auto-installed. none - No updates will be auto-installed.
(default: {flag_auto_update}). (default: {flag_auto_update}).
--release-track TRACK Set which release track we should use for updates. --release-track TRACK Set which release track we should use for updates.
stable - Stable releases. stable - Stable releases.
beta - Beta releases. beta - Beta releases.
nightly - Nightly releases (unstable). nightly - Nightly releases (unstable).
testing - Testing releases (do not use). testing - Testing releases (do not use).
current - Whatever track this executable was current - Whatever track this executable was
released on (default: {flag_release_track}). released on (default: {flag_release_track}).
--public-node Start Parity as a public web server. Account storage --public-node Start Parity as a public web server. Account storage
and transaction signing will be delegated to the UI. and transaction signing will be delegated to the UI.
(default: {flag_public_node}). (default: {flag_public_node}).
--no-download Normally new releases will be downloaded ready for --no-download Normally new releases will be downloaded ready for
updating. This disables it. Not recommended. updating. This disables it. Not recommended.
(default: {flag_no_download}). (default: {flag_no_download}).
--no-consensus Force the binary to run even if there are known --no-consensus Force the binary to run even if there are known
issues regarding consensus. Not recommended. issues regarding consensus. Not recommended.
(default: {flag_no_consensus}). (default: {flag_no_consensus}).
--force-direct Run the originally installed version of Parity, --force-direct Run the originally installed version of Parity,
ignoring any updates that have since been installed. ignoring any updates that have since been installed.
--chain CHAIN Specify the blockchain type. CHAIN may be either a --chain CHAIN Specify the blockchain type. CHAIN may be either a
JSON chain specification file or olympic, frontier, JSON chain specification file or olympic, frontier,
homestead, mainnet, morden, ropsten, classic, expanse, homestead, mainnet, morden, ropsten, classic, expanse,
testnet, kovan or dev (default: {flag_chain}). testnet, kovan or dev (default: {flag_chain}).
-d --base-path PATH Specify the base data storage path. -d --base-path PATH Specify the base data storage path.
(default: {flag_base_path}). (default: {flag_base_path}).
--db-path PATH Specify the database directory path --db-path PATH Specify the database directory path
(default: {flag_db_path}). (default: {flag_db_path}).
--keys-path PATH Specify the path for JSON key files to be found --keys-path PATH Specify the path for JSON key files to be found
(default: {flag_keys_path}). (default: {flag_keys_path}).
--identity NAME Specify your node's name. (default: {flag_identity}) --identity NAME Specify your node's name. (default: {flag_identity})
--light Experimental: run in light client mode. Light clients --light Experimental: run in light client mode. Light clients
synchronize a bare minimum of data and fetch necessary synchronize a bare minimum of data and fetch necessary
data on-demand from the network. Much lower in storage, data on-demand from the network. Much lower in storage,
potentially higher in bandwidth. Has no effect with potentially higher in bandwidth. Has no effect with
subcommands (default: {flag_light}). subcommands (default: {flag_light}).
Account Options: Account Options:
--unlock ACCOUNTS Unlock ACCOUNTS for the duration of the execution. --unlock ACCOUNTS Unlock ACCOUNTS for the duration of the execution.
ACCOUNTS is a comma-delimited list of addresses. ACCOUNTS is a comma-delimited list of addresses.
Implies --no-ui. (default: {flag_unlock:?}) Implies --no-ui. (default: {flag_unlock:?})
--password FILE Provide a file containing a password for unlocking --password FILE Provide a file containing a password for unlocking
an account. Leading and trailing whitespace is trimmed. an account. Leading and trailing whitespace is trimmed.
(default: {flag_password:?}) (default: {flag_password:?})
--keys-iterations NUM Specify the number of iterations to use when --keys-iterations NUM Specify the number of iterations to use when
deriving key from the password (bigger is more deriving key from the password (bigger is more
secure) (default: {flag_keys_iterations}). secure) (default: {flag_keys_iterations}).
--no-hardware-wallets Disables hardware wallet support. (default: {flag_no_hardware_wallets}) --no-hardware-wallets Disables hardware wallet support. (default: {flag_no_hardware_wallets})
UI Options: UI Options:
--force-ui Enable Trusted UI WebSocket endpoint, --force-ui Enable Trusted UI WebSocket endpoint,
even when --unlock is in use. (default: ${flag_force_ui}) even when --unlock is in use. (default: ${flag_force_ui})
--no-ui Disable Trusted UI WebSocket endpoint. --no-ui Disable Trusted UI WebSocket endpoint.
(default: ${flag_no_ui}) (default: ${flag_no_ui})
--ui-port PORT Specify the port of Trusted UI server --ui-port PORT Specify the port of Trusted UI server
(default: {flag_ui_port}). (default: {flag_ui_port}).
--ui-interface IP Specify the hostname portion of the Trusted UI --ui-interface IP Specify the hostname portion of the Trusted UI
server, IP should be an interface's IP address, server, IP should be an interface's IP address,
or local (default: {flag_ui_interface}). or local (default: {flag_ui_interface}).
--ui-path PATH Specify directory where Trusted UIs tokens should --ui-path PATH Specify directory where Trusted UIs tokens should
be stored. (default: {flag_ui_path}) be stored. (default: {flag_ui_path})
--ui-no-validation Disable Origin and Host headers validation for --ui-no-validation Disable Origin and Host headers validation for
Trusted UI. WARNING: INSECURE. Used only for Trusted UI. WARNING: INSECURE. Used only for
development. (default: {flag_ui_no_validation}) development. (default: {flag_ui_no_validation})
Networking Options: Networking Options:
--no-warp Disable syncing from the snapshot over the network. (default: {flag_no_warp}) --no-warp Disable syncing from the snapshot over the network. (default: {flag_no_warp})
--port PORT Override the port on which the node should listen --port PORT Override the port on which the node should listen
(default: {flag_port}). (default: {flag_port}).
--min-peers NUM Try to maintain at least NUM peers (default: {flag_min_peers}). --min-peers NUM Try to maintain at least NUM peers (default: {flag_min_peers}).
--max-peers NUM Allow up to NUM peers (default: {flag_max_peers}). --max-peers NUM Allow up to NUM peers (default: {flag_max_peers}).
--snapshot-peers NUM Allow additional NUM peers for a snapshot sync --snapshot-peers NUM Allow additional NUM peers for a snapshot sync
(default: {flag_snapshot_peers}). (default: {flag_snapshot_peers}).
--nat METHOD Specify method to use for determining public --nat METHOD Specify method to use for determining public
address. Must be one of: any, none, upnp, address. Must be one of: any, none, upnp,
extip:<IP> (default: {flag_nat}). extip:<IP> (default: {flag_nat}).
--network-id INDEX Override the network identifier from the chain we --network-id INDEX Override the network identifier from the chain we
are on. (default: {flag_network_id:?}) are on. (default: {flag_network_id:?})
--bootnodes NODES Override the bootnodes from our chain. NODES should --bootnodes NODES Override the bootnodes from our chain. NODES should
be comma-delimited enodes. (default: {flag_bootnodes:?}) be comma-delimited enodes. (default: {flag_bootnodes:?})
--no-discovery Disable new peer discovery. (default: {flag_no_discovery}) --no-discovery Disable new peer discovery. (default: {flag_no_discovery})
--node-key KEY Specify node secret key, either as 64-character hex --node-key KEY Specify node secret key, either as 64-character hex
string or input to SHA3 operation. (default: {flag_node_key:?}) string or input to SHA3 operation. (default: {flag_node_key:?})
--reserved-peers FILE Provide a file containing enodes, one per line. --reserved-peers FILE Provide a file containing enodes, one per line.
These nodes will always have a reserved slot on top These nodes will always have a reserved slot on top
of the normal maximum peers. (default: {flag_reserved_peers:?}) of the normal maximum peers. (default: {flag_reserved_peers:?})
--reserved-only Connect only to reserved nodes. (default: {flag_reserved_only}) --reserved-only Connect only to reserved nodes. (default: {flag_reserved_only})
--allow-ips FILTER Filter outbound connections. Must be one of: --allow-ips FILTER Filter outbound connections. Must be one of:
private - connect to private network IP addresses only; private - connect to private network IP addresses only;
public - connect to public network IP addresses only; public - connect to public network IP addresses only;
all - connect to any IP address. all - connect to any IP address.
(default: {flag_allow_ips}) (default: {flag_allow_ips})
--max-pending-peers NUM Allow up to NUM pending connections. (default: {flag_max_pending_peers}) --max-pending-peers NUM Allow up to NUM pending connections. (default: {flag_max_pending_peers})
--no-ancient-blocks Disable downloading old blocks after snapshot restoration --no-ancient-blocks Disable downloading old blocks after snapshot restoration
or warp sync. (default: {flag_no_ancient_blocks}) or warp sync. (default: {flag_no_ancient_blocks})
--no-serve-light Disable serving of light peers. (default: {flag_no_serve_light}) --no-serve-light Disable serving of light peers. (default: {flag_no_serve_light})
API and Console Options: API and Console Options:
--no-jsonrpc Disable the JSON-RPC API server. (default: {flag_no_jsonrpc}) --no-jsonrpc Disable the JSON-RPC API server. (default: {flag_no_jsonrpc})
--jsonrpc-port PORT Specify the port portion of the JSONRPC API server --jsonrpc-port PORT Specify the port portion of the JSONRPC API server
(default: {flag_jsonrpc_port}). (default: {flag_jsonrpc_port}).
--jsonrpc-interface IP Specify the hostname portion of the JSONRPC API --jsonrpc-interface IP Specify the hostname portion of the JSONRPC API
server, IP should be an interface's IP address, or server, IP should be an interface's IP address, or
all (all interfaces) or local (default: {flag_jsonrpc_interface}). all (all interfaces) or local (default: {flag_jsonrpc_interface}).
--jsonrpc-cors URL Specify CORS header for JSON-RPC API responses. --jsonrpc-cors URL Specify CORS header for JSON-RPC API responses.
(default: {flag_jsonrpc_cors:?}) (default: {flag_jsonrpc_cors:?})
--jsonrpc-apis APIS Specify the APIs available through the JSONRPC --jsonrpc-apis APIS Specify the APIs available through the JSONRPC
interface. APIS is a comma-delimited list of API interface. APIS is a comma-delimited list of API
name. Possible name are web3, eth, net, personal, name. Possible name are all, safe, web3, eth, net, personal,
parity, parity_set, traces, rpc, parity_accounts. parity, parity_set, traces, rpc, parity_accounts.
(default: {flag_jsonrpc_apis}). You can also disable a specific API by putting '-' in the front: all,-personal
--jsonrpc-hosts HOSTS List of allowed Host header values. This option will (default: {flag_jsonrpc_apis}).
validate the Host header sent by the browser, it --jsonrpc-hosts HOSTS List of allowed Host header values. This option will
is additional security against some attack validate the Host header sent by the browser, it
vectors. Special options: "all", "none", is additional security against some attack
(default: {flag_jsonrpc_hosts}). vectors. Special options: "all", "none",
--jsonrpc-threads THREADS Enables experimental faster implementation of JSON-RPC server. (default: {flag_jsonrpc_hosts}).
Requires Dapps server to be disabled using --no-dapps. (default: {flag_jsonrpc_threads:?}) --jsonrpc-threads THREADS Enables experimental faster implementation of JSON-RPC server.
Requires Dapps server to be disabled using --no-dapps. (default: {flag_jsonrpc_threads:?})
--no-ipc Disable JSON-RPC over IPC service. (default: {flag_no_ipc}) --no-ipc Disable JSON-RPC over IPC service. (default: {flag_no_ipc})
--ipc-path PATH Specify custom path for JSON-RPC over IPC service --ipc-path PATH Specify custom path for JSON-RPC over IPC service
(default: {flag_ipc_path}). (default: {flag_ipc_path}).
--ipc-apis APIS Specify custom API set available via JSON-RPC over --ipc-apis APIS Specify custom API set available via JSON-RPC over
IPC (default: {flag_ipc_apis}). IPC (default: {flag_ipc_apis}).
--no-dapps Disable the Dapps server (e.g. status page). (default: {flag_no_dapps})
--dapps-path PATH Specify directory where dapps should be installed.
(default: {flag_dapps_path})
--ipfs-api Enable IPFS-compatible HTTP API. (default: {flag_ipfs_api})
--ipfs-api-port PORT Configure on which port the IPFS HTTP API should listen.
(default: {flag_ipfs_api_port})
--ipfs-api-interface IP Specify the hostname portion of the IPFS API server,
IP should be an interface's IP address or local.
(default: {flag_ipfs_api_interface})
--ipfs-api-cors URL Specify CORS header for IPFS API responses.
(default: {flag_ipfs_api_cors:?})
--ipfs-api-hosts HOSTS List of allowed Host header values. This option will
validate the Host header sent by the browser, it
is additional security against some attack
vectors. Special options: "all", "none"
(default: {flag_ipfs_api_hosts}).
--no-dapps Disable the Dapps server (e.g. status page). (default: {flag_no_dapps})
--dapps-path PATH Specify directory where dapps should be installed.
(default: {flag_dapps_path})
--ipfs-api Enable IPFS-compatible HTTP API. (default: {flag_ipfs_api})
--ipfs-api-port PORT Configure on which port the IPFS HTTP API should listen.
(default: {flag_ipfs_api_port})
--ipfs-api-interface IP Specify the hostname portion of the IPFS API server,
IP should be an interface's IP address or local.
(default: {flag_ipfs_api_interface})
--ipfs-api-cors URL Specify CORS header for IPFS API responses.
(default: {flag_ipfs_api_cors:?})
--ipfs-api-hosts HOSTS List of allowed Host header values. This option will
validate the Host header sent by the browser, it
is additional security against some attack
vectors. Special options: "all", "none"
(default: {flag_ipfs_api_hosts}).
Secret Store Options: Secret Store Options:
--no-secretstore Disable Secret Store functionality. (default: {flag_no_secretstore}) --no-secretstore Disable Secret Store functionality. (default: {flag_no_secretstore})
--secretstore-port PORT Specify the port portion for Secret Store Key Server --secretstore-secret SECRET Hex-encoded secret key of this node.
(default: {flag_secretstore_port}). (required, default: {flag_secretstore_secret:?}).
--secretstore-interface IP Specify the hostname portion for Secret Store Key Server, IP --secretstore-nodes NODES Comma-separated list of other secret store cluster nodes in form
should be an interface's IP address, or local NODE_PUBLIC_KEY_IN_HEX@NODE_IP_ADDR:NODE_PORT.
(default: {flag_secretstore_interface}). (required, default: {flag_secretstore_nodes}).
--secretstore-path PATH Specify directory where Secret Store should save its data. --secretstore-interface IP Specify the hostname portion for listening to Secret Store Key Server
(default: {flag_secretstore_path}) internal requests, IP should be an interface's IP address, or local
(default: {flag_secretstore_interface}).
--secretstore-port PORT Specify the port portion for listening to Secret Store Key Server
internal requests (default: {flag_secretstore_port}).
--secretstore-http-interface IP Specify the hostname portion for listening to Secret Store Key Server
HTTP requests, IP should be an interface's IP address, or local
(default: {flag_secretstore_http_interface}).
--secretstore-http-port PORT Specify the port portion for listening to Secret Store Key Server
HTTP requests (default: {flag_secretstore_http_port}).
--secretstore-path PATH Specify directory where Secret Store should save its data.
(default: {flag_secretstore_path}).
Sealing/Mining Options: Sealing/Mining Options:
--author ADDRESS Specify the block author (aka "coinbase") address --author ADDRESS Specify the block author (aka "coinbase") address
for sending block rewards from sealed blocks. for sending block rewards from sealed blocks.
NOTE: MINING WILL NOT WORK WITHOUT THIS OPTION. NOTE: MINING WILL NOT WORK WITHOUT THIS OPTION.
(default: {flag_author:?}) (default: {flag_author:?})
--engine-signer ADDRESS Specify the address which should be used to --engine-signer ADDRESS Specify the address which should be used to
sign consensus messages and issue blocks. sign consensus messages and issue blocks.
Relevant only to non-PoW chains. Relevant only to non-PoW chains.
(default: {flag_engine_signer:?}) (default: {flag_engine_signer:?})
--force-sealing Force the node to author new blocks as if it were --force-sealing Force the node to author new blocks as if it were
always sealing/mining. always sealing/mining.
(default: {flag_force_sealing}) (default: {flag_force_sealing})
--reseal-on-txs SET Specify which transactions should force the node --reseal-on-txs SET Specify which transactions should force the node
to reseal a block. SET is one of: to reseal a block. SET is one of:
none - never reseal on new transactions; none - never reseal on new transactions;
own - reseal only on a new local transaction; own - reseal only on a new local transaction;
ext - reseal only on a new external transaction; ext - reseal only on a new external transaction;
all - reseal on all new transactions all - reseal on all new transactions
(default: {flag_reseal_on_txs}). (default: {flag_reseal_on_txs}).
--reseal-min-period MS Specify the minimum time between reseals from --reseal-min-period MS Specify the minimum time between reseals from
incoming transactions. MS is time measured in incoming transactions. MS is time measured in
milliseconds (default: {flag_reseal_min_period}). milliseconds (default: {flag_reseal_min_period}).
--reseal-max-period MS Specify the maximum time since last block to enable --reseal-max-period MS Specify the maximum time since last block to enable
force-sealing. MS is time measured in force-sealing. MS is time measured in
milliseconds (default: {flag_reseal_max_period}). milliseconds (default: {flag_reseal_max_period}).
--work-queue-size ITEMS Specify the number of historical work packages --work-queue-size ITEMS Specify the number of historical work packages
which are kept cached lest a solution is found for which are kept cached lest a solution is found for
them later. High values take more memory but result them later. High values take more memory but result
in fewer unusable solutions (default: {flag_work_queue_size}). in fewer unusable solutions (default: {flag_work_queue_size}).
--tx-gas-limit GAS Apply a limit of GAS as the maximum amount of gas --tx-gas-limit GAS Apply a limit of GAS as the maximum amount of gas
a single transaction may have for it to be mined. a single transaction may have for it to be mined.
(default: {flag_tx_gas_limit:?}) (default: {flag_tx_gas_limit:?})
--tx-time-limit MS Maximal time for processing single transaction. --tx-time-limit MS Maximal time for processing single transaction.
If enabled senders/recipients/code of transactions If enabled senders/recipients/code of transactions
offending the limit will be banned from being included offending the limit will be banned from being included
in transaction queue for 180 seconds. in transaction queue for 180 seconds.
(default: {flag_tx_time_limit:?}) (default: {flag_tx_time_limit:?})
--relay-set SET Set of transactions to relay. SET may be: --relay-set SET Set of transactions to relay. SET may be:
cheap - Relay any transaction in the queue (this cheap - Relay any transaction in the queue (this
may include invalid transactions); may include invalid transactions);
strict - Relay only executed transactions (this strict - Relay only executed transactions (this
guarantees we don't relay invalid transactions, but guarantees we don't relay invalid transactions, but
means we relay nothing if not mining); means we relay nothing if not mining);
lenient - Same as strict when mining, and cheap lenient - Same as strict when mining, and cheap
when not (default: {flag_relay_set}). when not (default: {flag_relay_set}).
--usd-per-tx USD Amount of USD to be paid for a basic transaction --usd-per-tx USD Amount of USD to be paid for a basic transaction
(default: {flag_usd_per_tx}). The minimum gas price is set (default: {flag_usd_per_tx}). The minimum gas price is set
accordingly. accordingly.
--usd-per-eth SOURCE USD value of a single ETH. SOURCE may be either an --usd-per-eth SOURCE USD value of a single ETH. SOURCE may be either an
amount in USD, a web service or 'auto' to use each amount in USD, a web service or 'auto' to use each
web service in turn and fallback on the last known web service in turn and fallback on the last known
good value (default: {flag_usd_per_eth}). good value (default: {flag_usd_per_eth}).
--price-update-period T T will be allowed to pass between each gas price --price-update-period T T will be allowed to pass between each gas price
update. T may be daily, hourly, a number of seconds, update. T may be daily, hourly, a number of seconds,
or a time string of the form "2 days", "30 minutes" or a time string of the form "2 days", "30 minutes"
etc. (default: {flag_price_update_period}). etc. (default: {flag_price_update_period}).
--gas-floor-target GAS Amount of gas per block to target when sealing a new --gas-floor-target GAS Amount of gas per block to target when sealing a new
block (default: {flag_gas_floor_target}). block (default: {flag_gas_floor_target}).
--gas-cap GAS A cap on how large we will raise the gas limit per --gas-cap GAS A cap on how large we will raise the gas limit per
block due to transaction volume (default: {flag_gas_cap}). block due to transaction volume (default: {flag_gas_cap}).
--extra-data STRING Specify a custom extra-data for authored blocks, no --extra-data STRING Specify a custom extra-data for authored blocks, no
more than 32 characters. (default: {flag_extra_data:?}) more than 32 characters. (default: {flag_extra_data:?})
--tx-queue-size LIMIT Maximum amount of transactions in the queue (waiting --tx-queue-size LIMIT Maximum amount of transactions in the queue (waiting
to be included in next block) (default: {flag_tx_queue_size}). to be included in next block) (default: {flag_tx_queue_size}).
--tx-queue-gas LIMIT Maximum amount of total gas for external transactions in --tx-queue-gas LIMIT Maximum amount of total gas for external transactions in
the queue. LIMIT can be either an amount of gas or the queue. LIMIT can be either an amount of gas or
'auto' or 'off'. 'auto' sets the limit to be 20x 'auto' or 'off'. 'auto' sets the limit to be 20x
the current block gas limit. (default: {flag_tx_queue_gas}). the current block gas limit. (default: {flag_tx_queue_gas}).
--tx-queue-strategy S Prioritization strategy used to order transactions --tx-queue-strategy S Prioritization strategy used to order transactions
in the queue. S may be: in the queue. S may be:
gas - Prioritize txs with low gas limit; gas - Prioritize txs with low gas limit;
gas_price - Prioritize txs with high gas price; gas_price - Prioritize txs with high gas price;
gas_factor - Prioritize txs using gas price gas_factor - Prioritize txs using gas price
and gas limit ratio (default: {flag_tx_queue_strategy}). and gas limit ratio (default: {flag_tx_queue_strategy}).
--tx-queue-ban-count C Number of times maximal time for execution (--tx-time-limit) --tx-queue-ban-count C Number of times maximal time for execution (--tx-time-limit)
can be exceeded before banning sender/recipient/code. can be exceeded before banning sender/recipient/code.
(default: {flag_tx_queue_ban_count}) (default: {flag_tx_queue_ban_count})
--tx-queue-ban-time SEC Banning time (in seconds) for offenders of specified --tx-queue-ban-time SEC Banning time (in seconds) for offenders of specified
execution time limit. Also number of offending actions execution time limit. Also number of offending actions
have to reach the threshold within that time. have to reach the threshold within that time.
(default: {flag_tx_queue_ban_time} seconds) (default: {flag_tx_queue_ban_time} seconds)
--remove-solved Move solved blocks from the work package queue --remove-solved Move solved blocks from the work package queue
instead of cloning them. This gives a slightly instead of cloning them. This gives a slightly
faster import speed, but means that extra solutions faster import speed, but means that extra solutions
submitted for the same work package will go unused. submitted for the same work package will go unused.
(default: {flag_remove_solved}) (default: {flag_remove_solved})
--notify-work URLS URLs to which work package notifications are pushed. --notify-work URLS URLs to which work package notifications are pushed.
URLS should be a comma-delimited list of HTTP URLs. URLS should be a comma-delimited list of HTTP URLs.
(default: {flag_notify_work:?}) (default: {flag_notify_work:?})
--refuse-service-transactions Always refuse service transactions. --refuse-service-transactions Always refuse service transactions.
(default: {flag_refuse_service_transactions}). (default: {flag_refuse_service_transactions}).
--stratum Run Stratum server for miner push notification. (default: {flag_stratum}) --stratum Run Stratum server for miner push notification. (default: {flag_stratum})
--stratum-interface IP Interface address for Stratum server. (default: {flag_stratum_interface}) --stratum-interface IP Interface address for Stratum server. (default: {flag_stratum_interface})
--stratum-port PORT Port for Stratum server to listen on. (default: {flag_stratum_port}) --stratum-port PORT Port for Stratum server to listen on. (default: {flag_stratum_port})
--stratum-secret STRING Secret for authorizing Stratum server for peers. --stratum-secret STRING Secret for authorizing Stratum server for peers.
(default: {flag_stratum_secret:?}) (default: {flag_stratum_secret:?})
Footprint Options: Footprint Options:
--tracing BOOL Indicates if full transaction tracing should be --tracing BOOL Indicates if full transaction tracing should be
enabled. Works only if client had been fully synced enabled. Works only if client had been fully synced
with tracing enabled. BOOL may be one of auto, on, with tracing enabled. BOOL may be one of auto, on,
off. auto uses last used value of this option (off off. auto uses last used value of this option (off
if it does not exist) (default: {flag_tracing}). if it does not exist) (default: {flag_tracing}).
--pruning METHOD Configure pruning of the state/storage trie. METHOD --pruning METHOD Configure pruning of the state/storage trie. METHOD
may be one of auto, archive, fast: may be one of auto, archive, fast:
archive - keep all state trie data. No pruning. archive - keep all state trie data. No pruning.
fast - maintain journal overlay. Fast but 50MB used. fast - maintain journal overlay. Fast but 50MB used.
auto - use the method most recently synced or auto - use the method most recently synced or
default to fast if none synced (default: {flag_pruning}). default to fast if none synced (default: {flag_pruning}).
--pruning-history NUM Set a minimum number of recent states to keep when pruning --pruning-history NUM Set a minimum number of recent states to keep when pruning
is active. (default: {flag_pruning_history}). is active. (default: {flag_pruning_history}).
--pruning-memory MB The ideal amount of memory in megabytes to use to store --pruning-memory MB The ideal amount of memory in megabytes to use to store
recent states. As many states as possible will be kept recent states. As many states as possible will be kept
within this limit, and at least --pruning-history states within this limit, and at least --pruning-history states
will always be kept. (default: {flag_pruning_memory}) will always be kept. (default: {flag_pruning_memory})
--cache-size-db MB Override database cache size (default: {flag_cache_size_db}). --cache-size-db MB Override database cache size (default: {flag_cache_size_db}).
--cache-size-blocks MB Specify the prefered size of the blockchain cache in --cache-size-blocks MB Specify the prefered size of the blockchain cache in
megabytes (default: {flag_cache_size_blocks}). megabytes (default: {flag_cache_size_blocks}).
--cache-size-queue MB Specify the maximum size of memory to use for block --cache-size-queue MB Specify the maximum size of memory to use for block
queue (default: {flag_cache_size_queue}). queue (default: {flag_cache_size_queue}).
--cache-size-state MB Specify the maximum size of memory to use for --cache-size-state MB Specify the maximum size of memory to use for
the state cache (default: {flag_cache_size_state}). the state cache (default: {flag_cache_size_state}).
--cache-size MB Set total amount of discretionary memory to use for --cache-size MB Set total amount of discretionary memory to use for
the entire system, overrides other cache and queue the entire system, overrides other cache and queue
options. (default: {flag_cache_size:?}) options. (default: {flag_cache_size:?})
--fast-and-loose Disables DB WAL, which gives a significant speed up --fast-and-loose Disables DB WAL, which gives a significant speed up
but means an unclean exit is unrecoverable. (default: {flag_fast_and_loose}) but means an unclean exit is unrecoverable. (default: {flag_fast_and_loose})
--db-compaction TYPE Database compaction type. TYPE may be one of: --db-compaction TYPE Database compaction type. TYPE may be one of:
ssd - suitable for SSDs and fast HDDs; ssd - suitable for SSDs and fast HDDs;
hdd - suitable for slow HDDs; hdd - suitable for slow HDDs;
auto - determine automatically (default: {flag_db_compaction}). auto - determine automatically (default: {flag_db_compaction}).
--fat-db BOOL Build appropriate information to allow enumeration --fat-db BOOL Build appropriate information to allow enumeration
of all accounts and storage keys. Doubles the size of all accounts and storage keys. Doubles the size
of the state database. BOOL may be one of on, off of the state database. BOOL may be one of on, off
or auto. (default: {flag_fat_db}) or auto. (default: {flag_fat_db})
--scale-verifiers Automatically scale amount of verifier threads based on --scale-verifiers Automatically scale amount of verifier threads based on
workload. Not guaranteed to be faster. workload. Not guaranteed to be faster.
(default: {flag_scale_verifiers}) (default: {flag_scale_verifiers})
--num-verifiers INT Amount of verifier threads to use or to begin with, if verifier --num-verifiers INT Amount of verifier threads to use or to begin with, if verifier
auto-scaling is enabled. (default: {flag_num_verifiers:?}) auto-scaling is enabled. (default: {flag_num_verifiers:?})
Import/Export Options: Import/Export Options:
--from BLOCK Export from block BLOCK, which may be an index or --from BLOCK Export from block BLOCK, which may be an index or
hash (default: {flag_from}). hash (default: {flag_from}).
--to BLOCK Export to (including) block BLOCK, which may be an --to BLOCK Export to (including) block BLOCK, which may be an
index, hash or 'latest' (default: {flag_to}). index, hash or 'latest' (default: {flag_to}).
--format FORMAT For import/export in given format. FORMAT must be --format FORMAT For import/export in given format. FORMAT must be
one of 'hex' and 'binary'. one of 'hex' and 'binary'.
(default: {flag_format:?} = Import: auto, Export: binary) (default: {flag_format:?} = Import: auto, Export: binary)
--no-seal-check Skip block seal check. (default: {flag_no_seal_check}) --no-seal-check Skip block seal check. (default: {flag_no_seal_check})
--at BLOCK Export state at the given block, which may be an --at BLOCK Export state at the given block, which may be an
index, hash, or 'latest'. (default: {flag_at}) index, hash, or 'latest'. (default: {flag_at})
--no-storage Don't export account storage. (default: {flag_no_storage}) --no-storage Don't export account storage. (default: {flag_no_storage})
--no-code Don't export account code. (default: {flag_no_code}) --no-code Don't export account code. (default: {flag_no_code})
--min-balance WEI Don't export accounts with balance less than specified. --min-balance WEI Don't export accounts with balance less than specified.
(default: {flag_min_balance:?}) (default: {flag_min_balance:?})
--max-balance WEI Don't export accounts with balance greater than specified. --max-balance WEI Don't export accounts with balance greater than specified.
(default: {flag_max_balance:?}) (default: {flag_max_balance:?})
Snapshot Options: Snapshot Options:
--at BLOCK Take a snapshot at the given block, which may be an --at BLOCK Take a snapshot at the given block, which may be an
index, hash, or 'latest'. Note that taking snapshots at index, hash, or 'latest'. Note that taking snapshots at
non-recent blocks will only work with --pruning archive non-recent blocks will only work with --pruning archive
(default: {flag_at}) (default: {flag_at})
--no-periodic-snapshot Disable automated snapshots which usually occur once --no-periodic-snapshot Disable automated snapshots which usually occur once
every 10000 blocks. (default: {flag_no_periodic_snapshot}) every 10000 blocks. (default: {flag_no_periodic_snapshot})
Virtual Machine Options: Virtual Machine Options:
--jitvm Enable the JIT VM. (default: {flag_jitvm}) --jitvm Enable the JIT VM. (default: {flag_jitvm})
Legacy Options: Legacy Options:
--geth Run in Geth-compatibility mode. Sets the IPC path --geth Run in Geth-compatibility mode. Sets the IPC path
to be the same as Geth's. Overrides the --ipc-path to be the same as Geth's. Overrides the --ipc-path
and --ipcpath options. Alters RPCs to reflect Geth and --ipcpath options. Alters RPCs to reflect Geth
bugs. Includes the personal_ RPC by default. bugs. Includes the personal_ RPC by default.
--testnet Testnet mode. Equivalent to --chain testnet. --testnet Testnet mode. Equivalent to --chain testnet.
Overrides the --keys-path option. Overrides the --keys-path option.
--import-geth-keys Attempt to import keys from Geth client. --import-geth-keys Attempt to import keys from Geth client.
--datadir PATH Equivalent to --base-path PATH. --datadir PATH Equivalent to --base-path PATH.
--networkid INDEX Equivalent to --network-id INDEX. --networkid INDEX Equivalent to --network-id INDEX.
--peers NUM Equivalent to --min-peers NUM. --peers NUM Equivalent to --min-peers NUM.
--nodekey KEY Equivalent to --node-key KEY. --nodekey KEY Equivalent to --node-key KEY.
--nodiscover Equivalent to --no-discovery. --nodiscover Equivalent to --no-discovery.
-j --jsonrpc Does nothing; JSON-RPC is on by default now. -j --jsonrpc Does nothing; JSON-RPC is on by default now.
--jsonrpc-off Equivalent to --no-jsonrpc. --jsonrpc-off Equivalent to --no-jsonrpc.
-w --webapp Does nothing; dapps server is on by default now. -w --webapp Does nothing; dapps server is on by default now.
--dapps-off Equivalent to --no-dapps. --dapps-off Equivalent to --no-dapps.
--dapps-user USERNAME Dapps server authentication has been removed. (default: {flag_dapps_user:?}) --dapps-user USERNAME Dapps server authentication has been removed. (default: {flag_dapps_user:?})
--dapps-pass PASSWORD Dapps server authentication has been removed. (default: {flag_dapps_pass:?}) --dapps-pass PASSWORD Dapps server authentication has been removed. (default: {flag_dapps_pass:?})
--dapps-apis-all Dapps server is merged with RPC server. Use --jsonrpc-apis. (default: {flag_dapps_apis_all:?}) --dapps-apis-all Dapps server is merged with RPC server. Use --jsonrpc-apis. (default: {flag_dapps_apis_all:?})
--dapps-cors URL Dapps server is merged with RPC server. Use --jsonrpc-cors. (default: {flag_dapps_cors:?}) --dapps-cors URL Dapps server is merged with RPC server. Use --jsonrpc-cors. (default: {flag_dapps_cors:?})
--dapps-hosts HOSTS Dapps server is merged with RPC server. Use --jsonrpc-hosts. (default: {flag_dapps_hosts:?}) --dapps-hosts HOSTS Dapps server is merged with RPC server. Use --jsonrpc-hosts. (default: {flag_dapps_hosts:?})
--dapps-interface IP Dapps server is merged with RPC server. Use --jsonrpc-interface. (default: {flag_dapps_interface:?}) --dapps-interface IP Dapps server is merged with RPC server. Use --jsonrpc-interface. (default: {flag_dapps_interface:?})
--dapps-port PORT Dapps server is merged with RPC server. Use --jsonrpc-port. (default: {flag_dapps_port:?}) --dapps-port PORT Dapps server is merged with RPC server. Use --jsonrpc-port. (default: {flag_dapps_port:?})
--rpc Does nothing; JSON-RPC is on by default now. --rpc Does nothing; JSON-RPC is on by default now.
--warp Does nothing; Warp sync is on by default. (default: {flag_warp}) --warp Does nothing; Warp sync is on by default. (default: {flag_warp})
--rpcaddr IP Equivalent to --jsonrpc-interface IP. --rpcaddr IP Equivalent to --jsonrpc-interface IP.
--rpcport PORT Equivalent to --jsonrpc-port PORT. --rpcport PORT Equivalent to --jsonrpc-port PORT.
--rpcapi APIS Equivalent to --jsonrpc-apis APIS. --rpcapi APIS Equivalent to --jsonrpc-apis APIS.
--rpccorsdomain URL Equivalent to --jsonrpc-cors URL. --rpccorsdomain URL Equivalent to --jsonrpc-cors URL.
--ipcdisable Equivalent to --no-ipc. --ipcdisable Equivalent to --no-ipc.
--ipc-off Equivalent to --no-ipc. --ipc-off Equivalent to --no-ipc.
--ipcapi APIS Equivalent to --ipc-apis APIS. --ipcapi APIS Equivalent to --ipc-apis APIS.
--ipcpath PATH Equivalent to --ipc-path PATH. --ipcpath PATH Equivalent to --ipc-path PATH.
--gasprice WEI Minimum amount of Wei per GAS to be paid for a --gasprice WEI Minimum amount of Wei per GAS to be paid for a
transaction to be accepted for mining. Overrides transaction to be accepted for mining. Overrides
--basic-tx-usd. --basic-tx-usd.
--etherbase ADDRESS Equivalent to --author ADDRESS. --etherbase ADDRESS Equivalent to --author ADDRESS.
--extradata STRING Equivalent to --extra-data STRING. --extradata STRING Equivalent to --extra-data STRING.
--cache MB Equivalent to --cache-size MB. --cache MB Equivalent to --cache-size MB.
Internal Options: Internal Options:
--can-restart Executable will auto-restart if exiting with 69. --can-restart Executable will auto-restart if exiting with 69.
Miscellaneous Options: Miscellaneous Options:
-c --config CONFIG Specify a filename containing a configuration file. -c --config CONFIG Specify a filename containing a configuration file.
(default: {flag_config}) (default: {flag_config})
-l --logging LOGGING Specify the logging level. Must conform to the same -l --logging LOGGING Specify the logging level. Must conform to the same
format as RUST_LOG. (default: {flag_logging:?}) format as RUST_LOG. (default: {flag_logging:?})
--log-file FILENAME Specify a filename into which logging should be --log-file FILENAME Specify a filename into which logging should be
appended. (default: {flag_log_file:?}) appended. (default: {flag_log_file:?})
--no-config Don't load a configuration file. --no-config Don't load a configuration file.
--no-color Don't use terminal color codes in output. (default: {flag_no_color}) --no-color Don't use terminal color codes in output. (default: {flag_no_color})
-v --version Show information about version. -v --version Show information about version.
-h --help Show this screen. -h --help Show this screen.

View File

@ -18,18 +18,20 @@ use std::time::Duration;
use std::io::{Read, Write, stderr}; use std::io::{Read, Write, stderr};
use std::net::SocketAddr; use std::net::SocketAddr;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::collections::BTreeMap;
use std::cmp::max; use std::cmp::max;
use cli::{Args, ArgsError}; use cli::{Args, ArgsError};
use util::{Hashable, H256, U256, Uint, Bytes, version_data, Address}; use util::{Hashable, H256, U256, Uint, Bytes, version_data, Address};
use util::journaldb::Algorithm; use util::journaldb::Algorithm;
use util::Colour; use util::Colour;
use ethsync::{NetworkConfiguration, is_valid_node_url, AllowIP}; use ethsync::{NetworkConfiguration, is_valid_node_url, AllowIP};
use ethcore::ethstore::ethkey::Secret; use ethcore::ethstore::ethkey::{Secret, Public};
use ethcore::client::{VMType}; use ethcore::client::{VMType};
use ethcore::miner::{MinerOptions, Banning, StratumOptions}; use ethcore::miner::{MinerOptions, Banning, StratumOptions};
use ethcore::verification::queue::VerifierSettings; use ethcore::verification::queue::VerifierSettings;
use rpc::{IpcConfiguration, HttpConfiguration}; use rpc::{IpcConfiguration, HttpConfiguration};
use rpc_apis::ApiSet;
use ethcore_rpc::NetworkSettings; use ethcore_rpc::NetworkSettings;
use cache::CacheConfig; use cache::CacheConfig;
use helpers::{to_duration, to_mode, to_block_id, to_u256, to_pending_set, to_price, replace_home, replace_home_for_db, use helpers::{to_duration, to_mode, to_block_id, to_u256, to_pending_set, to_price, replace_home, replace_home_for_db,
@ -135,7 +137,7 @@ impl Configuration {
let mut dapps_conf = self.dapps_config(); let mut dapps_conf = self.dapps_config();
let ipfs_conf = self.ipfs_config(); let ipfs_conf = self.ipfs_config();
let signer_conf = self.signer_config(); let signer_conf = self.signer_config();
let secretstore_conf = self.secretstore_config(); let secretstore_conf = self.secretstore_config()?;
let format = self.format()?; let format = self.format()?;
if self.args.flag_jsonrpc_threads.is_some() && dapps_conf.enabled { if self.args.flag_jsonrpc_threads.is_some() && dapps_conf.enabled {
@ -570,13 +572,17 @@ impl Configuration {
} }
} }
fn secretstore_config(&self) -> SecretStoreConfiguration { fn secretstore_config(&self) -> Result<SecretStoreConfiguration, String> {
SecretStoreConfiguration { Ok(SecretStoreConfiguration {
enabled: self.secretstore_enabled(), enabled: self.secretstore_enabled(),
self_secret: self.secretstore_self_secret()?,
nodes: self.secretstore_nodes()?,
interface: self.secretstore_interface(), interface: self.secretstore_interface(),
port: self.args.flag_secretstore_port, port: self.args.flag_secretstore_port,
http_interface: self.secretstore_http_interface(),
http_port: self.args.flag_secretstore_http_port,
data_path: self.directories().secretstore, data_path: self.directories().secretstore,
} })
} }
fn ipfs_config(&self) -> IpfsConfiguration { fn ipfs_config(&self) -> IpfsConfiguration {
@ -718,16 +724,7 @@ impl Configuration {
.collect(); .collect();
if self.args.flag_geth { if self.args.flag_geth {
apis.push("personal"); apis.insert(0, "personal");
}
if self.args.flag_public_node {
apis.retain(|api| {
match *api {
"eth" | "net" | "parity" | "rpc" | "web3" => true,
_ => false
}
});
} }
apis.join(",") apis.join(",")
@ -788,7 +785,10 @@ impl Configuration {
enabled: self.rpc_enabled(), enabled: self.rpc_enabled(),
interface: self.rpc_interface(), interface: self.rpc_interface(),
port: self.args.flag_rpcport.unwrap_or(self.args.flag_jsonrpc_port), port: self.args.flag_rpcport.unwrap_or(self.args.flag_jsonrpc_port),
apis: self.rpc_apis().parse()?, apis: match self.args.flag_public_node {
false => self.rpc_apis().parse()?,
true => self.rpc_apis().parse::<ApiSet>()?.retain(ApiSet::PublicContext),
},
hosts: self.rpc_hosts(), hosts: self.rpc_hosts(),
cors: self.rpc_cors(), cors: self.rpc_cors(),
threads: match self.args.flag_jsonrpc_threads { threads: match self.args.flag_jsonrpc_threads {
@ -918,10 +918,43 @@ impl Configuration {
} }
fn secretstore_interface(&self) -> String { fn secretstore_interface(&self) -> String {
match self.args.flag_secretstore_interface.as_str() { Self::interface(&self.args.flag_secretstore_interface)
"local" => "127.0.0.1", }
x => x,
}.into() fn secretstore_http_interface(&self) -> String {
Self::interface(&self.args.flag_secretstore_http_interface)
}
fn secretstore_self_secret(&self) -> Result<Option<Secret>, String> {
match self.args.flag_secretstore_secret {
Some(ref s) => Ok(Some(s.parse()
.map_err(|e| format!("Invalid secret store secret: {}. Error: {:?}", s, e))?)),
None => Ok(None),
}
}
fn secretstore_nodes(&self) -> Result<BTreeMap<Public, (String, u16)>, String> {
let mut nodes = BTreeMap::new();
for node in self.args.flag_secretstore_nodes.split(',').filter(|n| n != &"") {
let public_and_addr: Vec<_> = node.split('@').collect();
if public_and_addr.len() != 2 {
return Err(format!("Invalid secret store node: {}", node));
}
let ip_and_port: Vec<_> = public_and_addr[1].split(':').collect();
if ip_and_port.len() != 2 {
return Err(format!("Invalid secret store node: {}", node));
}
let public = public_and_addr[0].parse()
.map_err(|e| format!("Invalid public key in secret store node: {}. Error: {:?}", public_and_addr[0], e))?;
let port = ip_and_port[1].parse()
.map_err(|e| format!("Invalid port in secret store node: {}. Error: {:?}", ip_and_port[1], e))?;
nodes.insert(public, (ip_and_port[0].into(), port));
}
Ok(nodes)
} }
fn stratum_interface(&self) -> String { fn stratum_interface(&self) -> String {

View File

@ -82,7 +82,7 @@ impl ContractClient for FullRegistrar {
// TODO: light client implementation forwarding to OnDemand and waiting for future // TODO: light client implementation forwarding to OnDemand and waiting for future
// to resolve. // to resolve.
pub struct Dependencies { pub struct Dependencies {
pub sync_status: Arc<::parity_dapps::SyncStatus>, pub sync_status: Arc<SyncStatus>,
pub contract_client: Arc<ContractClient>, pub contract_client: Arc<ContractClient>,
pub remote: parity_reactor::TokioRemote, pub remote: parity_reactor::TokioRemote,
pub fetch: FetchClient, pub fetch: FetchClient,
@ -103,8 +103,7 @@ pub fn new(configuration: Configuration, deps: Dependencies)
).map(Some) ).map(Some)
} }
pub use self::server::Middleware; pub use self::server::{SyncStatus, Middleware, dapps_middleware};
pub use self::server::dapps_middleware;
#[cfg(not(feature = "dapps"))] #[cfg(not(feature = "dapps"))]
mod server { mod server {
@ -112,11 +111,12 @@ mod server {
use std::path::PathBuf; use std::path::PathBuf;
use ethcore_rpc::{hyper, RequestMiddleware, RequestMiddlewareAction}; use ethcore_rpc::{hyper, RequestMiddleware, RequestMiddlewareAction};
pub struct Middleware; pub type SyncStatus = Fn() -> bool;
pub struct Middleware;
impl RequestMiddleware for Middleware { impl RequestMiddleware for Middleware {
fn on_request( fn on_request(
&self, req: &hyper::server::Request<hyper::net::HttpStream>, control: &hyper::Control &self, _req: &hyper::server::Request<hyper::net::HttpStream>, _control: &hyper::Control
) -> RequestMiddlewareAction { ) -> RequestMiddlewareAction {
unreachable!() unreachable!()
} }
@ -137,11 +137,11 @@ mod server {
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::Arc; use std::sync::Arc;
use hash_fetch::fetch::Client as FetchClient;
use parity_dapps; use parity_dapps;
use parity_reactor; use parity_reactor;
pub type Middleware = parity_dapps::Middleware<FetchClient>; pub use parity_dapps::Middleware;
pub use parity_dapps::SyncStatus;
pub fn dapps_middleware( pub fn dapps_middleware(
deps: Dependencies, deps: Dependencies,

View File

@ -85,9 +85,17 @@ impl FromStr for Api {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum ApiSet { pub enum ApiSet {
// Safe context (like token-protected WS interface)
SafeContext, SafeContext,
// Unsafe context (like jsonrpc over http)
UnsafeContext, UnsafeContext,
// Public context (like public jsonrpc over http)
PublicContext,
// All possible APIs
All,
// Local "unsafe" context and accounts access
IpcContext, IpcContext,
// Fixed list of APis
List(HashSet<Api>), List(HashSet<Api>),
} }
@ -107,10 +115,30 @@ impl FromStr for ApiSet {
type Err = String; type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> { fn from_str(s: &str) -> Result<Self, Self::Err> {
s.split(',') let mut apis = HashSet::new();
.map(Api::from_str)
.collect::<Result<_, _>>() for api in s.split(',') {
.map(ApiSet::List) match api {
"all" => {
apis.extend(ApiSet::All.list_apis());
},
"safe" => {
// Safe APIs are those that are safe even in UnsafeContext.
apis.extend(ApiSet::UnsafeContext.list_apis());
},
// Remove the API
api if api.starts_with("-") => {
let api = api[1..].parse()?;
apis.remove(&api);
},
api => {
let api = api.parse()?;
apis.insert(api);
},
}
}
Ok(ApiSet::List(apis))
} }
} }
@ -403,21 +431,41 @@ impl Dependencies for LightDependencies {
} }
impl ApiSet { impl ApiSet {
/// Retains only APIs in given set.
pub fn retain(self, set: Self) -> Self {
ApiSet::List(&self.list_apis() & &set.list_apis())
}
pub fn list_apis(&self) -> HashSet<Api> { pub fn list_apis(&self) -> HashSet<Api> {
let mut safe_list = vec![Api::Web3, Api::Net, Api::Eth, Api::Parity, Api::Traces, Api::Rpc] let mut public_list = vec![
.into_iter().collect(); Api::Web3, Api::Net, Api::Eth, Api::Parity, Api::Rpc,
].into_iter().collect();
match *self { match *self {
ApiSet::List(ref apis) => apis.clone(), ApiSet::List(ref apis) => apis.clone(),
ApiSet::UnsafeContext => safe_list, ApiSet::PublicContext => public_list,
ApiSet::UnsafeContext => {
public_list.insert(Api::Traces);
public_list
},
ApiSet::IpcContext => { ApiSet::IpcContext => {
safe_list.insert(Api::ParityAccounts); public_list.insert(Api::Traces);
safe_list public_list.insert(Api::ParityAccounts);
public_list
}, },
ApiSet::SafeContext => { ApiSet::SafeContext => {
safe_list.insert(Api::ParityAccounts); public_list.insert(Api::Traces);
safe_list.insert(Api::ParitySet); public_list.insert(Api::ParityAccounts);
safe_list.insert(Api::Signer); public_list.insert(Api::ParitySet);
safe_list public_list.insert(Api::Signer);
public_list
},
ApiSet::All => {
public_list.insert(Api::Traces);
public_list.insert(Api::ParityAccounts);
public_list.insert(Api::ParitySet);
public_list.insert(Api::Signer);
public_list.insert(Api::Personal);
public_list
}, },
} }
} }
@ -493,4 +541,30 @@ mod test {
].into_iter().collect(); ].into_iter().collect();
assert_eq!(ApiSet::SafeContext.list_apis(), expected); assert_eq!(ApiSet::SafeContext.list_apis(), expected);
} }
#[test]
fn test_all_apis() {
assert_eq!("all".parse::<ApiSet>().unwrap(), ApiSet::List(vec![
Api::Web3, Api::Net, Api::Eth, Api::Parity, Api::Traces, Api::Rpc,
Api::ParityAccounts,
Api::ParitySet, Api::Signer,
Api::Personal
].into_iter().collect()));
}
#[test]
fn test_all_without_personal_apis() {
assert_eq!("personal,all,-personal".parse::<ApiSet>().unwrap(), ApiSet::List(vec![
Api::Web3, Api::Net, Api::Eth, Api::Parity, Api::Traces, Api::Rpc,
Api::ParityAccounts,
Api::ParitySet, Api::Signer,
].into_iter().collect()));
}
#[test]
fn test_safe_parsing() {
assert_eq!("safe".parse::<ApiSet>().unwrap(), ApiSet::List(vec![
Api::Web3, Api::Net, Api::Eth, Api::Parity, Api::Traces, Api::Rpc,
].into_iter().collect()));
}
} }

View File

@ -651,7 +651,7 @@ pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) -> R
let secretstore_deps = secretstore::Dependencies { let secretstore_deps = secretstore::Dependencies {
client: client.clone(), client: client.clone(),
}; };
let secretstore_key_server = secretstore::start(cmd.secretstore_conf.clone(), secretstore_deps); let secretstore_key_server = secretstore::start(cmd.secretstore_conf.clone(), secretstore_deps)?;
// the ipfs server // the ipfs server
let ipfs_server = ipfs::start_server(cmd.ipfs_conf.clone(), client.clone())?; let ipfs_server = ipfs::start_server(cmd.ipfs_conf.clone(), client.clone())?;

View File

@ -14,9 +14,11 @@
// 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::collections::BTreeMap;
use std::sync::Arc; use std::sync::Arc;
use dir::default_data_path; use dir::default_data_path;
use ethcore::client::Client; use ethcore::client::Client;
use ethkey::{Secret, Public};
use helpers::replace_home; use helpers::replace_home;
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
@ -24,10 +26,18 @@ use helpers::replace_home;
pub struct Configuration { pub struct Configuration {
/// Is secret store functionality enabled? /// Is secret store functionality enabled?
pub enabled: bool, pub enabled: bool,
/// This node secret.
pub self_secret: Option<Secret>,
/// Other nodes IDs + addresses.
pub nodes: BTreeMap<Public, (String, u16)>,
/// Interface to listen to /// Interface to listen to
pub interface: String, pub interface: String,
/// Port to listen to /// Port to listen to
pub port: u16, pub port: u16,
/// Interface to listen to
pub http_interface: String,
/// Port to listen to
pub http_port: u16,
/// Data directory path for secret store /// Data directory path for secret store
pub data_path: String, pub data_path: String,
} }
@ -55,8 +65,8 @@ mod server {
#[cfg(feature="secretstore")] #[cfg(feature="secretstore")]
mod server { mod server {
use ethkey;
use ethcore_secretstore; use ethcore_secretstore;
use ethkey::KeyPair;
use super::{Configuration, Dependencies}; use super::{Configuration, Dependencies};
/// Key server /// Key server
@ -67,37 +77,35 @@ mod server {
impl KeyServer { impl KeyServer {
/// Create new key server /// Create new key server
pub fn new(conf: Configuration, deps: Dependencies) -> Result<Self, String> { pub fn new(conf: Configuration, deps: Dependencies) -> Result<Self, String> {
let key_pairs = vec![ let self_secret = conf.self_secret.ok_or("self secret is required when using secretstore")?;
ethkey::KeyPair::from_secret("6c26a76e9b31048d170873a791401c7e799a11f0cefc0171cc31a49800967509".parse().unwrap()).unwrap(), let mut conf = ethcore_secretstore::ServiceConfiguration {
ethkey::KeyPair::from_secret("7e94018b3731afdb3b4e6f4c3e179475640166da12e1d1b0c7d80729b1a5b452".parse().unwrap()).unwrap(),
ethkey::KeyPair::from_secret("5ab6ed2a52c33142380032c39a03a86b12eacb3fa4b53bc16d84f51318156f8c".parse().unwrap()).unwrap(),
];
let conf = ethcore_secretstore::ServiceConfiguration {
listener_address: ethcore_secretstore::NodeAddress { listener_address: ethcore_secretstore::NodeAddress {
address: conf.interface.clone(), address: conf.http_interface.clone(),
port: conf.port, port: conf.http_port,
}, },
data_path: conf.data_path.clone(), data_path: conf.data_path.clone(),
// TODO: this is test configuration. how it will be configured in production?
cluster_config: ethcore_secretstore::ClusterConfiguration { cluster_config: ethcore_secretstore::ClusterConfiguration {
threads: 4, threads: 4,
self_private: (***key_pairs[(conf.port - 8082) as usize].secret()).into(), self_private: (**self_secret).into(),
listener_address: ethcore_secretstore::NodeAddress { listener_address: ethcore_secretstore::NodeAddress {
address: conf.interface.clone(), address: conf.interface.clone(),
port: conf.port + 10, port: conf.port,
}, },
nodes: key_pairs.iter().enumerate().map(|(i, kp)| (kp.public().clone(), nodes: conf.nodes.into_iter().map(|(p, (ip, port))| (p, ethcore_secretstore::NodeAddress {
ethcore_secretstore::NodeAddress { address: ip,
address: conf.interface.clone(), port: port,
port: 8082 + 10 + (i as u16), })).collect(),
})).collect(),
allow_connecting_to_higher_nodes: true, allow_connecting_to_higher_nodes: true,
encryption_config: ethcore_secretstore::EncryptionConfiguration { encryption_config: ethcore_secretstore::EncryptionConfiguration {
key_check_timeout_ms: 1000, key_check_timeout_ms: 1000,
}, },
} },
}; };
let self_key_pair = KeyPair::from_secret(self_secret.clone())
.map_err(|e| format!("valid secret is required when using secretstore. Error: {}", e))?;
conf.cluster_config.nodes.insert(self_key_pair.public().clone(), conf.cluster_config.listener_address.clone());
let key_server = ethcore_secretstore::start(deps.client, conf) let key_server = ethcore_secretstore::start(deps.client, conf)
.map_err(Into::<String>::into)?; .map_err(Into::<String>::into)?;
@ -115,8 +123,12 @@ impl Default for Configuration {
let data_dir = default_data_path(); let data_dir = default_data_path();
Configuration { Configuration {
enabled: true, enabled: true,
self_secret: None,
nodes: BTreeMap::new(),
interface: "127.0.0.1".to_owned(), interface: "127.0.0.1".to_owned(),
port: 8082, port: 8083,
http_interface: "127.0.0.1".to_owned(),
http_port: 8082,
data_path: replace_home(&data_dir, "$BASE/secretstore"), data_path: replace_home(&data_dir, "$BASE/secretstore"),
} }
} }

View File

@ -18,6 +18,9 @@ serde_derive = "0.9"
serde_json = "0.9" serde_json = "0.9"
time = "0.1" time = "0.1"
transient-hashmap = "0.4" transient-hashmap = "0.4"
cid = "0.2.1"
multihash = "0.5"
rust-crypto = "0.2.36"
jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.7" } jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.7" }
jsonrpc-http-server = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.7" } jsonrpc-http-server = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.7" }

View File

@ -27,6 +27,9 @@ extern crate serde;
extern crate serde_json; extern crate serde_json;
extern crate time; extern crate time;
extern crate transient_hashmap; extern crate transient_hashmap;
extern crate cid;
extern crate multihash;
extern crate crypto as rust_crypto;
extern crate jsonrpc_core; extern crate jsonrpc_core;
extern crate jsonrpc_http_server as http; extern crate jsonrpc_http_server as http;

View File

@ -44,6 +44,7 @@ mod codes {
pub const REQUEST_REJECTED_LIMIT: i64 = -32041; pub const REQUEST_REJECTED_LIMIT: i64 = -32041;
pub const REQUEST_NOT_FOUND: i64 = -32042; pub const REQUEST_NOT_FOUND: i64 = -32042;
pub const ENCRYPTION_ERROR: i64 = -32055; pub const ENCRYPTION_ERROR: i64 = -32055;
pub const ENCODING_ERROR: i64 = -32058;
pub const FETCH_ERROR: i64 = -32060; pub const FETCH_ERROR: i64 = -32060;
pub const NO_LIGHT_PEERS: i64 = -32065; pub const NO_LIGHT_PEERS: i64 = -32065;
pub const DEPRECATED: i64 = -32070; pub const DEPRECATED: i64 = -32070;
@ -224,6 +225,14 @@ pub fn encryption_error<T: fmt::Debug>(error: T) -> Error {
} }
} }
pub fn encoding_error<T: fmt::Debug>(error: T) -> Error {
Error {
code: ErrorCode::ServerError(codes::ENCODING_ERROR),
message: "Encoding error.".into(),
data: Some(Value::String(format!("{:?}", error))),
}
}
pub fn database_error<T: fmt::Debug>(error: T) -> Error { pub fn database_error<T: fmt::Debug>(error: T) -> Error {
Error { Error {
code: ErrorCode::ServerError(codes::DATABASE_ERROR), code: ErrorCode::ServerError(codes::DATABASE_ERROR),

View File

@ -0,0 +1,38 @@
// 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/>.
//! IPFS utility functions
use multihash;
use cid::{Cid, Codec, Version};
use rust_crypto::sha2::Sha256;
use rust_crypto::digest::Digest;
use jsonrpc_core::Error;
use v1::types::Bytes;
use super::errors;
/// Compute CIDv0 from protobuf encoded bytes.
pub fn cid(content: Bytes) -> Result<String, Error> {
let mut hasher = Sha256::new();
hasher.input(&content.0);
let len = hasher.output_bytes();
let mut buf = Vec::with_capacity(len);
buf.resize(len, 0);
hasher.result(&mut buf);
let mh = multihash::encode(multihash::Hash::SHA2256, &buf).map_err(errors::encoding_error)?;
let cid = Cid::new(Codec::DagProtobuf, Version::V0, &mh);
Ok(cid.to_string().into())
}

View File

@ -24,6 +24,7 @@ pub mod fake_sign;
pub mod light_fetch; pub mod light_fetch;
pub mod informant; pub mod informant;
pub mod oneshot; pub mod oneshot;
pub mod ipfs;
mod network_settings; mod network_settings;
mod poll_manager; mod poll_manager;

View File

@ -30,7 +30,7 @@ use ethcore::account_provider::AccountProvider;
use jsonrpc_core::Error; use jsonrpc_core::Error;
use jsonrpc_macros::Trailing; use jsonrpc_macros::Trailing;
use v1::helpers::{errors, SigningQueue, SignerService, NetworkSettings}; use v1::helpers::{errors, ipfs, SigningQueue, SignerService, NetworkSettings};
use v1::helpers::dispatch::{LightDispatcher, DEFAULT_MAC}; use v1::helpers::dispatch::{LightDispatcher, DEFAULT_MAC};
use v1::helpers::light_fetch::LightFetch; use v1::helpers::light_fetch::LightFetch;
use v1::metadata::Metadata; use v1::metadata::Metadata;
@ -387,4 +387,8 @@ impl Parity for ParityClient {
self.fetcher().header(number.0.into()).map(move |encoded| encoded.map(from_encoded)).boxed() self.fetcher().header(number.0.into()).map(move |encoded| encoded.map(from_encoded)).boxed()
} }
fn ipfs_cid(&self, content: Bytes) -> Result<String, Error> {
ipfs::cid(content)
}
} }

View File

@ -37,7 +37,7 @@ use updater::{Service as UpdateService};
use jsonrpc_core::Error; use jsonrpc_core::Error;
use jsonrpc_macros::Trailing; use jsonrpc_macros::Trailing;
use v1::helpers::{errors, SigningQueue, SignerService, NetworkSettings}; use v1::helpers::{errors, ipfs, SigningQueue, SignerService, NetworkSettings};
use v1::helpers::accounts::unwrap_provider; use v1::helpers::accounts::unwrap_provider;
use v1::helpers::dispatch::DEFAULT_MAC; use v1::helpers::dispatch::DEFAULT_MAC;
use v1::metadata::Metadata; use v1::metadata::Metadata;
@ -427,5 +427,8 @@ impl<C, M, S: ?Sized, U> Parity for ParityClient<C, M, S, U> where
}, },
extra_info: client.block_extra_info(id).expect(EXTRA_INFO_PROOF), extra_info: client.block_extra_info(id).expect(EXTRA_INFO_PROOF),
})).boxed() })).boxed()
fn ipfs_cid(&self, content: Bytes) -> Result<String, Error> {
ipfs::cid(content)
} }
} }

View File

@ -510,3 +510,14 @@ fn rpc_parity_node_kind() {
assert_eq!(io.handle_request_sync(request), Some(response.to_owned())); assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
} }
#[test]
fn rpc_parity_cid() {
let deps = Dependencies::new();
let io = deps.default_client();
let request = r#"{"jsonrpc": "2.0", "method": "parity_cidV0", "params":["0x414243"], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":"QmSF59MAENc8ZhM4aM1thuAE8w5gDmyfzkAvNoyPea7aDz","id":1}"#;
assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
}

View File

@ -203,5 +203,9 @@ build_rpc_trait! {
/// Same as `eth_getBlockByNumber` but without uncles and transactions. /// Same as `eth_getBlockByNumber` but without uncles and transactions.
#[rpc(async, name = "parity_getBlockHeaderByNumber")] #[rpc(async, name = "parity_getBlockHeaderByNumber")]
fn block_header(&self, Trailing<BlockNumber>) -> BoxFuture<Option<RichHeader>, Error>; fn block_header(&self, Trailing<BlockNumber>) -> BoxFuture<Option<RichHeader>, Error>;
/// Get IPFS CIDv0 given protobuf encoded bytes.
#[rpc(name = "parity_cidV0")]
fn ipfs_cid(&self, Bytes) -> Result<String, Error>;
} }
} }

View File

@ -20,7 +20,8 @@ serde_derive = "0.9"
futures = "0.1" futures = "0.1"
futures-cpupool = "0.1" futures-cpupool = "0.1"
rustc-serialize = "0.3" rustc-serialize = "0.3"
tokio-core = "0.1" tokio-core = "0.1.6"
tokio-io = "0.1.0"
tokio-service = "0.1" tokio-service = "0.1"
tokio-proto = "0.1" tokio-proto = "0.1"
url = "1.0" url = "1.0"

View File

@ -21,11 +21,13 @@ use hyper::method::Method as HttpMethod;
use hyper::status::StatusCode as HttpStatusCode; use hyper::status::StatusCode as HttpStatusCode;
use hyper::server::{Server as HttpServer, Request as HttpRequest, Response as HttpResponse, Handler as HttpHandler, use hyper::server::{Server as HttpServer, Request as HttpRequest, Response as HttpResponse, Handler as HttpHandler,
Listening as HttpListening}; Listening as HttpListening};
use serde_json;
use url::percent_encoding::percent_decode; use url::percent_encoding::percent_decode;
use util::ToPretty; use util::ToPretty;
use traits::KeyServer; use traits::KeyServer;
use types::all::{Error, ServiceConfiguration, RequestSignature, DocumentAddress, DocumentEncryptedKey}; use serialization::SerializableDocumentEncryptedKeyShadow;
use types::all::{Error, ServiceConfiguration, RequestSignature, DocumentAddress, DocumentEncryptedKey, DocumentEncryptedKeyShadow};
/// Key server http-requests listener /// Key server http-requests listener
pub struct KeyServerHttpListener<T: KeyServer + 'static> { pub struct KeyServerHttpListener<T: KeyServer + 'static> {
@ -42,6 +44,8 @@ enum Request {
GenerateDocumentKey(DocumentAddress, RequestSignature, usize), GenerateDocumentKey(DocumentAddress, RequestSignature, usize),
/// Request encryption key of given document for given requestor. /// Request encryption key of given document for given requestor.
GetDocumentKey(DocumentAddress, RequestSignature), GetDocumentKey(DocumentAddress, RequestSignature),
/// Request shadow of encryption key of given document for given requestor.
GetDocumentKeyShadow(DocumentAddress, RequestSignature),
} }
/// Cloneable http handler /// Cloneable http handler
@ -83,6 +87,10 @@ impl<T> KeyServer for KeyServerHttpListener<T> where T: KeyServer + 'static {
fn document_key(&self, signature: &RequestSignature, document: &DocumentAddress) -> Result<DocumentEncryptedKey, Error> { fn document_key(&self, signature: &RequestSignature, document: &DocumentAddress) -> Result<DocumentEncryptedKey, Error> {
self.handler.key_server.document_key(signature, document) self.handler.key_server.document_key(signature, document)
} }
fn document_key_shadow(&self, signature: &RequestSignature, document: &DocumentAddress) -> Result<DocumentEncryptedKeyShadow, Error> {
self.handler.key_server.document_key_shadow(signature, document)
}
} }
impl<T> HttpHandler for KeyServerHttpHandler<T> where T: KeyServer + 'static { impl<T> HttpHandler for KeyServerHttpHandler<T> where T: KeyServer + 'static {
@ -111,6 +119,34 @@ impl<T> HttpHandler for KeyServerHttpHandler<T> where T: KeyServer + 'static {
err err
})); }));
}, },
Request::GetDocumentKeyShadow(document, signature) => {
match self.handler.key_server.document_key_shadow(&signature, &document)
.map_err(|err| {
warn!(target: "secretstore", "GetDocumentKeyShadow request {} has failed with: {}", req_uri, err);
err
}) {
Ok(document_key_shadow) => {
let document_key_shadow = SerializableDocumentEncryptedKeyShadow {
decrypted_secret: document_key_shadow.decrypted_secret.into(),
common_point: document_key_shadow.common_point.expect("always filled when requesting document_key_shadow; qed").into(),
decrypt_shadows: document_key_shadow.decrypt_shadows.expect("always filled when requesting document_key_shadow; qed").into_iter().map(Into::into).collect(),
};
match serde_json::to_vec(&document_key_shadow) {
Ok(document_key) => {
res.headers_mut().set(header::ContentType::json());
if let Err(err) = res.send(&document_key) {
// nothing to do, but to log an error
warn!(target: "secretstore", "response to request {} has failed with: {}", req.uri, err);
}
},
Err(err) => {
warn!(target: "secretstore", "response to request {} has failed with: {}", req.uri, err);
}
}
},
Err(err) => return_error(res, err),
}
},
Request::Invalid => { Request::Invalid => {
warn!(target: "secretstore", "Ignoring invalid {}-request {}", req_method, req_uri); warn!(target: "secretstore", "Ignoring invalid {}-request {}", req_method, req_uri);
*res.status_mut() = HttpStatusCode::BadRequest; *res.status_mut() = HttpStatusCode::BadRequest;
@ -134,11 +170,17 @@ fn return_document_key(req: HttpRequest, mut res: HttpResponse, document_key: Re
warn!(target: "secretstore", "response to request {} has failed with: {}", req.uri, err); warn!(target: "secretstore", "response to request {} has failed with: {}", req.uri, err);
} }
}, },
Err(Error::BadSignature) => *res.status_mut() = HttpStatusCode::BadRequest, Err(err) => return_error(res, err),
Err(Error::AccessDenied) => *res.status_mut() = HttpStatusCode::Forbidden, }
Err(Error::DocumentNotFound) => *res.status_mut() = HttpStatusCode::NotFound, }
Err(Error::Database(_)) => *res.status_mut() = HttpStatusCode::InternalServerError,
Err(Error::Internal(_)) => *res.status_mut() = HttpStatusCode::InternalServerError, fn return_error(mut res: HttpResponse, err: Error) {
match err {
Error::BadSignature => *res.status_mut() = HttpStatusCode::BadRequest,
Error::AccessDenied => *res.status_mut() = HttpStatusCode::Forbidden,
Error::DocumentNotFound => *res.status_mut() = HttpStatusCode::NotFound,
Error::Database(_) => *res.status_mut() = HttpStatusCode::InternalServerError,
Error::Internal(_) => *res.status_mut() = HttpStatusCode::InternalServerError,
} }
} }
@ -149,17 +191,27 @@ fn parse_request(method: &HttpMethod, uri_path: &str) -> Request {
}; };
let path: Vec<String> = uri_path.trim_left_matches('/').split('/').map(Into::into).collect(); let path: Vec<String> = uri_path.trim_left_matches('/').split('/').map(Into::into).collect();
if path.len() < 2 || path[0].is_empty() || path[1].is_empty() { if path.len() == 0 {
return Request::Invalid;
}
let (args_prefix, args_offset) = if &path[0] == "shadow" {
("shadow", 1)
} else {
("", 0)
};
if path.len() < 2 + args_offset || path[args_offset].is_empty() || path[args_offset + 1].is_empty() {
return Request::Invalid; return Request::Invalid;
} }
let args_len = path.len(); let args_len = path.len();
let document = path[0].parse(); let document = path[args_offset].parse();
let signature = path[1].parse(); let signature = path[args_offset + 1].parse();
let threshold = (if args_len > 2 { &path[2] } else { "" }).parse(); let threshold = (if args_len > args_offset + 2 { &path[args_offset + 2] } else { "" }).parse();
match (args_len, method, document, signature, threshold) { match (args_prefix, args_len, method, document, signature, threshold) {
(3, &HttpMethod::Post, Ok(document), Ok(signature), Ok(threshold)) => Request::GenerateDocumentKey(document, signature, threshold), ("", 3, &HttpMethod::Post, Ok(document), Ok(signature), Ok(threshold)) => Request::GenerateDocumentKey(document, signature, threshold),
(2, &HttpMethod::Get, Ok(document), Ok(signature), _) => Request::GetDocumentKey(document, signature), ("", 2, &HttpMethod::Get, Ok(document), Ok(signature), _) => Request::GetDocumentKey(document, signature),
("shadow", 3, &HttpMethod::Get, Ok(document), Ok(signature), _) => Request::GetDocumentKeyShadow(document, signature),
_ => Request::Invalid, _ => Request::Invalid,
} }
} }

View File

@ -26,7 +26,7 @@ use super::acl_storage::AclStorage;
use super::key_storage::KeyStorage; use super::key_storage::KeyStorage;
use key_server_cluster::ClusterCore; use key_server_cluster::ClusterCore;
use traits::KeyServer; use traits::KeyServer;
use types::all::{Error, RequestSignature, DocumentAddress, DocumentEncryptedKey, ClusterConfiguration}; use types::all::{Error, RequestSignature, DocumentAddress, DocumentEncryptedKey, DocumentEncryptedKeyShadow, ClusterConfiguration};
use key_server_cluster::{ClusterClient, ClusterConfiguration as NetClusterConfiguration}; use key_server_cluster::{ClusterClient, ClusterConfiguration as NetClusterConfiguration};
/// Secret store key server implementation /// Secret store key server implementation
@ -38,7 +38,7 @@ pub struct KeyServerImpl {
pub struct KeyServerCore { pub struct KeyServerCore {
close: Option<futures::Complete<()>>, close: Option<futures::Complete<()>>,
handle: Option<thread::JoinHandle<()>>, handle: Option<thread::JoinHandle<()>>,
cluster: Option<Arc<ClusterClient>>, cluster: Arc<ClusterClient>,
} }
impl KeyServerImpl { impl KeyServerImpl {
@ -53,7 +53,6 @@ impl KeyServerImpl {
/// Get cluster client reference. /// Get cluster client reference.
pub fn cluster(&self) -> Arc<ClusterClient> { pub fn cluster(&self) -> Arc<ClusterClient> {
self.data.lock().cluster.clone() self.data.lock().cluster.clone()
.expect("cluster can be None in test cfg only; test cfg is for correct tests; qed")
} }
} }
@ -64,9 +63,7 @@ impl KeyServer for KeyServerImpl {
.map_err(|_| Error::BadSignature)?; .map_err(|_| Error::BadSignature)?;
// generate document key // generate document key
let data = self.data.lock(); let encryption_session = self.data.lock().cluster.new_encryption_session(document.clone(), threshold)?;
let encryption_session = data.cluster.as_ref().expect("cluster can be None in test cfg only; test cfg is for correct tests; qed")
.new_encryption_session(document.clone(), threshold)?;
let document_key = encryption_session.wait()?; let document_key = encryption_session.wait()?;
// encrypt document key with requestor public key // encrypt document key with requestor public key
@ -80,17 +77,21 @@ impl KeyServer for KeyServerImpl {
let public = ethkey::recover(signature, document) let public = ethkey::recover(signature, document)
.map_err(|_| Error::BadSignature)?; .map_err(|_| Error::BadSignature)?;
// decrypt document key // decrypt document key
let data = self.data.lock(); let decryption_session = self.data.lock().cluster.new_decryption_session(document.clone(), signature.clone(), false)?;
let decryption_session = data.cluster.as_ref().expect("cluster can be None in test cfg only; test cfg is for correct tests; qed") let document_key = decryption_session.wait()?.decrypted_secret;
.new_decryption_session(document.clone(), signature.clone())?;
let document_key = decryption_session.wait()?;
// encrypt document key with requestor public key // encrypt document key with requestor public key
let document_key = ethcrypto::ecies::encrypt_single_message(&public, &document_key) let document_key = ethcrypto::ecies::encrypt_single_message(&public, &document_key)
.map_err(|err| Error::Internal(format!("Error encrypting document key: {}", err)))?; .map_err(|err| Error::Internal(format!("Error encrypting document key: {}", err)))?;
Ok(document_key) Ok(document_key)
} }
fn document_key_shadow(&self, signature: &RequestSignature, document: &DocumentAddress) -> Result<DocumentEncryptedKeyShadow, Error> {
let decryption_session = self.data.lock().cluster.new_decryption_session(document.clone(), signature.clone(), false)?;
decryption_session.wait().map_err(Into::into)
}
} }
impl KeyServerCore { impl KeyServerCore {
@ -129,7 +130,7 @@ impl KeyServerCore {
Ok(KeyServerCore { Ok(KeyServerCore {
close: Some(stop), close: Some(stop),
handle: Some(handle), handle: Some(handle),
cluster: Some(cluster), cluster: cluster,
}) })
} }
} }
@ -149,24 +150,9 @@ mod tests {
use ethkey::{self, Random, Generator}; use ethkey::{self, Random, Generator};
use acl_storage::tests::DummyAclStorage; use acl_storage::tests::DummyAclStorage;
use key_storage::tests::DummyKeyStorage; use key_storage::tests::DummyKeyStorage;
use types::all::{ClusterConfiguration, NodeAddress, EncryptionConfiguration, DocumentEncryptedKey, DocumentKey}; use types::all::{ClusterConfiguration, NodeAddress, EncryptionConfiguration};
use super::super::{RequestSignature, DocumentAddress};
use super::{KeyServer, KeyServerImpl}; use super::{KeyServer, KeyServerImpl};
const DOCUMENT1: &'static str = "0000000000000000000000000000000000000000000000000000000000000001";
const PRIVATE1: &'static str = "03055e18a8434dcc9061cc1b81c4ef84dc7cf4574d755e52cdcf0c8898b25b11";
fn make_signature(secret: &str, document: &'static str) -> RequestSignature {
let secret = secret.parse().unwrap();
let document: DocumentAddress = document.into();
ethkey::sign(&secret, &document).unwrap()
}
fn decrypt_document_key(secret: &str, document_key: DocumentEncryptedKey) -> DocumentKey {
let secret = secret.parse().unwrap();
ethcrypto::ecies::decrypt_single_message(&secret, &document_key).unwrap()
}
#[test] #[test]
fn document_key_generation_and_retrievement_works_over_network() { fn document_key_generation_and_retrievement_works_over_network() {
//::util::log::init_log(); //::util::log::init_log();
@ -208,15 +194,16 @@ mod tests {
let test_cases = [0, 1, 2]; let test_cases = [0, 1, 2];
for threshold in &test_cases { for threshold in &test_cases {
// generate document key // generate document key
// TODO: it is an error that we can regenerate key for the same DOCUMENT let document = Random.generate().unwrap().secret().clone();
let signature = make_signature(PRIVATE1, DOCUMENT1); let secret = Random.generate().unwrap().secret().clone();
let generated_key = key_servers[0].generate_document_key(&signature, &DOCUMENT1.into(), *threshold).unwrap(); let signature = ethkey::sign(&secret, &document).unwrap();
let generated_key = decrypt_document_key(PRIVATE1, generated_key); let generated_key = key_servers[0].generate_document_key(&signature, &document, *threshold).unwrap();
let generated_key = ethcrypto::ecies::decrypt_single_message(&secret, &generated_key).unwrap();
// now let's try to retrieve key back // now let's try to retrieve key back
for key_server in key_servers.iter() { for key_server in key_servers.iter() {
let retrieved_key = key_server.document_key(&signature, &DOCUMENT1.into()).unwrap(); let retrieved_key = key_server.document_key(&signature, &document).unwrap();
let retrieved_key = decrypt_document_key(PRIVATE1, retrieved_key); let retrieved_key = ethcrypto::ecies::decrypt_single_message(&secret, &retrieved_key).unwrap();
assert_eq!(retrieved_key, generated_key); assert_eq!(retrieved_key, generated_key);
} }
} }

View File

@ -23,7 +23,7 @@ use std::net::{SocketAddr, IpAddr};
use futures::{finished, failed, Future, Stream, BoxFuture}; use futures::{finished, failed, Future, Stream, BoxFuture};
use futures_cpupool::CpuPool; use futures_cpupool::CpuPool;
use parking_lot::{RwLock, Mutex}; use parking_lot::{RwLock, Mutex};
use tokio_core::io::IoFuture; use tokio_io::IoFuture;
use tokio_core::reactor::{Handle, Remote, Timeout, Interval}; use tokio_core::reactor::{Handle, Remote, Timeout, Interval};
use tokio_core::net::{TcpListener, TcpStream}; use tokio_core::net::{TcpListener, TcpStream};
use ethkey::{Secret, KeyPair, Signature, Random, Generator}; use ethkey::{Secret, KeyPair, Signature, Random, Generator};
@ -45,7 +45,7 @@ pub trait ClusterClient: Send + Sync {
/// Start new encryption session. /// Start new encryption session.
fn new_encryption_session(&self, session_id: SessionId, threshold: usize) -> Result<Arc<EncryptionSession>, Error>; fn new_encryption_session(&self, session_id: SessionId, threshold: usize) -> Result<Arc<EncryptionSession>, Error>;
/// Start new decryption session. /// Start new decryption session.
fn new_decryption_session(&self, session_id: SessionId, requestor_signature: Signature) -> Result<Arc<DecryptionSession>, Error>; fn new_decryption_session(&self, session_id: SessionId, requestor_signature: Signature, is_shadow_decryption: bool) -> Result<Arc<DecryptionSession>, Error>;
} }
/// Cluster access for single encryption/decryption participant. /// Cluster access for single encryption/decryption participant.
@ -181,7 +181,7 @@ pub struct Connection {
/// Tcp stream. /// Tcp stream.
stream: SharedTcpStream, stream: SharedTcpStream,
/// Connection key. /// Connection key.
key: Secret, key: KeyPair,
/// Last message time. /// Last message time.
last_message_time: Mutex<time::Instant>, last_message_time: Mutex<time::Instant>,
} }
@ -649,9 +649,14 @@ impl ClusterSessions {
pub fn new_encryption_session(&self, _master: NodeId, session_id: SessionId, cluster: Arc<Cluster>) -> Result<Arc<EncryptionSessionImpl>, Error> { pub fn new_encryption_session(&self, _master: NodeId, session_id: SessionId, cluster: Arc<Cluster>) -> Result<Arc<EncryptionSessionImpl>, Error> {
let mut encryption_sessions = self.encryption_sessions.write(); let mut encryption_sessions = self.encryption_sessions.write();
// check that there's no active encryption session with the same id
if encryption_sessions.contains_key(&session_id) { if encryption_sessions.contains_key(&session_id) {
return Err(Error::DuplicateSessionId); return Err(Error::DuplicateSessionId);
} }
// check that there's no finished encryption session with the same id
if self.key_storage.contains(&session_id) {
return Err(Error::DuplicateSessionId);
}
let session = Arc::new(EncryptionSessionImpl::new(EncryptionSessionParams { let session = Arc::new(EncryptionSessionImpl::new(EncryptionSessionParams {
id: session_id.clone(), id: session_id.clone(),
@ -865,14 +870,14 @@ impl ClusterClient for ClusterClientImpl {
Ok(session) Ok(session)
} }
fn new_decryption_session(&self, session_id: SessionId, requestor_signature: Signature) -> Result<Arc<DecryptionSession>, Error> { fn new_decryption_session(&self, session_id: SessionId, requestor_signature: Signature, is_shadow_decryption: bool) -> Result<Arc<DecryptionSession>, Error> {
let mut connected_nodes = self.data.connections.connected_nodes(); let mut connected_nodes = self.data.connections.connected_nodes();
connected_nodes.insert(self.data.self_key_pair.public().clone()); connected_nodes.insert(self.data.self_key_pair.public().clone());
let access_key = Random.generate()?.secret().clone(); let access_key = Random.generate()?.secret().clone();
let cluster = Arc::new(ClusterView::new(self.data.clone(), connected_nodes.clone())); let cluster = Arc::new(ClusterView::new(self.data.clone(), connected_nodes.clone()));
let session = self.data.sessions.new_decryption_session(self.data.self_key_pair.public().clone(), session_id, access_key, cluster)?; let session = self.data.sessions.new_decryption_session(self.data.self_key_pair.public().clone(), session_id, access_key, cluster)?;
session.initialize(requestor_signature)?; session.initialize(requestor_signature, is_shadow_decryption)?;
Ok(session) Ok(session)
} }
} }

View File

@ -18,8 +18,9 @@ use std::cmp::{Ord, PartialOrd, Ordering};
use std::collections::{BTreeSet, BTreeMap}; use std::collections::{BTreeSet, BTreeMap};
use std::sync::Arc; use std::sync::Arc;
use parking_lot::{Mutex, Condvar}; use parking_lot::{Mutex, Condvar};
use ethcrypto::ecies::encrypt_single_message;
use ethkey::{self, Secret, Public, Signature}; use ethkey::{self, Secret, Public, Signature};
use key_server_cluster::{Error, AclStorage, DocumentKeyShare, NodeId, SessionId}; use key_server_cluster::{Error, AclStorage, DocumentKeyShare, NodeId, SessionId, DocumentEncryptedKeyShadow};
use key_server_cluster::cluster::Cluster; use key_server_cluster::cluster::Cluster;
use key_server_cluster::math; use key_server_cluster::math;
use key_server_cluster::message::{Message, DecryptionMessage, InitializeDecryptionSession, ConfirmDecryptionInitialization, use key_server_cluster::message::{Message, DecryptionMessage, InitializeDecryptionSession, ConfirmDecryptionInitialization,
@ -28,7 +29,7 @@ use key_server_cluster::message::{Message, DecryptionMessage, InitializeDecrypti
/// Decryption session API. /// Decryption session API.
pub trait Session: Send + Sync + 'static { pub trait Session: Send + Sync + 'static {
/// Wait until session is completed. Returns distributely restored secret key. /// Wait until session is completed. Returns distributely restored secret key.
fn wait(&self) -> Result<Public, Error>; fn wait(&self) -> Result<DocumentEncryptedKeyShadow, Error>;
} }
/// Distributed decryption session. /// Distributed decryption session.
@ -83,6 +84,15 @@ pub struct SessionParams {
pub cluster: Arc<Cluster>, pub cluster: Arc<Cluster>,
} }
#[derive(Debug)]
/// Partial decryption result.
struct PartialDecryptionResult {
/// Shadow point.
pub shadow_point: Public,
/// Decryption shadow coefficient, if requested.
pub decrypt_shadow: Option<Vec<u8>>,
}
#[derive(Debug)] #[derive(Debug)]
/// Mutable data of encryption (distributed key generation) session. /// Mutable data of encryption (distributed key generation) session.
struct SessionData { struct SessionData {
@ -94,6 +104,8 @@ struct SessionData {
master: Option<NodeId>, master: Option<NodeId>,
/// Public key of requestor. /// Public key of requestor.
requestor: Option<Public>, requestor: Option<Public>,
/// Is shadow decryption requested?
is_shadow_decryption: Option<bool>,
// === Values, filled during session initialization === // === Values, filled during session initialization ===
/// Nodes, which have been requested for decryption initialization. /// Nodes, which have been requested for decryption initialization.
@ -105,11 +117,11 @@ struct SessionData {
// === Values, filled during partial decryption === // === Values, filled during partial decryption ===
/// Shadow points, received from nodes as a response to partial decryption request. /// Shadow points, received from nodes as a response to partial decryption request.
shadow_points: BTreeMap<NodeId, Public>, shadow_points: BTreeMap<NodeId, PartialDecryptionResult>,
/// === Values, filled during final decryption === /// === Values, filled during final decryption ===
/// Decrypted secret /// Decrypted secret
decrypted_secret: Option<Result<Public, Error>>, decrypted_secret: Option<Result<DocumentEncryptedKeyShadow, Error>>,
} }
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
@ -146,6 +158,7 @@ impl SessionImpl {
state: SessionState::WaitingForInitialization, state: SessionState::WaitingForInitialization,
master: None, master: None,
requestor: None, requestor: None,
is_shadow_decryption: None,
requested_nodes: BTreeSet::new(), requested_nodes: BTreeSet::new(),
rejected_nodes: BTreeSet::new(), rejected_nodes: BTreeSet::new(),
confirmed_nodes: BTreeSet::new(), confirmed_nodes: BTreeSet::new(),
@ -174,12 +187,12 @@ impl SessionImpl {
#[cfg(test)] #[cfg(test)]
/// Get decrypted secret /// Get decrypted secret
pub fn decrypted_secret(&self) -> Option<Public> { pub fn decrypted_secret(&self) -> Option<DocumentEncryptedKeyShadow> {
self.data.lock().decrypted_secret.clone().and_then(|r| r.ok()) self.data.lock().decrypted_secret.clone().and_then(|r| r.ok())
} }
/// Initialize decryption session. /// Initialize decryption session.
pub fn initialize(&self, requestor_signature: Signature) -> Result<(), Error> { pub fn initialize(&self, requestor_signature: Signature, is_shadow_decryption: bool) -> Result<(), Error> {
let mut data = self.data.lock(); let mut data = self.data.lock();
// check state // check state
@ -194,6 +207,7 @@ impl SessionImpl {
data.master = Some(self.node().clone()); data.master = Some(self.node().clone());
data.state = SessionState::WaitingForInitializationConfirm; data.state = SessionState::WaitingForInitializationConfirm;
data.requestor = Some(requestor_public.clone()); data.requestor = Some(requestor_public.clone());
data.is_shadow_decryption = Some(is_shadow_decryption);
data.requested_nodes.extend(self.encrypted_data.id_numbers.keys().cloned()); data.requested_nodes.extend(self.encrypted_data.id_numbers.keys().cloned());
// ..and finally check access on our's own // ..and finally check access on our's own
@ -209,6 +223,7 @@ impl SessionImpl {
session: self.id.clone().into(), session: self.id.clone().into(),
sub_session: self.access_key.clone().into(), sub_session: self.access_key.clone().into(),
requestor_signature: requestor_signature.clone().into(), requestor_signature: requestor_signature.clone().into(),
is_shadow_decryption: is_shadow_decryption,
})))?; })))?;
} }
}, },
@ -249,6 +264,7 @@ impl SessionImpl {
data.state = if is_requestor_allowed_to_read { SessionState::WaitingForPartialDecryptionRequest } data.state = if is_requestor_allowed_to_read { SessionState::WaitingForPartialDecryptionRequest }
else { SessionState::Failed }; else { SessionState::Failed };
data.requestor = Some(requestor_public); data.requestor = Some(requestor_public);
data.is_shadow_decryption = Some(message.is_shadow_decryption);
// respond to master node // respond to master node
data.master = Some(sender.clone()); data.master = Some(sender.clone());
@ -316,14 +332,17 @@ impl SessionImpl {
} }
// calculate shadow point // calculate shadow point
let shadow_point = { let decryption_result = {
let requestor = data.requestor.as_ref().expect("requestor public is filled during initialization; WaitingForPartialDecryptionRequest follows initialization; qed"); let requestor = data.requestor.as_ref().expect("requestor public is filled during initialization; WaitingForPartialDecryptionRequest follows initialization; qed");
do_partial_decryption(self.node(), &requestor, &message.nodes.iter().cloned().map(Into::into).collect(), &self.access_key, &self.encrypted_data)? let is_shadow_decryption = data.is_shadow_decryption.expect("is_shadow_decryption is filled during initialization; WaitingForPartialDecryptionRequest follows initialization; qed");
let nodes = message.nodes.iter().cloned().map(Into::into).collect();
do_partial_decryption(self.node(), &requestor, is_shadow_decryption, &nodes, &self.access_key, &self.encrypted_data)?
}; };
self.cluster.send(&sender, Message::Decryption(DecryptionMessage::PartialDecryption(PartialDecryption { self.cluster.send(&sender, Message::Decryption(DecryptionMessage::PartialDecryption(PartialDecryption {
session: self.id.clone().into(), session: self.id.clone().into(),
sub_session: self.access_key.clone().into(), sub_session: self.access_key.clone().into(),
shadow_point: shadow_point.into(), shadow_point: decryption_result.shadow_point.into(),
decrypt_shadow: decryption_result.decrypt_shadow,
})))?; })))?;
// update sate // update sate
@ -348,7 +367,10 @@ impl SessionImpl {
if !data.confirmed_nodes.remove(&sender) { if !data.confirmed_nodes.remove(&sender) {
return Err(Error::InvalidStateForRequest); return Err(Error::InvalidStateForRequest);
} }
data.shadow_points.insert(sender, message.shadow_point.clone().into()); data.shadow_points.insert(sender, PartialDecryptionResult {
shadow_point: message.shadow_point.clone().into(),
decrypt_shadow: message.decrypt_shadow.clone(),
});
// check if we have enough shadow points to decrypt the secret // check if we have enough shadow points to decrypt the secret
if data.shadow_points.len() != self.encrypted_data.threshold + 1 { if data.shadow_points.len() != self.encrypted_data.threshold + 1 {
@ -390,22 +412,38 @@ impl SessionImpl {
})))?; })))?;
} }
assert!(data.confirmed_nodes.remove(&self_node_id)); if data.confirmed_nodes.remove(&self_node_id) {
let decryption_result = {
let shadow_point = { let requestor = data.requestor.as_ref().expect("requestor public is filled during initialization; WaitingForPartialDecryption follows initialization; qed");
let requestor = data.requestor.as_ref().expect("requestor public is filled during initialization; WaitingForPartialDecryption follows initialization; qed"); let is_shadow_decryption = data.is_shadow_decryption.expect("is_shadow_decryption is filled during initialization; WaitingForPartialDecryption follows initialization; qed");
do_partial_decryption(&self_node_id, &requestor, &data.confirmed_nodes, &access_key, &encrypted_data)? do_partial_decryption(&self_node_id, &requestor, is_shadow_decryption, &data.confirmed_nodes, &access_key, &encrypted_data)?
}; };
data.shadow_points.insert(self_node_id.clone(), shadow_point); data.shadow_points.insert(self_node_id.clone(), decryption_result);
}
Ok(()) Ok(())
} }
fn do_decryption(access_key: Secret, encrypted_data: &DocumentKeyShare, data: &mut SessionData) -> Result<(), Error> { fn do_decryption(access_key: Secret, encrypted_data: &DocumentKeyShare, data: &mut SessionData) -> Result<(), Error> {
// decrypt the secret using shadow points // decrypt the secret using shadow points
let joint_shadow_point = math::compute_joint_shadow_point(data.shadow_points.values())?; let joint_shadow_point = math::compute_joint_shadow_point(data.shadow_points.values().map(|s| &s.shadow_point))?;
let decrypted_secret = math::decrypt_with_joint_shadow(encrypted_data.threshold, &access_key, &encrypted_data.encrypted_point, &joint_shadow_point)?; let decrypted_secret = math::decrypt_with_joint_shadow(encrypted_data.threshold, &access_key, &encrypted_data.encrypted_point, &joint_shadow_point)?;
data.decrypted_secret = Some(Ok(decrypted_secret)); let is_shadow_decryption = data.is_shadow_decryption.expect("is_shadow_decryption is filled during initialization; decryption follows initialization; qed");
let (common_point, decrypt_shadows) = if is_shadow_decryption {
(
Some(math::make_common_shadow_point(encrypted_data.threshold, encrypted_data.common_point.clone())?),
Some(data.shadow_points.values()
.map(|s| s.decrypt_shadow.as_ref().expect("decrypt_shadow is filled during partial decryption; decryption follows partial decryption; qed").clone())
.collect())
)
} else {
(None, None)
};
data.decrypted_secret = Some(Ok(DocumentEncryptedKeyShadow {
decrypted_secret: decrypted_secret,
common_point: common_point,
decrypt_shadows: decrypt_shadows,
}));
// switch to completed state // switch to completed state
data.state = SessionState::Finished; data.state = SessionState::Finished;
@ -415,7 +453,7 @@ impl SessionImpl {
} }
impl Session for SessionImpl { impl Session for SessionImpl {
fn wait(&self) -> Result<Public, Error> { fn wait(&self) -> Result<DocumentEncryptedKeyShadow, Error> {
let mut data = self.data.lock(); let mut data = self.data.lock();
if !data.decrypted_secret.is_some() { if !data.decrypted_secret.is_some() {
self.completed.wait(&mut data); self.completed.wait(&mut data);
@ -492,15 +530,22 @@ fn process_initialization_response(encrypted_data: &DocumentKeyShare, data: &mut
Ok(()) Ok(())
} }
fn do_partial_decryption(node: &NodeId, _requestor_public: &Public, participants: &BTreeSet<NodeId>, access_key: &Secret, encrypted_data: &DocumentKeyShare) -> Result<Public, Error> { fn do_partial_decryption(node: &NodeId, requestor_public: &Public, is_shadow_decryption: bool, participants: &BTreeSet<NodeId>, access_key: &Secret, encrypted_data: &DocumentKeyShare) -> Result<PartialDecryptionResult, Error> {
let node_id_number = &encrypted_data.id_numbers[node]; let node_id_number = &encrypted_data.id_numbers[node];
let node_secret_share = &encrypted_data.secret_share; let node_secret_share = &encrypted_data.secret_share;
let other_id_numbers = participants.iter() let other_id_numbers = participants.iter()
.filter(|id| *id != node) .filter(|id| *id != node)
.map(|id| &encrypted_data.id_numbers[id]); .map(|id| &encrypted_data.id_numbers[id]);
// TODO: commutative encryption using _requestor_public
let node_shadow = math::compute_node_shadow(node_id_number, node_secret_share, other_id_numbers)?; let node_shadow = math::compute_node_shadow(node_id_number, node_secret_share, other_id_numbers)?;
math::compute_node_shadow_point(access_key, &encrypted_data.common_point, &node_shadow) let decrypt_shadow = if is_shadow_decryption { Some(math::generate_random_scalar()?) } else { None };
let (shadow_point, decrypt_shadow) = math::compute_node_shadow_point(access_key, &encrypted_data.common_point, &node_shadow, decrypt_shadow)?;
Ok(PartialDecryptionResult {
shadow_point: shadow_point,
decrypt_shadow: match decrypt_shadow {
None => None,
Some(decrypt_shadow) => Some(encrypt_single_message(requestor_public, &**decrypt_shadow)?),
},
})
} }
#[cfg(test)] #[cfg(test)]
@ -509,10 +554,11 @@ mod tests {
use std::collections::BTreeMap; use std::collections::BTreeMap;
use super::super::super::acl_storage::tests::DummyAclStorage; use super::super::super::acl_storage::tests::DummyAclStorage;
use ethkey::{self, Random, Generator, Public, Secret}; use ethkey::{self, Random, Generator, Public, Secret};
use key_server_cluster::{NodeId, DocumentKeyShare, SessionId, Error}; use key_server_cluster::{NodeId, DocumentKeyShare, SessionId, Error, DocumentEncryptedKeyShadow};
use key_server_cluster::cluster::tests::DummyCluster; use key_server_cluster::cluster::tests::DummyCluster;
use key_server_cluster::decryption_session::{SessionImpl, SessionParams, SessionState}; use key_server_cluster::decryption_session::{SessionImpl, SessionParams, SessionState};
use key_server_cluster::message::{self, Message, DecryptionMessage}; use key_server_cluster::message::{self, Message, DecryptionMessage};
use key_server_cluster::math;
const SECRET_PLAIN: &'static str = "d2b57ae7619e070af0af6bc8c703c0cd27814c54d5d6a999cacac0da34ede279ca0d9216e85991029e54e2f0c92ee0bd30237725fa765cbdbfc4529489864c5f"; const SECRET_PLAIN: &'static str = "d2b57ae7619e070af0af6bc8c703c0cd27814c54d5d6a999cacac0da34ede279ca0d9216e85991029e54e2f0c92ee0bd30237725fa765cbdbfc4529489864c5f";
@ -660,18 +706,19 @@ mod tests {
#[test] #[test]
fn fails_to_initialize_when_already_initialized() { fn fails_to_initialize_when_already_initialized() {
let (_, _, sessions) = prepare_decryption_sessions(); let (_, _, sessions) = prepare_decryption_sessions();
assert_eq!(sessions[0].initialize(ethkey::sign(Random.generate().unwrap().secret(), &SessionId::default()).unwrap()).unwrap(), ()); assert_eq!(sessions[0].initialize(ethkey::sign(Random.generate().unwrap().secret(), &SessionId::default()).unwrap(), false).unwrap(), ());
assert_eq!(sessions[0].initialize(ethkey::sign(Random.generate().unwrap().secret(), &SessionId::default()).unwrap()).unwrap_err(), Error::InvalidStateForRequest); assert_eq!(sessions[0].initialize(ethkey::sign(Random.generate().unwrap().secret(), &SessionId::default()).unwrap(), false).unwrap_err(), Error::InvalidStateForRequest);
} }
#[test] #[test]
fn fails_to_accept_initialization_when_already_initialized() { fn fails_to_accept_initialization_when_already_initialized() {
let (_, _, sessions) = prepare_decryption_sessions(); let (_, _, sessions) = prepare_decryption_sessions();
assert_eq!(sessions[0].initialize(ethkey::sign(Random.generate().unwrap().secret(), &SessionId::default()).unwrap()).unwrap(), ()); assert_eq!(sessions[0].initialize(ethkey::sign(Random.generate().unwrap().secret(), &SessionId::default()).unwrap(), false).unwrap(), ());
assert_eq!(sessions[0].on_initialize_session(sessions[1].node().clone(), &message::InitializeDecryptionSession { assert_eq!(sessions[0].on_initialize_session(sessions[1].node().clone(), &message::InitializeDecryptionSession {
session: SessionId::default().into(), session: SessionId::default().into(),
sub_session: sessions[0].access_key().clone().into(), sub_session: sessions[0].access_key().clone().into(),
requestor_signature: ethkey::sign(Random.generate().unwrap().secret(), &SessionId::default()).unwrap().into(), requestor_signature: ethkey::sign(Random.generate().unwrap().secret(), &SessionId::default()).unwrap().into(),
is_shadow_decryption: false,
}).unwrap_err(), Error::InvalidStateForRequest); }).unwrap_err(), Error::InvalidStateForRequest);
} }
@ -682,6 +729,7 @@ mod tests {
session: SessionId::default().into(), session: SessionId::default().into(),
sub_session: sessions[0].access_key().clone().into(), sub_session: sessions[0].access_key().clone().into(),
requestor_signature: ethkey::sign(Random.generate().unwrap().secret(), &SessionId::default()).unwrap().into(), requestor_signature: ethkey::sign(Random.generate().unwrap().secret(), &SessionId::default()).unwrap().into(),
is_shadow_decryption: false,
}).unwrap(), ()); }).unwrap(), ());
assert_eq!(sessions[1].on_partial_decryption_requested(sessions[0].node().clone(), &message::RequestPartialDecryption { assert_eq!(sessions[1].on_partial_decryption_requested(sessions[0].node().clone(), &message::RequestPartialDecryption {
session: SessionId::default().into(), session: SessionId::default().into(),
@ -702,6 +750,7 @@ mod tests {
session: SessionId::default().into(), session: SessionId::default().into(),
sub_session: sessions[0].access_key().clone().into(), sub_session: sessions[0].access_key().clone().into(),
requestor_signature: ethkey::sign(Random.generate().unwrap().secret(), &SessionId::default()).unwrap().into(), requestor_signature: ethkey::sign(Random.generate().unwrap().secret(), &SessionId::default()).unwrap().into(),
is_shadow_decryption: false,
}).unwrap(), ()); }).unwrap(), ());
assert_eq!(sessions[1].on_partial_decryption_requested(sessions[2].node().clone(), &message::RequestPartialDecryption { assert_eq!(sessions[1].on_partial_decryption_requested(sessions[2].node().clone(), &message::RequestPartialDecryption {
session: SessionId::default().into(), session: SessionId::default().into(),
@ -717,6 +766,7 @@ mod tests {
session: SessionId::default().into(), session: SessionId::default().into(),
sub_session: sessions[0].access_key().clone().into(), sub_session: sessions[0].access_key().clone().into(),
requestor_signature: ethkey::sign(Random.generate().unwrap().secret(), &SessionId::default()).unwrap().into(), requestor_signature: ethkey::sign(Random.generate().unwrap().secret(), &SessionId::default()).unwrap().into(),
is_shadow_decryption: false,
}).unwrap(), ()); }).unwrap(), ());
assert_eq!(sessions[1].on_partial_decryption_requested(sessions[0].node().clone(), &message::RequestPartialDecryption { assert_eq!(sessions[1].on_partial_decryption_requested(sessions[0].node().clone(), &message::RequestPartialDecryption {
session: SessionId::default().into(), session: SessionId::default().into(),
@ -732,13 +782,14 @@ mod tests {
session: SessionId::default().into(), session: SessionId::default().into(),
sub_session: sessions[0].access_key().clone().into(), sub_session: sessions[0].access_key().clone().into(),
shadow_point: Random.generate().unwrap().public().clone().into(), shadow_point: Random.generate().unwrap().public().clone().into(),
decrypt_shadow: None,
}).unwrap_err(), Error::InvalidStateForRequest); }).unwrap_err(), Error::InvalidStateForRequest);
} }
#[test] #[test]
fn fails_to_accept_partial_decrypt_twice() { fn fails_to_accept_partial_decrypt_twice() {
let (clusters, _, sessions) = prepare_decryption_sessions(); let (clusters, _, sessions) = prepare_decryption_sessions();
sessions[0].initialize(ethkey::sign(Random.generate().unwrap().secret(), &SessionId::default()).unwrap()).unwrap(); sessions[0].initialize(ethkey::sign(Random.generate().unwrap().secret(), &SessionId::default()).unwrap(), false).unwrap();
let mut pd_from = None; let mut pd_from = None;
let mut pd_msg = None; let mut pd_msg = None;
@ -762,7 +813,7 @@ mod tests {
// now let's try to do a decryption // now let's try to do a decryption
let key_pair = Random.generate().unwrap(); let key_pair = Random.generate().unwrap();
let signature = ethkey::sign(key_pair.secret(), &SessionId::default()).unwrap(); let signature = ethkey::sign(key_pair.secret(), &SessionId::default()).unwrap();
sessions[0].initialize(signature).unwrap(); sessions[0].initialize(signature, false).unwrap();
do_messages_exchange(&clusters, &sessions); do_messages_exchange(&clusters, &sessions);
@ -773,7 +824,45 @@ mod tests {
assert_eq!(sessions.iter().filter(|s| s.state() == SessionState::WaitingForPartialDecryptionRequest).count(), 1); assert_eq!(sessions.iter().filter(|s| s.state() == SessionState::WaitingForPartialDecryptionRequest).count(), 1);
// 3) 1 session has decrypted key value // 3) 1 session has decrypted key value
assert!(sessions.iter().skip(1).all(|s| s.decrypted_secret().is_none())); assert!(sessions.iter().skip(1).all(|s| s.decrypted_secret().is_none()));
assert_eq!(sessions[0].decrypted_secret(), Some(SECRET_PLAIN.into())); assert_eq!(sessions[0].decrypted_secret(), Some(DocumentEncryptedKeyShadow {
decrypted_secret: SECRET_PLAIN.into(),
common_point: None,
decrypt_shadows: None,
}));
}
#[test]
fn complete_shadow_dec_session() {
let (clusters, _, sessions) = prepare_decryption_sessions();
// now let's try to do a decryption
let key_pair = Random.generate().unwrap();
let signature = ethkey::sign(key_pair.secret(), &SessionId::default()).unwrap();
sessions[0].initialize(signature, true).unwrap();
do_messages_exchange(&clusters, &sessions);
// now check that:
// 1) 4 of 5 sessions are in Finished state
assert_eq!(sessions.iter().filter(|s| s.state() == SessionState::Finished).count(), 4);
// 2) 1 session is in WaitingForPartialDecryptionRequest state
assert_eq!(sessions.iter().filter(|s| s.state() == SessionState::WaitingForPartialDecryptionRequest).count(), 1);
// 3) 1 session has decrypted key value
assert!(sessions.iter().skip(1).all(|s| s.decrypted_secret().is_none()));
let decrypted_secret = sessions[0].decrypted_secret().unwrap();
// check that decrypted_secret != SECRET_PLAIN
assert!(decrypted_secret.decrypted_secret != SECRET_PLAIN.into());
// check that common point && shadow coefficients are returned
assert!(decrypted_secret.common_point.is_some());
assert!(decrypted_secret.decrypt_shadows.is_some());
// check that KS client is able to restore original secret
use ethcrypto::ecies::decrypt_single_message;
let decrypt_shadows: Vec<_> = decrypted_secret.decrypt_shadows.unwrap().into_iter()
.map(|c| Secret::from_slice(&decrypt_single_message(key_pair.secret(), &c).unwrap()).unwrap())
.collect();
let decrypted_secret = math::decrypt_with_shadow_coefficients(decrypted_secret.decrypted_secret, decrypted_secret.common_point.unwrap(), decrypt_shadows).unwrap();
assert_eq!(decrypted_secret, SECRET_PLAIN.into());
} }
#[test] #[test]
@ -783,7 +872,7 @@ mod tests {
// now let's try to do a decryption // now let's try to do a decryption
let key_pair = Random.generate().unwrap(); let key_pair = Random.generate().unwrap();
let signature = ethkey::sign(key_pair.secret(), &SessionId::default()).unwrap(); let signature = ethkey::sign(key_pair.secret(), &SessionId::default()).unwrap();
sessions[0].initialize(signature).unwrap(); sessions[0].initialize(signature, false).unwrap();
// we need 4 out of 5 nodes to agree to do a decryption // we need 4 out of 5 nodes to agree to do a decryption
// let's say that 2 of these nodes are disagree // let's say that 2 of these nodes are disagree
@ -801,6 +890,33 @@ mod tests {
assert!(sessions.iter().all(|s| s.decrypted_secret().is_none())); assert!(sessions.iter().all(|s| s.decrypted_secret().is_none()));
} }
#[test]
fn complete_dec_session_with_acl_check_failed_on_master() {
let (clusters, acl_storages, sessions) = prepare_decryption_sessions();
// we need 4 out of 5 nodes to agree to do a decryption
// let's say that 1 of these nodes (master) is disagree
let key_pair = Random.generate().unwrap();
acl_storages[0].prohibit(key_pair.public().clone(), SessionId::default());
// now let's try to do a decryption
let signature = ethkey::sign(key_pair.secret(), &SessionId::default()).unwrap();
sessions[0].initialize(signature, false).unwrap();
do_messages_exchange(&clusters, &sessions);
// now check that:
// 1) 4 of 5 sessions are in Finished state
assert_eq!(sessions.iter().filter(|s| s.state() == SessionState::Finished).count(), 5);
// 2) 1 session has decrypted key value
assert!(sessions.iter().skip(1).all(|s| s.decrypted_secret().is_none()));
assert_eq!(sessions[0].decrypted_secret(), Some(DocumentEncryptedKeyShadow {
decrypted_secret: SECRET_PLAIN.into(),
common_point: None,
decrypt_shadows: None,
}));
}
#[test] #[test]
fn decryption_session_works_over_network() { fn decryption_session_works_over_network() {
// TODO // TODO

View File

@ -17,21 +17,22 @@
use std::io; use std::io;
use std::collections::BTreeSet; use std::collections::BTreeSet;
use futures::{Future, Poll, Async}; use futures::{Future, Poll, Async};
use tokio_io::{AsyncRead, AsyncWrite};
use ethkey::{Random, Generator, KeyPair, Secret, sign, verify_public}; use ethkey::{Random, Generator, KeyPair, Secret, sign, verify_public};
use util::H256; use util::H256;
use key_server_cluster::{NodeId, Error}; use key_server_cluster::{NodeId, Error};
use key_server_cluster::message::{Message, ClusterMessage, NodePublicKey, NodePrivateKeySignature}; use key_server_cluster::message::{Message, ClusterMessage, NodePublicKey, NodePrivateKeySignature};
use key_server_cluster::io::{write_message, write_encrypted_message, WriteMessage, ReadMessage, use key_server_cluster::io::{write_message, write_encrypted_message, WriteMessage, ReadMessage,
read_message, compute_shared_key}; read_message, read_encrypted_message, compute_shared_key};
/// Start handshake procedure with another node from the cluster. /// Start handshake procedure with another node from the cluster.
pub fn handshake<A>(a: A, self_key_pair: KeyPair, trusted_nodes: BTreeSet<NodeId>) -> Handshake<A> where A: io::Write + io::Read { pub fn handshake<A>(a: A, self_key_pair: KeyPair, trusted_nodes: BTreeSet<NodeId>) -> Handshake<A> where A: AsyncWrite + AsyncRead {
let self_confirmation_plain = Random.generate().map(|kp| *kp.secret().clone()).map_err(Into::into); let self_confirmation_plain = Random.generate().map(|kp| *kp.secret().clone()).map_err(Into::into);
handshake_with_plain_confirmation(a, self_confirmation_plain, self_key_pair, trusted_nodes) handshake_with_plain_confirmation(a, self_confirmation_plain, self_key_pair, trusted_nodes)
} }
/// Start handshake procedure with another node from the cluster and given plain confirmation. /// Start handshake procedure with another node from the cluster and given plain confirmation.
pub fn handshake_with_plain_confirmation<A>(a: A, self_confirmation_plain: Result<H256, Error>, self_key_pair: KeyPair, trusted_nodes: BTreeSet<NodeId>) -> Handshake<A> where A: io::Write + io::Read { pub fn handshake_with_plain_confirmation<A>(a: A, self_confirmation_plain: Result<H256, Error>, self_key_pair: KeyPair, trusted_nodes: BTreeSet<NodeId>) -> Handshake<A> where A: AsyncWrite + AsyncRead {
let (error, state) = match self_confirmation_plain.clone() let (error, state) = match self_confirmation_plain.clone()
.and_then(|c| Handshake::<A>::make_public_key_message(self_key_pair.public().clone(), c)) { .and_then(|c| Handshake::<A>::make_public_key_message(self_key_pair.public().clone(), c)) {
Ok(message) => (None, HandshakeState::SendPublicKey(write_message(a, message))), Ok(message) => (None, HandshakeState::SendPublicKey(write_message(a, message))),
@ -52,7 +53,7 @@ pub fn handshake_with_plain_confirmation<A>(a: A, self_confirmation_plain: Resul
} }
/// Wait for handshake procedure to be started by another node from the cluster. /// Wait for handshake procedure to be started by another node from the cluster.
pub fn accept_handshake<A>(a: A, self_key_pair: KeyPair, trusted_nodes: BTreeSet<NodeId>) -> Handshake<A> where A: io::Write + io::Read { pub fn accept_handshake<A>(a: A, self_key_pair: KeyPair, trusted_nodes: BTreeSet<NodeId>) -> Handshake<A> where A: AsyncWrite + AsyncRead {
let self_confirmation_plain = Random.generate().map(|kp| *kp.secret().clone()).map_err(Into::into); let self_confirmation_plain = Random.generate().map(|kp| *kp.secret().clone()).map_err(Into::into);
let (error, state) = match self_confirmation_plain.clone() { let (error, state) = match self_confirmation_plain.clone() {
Ok(_) => (None, HandshakeState::ReceivePublicKey(read_message(a))), Ok(_) => (None, HandshakeState::ReceivePublicKey(read_message(a))),
@ -78,7 +79,7 @@ pub struct HandshakeResult {
/// Node id. /// Node id.
pub node_id: NodeId, pub node_id: NodeId,
/// Shared key. /// Shared key.
pub shared_key: Secret, pub shared_key: KeyPair,
} }
/// Future handshake procedure. /// Future handshake procedure.
@ -91,7 +92,7 @@ pub struct Handshake<A> {
trusted_nodes: BTreeSet<NodeId>, trusted_nodes: BTreeSet<NodeId>,
other_node_id: Option<NodeId>, other_node_id: Option<NodeId>,
other_confirmation_plain: Option<H256>, other_confirmation_plain: Option<H256>,
shared_key: Option<Secret>, shared_key: Option<KeyPair>,
} }
/// Active handshake state. /// Active handshake state.
@ -103,7 +104,7 @@ enum HandshakeState<A> {
Finished, Finished,
} }
impl<A> Handshake<A> where A: io::Read + io::Write { impl<A> Handshake<A> where A: AsyncRead + AsyncWrite {
#[cfg(test)] #[cfg(test)]
pub fn set_self_confirmation_plain(&mut self, self_confirmation_plain: H256) { pub fn set_self_confirmation_plain(&mut self, self_confirmation_plain: H256) {
self.self_confirmation_plain = self_confirmation_plain; self.self_confirmation_plain = self_confirmation_plain;
@ -123,7 +124,7 @@ impl<A> Handshake<A> where A: io::Read + io::Write {
} }
} }
impl<A> Future for Handshake<A> where A: io::Read + io::Write { impl<A> Future for Handshake<A> where A: AsyncRead + AsyncWrite {
type Item = (A, Result<HandshakeResult, Error>); type Item = (A, Result<HandshakeResult, Error>);
type Error = io::Error; type Error = io::Error;
@ -207,7 +208,9 @@ impl<A> Future for Handshake<A> where A: io::Read + io::Write {
let (stream, _) = try_ready!(future.poll()); let (stream, _) = try_ready!(future.poll());
(HandshakeState::ReceivePrivateKeySignature( (HandshakeState::ReceivePrivateKeySignature(
read_message(stream) read_encrypted_message(stream,
self.shared_key.as_ref().expect("shared_key is filled in Send/ReceivePublicKey; SendPrivateKeySignature follows Send/ReceivePublicKey; qed").clone()
)
), Async::NotReady) ), Async::NotReady)
}, },
HandshakeState::ReceivePrivateKeySignature(ref mut future) => { HandshakeState::ReceivePrivateKeySignature(ref mut future) => {
@ -247,9 +250,9 @@ impl<A> Future for Handshake<A> where A: io::Read + io::Write {
mod tests { mod tests {
use std::collections::BTreeSet; use std::collections::BTreeSet;
use futures::Future; use futures::Future;
use ethcrypto::ecdh::agree;
use ethkey::{Random, Generator, sign}; use ethkey::{Random, Generator, sign};
use util::H256; use util::H256;
use key_server_cluster::io::message::compute_shared_key;
use key_server_cluster::io::message::tests::TestIo; use key_server_cluster::io::message::tests::TestIo;
use key_server_cluster::message::{Message, ClusterMessage, NodePublicKey, NodePrivateKeySignature}; use key_server_cluster::message::{Message, ClusterMessage, NodePublicKey, NodePrivateKeySignature};
use super::{handshake_with_plain_confirmation, accept_handshake, HandshakeResult}; use super::{handshake_with_plain_confirmation, accept_handshake, HandshakeResult};
@ -263,24 +266,15 @@ mod tests {
let peer_confirmation_plain = *Random.generate().unwrap().secret().clone(); let peer_confirmation_plain = *Random.generate().unwrap().secret().clone();
let self_confirmation_signed = sign(peer_key_pair.secret(), &self_confirmation_plain).unwrap(); let self_confirmation_signed = sign(peer_key_pair.secret(), &self_confirmation_plain).unwrap();
let peer_confirmation_signed = sign(self_key_pair.secret(), &peer_confirmation_plain).unwrap();
io.add_input_message(Message::Cluster(ClusterMessage::NodePublicKey(NodePublicKey { io.add_input_message(Message::Cluster(ClusterMessage::NodePublicKey(NodePublicKey {
node_id: peer_key_pair.public().clone().into(), node_id: peer_key_pair.public().clone().into(),
confirmation_plain: peer_confirmation_plain.into(), confirmation_plain: peer_confirmation_plain.into(),
}))); })));
io.add_input_message(Message::Cluster(ClusterMessage::NodePrivateKeySignature(NodePrivateKeySignature { io.add_encrypted_input_message(Message::Cluster(ClusterMessage::NodePrivateKeySignature(NodePrivateKeySignature {
confirmation_signed: self_confirmation_signed.into(), confirmation_signed: self_confirmation_signed.into(),
}))); })));
io.add_output_message(Message::Cluster(ClusterMessage::NodePublicKey(NodePublicKey {
node_id: self_key_pair.public().clone().into(),
confirmation_plain: self_confirmation_plain.clone().into(),
})));
io.add_output_message(Message::Cluster(ClusterMessage::NodePrivateKeySignature(NodePrivateKeySignature {
confirmation_signed: peer_confirmation_signed.into(),
})));
(self_confirmation_plain, io) (self_confirmation_plain, io)
} }
@ -289,7 +283,7 @@ mod tests {
let (self_confirmation_plain, io) = prepare_test_io(); let (self_confirmation_plain, io) = prepare_test_io();
let self_key_pair = io.self_key_pair().clone(); let self_key_pair = io.self_key_pair().clone();
let trusted_nodes: BTreeSet<_> = vec![io.peer_public().clone()].into_iter().collect(); let trusted_nodes: BTreeSet<_> = vec![io.peer_public().clone()].into_iter().collect();
let shared_key = agree(self_key_pair.secret(), trusted_nodes.iter().nth(0).unwrap()).unwrap(); let shared_key = compute_shared_key(self_key_pair.secret(), trusted_nodes.iter().nth(0).unwrap()).unwrap();
let handshake = handshake_with_plain_confirmation(io, Ok(self_confirmation_plain), self_key_pair, trusted_nodes); let handshake = handshake_with_plain_confirmation(io, Ok(self_confirmation_plain), self_key_pair, trusted_nodes);
let handshake_result = handshake.wait().unwrap(); let handshake_result = handshake.wait().unwrap();
@ -297,7 +291,6 @@ mod tests {
node_id: handshake_result.0.peer_public().clone(), node_id: handshake_result.0.peer_public().clone(),
shared_key: shared_key, shared_key: shared_key,
})); }));
handshake_result.0.assert_output();
} }
#[test] #[test]
@ -305,7 +298,7 @@ mod tests {
let (self_confirmation_plain, io) = prepare_test_io(); let (self_confirmation_plain, io) = prepare_test_io();
let self_key_pair = io.self_key_pair().clone(); let self_key_pair = io.self_key_pair().clone();
let trusted_nodes: BTreeSet<_> = vec![io.peer_public().clone()].into_iter().collect(); let trusted_nodes: BTreeSet<_> = vec![io.peer_public().clone()].into_iter().collect();
let shared_key = agree(self_key_pair.secret(), io.peer_public()).unwrap(); let shared_key = compute_shared_key(self_key_pair.secret(), trusted_nodes.iter().nth(0).unwrap()).unwrap();
let mut handshake = accept_handshake(io, self_key_pair, trusted_nodes); let mut handshake = accept_handshake(io, self_key_pair, trusted_nodes);
handshake.set_self_confirmation_plain(self_confirmation_plain); handshake.set_self_confirmation_plain(self_confirmation_plain);
@ -315,6 +308,5 @@ mod tests {
node_id: handshake_result.0.peer_public().clone(), node_id: handshake_result.0.peer_public().clone(),
shared_key: shared_key, shared_key: shared_key,
})); }));
handshake_result.0.assert_output();
} }
} }

View File

@ -20,7 +20,10 @@ use std::ops::Deref;
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use serde_json; use serde_json;
use ethcrypto::ecdh::agree; use ethcrypto::ecdh::agree;
use ethkey::{Public, Secret}; use ethcrypto::ecies::{encrypt_single_message, decrypt_single_message};
use ethkey::{Public, Secret, KeyPair};
use ethkey::math::curve_order;
use util::{H256, U256};
use key_server_cluster::Error; use key_server_cluster::Error;
use key_server_cluster::message::{Message, ClusterMessage, EncryptionMessage, DecryptionMessage}; use key_server_cluster::message::{Message, ClusterMessage, EncryptionMessage, DecryptionMessage};
@ -82,20 +85,11 @@ pub fn serialize_message(message: Message) -> Result<SerializedMessage, Error> {
}; };
let payload = payload.map_err(|err| Error::Serde(err.to_string()))?; let payload = payload.map_err(|err| Error::Serde(err.to_string()))?;
let payload_len = payload.len(); build_serialized_message(MessageHeader {
if payload_len > u16::MAX as usize {
return Err(Error::InvalidMessage);
}
let header = MessageHeader {
kind: message_kind, kind: message_kind,
version: 1, version: 1,
size: payload_len as u16, size: 0,
}; }, payload)
let mut serialized_message = serialize_header(&header)?;
serialized_message.extend(payload);
Ok(SerializedMessage(serialized_message))
} }
/// Deserialize message. /// Deserialize message.
@ -127,18 +121,30 @@ pub fn deserialize_message(header: &MessageHeader, payload: Vec<u8>) -> Result<M
} }
/// Encrypt serialized message. /// Encrypt serialized message.
pub fn encrypt_message(_key: &Secret, message: SerializedMessage) -> Result<SerializedMessage, Error> { pub fn encrypt_message(key: &KeyPair, message: SerializedMessage) -> Result<SerializedMessage, Error> {
Ok(message) // TODO: implement me let mut header: Vec<_> = message.into();
let payload = header.split_off(MESSAGE_HEADER_SIZE);
let encrypted_payload = encrypt_single_message(key.public(), &payload)?;
let header = deserialize_header(&header)?;
build_serialized_message(header, encrypted_payload)
} }
/// Decrypt serialized message. /// Decrypt serialized message.
pub fn decrypt_message(_key: &Secret, payload: Vec<u8>) -> Result<Vec<u8>, Error> { pub fn decrypt_message(key: &KeyPair, payload: Vec<u8>) -> Result<Vec<u8>, Error> {
Ok(payload) // TODO: implement me Ok(decrypt_single_message(key.secret(), &payload)?)
} }
/// Compute shared encryption key. /// Compute shared encryption key.
pub fn compute_shared_key(self_secret: &Secret, other_public: &Public) -> Result<Secret, Error> { pub fn compute_shared_key(self_secret: &Secret, other_public: &Public) -> Result<KeyPair, Error> {
Ok(agree(self_secret, other_public)?) // secret key created in agree function is invalid, as it is not calculated mod EC.field.n
// => let's do it manually
let shared_secret = agree(self_secret, other_public)?;
let shared_secret: H256 = (*shared_secret).into();
let shared_secret: U256 = shared_secret.into();
let shared_secret: H256 = (shared_secret % curve_order()).into();
let shared_key_pair = KeyPair::from_secret_slice(&*shared_secret)?;
Ok(shared_key_pair)
} }
/// Serialize message header. /// Serialize message header.
@ -160,29 +166,44 @@ pub fn deserialize_header(data: &[u8]) -> Result<MessageHeader, Error> {
}) })
} }
/// Build serialized message from header && payload
fn build_serialized_message(mut header: MessageHeader, payload: Vec<u8>) -> Result<SerializedMessage, Error> {
let payload_len = payload.len();
if payload_len > u16::MAX as usize {
return Err(Error::InvalidMessage);
}
header.size = payload.len() as u16;
let mut message = serialize_header(&header)?;
message.extend(payload);
Ok(SerializedMessage(message))
}
#[cfg(test)] #[cfg(test)]
pub mod tests { pub mod tests {
use std::io; use std::io;
use futures::Poll;
use tokio_io::{AsyncRead, AsyncWrite};
use ethkey::{KeyPair, Public}; use ethkey::{KeyPair, Public};
use key_server_cluster::message::Message; use key_server_cluster::message::Message;
use super::{MESSAGE_HEADER_SIZE, MessageHeader, serialize_message, serialize_header, deserialize_header}; use super::{MESSAGE_HEADER_SIZE, MessageHeader, compute_shared_key, encrypt_message, serialize_message,
serialize_header, deserialize_header};
pub struct TestIo { pub struct TestIo {
self_key_pair: KeyPair, self_key_pair: KeyPair,
peer_public: Public, peer_public: Public,
shared_key_pair: KeyPair,
input_buffer: io::Cursor<Vec<u8>>, input_buffer: io::Cursor<Vec<u8>>,
output_buffer: Vec<u8>,
expected_output_buffer: Vec<u8>,
} }
impl TestIo { impl TestIo {
pub fn new(self_key_pair: KeyPair, peer_public: Public) -> Self { pub fn new(self_key_pair: KeyPair, peer_public: Public) -> Self {
let shared_key_pair = compute_shared_key(self_key_pair.secret(), &peer_public).unwrap();
TestIo { TestIo {
self_key_pair: self_key_pair, self_key_pair: self_key_pair,
peer_public: peer_public, peer_public: peer_public,
shared_key_pair: shared_key_pair,
input_buffer: io::Cursor::new(Vec::new()), input_buffer: io::Cursor::new(Vec::new()),
output_buffer: Vec::new(),
expected_output_buffer: Vec::new(),
} }
} }
@ -203,14 +224,21 @@ pub mod tests {
} }
} }
pub fn add_output_message(&mut self, message: Message) { pub fn add_encrypted_input_message(&mut self, message: Message) {
let serialized_message = serialize_message(message).unwrap(); let serialized_message = encrypt_message(&self.shared_key_pair, serialize_message(message).unwrap()).unwrap();
let serialized_message: Vec<_> = serialized_message.into(); let serialized_message: Vec<_> = serialized_message.into();
self.expected_output_buffer.extend(serialized_message); let input_buffer = self.input_buffer.get_mut();
for b in serialized_message {
input_buffer.push(b);
}
} }
}
pub fn assert_output(&self) { impl AsyncRead for TestIo {}
assert_eq!(self.output_buffer, self.expected_output_buffer);
impl AsyncWrite for TestIo {
fn shutdown(&mut self) -> Poll<(), io::Error> {
Ok(().into())
} }
} }
@ -222,11 +250,11 @@ pub mod tests {
impl io::Write for TestIo { impl io::Write for TestIo {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> { fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
io::Write::write(&mut self.output_buffer, buf) Ok(buf.len())
} }
fn flush(&mut self) -> io::Result<()> { fn flush(&mut self) -> io::Result<()> {
io::Write::flush(&mut self.output_buffer) Ok(())
} }
} }

View File

@ -16,12 +16,13 @@
use std::io; use std::io;
use futures::{Future, Poll, Async}; use futures::{Future, Poll, Async};
use tokio_core::io::{ReadExact, read_exact}; use tokio_io::AsyncRead;
use tokio_io::io::{ReadExact, read_exact};
use key_server_cluster::Error; use key_server_cluster::Error;
use key_server_cluster::io::message::{MESSAGE_HEADER_SIZE, MessageHeader, deserialize_header}; use key_server_cluster::io::message::{MESSAGE_HEADER_SIZE, MessageHeader, deserialize_header};
/// Create future for read single message header from the stream. /// Create future for read single message header from the stream.
pub fn read_header<A>(a: A) -> ReadHeader<A> where A: io::Read { pub fn read_header<A>(a: A) -> ReadHeader<A> where A: AsyncRead {
ReadHeader { ReadHeader {
reader: read_exact(a, [0; MESSAGE_HEADER_SIZE]), reader: read_exact(a, [0; MESSAGE_HEADER_SIZE]),
} }
@ -32,7 +33,7 @@ pub struct ReadHeader<A> {
reader: ReadExact<A, [u8; MESSAGE_HEADER_SIZE]>, reader: ReadExact<A, [u8; MESSAGE_HEADER_SIZE]>,
} }
impl<A> Future for ReadHeader<A> where A: io::Read { impl<A> Future for ReadHeader<A> where A: AsyncRead {
type Item = (A, Result<MessageHeader, Error>); type Item = (A, Result<MessageHeader, Error>);
type Error = io::Error; type Error = io::Error;

View File

@ -16,13 +16,14 @@
use std::io; use std::io;
use futures::{Poll, Future, Async}; use futures::{Poll, Future, Async};
use ethkey::Secret; use tokio_io::AsyncRead;
use ethkey::KeyPair;
use key_server_cluster::Error; use key_server_cluster::Error;
use key_server_cluster::message::Message; use key_server_cluster::message::Message;
use key_server_cluster::io::{read_header, ReadHeader, read_payload, read_encrypted_payload, ReadPayload}; use key_server_cluster::io::{read_header, ReadHeader, read_payload, read_encrypted_payload, ReadPayload};
/// Create future for read single message from the stream. /// Create future for read single message from the stream.
pub fn read_message<A>(a: A) -> ReadMessage<A> where A: io::Read { pub fn read_message<A>(a: A) -> ReadMessage<A> where A: AsyncRead {
ReadMessage { ReadMessage {
key: None, key: None,
state: ReadMessageState::ReadHeader(read_header(a)), state: ReadMessageState::ReadHeader(read_header(a)),
@ -30,7 +31,7 @@ pub fn read_message<A>(a: A) -> ReadMessage<A> where A: io::Read {
} }
/// Create future for read single encrypted message from the stream. /// Create future for read single encrypted message from the stream.
pub fn read_encrypted_message<A>(a: A, key: Secret) -> ReadMessage<A> where A: io::Read { pub fn read_encrypted_message<A>(a: A, key: KeyPair) -> ReadMessage<A> where A: AsyncRead {
ReadMessage { ReadMessage {
key: Some(key), key: Some(key),
state: ReadMessageState::ReadHeader(read_header(a)), state: ReadMessageState::ReadHeader(read_header(a)),
@ -45,11 +46,11 @@ enum ReadMessageState<A> {
/// Future for read single message from the stream. /// Future for read single message from the stream.
pub struct ReadMessage<A> { pub struct ReadMessage<A> {
key: Option<Secret>, key: Option<KeyPair>,
state: ReadMessageState<A>, state: ReadMessageState<A>,
} }
impl<A> Future for ReadMessage<A> where A: io::Read { impl<A> Future for ReadMessage<A> where A: AsyncRead {
type Item = (A, Result<Message, Error>); type Item = (A, Result<Message, Error>);
type Error = io::Error; type Error = io::Error;

View File

@ -16,14 +16,15 @@
use std::io; use std::io;
use futures::{Poll, Future}; use futures::{Poll, Future};
use tokio_core::io::{read_exact, ReadExact}; use tokio_io::AsyncRead;
use ethkey::Secret; use tokio_io::io::{read_exact, ReadExact};
use ethkey::KeyPair;
use key_server_cluster::Error; use key_server_cluster::Error;
use key_server_cluster::message::Message; use key_server_cluster::message::Message;
use key_server_cluster::io::message::{MessageHeader, deserialize_message, decrypt_message}; use key_server_cluster::io::message::{MessageHeader, deserialize_message, decrypt_message};
/// Create future for read single message payload from the stream. /// Create future for read single message payload from the stream.
pub fn read_payload<A>(a: A, header: MessageHeader) -> ReadPayload<A> where A: io::Read { pub fn read_payload<A>(a: A, header: MessageHeader) -> ReadPayload<A> where A: AsyncRead {
ReadPayload { ReadPayload {
reader: read_exact(a, vec![0; header.size as usize]), reader: read_exact(a, vec![0; header.size as usize]),
header: header, header: header,
@ -32,7 +33,7 @@ pub fn read_payload<A>(a: A, header: MessageHeader) -> ReadPayload<A> where A: i
} }
/// Create future for read single encrypted message payload from the stream. /// Create future for read single encrypted message payload from the stream.
pub fn read_encrypted_payload<A>(a: A, header: MessageHeader, key: Secret) -> ReadPayload<A> where A: io::Read { pub fn read_encrypted_payload<A>(a: A, header: MessageHeader, key: KeyPair) -> ReadPayload<A> where A: AsyncRead {
ReadPayload { ReadPayload {
reader: read_exact(a, vec![0; header.size as usize]), reader: read_exact(a, vec![0; header.size as usize]),
header: header, header: header,
@ -44,10 +45,10 @@ pub fn read_encrypted_payload<A>(a: A, header: MessageHeader, key: Secret) -> Re
pub struct ReadPayload<A> { pub struct ReadPayload<A> {
reader: ReadExact<A, Vec<u8>>, reader: ReadExact<A, Vec<u8>>,
header: MessageHeader, header: MessageHeader,
key: Option<Secret>, key: Option<KeyPair>,
} }
impl<A> Future for ReadPayload<A> where A: io::Read { impl<A> Future for ReadPayload<A> where A: AsyncRead {
type Item = (A, Result<Message, Error>); type Item = (A, Result<Message, Error>);
type Error = io::Error; type Error = io::Error;

View File

@ -15,7 +15,10 @@
// 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; use std::sync::Arc;
use std::net::Shutdown;
use std::io::{Read, Write, Error}; use std::io::{Read, Write, Error};
use futures::Poll;
use tokio_io::{AsyncRead, AsyncWrite};
use tokio_core::net::TcpStream; use tokio_core::net::TcpStream;
/// Read+Write implementation for Arc<TcpStream>. /// Read+Write implementation for Arc<TcpStream>.
@ -37,6 +40,14 @@ impl From<TcpStream> for SharedTcpStream {
} }
} }
impl AsyncRead for SharedTcpStream {}
impl AsyncWrite for SharedTcpStream {
fn shutdown(&mut self) -> Poll<(), Error> {
self.io.shutdown(Shutdown::Both).map(Into::into)
}
}
impl Read for SharedTcpStream { impl Read for SharedTcpStream {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> { fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
Read::read(&mut (&*self.io as &TcpStream), buf) Read::read(&mut (&*self.io as &TcpStream), buf)

View File

@ -16,13 +16,14 @@
use std::io; use std::io;
use futures::{Future, Poll}; use futures::{Future, Poll};
use tokio_core::io::{WriteAll, write_all}; use tokio_io::AsyncWrite;
use ethkey::Secret; use tokio_io::io::{WriteAll, write_all};
use ethkey::KeyPair;
use key_server_cluster::message::Message; use key_server_cluster::message::Message;
use key_server_cluster::io::{serialize_message, encrypt_message}; use key_server_cluster::io::{serialize_message, encrypt_message};
/// Write plain message to the channel. /// Write plain message to the channel.
pub fn write_message<A>(a: A, message: Message) -> WriteMessage<A> where A: io::Write { pub fn write_message<A>(a: A, message: Message) -> WriteMessage<A> where A: AsyncWrite {
let (error, future) = match serialize_message(message) let (error, future) = match serialize_message(message)
.map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string())) { .map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string())) {
Ok(message) => (None, write_all(a, message.into())), Ok(message) => (None, write_all(a, message.into())),
@ -35,7 +36,7 @@ pub fn write_message<A>(a: A, message: Message) -> WriteMessage<A> where A: io::
} }
/// Write encrypted message to the channel. /// Write encrypted message to the channel.
pub fn write_encrypted_message<A>(a: A, key: &Secret, message: Message) -> WriteMessage<A> where A: io::Write { pub fn write_encrypted_message<A>(a: A, key: &KeyPair, message: Message) -> WriteMessage<A> where A: AsyncWrite {
let (error, future) = match serialize_message(message) let (error, future) = match serialize_message(message)
.and_then(|message| encrypt_message(key, message)) .and_then(|message| encrypt_message(key, message))
.map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string())) { .map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string())) {
@ -56,7 +57,7 @@ pub struct WriteMessage<A> {
future: WriteAll<A, Vec<u8>>, future: WriteAll<A, Vec<u8>>,
} }
impl<A> Future for WriteMessage<A> where A: io::Write { impl<A> Future for WriteMessage<A> where A: AsyncWrite {
type Item = (A, Vec<u8>); type Item = (A, Vec<u8>);
type Error = io::Error; type Error = io::Error;

View File

@ -203,12 +203,24 @@ pub fn compute_node_shadow<'a, I>(node_number: &Secret, node_secret_share: &Secr
} }
/// Compute shadow point for the node. /// Compute shadow point for the node.
pub fn compute_node_shadow_point(access_key: &Secret, common_point: &Public, node_shadow: &Secret) -> Result<Public, Error> { pub fn compute_node_shadow_point(access_key: &Secret, common_point: &Public, node_shadow: &Secret, decrypt_shadow: Option<Secret>) -> Result<(Public, Option<Secret>), Error> {
let mut shadow_key = access_key.clone(); let mut shadow_key = node_shadow.clone();
shadow_key.mul(node_shadow)?; let decrypt_shadow = match decrypt_shadow {
None => None,
Some(mut decrypt_shadow) => {
// update shadow key
shadow_key.mul(&decrypt_shadow)?;
// now udate decrypt shadow itself
decrypt_shadow.dec()?;
decrypt_shadow.mul(node_shadow)?;
Some(decrypt_shadow)
}
};
shadow_key.mul(access_key)?;
let mut node_shadow_point = common_point.clone(); let mut node_shadow_point = common_point.clone();
math::public_mul_secret(&mut node_shadow_point, &shadow_key)?; math::public_mul_secret(&mut node_shadow_point, &shadow_key)?;
Ok(node_shadow_point) Ok((node_shadow_point, decrypt_shadow))
} }
/// Compute joint shadow point. /// Compute joint shadow point.
@ -252,6 +264,28 @@ pub fn decrypt_with_joint_shadow(threshold: usize, access_key: &Secret, encrypte
Ok(decrypted_point) Ok(decrypted_point)
} }
/// Prepare common point for shadow decryption.
pub fn make_common_shadow_point(threshold: usize, mut common_point: Public) -> Result<Public, Error> {
if threshold % 2 != 1 {
Ok(common_point)
} else {
math::public_negate(&mut common_point)?;
Ok(common_point)
}
}
#[cfg(test)]
/// Decrypt shadow-encrypted secret.
pub fn decrypt_with_shadow_coefficients(mut decrypted_shadow: Public, mut common_shadow_point: Public, shadow_coefficients: Vec<Secret>) -> Result<Public, Error> {
let mut shadow_coefficients_sum = shadow_coefficients[0].clone();
for shadow_coefficient in shadow_coefficients.iter().skip(1) {
shadow_coefficients_sum.add(shadow_coefficient)?;
}
math::public_mul_secret(&mut common_shadow_point, &shadow_coefficients_sum)?;
math::public_add(&mut decrypted_shadow, &common_shadow_point)?;
Ok(decrypted_shadow)
}
#[cfg(test)] #[cfg(test)]
/// Decrypt data using joint secret (version for tests). /// Decrypt data using joint secret (version for tests).
pub fn decrypt_with_joint_secret(encrypted_point: &Public, common_point: &Public, joint_secret: &Secret) -> Result<Public, Error> { pub fn decrypt_with_joint_secret(encrypted_point: &Public, common_point: &Public, joint_secret: &Secret) -> Result<Public, Error> {
@ -287,7 +321,10 @@ pub mod tests {
.filter(|&(j, _)| j != i) .filter(|&(j, _)| j != i)
.take(t) .take(t)
.map(|(_, id_number)| id_number)).unwrap()).collect(); .map(|(_, id_number)| id_number)).unwrap()).collect();
let nodes_shadow_points: Vec<_> = nodes_shadows.iter().map(|s| compute_node_shadow_point(&access_key, &encrypted_secret.common_point, s).unwrap()).collect(); let nodes_shadow_points: Vec<_> = nodes_shadows.iter()
.map(|s| compute_node_shadow_point(&access_key, &encrypted_secret.common_point, s, None).unwrap())
.map(|sp| sp.0)
.collect();
assert_eq!(nodes_shadows.len(), t + 1); assert_eq!(nodes_shadows.len(), t + 1);
assert_eq!(nodes_shadow_points.len(), t + 1); assert_eq!(nodes_shadow_points.len(), t + 1);

View File

@ -218,6 +218,9 @@ pub struct InitializeDecryptionSession {
pub sub_session: SerializableSecret, pub sub_session: SerializableSecret,
/// Requestor signature. /// Requestor signature.
pub requestor_signature: SerializableSignature, pub requestor_signature: SerializableSignature,
/// Is shadow decryption requested? When true, decryption result
/// will be visible to the owner of requestor public key only.
pub is_shadow_decryption: bool,
} }
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
@ -251,6 +254,8 @@ pub struct PartialDecryption {
pub sub_session: SerializableSecret, pub sub_session: SerializableSecret,
/// Partially decrypted secret. /// Partially decrypted secret.
pub shadow_point: SerializablePublic, pub shadow_point: SerializablePublic,
/// Decrypt shadow coefficient (if requested), encrypted with requestor public.
pub decrypt_shadow: Option<Vec<u8>>,
} }
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]

View File

@ -20,7 +20,7 @@ use ethkey;
use ethcrypto; use ethcrypto;
use super::types::all::DocumentAddress; use super::types::all::DocumentAddress;
pub use super::types::all::{NodeId, EncryptionConfiguration}; pub use super::types::all::{NodeId, EncryptionConfiguration, DocumentEncryptedKeyShadow};
pub use super::acl_storage::AclStorage; pub use super::acl_storage::AclStorage;
pub use super::key_storage::{KeyStorage, DocumentKeyShare}; pub use super::key_storage::{KeyStorage, DocumentKeyShare};
pub use super::serialization::{SerializableSignature, SerializableH256, SerializableSecret, SerializablePublic}; pub use super::serialization::{SerializableSignature, SerializableH256, SerializableSecret, SerializablePublic};

View File

@ -15,7 +15,7 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::net; use std::net;
use ethkey::Secret; use ethkey::KeyPair;
use key_server_cluster::NodeId; use key_server_cluster::NodeId;
use key_server_cluster::io::SharedTcpStream; use key_server_cluster::io::SharedTcpStream;
@ -28,5 +28,5 @@ pub struct Connection {
/// Peer node id. /// Peer node id.
pub node_id: NodeId, pub node_id: NodeId,
/// Encryption key. /// Encryption key.
pub key: Secret, pub key: KeyPair,
} }

View File

@ -43,6 +43,8 @@ pub trait KeyStorage: Send + Sync {
fn insert(&self, document: DocumentAddress, key: DocumentKeyShare) -> Result<(), Error>; fn insert(&self, document: DocumentAddress, key: DocumentKeyShare) -> Result<(), Error>;
/// Get document encryption key /// Get document encryption key
fn get(&self, document: &DocumentAddress) -> Result<DocumentKeyShare, Error>; fn get(&self, document: &DocumentAddress) -> Result<DocumentKeyShare, Error>;
/// Check if storage contains document encryption key
fn contains(&self, document: &DocumentAddress) -> bool;
} }
/// Persistent document encryption keys storage /// Persistent document encryption keys storage
@ -95,6 +97,12 @@ impl KeyStorage for PersistentKeyStorage {
.and_then(|key| serde_json::from_slice::<SerializableDocumentKeyShare>(&key).map_err(|e| Error::Database(e.to_string()))) .and_then(|key| serde_json::from_slice::<SerializableDocumentKeyShare>(&key).map_err(|e| Error::Database(e.to_string())))
.map(Into::into) .map(Into::into)
} }
fn contains(&self, document: &DocumentAddress) -> bool {
self.db.get(None, document)
.map(|k| k.is_some())
.unwrap_or(false)
}
} }
impl From<DocumentKeyShare> for SerializableDocumentKeyShare { impl From<DocumentKeyShare> for SerializableDocumentKeyShare {
@ -146,6 +154,10 @@ pub mod tests {
fn get(&self, document: &DocumentAddress) -> Result<DocumentKeyShare, Error> { fn get(&self, document: &DocumentAddress) -> Result<DocumentKeyShare, Error> {
self.keys.read().get(document).cloned().ok_or(Error::DocumentNotFound) self.keys.read().get(document).cloned().ok_or(Error::DocumentNotFound)
} }
fn contains(&self, document: &DocumentAddress) -> bool {
self.keys.read().contains_key(document)
}
} }
#[test] #[test]

View File

@ -27,6 +27,7 @@ extern crate serde;
extern crate serde_json; extern crate serde_json;
#[macro_use] #[macro_use]
extern crate serde_derive; extern crate serde_derive;
extern crate tokio_io;
extern crate tokio_core; extern crate tokio_core;
extern crate tokio_service; extern crate tokio_service;
extern crate tokio_proto; extern crate tokio_proto;

View File

@ -17,11 +17,62 @@
use std::fmt; use std::fmt;
use std::cmp::{Ord, PartialOrd, Ordering}; use std::cmp::{Ord, PartialOrd, Ordering};
use std::ops::Deref; use std::ops::Deref;
use rustc_serialize::hex::ToHex; use rustc_serialize::hex::{ToHex, FromHex};
use serde::{Serialize, Deserialize, Serializer, Deserializer}; use serde::{Serialize, Deserialize, Serializer, Deserializer};
use serde::de::{Visitor, Error as SerdeError}; use serde::de::{Visitor, Error as SerdeError};
use ethkey::{Public, Secret, Signature}; use ethkey::{Public, Secret, Signature};
use util::H256; use util::{H256, Bytes};
#[derive(Clone, Debug, Serialize, Deserialize)]
/// Serializable shadow decryption result.
pub struct SerializableDocumentEncryptedKeyShadow {
/// Decrypted secret point. It is partially decrypted if shadow decrpytion was requested.
pub decrypted_secret: SerializablePublic,
/// Shared common point.
pub common_point: SerializablePublic,
/// If shadow decryption was requested: shadow decryption coefficients, encrypted with requestor public.
pub decrypt_shadows: Vec<SerializableBytes>,
}
#[derive(Clone, Debug)]
/// Serializable Bytes.
pub struct SerializableBytes(Bytes);
impl<T> From<T> for SerializableBytes where Bytes: From<T> {
fn from(s: T) -> SerializableBytes {
SerializableBytes(s.into())
}
}
impl Into<Bytes> for SerializableBytes {
fn into(self) -> Bytes {
self.0
}
}
impl Deref for SerializableBytes {
type Target = Bytes;
fn deref(&self) -> &Bytes {
&self.0
}
}
impl Serialize for SerializableBytes {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
serializer.serialize_str(&(*self.0).to_hex())
}
}
impl Deserialize for SerializableBytes {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer
{
let s = String::deserialize(deserializer)?;
let data = s.from_hex().map_err(SerdeError::custom)?;
Ok(SerializableBytes(data))
}
}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
/// Serializable Signature. /// Serializable Signature.

View File

@ -14,7 +14,7 @@
// 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 types::all::{Error, RequestSignature, DocumentAddress, DocumentEncryptedKey}; use types::all::{Error, RequestSignature, DocumentAddress, DocumentEncryptedKey, DocumentEncryptedKeyShadow};
#[ipc(client_ident="RemoteKeyServer")] #[ipc(client_ident="RemoteKeyServer")]
/// Secret store key server /// Secret store key server
@ -23,4 +23,12 @@ pub trait KeyServer: Send + Sync {
fn generate_document_key(&self, signature: &RequestSignature, document: &DocumentAddress, threshold: usize) -> Result<DocumentEncryptedKey, Error>; fn generate_document_key(&self, signature: &RequestSignature, document: &DocumentAddress, threshold: usize) -> Result<DocumentEncryptedKey, Error>;
/// Request encryption key of given document for given requestor /// Request encryption key of given document for given requestor
fn document_key(&self, signature: &RequestSignature, document: &DocumentAddress) -> Result<DocumentEncryptedKey, Error>; fn document_key(&self, signature: &RequestSignature, document: &DocumentAddress) -> Result<DocumentEncryptedKey, Error>;
/// Request encryption key of given document for given requestor.
/// This method does not reveal document_key to any KeyServer, but it requires additional actions on client.
/// To calculate decrypted key on client:
/// 1) use requestor secret key to decrypt secret coefficients from result.decrypt_shadows
/// 2) calculate decrypt_shadows_sum = sum of all secrets from (1)
/// 3) calculate decrypt_shadow_point: decrypt_shadows_sum * result.common_point
/// 4) calculate decrypted_secret: result.decrypted_secret + decrypt_shadow_point
fn document_key_shadow(&self, signature: &RequestSignature, document: &DocumentAddress) -> Result<DocumentEncryptedKeyShadow, Error>;
} }

View File

@ -50,7 +50,7 @@ pub enum Error {
Internal(String), Internal(String),
} }
#[derive(Debug)] #[derive(Debug, Clone)]
#[binary] #[binary]
/// Secret store configuration /// Secret store configuration
pub struct NodeAddress { pub struct NodeAddress {
@ -99,6 +99,18 @@ pub struct EncryptionConfiguration {
pub key_check_timeout_ms: u64, pub key_check_timeout_ms: u64,
} }
#[derive(Clone, Debug, PartialEq)]
#[binary]
/// Shadow decryption result.
pub struct DocumentEncryptedKeyShadow {
/// Decrypted secret point. It is partially decrypted if shadow decrpytion was requested.
pub decrypted_secret: ethkey::Public,
/// Shared common point.
pub common_point: Option<ethkey::Public>,
/// If shadow decryption was requested: shadow decryption coefficients, encrypted with requestor public.
pub decrypt_shadows: Option<Vec<Vec<u8>>>,
}
impl fmt::Display for Error { impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self { match *self {

View File

@ -23,11 +23,11 @@ use traits::Encodable;
struct ListInfo { struct ListInfo {
position: usize, position: usize,
current: usize, current: usize,
max: usize, max: Option<usize>,
} }
impl ListInfo { impl ListInfo {
fn new(position: usize, max: usize) -> ListInfo { fn new(position: usize, max: Option<usize>) -> ListInfo {
ListInfo { ListInfo {
position: position, position: position,
current: 0, current: 0,
@ -133,7 +133,7 @@ impl RlpStream {
self.buffer.push(0); self.buffer.push(0);
let position = self.buffer.len(); let position = self.buffer.len();
self.unfinished_lists.push(ListInfo::new(position, len)); self.unfinished_lists.push(ListInfo::new(position, Some(len)));
}, },
} }
@ -141,6 +141,19 @@ impl RlpStream {
self self
} }
/// Declare appending the list of unknown size, chainable.
pub fn begin_unbounded_list(&mut self) -> &mut RlpStream {
self.finished_list = false;
// payload is longer than 1 byte only for lists > 55 bytes
// by pushing always this 1 byte we may avoid unnecessary shift of data
self.buffer.push(0);
let position = self.buffer.len();
self.unfinished_lists.push(ListInfo::new(position, None));
// return chainable self
self
}
/// Apends null to the end of stream, chainable. /// Apends null to the end of stream, chainable.
/// ///
/// ```rust /// ```rust
@ -177,6 +190,36 @@ impl RlpStream {
self self
} }
/// Appends raw (pre-serialised) RLP data. Checks for size oveflow.
pub fn append_raw_checked<'a>(&'a mut self, bytes: &[u8], item_count: usize, max_size: usize) -> bool {
if self.estimate_size(bytes.len()) > max_size {
return false;
}
self.append_raw(bytes, item_count);
true
}
/// Calculate total RLP size for appended payload.
pub fn estimate_size<'a>(&'a self, add: usize) -> usize {
let total_size = self.buffer.len() + add;
let mut base_size = total_size;
for list in &self.unfinished_lists[..] {
let len = total_size - list.position;
if len > 55 {
let leading_empty_bytes = (len as u64).leading_zeros() as usize / 8;
let size_bytes = 8 - leading_empty_bytes;
base_size += size_bytes;
}
}
base_size
}
/// Returns current RLP size in bytes for the data pushed into the list.
pub fn len<'a>(&'a self) -> usize {
self.estimate_size(0)
}
/// Clear the output stream so far. /// Clear the output stream so far.
/// ///
/// ```rust /// ```rust
@ -246,10 +289,11 @@ impl RlpStream {
None => false, None => false,
Some(ref mut x) => { Some(ref mut x) => {
x.current += inserted_items; x.current += inserted_items;
if x.current > x.max { match x.max {
panic!("You cannot append more items then you expect!"); Some(ref max) if x.current > *max => panic!("You cannot append more items then you expect!"),
Some(ref max) => x.current == *max,
_ => false,
} }
x.current == x.max
} }
}; };
@ -273,6 +317,17 @@ impl RlpStream {
false => panic!() false => panic!()
} }
} }
/// Finalize current ubnbound list. Panics if no unbounded list has been opened.
pub fn complete_unbounded_list(&mut self) {
let list = self.unfinished_lists.pop().expect("No open list.");
if list.max.is_some() {
panic!("List type mismatch.");
}
let len = self.buffer.len() - list.position;
self.encoder().insert_list_payload(len, list.position);
self.note_appended(1);
}
} }
pub struct BasicEncoder<'a> { pub struct BasicEncoder<'a> {

View File

@ -412,3 +412,25 @@ fn test_rlp_list_length_overflow() {
let as_val: Result<String, DecoderError> = rlp.val_at(0); let as_val: Result<String, DecoderError> = rlp.val_at(0);
assert_eq!(Err(DecoderError::RlpIsTooShort), as_val); assert_eq!(Err(DecoderError::RlpIsTooShort), as_val);
} }
#[test]
fn test_rlp_stream_size_limit() {
for limit in 40 .. 270 {
let item = [0u8; 1];
let mut stream = RlpStream::new();
while stream.append_raw_checked(&item, 1, limit) {}
assert_eq!(stream.drain().len(), limit);
}
}
#[test]
fn test_rlp_stream_unbounded_list() {
let mut stream = RlpStream::new();
stream.begin_unbounded_list();
stream.append(&40u32);
stream.append(&41u32);
assert!(!stream.is_finished());
stream.complete_unbounded_list();
assert!(stream.is_finished());
}